blob: 77f21e068da0e710a11d0fd2a370b9015458ff63 [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02008 */
9/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10/*
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; version 2 of the License.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 NO WARRANTY
21 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
22 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
23 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
24 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
25 solely responsible for determining the appropriateness of using and
26 distributing the Program and assumes all risks associated with its
27 exercise of rights under this Agreement, including but not limited to
28 the risks and costs of program errors, damage to or loss of data,
29 programs or equipment, and unavailability or interruption of operations.
30
31 DISCLAIMER OF LIABILITY
32 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
33 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
35 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
38 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43*/
44/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
45
46#include <linux/module.h>
47#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090048#include <linux/slab.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020049#include <linux/init.h>
50#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080051#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020052#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060053#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020054
Eric Moore547f9a22006-06-27 14:42:12 -060055#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020056#include <scsi/scsi_cmnd.h>
57#include <scsi/scsi_device.h>
58#include <scsi/scsi_host.h>
59#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060060#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020061
62#include "mptbase.h"
63#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053064#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020065
66
67#define my_NAME "Fusion MPT SAS Host driver"
68#define my_VERSION MPT_LINUX_VERSION_COMMON
69#define MYNAM "mptsas"
70
James Bottomleye8bf3942006-07-11 17:49:34 -040071/*
72 * Reserved channel for integrated raid
73 */
74#define MPTSAS_RAID_CHANNEL 1
75
Kashyap, Desai4b976502009-08-05 12:52:03 +053076#define SAS_CONFIG_PAGE_TIMEOUT 30
Christoph Hellwig0c33b272005-09-09 16:27:19 +020077MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070080MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020081
Christoph Hellwig0c33b272005-09-09 16:27:19 +020082static int mpt_pt_clear;
83module_param(mpt_pt_clear, int, 0);
84MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060085 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020086 "(default=MPTSCSIH_PT_CLEAR=0)");
87
Eric Moore793955f2007-01-29 09:42:20 -070088/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
89#define MPTSAS_MAX_LUN (16895)
90static int max_lun = MPTSAS_MAX_LUN;
91module_param(max_lun, int, 0);
92MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
93
Prakash, Sathyaf606f572007-08-14 16:12:53 +053094static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
96static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
97static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053098static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020099
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530100static void mptsas_firmware_event_work(struct work_struct *work);
101static void mptsas_send_sas_event(struct fw_event_work *fw_event);
102static void mptsas_send_raid_event(struct fw_event_work *fw_event);
103static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
104static void mptsas_parse_device_info(struct sas_identify *identify,
105 struct mptsas_devinfo *device_info);
106static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
107 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
108static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
109 (MPT_ADAPTER *ioc, u64 sas_address);
110static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
111 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
112static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
113 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
114static int mptsas_add_end_device(MPT_ADAPTER *ioc,
115 struct mptsas_phyinfo *phy_info);
116static void mptsas_del_end_device(MPT_ADAPTER *ioc,
117 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530118static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
119static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
120 (MPT_ADAPTER *ioc, u64 sas_address);
121static void mptsas_expander_delete(MPT_ADAPTER *ioc,
122 struct mptsas_portinfo *port_info, u8 force);
123static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530124static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
125static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530126static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530127static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530128static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200129
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530130static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
131 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200132{
Eric Moore29dd3602007-09-14 18:46:51 -0600133 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
134 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
135 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
136 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
137 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
138 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
139 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
140 ioc->name, phy_data->Port));
141 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
142 ioc->name, phy_data->PortFlags));
143 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
144 ioc->name, phy_data->PhyFlags));
145 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
146 ioc->name, phy_data->NegotiatedLinkRate));
147 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
148 "Controller PHY Device Info=0x%X\n", ioc->name,
149 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
150 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
151 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200152}
153
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530154static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200155{
156 __le64 sas_address;
157
158 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
159
Eric Moore29dd3602007-09-14 18:46:51 -0600160 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
161 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
162 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
163 "Attached Device Handle=0x%X\n", ioc->name,
164 le16_to_cpu(pg0->AttachedDevHandle)));
165 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
166 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
167 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
168 "Attached PHY Identifier=0x%X\n", ioc->name,
169 pg0->AttachedPhyIdentifier));
170 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
171 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
172 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
173 ioc->name, pg0->ProgrammedLinkRate));
174 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
175 ioc->name, pg0->ChangeCount));
176 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
177 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200178}
179
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530180static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200181{
Eric Moore29dd3602007-09-14 18:46:51 -0600182 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
183 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
184 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
185 ioc->name, pg1->InvalidDwordCount));
186 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
187 "Running Disparity Error Count=0x%x\n", ioc->name,
188 pg1->RunningDisparityErrorCount));
189 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
190 "Loss Dword Synch Count=0x%x\n", ioc->name,
191 pg1->LossDwordSynchCount));
192 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
193 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
194 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200195}
196
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530197static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200198{
199 __le64 sas_address;
200
201 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
202
Eric Moore29dd3602007-09-14 18:46:51 -0600203 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
204 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
205 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
206 ioc->name, le16_to_cpu(pg0->DevHandle)));
207 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
208 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
209 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
210 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
211 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
212 ioc->name, le16_to_cpu(pg0->Slot)));
213 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
214 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
215 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
216 ioc->name, pg0->TargetID));
217 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
218 ioc->name, pg0->Bus));
219 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
220 ioc->name, pg0->PhyNum));
221 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
222 ioc->name, le16_to_cpu(pg0->AccessStatus)));
223 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
224 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
225 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
226 ioc->name, le16_to_cpu(pg0->Flags)));
227 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
228 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200229}
230
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530231static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200232{
Eric Moore29dd3602007-09-14 18:46:51 -0600233 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
234 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
235 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
236 ioc->name, pg1->PhysicalPort));
237 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
238 ioc->name, pg1->PhyIdentifier));
239 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
240 ioc->name, pg1->NegotiatedLinkRate));
241 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
242 ioc->name, pg1->ProgrammedLinkRate));
243 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
244 ioc->name, pg1->HwLinkRate));
245 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
246 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
247 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
248 "Attached Device Handle=0x%X\n\n", ioc->name,
249 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200250}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200251
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530252/* inhibit sas firmware event handling */
253static void
254mptsas_fw_event_off(MPT_ADAPTER *ioc)
255{
256 unsigned long flags;
257
258 spin_lock_irqsave(&ioc->fw_event_lock, flags);
259 ioc->fw_events_off = 1;
260 ioc->sas_discovery_quiesce_io = 0;
261 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
262
263}
264
265/* enable sas firmware event handling */
266static void
267mptsas_fw_event_on(MPT_ADAPTER *ioc)
268{
269 unsigned long flags;
270
271 spin_lock_irqsave(&ioc->fw_event_lock, flags);
272 ioc->fw_events_off = 0;
273 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
274}
275
276/* queue a sas firmware event */
277static void
278mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
279 unsigned long delay)
280{
281 unsigned long flags;
282
283 spin_lock_irqsave(&ioc->fw_event_lock, flags);
284 list_add_tail(&fw_event->list, &ioc->fw_event_list);
285 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
286 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
287 ioc->name, __func__, fw_event));
288 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
289 delay);
290 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
291}
292
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530293/* requeue a sas firmware event */
294static void
295mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
296 unsigned long delay)
297{
298 unsigned long flags;
299 spin_lock_irqsave(&ioc->fw_event_lock, flags);
300 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
301 "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
302 fw_event->retries++;
303 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
304 msecs_to_jiffies(delay));
305 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
306}
307
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530308/* free memory assoicated to a sas firmware event */
309static void
310mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
311{
312 unsigned long flags;
313
314 spin_lock_irqsave(&ioc->fw_event_lock, flags);
315 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
316 ioc->name, __func__, fw_event));
317 list_del(&fw_event->list);
318 kfree(fw_event);
319 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
320}
321
322/* walk the firmware event queue, and either stop or wait for
323 * outstanding events to complete */
324static void
325mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
326{
327 struct fw_event_work *fw_event, *next;
328 struct mptsas_target_reset_event *target_reset_list, *n;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530329 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
330
331 /* flush the target_reset_list */
332 if (!list_empty(&hd->target_reset_list)) {
333 list_for_each_entry_safe(target_reset_list, n,
334 &hd->target_reset_list, list) {
335 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
336 "%s: removing target reset for id=%d\n",
337 ioc->name, __func__,
338 target_reset_list->sas_event_data.TargetID));
339 list_del(&target_reset_list->list);
340 kfree(target_reset_list);
341 }
342 }
343
344 if (list_empty(&ioc->fw_event_list) ||
345 !ioc->fw_event_q || in_interrupt())
346 return;
347
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530348 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
349 if (cancel_delayed_work(&fw_event->work))
350 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530351 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530352}
353
354
Christoph Hellwige3094442006-02-16 13:25:36 +0100355static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
356{
357 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
358 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
359}
360
361static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
362{
363 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
364 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
365}
366
Moore, Erice6b2d762006-03-14 09:14:24 -0700367/*
368 * mptsas_find_portinfo_by_handle
369 *
370 * This function should be called with the sas_topology_mutex already held
371 */
372static struct mptsas_portinfo *
373mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
374{
375 struct mptsas_portinfo *port_info, *rc=NULL;
376 int i;
377
378 list_for_each_entry(port_info, &ioc->sas_topology, list)
379 for (i = 0; i < port_info->num_phys; i++)
380 if (port_info->phy_info[i].identify.handle == handle) {
381 rc = port_info;
382 goto out;
383 }
384 out:
385 return rc;
386}
387
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530388/**
389 * mptsas_find_portinfo_by_sas_address -
390 * @ioc: Pointer to MPT_ADAPTER structure
391 * @handle:
392 *
393 * This function should be called with the sas_topology_mutex already held
394 *
395 **/
396static struct mptsas_portinfo *
397mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
398{
399 struct mptsas_portinfo *port_info, *rc = NULL;
400 int i;
401
402 if (sas_address >= ioc->hba_port_sas_addr &&
403 sas_address < (ioc->hba_port_sas_addr +
404 ioc->hba_port_num_phy))
405 return ioc->hba_port_info;
406
407 mutex_lock(&ioc->sas_topology_mutex);
408 list_for_each_entry(port_info, &ioc->sas_topology, list)
409 for (i = 0; i < port_info->num_phys; i++)
410 if (port_info->phy_info[i].identify.sas_address ==
411 sas_address) {
412 rc = port_info;
413 goto out;
414 }
415 out:
416 mutex_unlock(&ioc->sas_topology_mutex);
417 return rc;
418}
419
Moore, Ericbd23e942006-04-17 12:43:04 -0600420/*
421 * Returns true if there is a scsi end device
422 */
423static inline int
424mptsas_is_end_device(struct mptsas_devinfo * attached)
425{
Eric Moore547f9a22006-06-27 14:42:12 -0600426 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600427 (attached->device_info &
428 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
429 ((attached->device_info &
430 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
431 (attached->device_info &
432 MPI_SAS_DEVICE_INFO_STP_TARGET) |
433 (attached->device_info &
434 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
435 return 1;
436 else
437 return 0;
438}
439
Eric Moore547f9a22006-06-27 14:42:12 -0600440/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600441static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530442mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600443{
444 struct mptsas_portinfo *port_info;
445 struct mptsas_phyinfo *phy_info;
446 u8 i;
447
448 if (!port_details)
449 return;
450
451 port_info = port_details->port_info;
452 phy_info = port_info->phy_info;
453
Eric Moore29dd3602007-09-14 18:46:51 -0600454 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700455 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700456 port_details->num_phys, (unsigned long long)
457 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600458
459 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
460 if(phy_info->port_details != port_details)
461 continue;
462 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530463 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600464 phy_info->port_details = NULL;
465 }
466 kfree(port_details);
467}
468
469static inline struct sas_rphy *
470mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
471{
472 if (phy_info->port_details)
473 return phy_info->port_details->rphy;
474 else
475 return NULL;
476}
477
478static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530479mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600480{
481 if (phy_info->port_details) {
482 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600483 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
484 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600485 }
486
Eric Moore547f9a22006-06-27 14:42:12 -0600487 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600488 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
489 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600490 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
491 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600492 }
Eric Moore547f9a22006-06-27 14:42:12 -0600493}
494
495static inline struct sas_port *
496mptsas_get_port(struct mptsas_phyinfo *phy_info)
497{
498 if (phy_info->port_details)
499 return phy_info->port_details->port;
500 else
501 return NULL;
502}
503
504static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530505mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600506{
507 if (phy_info->port_details)
508 phy_info->port_details->port = port;
509
Eric Moore547f9a22006-06-27 14:42:12 -0600510 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600511 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
512 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600513 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
514 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600515 }
Eric Moore547f9a22006-06-27 14:42:12 -0600516}
517
518static inline struct scsi_target *
519mptsas_get_starget(struct mptsas_phyinfo *phy_info)
520{
521 if (phy_info->port_details)
522 return phy_info->port_details->starget;
523 else
524 return NULL;
525}
526
527static inline void
528mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
529starget)
530{
531 if (phy_info->port_details)
532 phy_info->port_details->starget = starget;
533}
534
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530535/**
536 * mptsas_add_device_component -
537 * @ioc: Pointer to MPT_ADAPTER structure
538 * @channel: fw mapped id's
539 * @id:
540 * @sas_address:
541 * @device_info:
542 *
543 **/
544static void
545mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
546 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
547{
548 struct mptsas_device_info *sas_info, *next;
549 struct scsi_device *sdev;
550 struct scsi_target *starget;
551 struct sas_rphy *rphy;
552
553 /*
554 * Delete all matching devices out of the list
555 */
556 mutex_lock(&ioc->sas_device_info_mutex);
557 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
558 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530559 if (!sas_info->is_logical_volume &&
560 (sas_info->sas_address == sas_address ||
561 (sas_info->fw.channel == channel &&
562 sas_info->fw.id == id))) {
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530563 list_del(&sas_info->list);
564 kfree(sas_info);
565 }
566 }
567
568 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
569 if (!sas_info)
570 goto out;
571
572 /*
573 * Set Firmware mapping
574 */
575 sas_info->fw.id = id;
576 sas_info->fw.channel = channel;
577
578 sas_info->sas_address = sas_address;
579 sas_info->device_info = device_info;
580 sas_info->slot = slot;
581 sas_info->enclosure_logical_id = enclosure_logical_id;
582 INIT_LIST_HEAD(&sas_info->list);
583 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
584
585 /*
586 * Set OS mapping
587 */
588 shost_for_each_device(sdev, ioc->sh) {
589 starget = scsi_target(sdev);
590 rphy = dev_to_rphy(starget->dev.parent);
591 if (rphy->identify.sas_address == sas_address) {
592 sas_info->os.id = starget->id;
593 sas_info->os.channel = starget->channel;
594 }
595 }
596
597 out:
598 mutex_unlock(&ioc->sas_device_info_mutex);
599 return;
600}
601
602/**
603 * mptsas_add_device_component_by_fw -
604 * @ioc: Pointer to MPT_ADAPTER structure
605 * @channel: fw mapped id's
606 * @id:
607 *
608 **/
609static void
610mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
611{
612 struct mptsas_devinfo sas_device;
613 struct mptsas_enclosure enclosure_info;
614 int rc;
615
616 rc = mptsas_sas_device_pg0(ioc, &sas_device,
617 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
618 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
619 (channel << 8) + id);
620 if (rc)
621 return;
622
623 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
624 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
625 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
626 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
627 sas_device.handle_enclosure);
628
629 mptsas_add_device_component(ioc, sas_device.channel,
630 sas_device.id, sas_device.sas_address, sas_device.device_info,
631 sas_device.slot, enclosure_info.enclosure_logical_id);
632}
633
634/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000635 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530636 * @ioc: Pointer to MPT_ADAPTER structure
637 * @channel: fw mapped id's
638 * @id:
639 *
640 **/
641static void
642mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
643 struct scsi_target *starget)
644{
645 CONFIGPARMS cfg;
646 ConfigPageHeader_t hdr;
647 dma_addr_t dma_handle;
648 pRaidVolumePage0_t buffer = NULL;
649 int i;
650 RaidPhysDiskPage0_t phys_disk;
651 struct mptsas_device_info *sas_info, *next;
652
653 memset(&cfg, 0 , sizeof(CONFIGPARMS));
654 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
655 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
656 /* assumption that all volumes on channel = 0 */
657 cfg.pageAddr = starget->id;
658 cfg.cfghdr.hdr = &hdr;
659 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +0530660 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530661
662 if (mpt_config(ioc, &cfg) != 0)
663 goto out;
664
665 if (!hdr.PageLength)
666 goto out;
667
668 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
669 &dma_handle);
670
671 if (!buffer)
672 goto out;
673
674 cfg.physAddr = dma_handle;
675 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
676
677 if (mpt_config(ioc, &cfg) != 0)
678 goto out;
679
680 if (!buffer->NumPhysDisks)
681 goto out;
682
683 /*
684 * Adding entry for hidden components
685 */
686 for (i = 0; i < buffer->NumPhysDisks; i++) {
687
688 if (mpt_raid_phys_disk_pg0(ioc,
689 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
690 continue;
691
692 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
693 phys_disk.PhysDiskID);
694
Kashyap, Desai57e98512009-05-29 16:55:09 +0530695 mutex_lock(&ioc->sas_device_info_mutex);
696 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
697 list) {
698 if (!sas_info->is_logical_volume &&
699 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
700 sas_info->fw.id == phys_disk.PhysDiskID)) {
701 sas_info->is_hidden_raid_component = 1;
702 sas_info->volume_id = starget->id;
703 }
704 }
705 mutex_unlock(&ioc->sas_device_info_mutex);
706
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530707 }
708
709 /*
710 * Delete all matching devices out of the list
711 */
712 mutex_lock(&ioc->sas_device_info_mutex);
713 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
714 list) {
715 if (sas_info->is_logical_volume && sas_info->fw.id ==
716 starget->id) {
717 list_del(&sas_info->list);
718 kfree(sas_info);
719 }
720 }
721
722 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
723 if (sas_info) {
724 sas_info->fw.id = starget->id;
725 sas_info->os.id = starget->id;
726 sas_info->os.channel = starget->channel;
727 sas_info->is_logical_volume = 1;
728 INIT_LIST_HEAD(&sas_info->list);
729 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
730 }
731 mutex_unlock(&ioc->sas_device_info_mutex);
732
733 out:
734 if (buffer)
735 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
736 dma_handle);
737}
738
739/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530740 * mptsas_add_device_component_starget -
741 * @ioc: Pointer to MPT_ADAPTER structure
742 * @starget:
743 *
744 **/
745static void
746mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
747 struct scsi_target *starget)
748{
749 VirtTarget *vtarget;
750 struct sas_rphy *rphy;
751 struct mptsas_phyinfo *phy_info = NULL;
752 struct mptsas_enclosure enclosure_info;
753
754 rphy = dev_to_rphy(starget->dev.parent);
755 vtarget = starget->hostdata;
756 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
757 rphy->identify.sas_address);
758 if (!phy_info)
759 return;
760
761 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
762 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
763 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
764 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
765 phy_info->attached.handle_enclosure);
766
767 mptsas_add_device_component(ioc, phy_info->attached.channel,
768 phy_info->attached.id, phy_info->attached.sas_address,
769 phy_info->attached.device_info,
770 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
771}
772
773/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000774 * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
Kashyap, Desai57e98512009-05-29 16:55:09 +0530775 * @ioc: Pointer to MPT_ADAPTER structure
776 * @channel: os mapped id's
777 * @id:
778 *
779 **/
780static void
781mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
782{
783 struct mptsas_device_info *sas_info, *next;
784
785 /*
786 * Set is_cached flag
787 */
788 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
789 list) {
790 if (sas_info->os.channel == channel && sas_info->os.id == id)
791 sas_info->is_cached = 1;
792 }
793}
794
795/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530796 * mptsas_del_device_components - Cleaning the list
797 * @ioc: Pointer to MPT_ADAPTER structure
798 *
799 **/
800static void
801mptsas_del_device_components(MPT_ADAPTER *ioc)
802{
803 struct mptsas_device_info *sas_info, *next;
804
805 mutex_lock(&ioc->sas_device_info_mutex);
806 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
807 list) {
808 list_del(&sas_info->list);
809 kfree(sas_info);
810 }
811 mutex_unlock(&ioc->sas_device_info_mutex);
812}
813
Eric Moore547f9a22006-06-27 14:42:12 -0600814
815/*
816 * mptsas_setup_wide_ports
817 *
818 * Updates for new and existing narrow/wide port configuration
819 * in the sas_topology
820 */
Eric Moore376ac832006-06-29 17:36:26 -0600821static void
Eric Moore547f9a22006-06-27 14:42:12 -0600822mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
823{
824 struct mptsas_portinfo_details * port_details;
825 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
826 u64 sas_address;
827 int i, j;
828
829 mutex_lock(&ioc->sas_topology_mutex);
830
831 phy_info = port_info->phy_info;
832 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
833 if (phy_info->attached.handle)
834 continue;
835 port_details = phy_info->port_details;
836 if (!port_details)
837 continue;
838 if (port_details->num_phys < 2)
839 continue;
840 /*
841 * Removing a phy from a port, letting the last
842 * phy be removed by firmware events.
843 */
Eric Moore29dd3602007-09-14 18:46:51 -0600844 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
845 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700846 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600847 port_details->num_phys--;
848 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
849 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai9e390892009-09-02 11:43:36 +0530850 if (phy_info->phy) {
851 devtprintk(ioc, dev_printk(KERN_DEBUG,
852 &phy_info->phy->dev, MYIOC_s_FMT
853 "delete phy %d, phy-obj (0x%p)\n", ioc->name,
854 phy_info->phy_id, phy_info->phy));
855 sas_port_delete_phy(port_details->port, phy_info->phy);
856 }
Eric Moore547f9a22006-06-27 14:42:12 -0600857 phy_info->port_details = NULL;
858 }
859
860 /*
861 * Populate and refresh the tree
862 */
863 phy_info = port_info->phy_info;
864 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
865 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600866 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
867 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600868 if (!sas_address)
869 continue;
870 port_details = phy_info->port_details;
871 /*
872 * Forming a port
873 */
874 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530875 port_details = kzalloc(sizeof(struct
876 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600877 if (!port_details)
878 goto out;
879 port_details->num_phys = 1;
880 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600881 if (phy_info->phy_id < 64 )
882 port_details->phy_bitmask |=
883 (1 << phy_info->phy_id);
884 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600885 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700886 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600887 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600888 phy_info->port_details = port_details;
889 }
890
891 if (i == port_info->num_phys - 1)
892 continue;
893 phy_info_cmp = &port_info->phy_info[i + 1];
894 for (j = i + 1 ; j < port_info->num_phys ; j++,
895 phy_info_cmp++) {
896 if (!phy_info_cmp->attached.sas_address)
897 continue;
898 if (sas_address != phy_info_cmp->attached.sas_address)
899 continue;
900 if (phy_info_cmp->port_details == port_details )
901 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600902 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700903 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600904 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700905 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600906 if (phy_info_cmp->port_details) {
907 port_details->rphy =
908 mptsas_get_rphy(phy_info_cmp);
909 port_details->port =
910 mptsas_get_port(phy_info_cmp);
911 port_details->starget =
912 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600913 port_details->num_phys =
914 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600915 if (!phy_info_cmp->port_details->num_phys)
916 kfree(phy_info_cmp->port_details);
917 } else
918 phy_info_cmp->sas_port_add_phy=1;
919 /*
920 * Adding a phy to a port
921 */
922 phy_info_cmp->port_details = port_details;
923 if (phy_info_cmp->phy_id < 64 )
924 port_details->phy_bitmask |=
925 (1 << phy_info_cmp->phy_id);
926 port_details->num_phys++;
927 }
928 }
929
930 out:
931
Eric Moore547f9a22006-06-27 14:42:12 -0600932 for (i = 0; i < port_info->num_phys; i++) {
933 port_details = port_info->phy_info[i].port_details;
934 if (!port_details)
935 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600936 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700937 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700938 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700939 port_details, i, port_details->num_phys,
940 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600941 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
942 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600943 }
Eric Moore29dd3602007-09-14 18:46:51 -0600944 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600945 mutex_unlock(&ioc->sas_topology_mutex);
946}
947
Eric Mooredf9e0622007-01-29 09:46:21 -0700948/**
949 * csmisas_find_vtarget
950 *
951 * @ioc
952 * @volume_id
953 * @volume_bus
954 *
955 **/
956static VirtTarget *
957mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600958{
Eric Mooredf9e0622007-01-29 09:46:21 -0700959 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600960 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700961 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600962
Eric Mooredf9e0622007-01-29 09:46:21 -0700963 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530964 vdevice = sdev->hostdata;
965 if ((vdevice == NULL) ||
966 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700967 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530968 if ((vdevice->vtarget->tflags &
969 MPT_TARGET_FLAGS_RAID_COMPONENT ||
970 vdevice->vtarget->raidVolume))
971 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600972 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530973 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600974 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600975 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700976 return vtarget;
977}
978
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530979static void
980mptsas_queue_device_delete(MPT_ADAPTER *ioc,
981 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
982{
983 struct fw_event_work *fw_event;
984 int sz;
985
986 sz = offsetof(struct fw_event_work, event_data) +
987 sizeof(MpiEventDataSasDeviceStatusChange_t);
988 fw_event = kzalloc(sz, GFP_ATOMIC);
989 if (!fw_event) {
990 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
991 ioc->name, __func__, __LINE__);
992 return;
993 }
994 memcpy(fw_event->event_data, sas_event_data,
995 sizeof(MpiEventDataSasDeviceStatusChange_t));
996 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
997 fw_event->ioc = ioc;
998 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
999}
1000
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301001static void
1002mptsas_queue_rescan(MPT_ADAPTER *ioc)
1003{
1004 struct fw_event_work *fw_event;
1005 int sz;
1006
1007 sz = offsetof(struct fw_event_work, event_data);
1008 fw_event = kzalloc(sz, GFP_ATOMIC);
1009 if (!fw_event) {
1010 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1011 ioc->name, __func__, __LINE__);
1012 return;
1013 }
1014 fw_event->event = -1;
1015 fw_event->ioc = ioc;
1016 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1017}
1018
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301019
Eric Mooredf9e0622007-01-29 09:46:21 -07001020/**
1021 * mptsas_target_reset
1022 *
1023 * Issues TARGET_RESET to end device using handshaking method
1024 *
1025 * @ioc
1026 * @channel
1027 * @id
1028 *
1029 * Returns (1) success
1030 * (0) failure
1031 *
1032 **/
1033static int
1034mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1035{
1036 MPT_FRAME_HDR *mf;
1037 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301038 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1039 return 0;
1040
Eric Mooredf9e0622007-01-29 09:46:21 -07001041
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301042 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1043 if (mf == NULL) {
1044 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301045 "%s, no msg frames @%d!!\n", ioc->name,
1046 __func__, __LINE__));
1047 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001048 }
1049
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301050 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1051 ioc->name, mf));
1052
Eric Mooredf9e0622007-01-29 09:46:21 -07001053 /* Format the Request
1054 */
1055 pScsiTm = (SCSITaskMgmt_t *) mf;
1056 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1057 pScsiTm->TargetID = id;
1058 pScsiTm->Bus = channel;
1059 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1060 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1061 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1062
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301063 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001064
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301065 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1066 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1067 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1068
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301069 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001070
1071 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301072
1073 out_fail:
1074
1075 mpt_clear_taskmgmt_in_progress_flag(ioc);
1076 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001077}
1078
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301079static void
1080mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
1081{
1082 scsi_device_set_state(sdev, SDEV_BLOCK);
1083}
1084
1085static void
1086mptsas_block_io_starget(struct scsi_target *starget)
1087{
1088 if (starget)
1089 starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
1090}
1091
Eric Mooredf9e0622007-01-29 09:46:21 -07001092/**
1093 * mptsas_target_reset_queue
1094 *
1095 * Receive request for TARGET_RESET after recieving an firmware
1096 * event NOT_RESPONDING_EVENT, then put command in link list
1097 * and queue if task_queue already in use.
1098 *
1099 * @ioc
1100 * @sas_event_data
1101 *
1102 **/
1103static void
1104mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1105 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1106{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001107 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001108 VirtTarget *vtarget = NULL;
1109 struct mptsas_target_reset_event *target_reset_list;
1110 u8 id, channel;
1111
1112 id = sas_event_data->TargetID;
1113 channel = sas_event_data->Bus;
1114
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301115 vtarget = mptsas_find_vtarget(ioc, channel, id);
1116 if (vtarget) {
1117 mptsas_block_io_starget(vtarget->starget);
1118 vtarget->deleted = 1; /* block IO */
1119 }
Eric Mooredf9e0622007-01-29 09:46:21 -07001120
Kashyap, Desai2f187862009-05-29 16:52:37 +05301121 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001122 GFP_ATOMIC);
1123 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301124 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1125 "%s, failed to allocate mem @%d..!!\n",
1126 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001127 return;
1128 }
1129
1130 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1131 sizeof(*sas_event_data));
1132 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1133
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301134 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001135
1136 if (mptsas_target_reset(ioc, channel, id)) {
1137 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001138 }
1139}
1140
1141/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001142 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301143 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001144 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001145 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1146 * queue to finish off removing device from upper layers. then send next
1147 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001148 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301149static int
1150mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001151{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001152 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001153 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001154 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301155 struct mptsas_target_reset_event *target_reset_list;
1156 SCSITaskMgmtReply_t *pScsiTmReply;
1157
1158 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1159 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1160
1161 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1162 if (pScsiTmReply) {
1163 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1164 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1165 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1166 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1167 "term_cmnds = %d\n", ioc->name,
1168 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1169 pScsiTmReply->TaskType,
1170 le16_to_cpu(pScsiTmReply->IOCStatus),
1171 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1172 pScsiTmReply->ResponseCode,
1173 le32_to_cpu(pScsiTmReply->TerminationCount)));
1174
1175 if (pScsiTmReply->ResponseCode)
1176 mptscsih_taskmgmt_response_code(ioc,
1177 pScsiTmReply->ResponseCode);
1178 }
1179
1180 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1181 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1182 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1183 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1184 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1185 memcpy(ioc->taskmgmt_cmds.reply, mr,
1186 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1187 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1188 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1189 complete(&ioc->taskmgmt_cmds.done);
1190 return 1;
1191 }
1192 return 0;
1193 }
1194
1195 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001196
1197 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301198 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001199
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301200 target_reset_list = list_entry(head->next,
1201 struct mptsas_target_reset_event, list);
1202
1203 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1204 "TaskMgmt: completed (%d seconds)\n",
1205 ioc->name, jiffies_to_msecs(jiffies -
1206 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001207
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301208 id = pScsiTmReply->TargetID;
1209 channel = pScsiTmReply->Bus;
1210 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001211
1212 /*
1213 * retry target reset
1214 */
1215 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301216 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001217 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301218 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001219 }
1220
1221 /*
1222 * enable work queue to remove device from upper layers
1223 */
1224 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301225 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1226 mptsas_queue_device_delete(ioc,
1227 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301228
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301229
Eric Mooredf9e0622007-01-29 09:46:21 -07001230 /*
1231 * issue target reset to next device in the queue
1232 */
1233
1234 head = &hd->target_reset_list;
1235 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301236 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001237
1238 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1239 list);
1240
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301241 id = target_reset_list->sas_event_data.TargetID;
1242 channel = target_reset_list->sas_event_data.Bus;
1243 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001244
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301245 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001246 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001247
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301248 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001249}
1250
1251/**
1252 * mptscsih_ioc_reset
1253 *
1254 * @ioc
1255 * @reset_phase
1256 *
1257 **/
1258static int
1259mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1260{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001261 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001262 int rc;
1263
1264 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301265 if ((ioc->bus_type != SAS) || (!rc))
1266 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001267
Eric Mooree7eae9f2007-09-29 10:15:59 -06001268 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001269 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001270 goto out;
1271
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301272 switch (reset_phase) {
1273 case MPT_IOC_SETUP_RESET:
1274 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1275 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1276 mptsas_fw_event_off(ioc);
1277 break;
1278 case MPT_IOC_PRE_RESET:
1279 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1280 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1281 break;
1282 case MPT_IOC_POST_RESET:
1283 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1284 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1285 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1286 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1287 complete(&ioc->sas_mgmt.done);
1288 }
1289 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301290 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301291 break;
1292 default:
1293 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001294 }
1295
1296 out:
1297 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001298}
1299
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301300
1301/**
1302 * enum device_state -
1303 * @DEVICE_RETRY: need to retry the TUR
1304 * @DEVICE_ERROR: TUR return error, don't add device
1305 * @DEVICE_READY: device can be added
1306 *
1307 */
1308enum device_state{
1309 DEVICE_RETRY,
1310 DEVICE_ERROR,
1311 DEVICE_READY,
1312};
1313
Christoph Hellwige3094442006-02-16 13:25:36 +01001314static int
Moore, Eric52435432006-03-14 09:14:15 -07001315mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001316 u32 form, u32 form_specific)
1317{
1318 ConfigExtendedPageHeader_t hdr;
1319 CONFIGPARMS cfg;
1320 SasEnclosurePage0_t *buffer;
1321 dma_addr_t dma_handle;
1322 int error;
1323 __le64 le_identifier;
1324
1325 memset(&hdr, 0, sizeof(hdr));
1326 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1327 hdr.PageNumber = 0;
1328 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1329 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1330
1331 cfg.cfghdr.ehdr = &hdr;
1332 cfg.physAddr = -1;
1333 cfg.pageAddr = form + form_specific;
1334 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1335 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301336 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwige3094442006-02-16 13:25:36 +01001337
1338 error = mpt_config(ioc, &cfg);
1339 if (error)
1340 goto out;
1341 if (!hdr.ExtPageLength) {
1342 error = -ENXIO;
1343 goto out;
1344 }
1345
1346 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1347 &dma_handle);
1348 if (!buffer) {
1349 error = -ENOMEM;
1350 goto out;
1351 }
1352
1353 cfg.physAddr = dma_handle;
1354 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1355
1356 error = mpt_config(ioc, &cfg);
1357 if (error)
1358 goto out_free_consistent;
1359
1360 /* save config data */
1361 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1362 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1363 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1364 enclosure->flags = le16_to_cpu(buffer->Flags);
1365 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1366 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1367 enclosure->start_id = buffer->StartTargetID;
1368 enclosure->start_channel = buffer->StartBus;
1369 enclosure->sep_id = buffer->SEPTargetID;
1370 enclosure->sep_channel = buffer->SEPBus;
1371
1372 out_free_consistent:
1373 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1374 buffer, dma_handle);
1375 out:
1376 return error;
1377}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001378
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301379/**
1380 * mptsas_add_end_device - report a new end device to sas transport layer
1381 * @ioc: Pointer to MPT_ADAPTER structure
1382 * @phy_info: decribes attached device
1383 *
1384 * return (0) success (1) failure
1385 *
1386 **/
1387static int
1388mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1389{
1390 struct sas_rphy *rphy;
1391 struct sas_port *port;
1392 struct sas_identify identify;
1393 char *ds = NULL;
1394 u8 fw_id;
1395
1396 if (!phy_info) {
1397 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1398 "%s: exit at line=%d\n", ioc->name,
1399 __func__, __LINE__));
1400 return 1;
1401 }
1402
1403 fw_id = phy_info->attached.id;
1404
1405 if (mptsas_get_rphy(phy_info)) {
1406 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1407 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1408 __func__, fw_id, __LINE__));
1409 return 2;
1410 }
1411
1412 port = mptsas_get_port(phy_info);
1413 if (!port) {
1414 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1415 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1416 __func__, fw_id, __LINE__));
1417 return 3;
1418 }
1419
1420 if (phy_info->attached.device_info &
1421 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1422 ds = "ssp";
1423 if (phy_info->attached.device_info &
1424 MPI_SAS_DEVICE_INFO_STP_TARGET)
1425 ds = "stp";
1426 if (phy_info->attached.device_info &
1427 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1428 ds = "sata";
1429
1430 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1431 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1432 phy_info->attached.channel, phy_info->attached.id,
1433 phy_info->attached.phy_id, (unsigned long long)
1434 phy_info->attached.sas_address);
1435
1436 mptsas_parse_device_info(&identify, &phy_info->attached);
1437 rphy = sas_end_device_alloc(port);
1438 if (!rphy) {
1439 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1440 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1441 __func__, fw_id, __LINE__));
1442 return 5; /* non-fatal: an rphy can be added later */
1443 }
1444
1445 rphy->identify = identify;
1446 if (sas_rphy_add(rphy)) {
1447 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1448 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1449 __func__, fw_id, __LINE__));
1450 sas_rphy_free(rphy);
1451 return 6;
1452 }
1453 mptsas_set_rphy(ioc, phy_info, rphy);
1454 return 0;
1455}
1456
1457/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001458 * mptsas_del_end_device - report a deleted end device to sas transport layer
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301459 * @ioc: Pointer to MPT_ADAPTER structure
1460 * @phy_info: decribes attached device
1461 *
1462 **/
1463static void
1464mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1465{
1466 struct sas_rphy *rphy;
1467 struct sas_port *port;
1468 struct mptsas_portinfo *port_info;
1469 struct mptsas_phyinfo *phy_info_parent;
1470 int i;
1471 char *ds = NULL;
1472 u8 fw_id;
1473 u64 sas_address;
1474
1475 if (!phy_info)
1476 return;
1477
1478 fw_id = phy_info->attached.id;
1479 sas_address = phy_info->attached.sas_address;
1480
1481 if (!phy_info->port_details) {
1482 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1483 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1484 __func__, fw_id, __LINE__));
1485 return;
1486 }
1487 rphy = mptsas_get_rphy(phy_info);
1488 if (!rphy) {
1489 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1490 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1491 __func__, fw_id, __LINE__));
1492 return;
1493 }
1494
1495 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1496 || phy_info->attached.device_info
1497 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1498 || phy_info->attached.device_info
1499 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1500 ds = "initiator";
1501 if (phy_info->attached.device_info &
1502 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1503 ds = "ssp";
1504 if (phy_info->attached.device_info &
1505 MPI_SAS_DEVICE_INFO_STP_TARGET)
1506 ds = "stp";
1507 if (phy_info->attached.device_info &
1508 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1509 ds = "sata";
1510
1511 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1512 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1513 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1514 phy_info->attached.id, phy_info->attached.phy_id,
1515 (unsigned long long) sas_address);
1516
1517 port = mptsas_get_port(phy_info);
1518 if (!port) {
1519 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1520 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1521 __func__, fw_id, __LINE__));
1522 return;
1523 }
1524 port_info = phy_info->portinfo;
1525 phy_info_parent = port_info->phy_info;
1526 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1527 if (!phy_info_parent->phy)
1528 continue;
1529 if (phy_info_parent->attached.sas_address !=
1530 sas_address)
1531 continue;
1532 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1533 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1534 ioc->name, phy_info_parent->phy_id,
1535 phy_info_parent->phy);
1536 sas_port_delete_phy(port, phy_info_parent->phy);
1537 }
1538
1539 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1540 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1541 port->port_identifier, (unsigned long long)sas_address);
1542 sas_port_delete(port);
1543 mptsas_set_port(ioc, phy_info, NULL);
1544 mptsas_port_delete(ioc, phy_info->port_details);
1545}
1546
1547struct mptsas_phyinfo *
1548mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1549 struct mptsas_devinfo *sas_device)
1550{
1551 struct mptsas_phyinfo *phy_info;
1552 struct mptsas_portinfo *port_info;
1553 int i;
1554
1555 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1556 sas_device->sas_address);
1557 if (!phy_info)
1558 goto out;
1559 port_info = phy_info->portinfo;
1560 if (!port_info)
1561 goto out;
1562 mutex_lock(&ioc->sas_topology_mutex);
1563 for (i = 0; i < port_info->num_phys; i++) {
1564 if (port_info->phy_info[i].attached.sas_address !=
1565 sas_device->sas_address)
1566 continue;
1567 port_info->phy_info[i].attached.channel = sas_device->channel;
1568 port_info->phy_info[i].attached.id = sas_device->id;
1569 port_info->phy_info[i].attached.sas_address =
1570 sas_device->sas_address;
1571 port_info->phy_info[i].attached.handle = sas_device->handle;
1572 port_info->phy_info[i].attached.handle_parent =
1573 sas_device->handle_parent;
1574 port_info->phy_info[i].attached.handle_enclosure =
1575 sas_device->handle_enclosure;
1576 }
1577 mutex_unlock(&ioc->sas_topology_mutex);
1578 out:
1579 return phy_info;
1580}
1581
1582/**
1583 * mptsas_firmware_event_work - work thread for processing fw events
1584 * @work: work queue payload containing info describing the event
1585 * Context: user
1586 *
1587 */
1588static void
1589mptsas_firmware_event_work(struct work_struct *work)
1590{
1591 struct fw_event_work *fw_event =
1592 container_of(work, struct fw_event_work, work.work);
1593 MPT_ADAPTER *ioc = fw_event->ioc;
1594
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301595 /* special rescan topology handling */
1596 if (fw_event->event == -1) {
1597 if (ioc->in_rescan) {
1598 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1599 "%s: rescan ignored as it is in progress\n",
1600 ioc->name, __func__));
1601 return;
1602 }
1603 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1604 "reset\n", ioc->name, __func__));
1605 ioc->in_rescan = 1;
1606 mptsas_not_responding_devices(ioc);
1607 mptsas_scan_sas_topology(ioc);
1608 ioc->in_rescan = 0;
1609 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai97660962009-09-02 11:46:33 +05301610 mptsas_fw_event_on(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301611 return;
1612 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301613
1614 /* events handling turned off during host reset */
1615 if (ioc->fw_events_off) {
1616 mptsas_free_fw_event(ioc, fw_event);
1617 return;
1618 }
1619
1620 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1621 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1622 (fw_event->event & 0xFF)));
1623
1624 switch (fw_event->event) {
1625 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1626 mptsas_send_sas_event(fw_event);
1627 break;
1628 case MPI_EVENT_INTEGRATED_RAID:
1629 mptsas_send_raid_event(fw_event);
1630 break;
1631 case MPI_EVENT_IR2:
1632 mptsas_send_ir2_event(fw_event);
1633 break;
1634 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1635 mptbase_sas_persist_operation(ioc,
1636 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1637 mptsas_free_fw_event(ioc, fw_event);
1638 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301639 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1640 mptsas_broadcast_primative_work(fw_event);
1641 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301642 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1643 mptsas_send_expander_event(fw_event);
1644 break;
1645 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1646 mptsas_send_link_status_event(fw_event);
1647 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301648 case MPI_EVENT_QUEUE_FULL:
1649 mptsas_handle_queue_full_event(fw_event);
1650 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301651 }
1652}
1653
1654
1655
James Bottomleyf013db32006-03-18 14:54:36 -06001656static int
1657mptsas_slave_configure(struct scsi_device *sdev)
1658{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301659 struct Scsi_Host *host = sdev->host;
1660 MPT_SCSI_HOST *hd = shost_priv(host);
1661 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301662 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001663
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301664 if (vdevice->vtarget->deleted) {
1665 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1666 vdevice->vtarget->deleted = 0;
1667 }
1668
1669 /*
1670 * RAID volumes placed beyond the last expected port.
1671 * Ignore sending sas mode pages in that case..
1672 */
1673 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1674 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001675 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301676 }
James Bottomleyf013db32006-03-18 14:54:36 -06001677
James Bottomleye8bf3942006-07-11 17:49:34 -04001678 sas_read_port_mode_page(sdev);
1679
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301680 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1681
James Bottomleye8bf3942006-07-11 17:49:34 -04001682 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001683 return mptscsih_slave_configure(sdev);
1684}
1685
Eric Moore547f9a22006-06-27 14:42:12 -06001686static int
1687mptsas_target_alloc(struct scsi_target *starget)
1688{
1689 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001690 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001691 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001692 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001693 struct sas_rphy *rphy;
1694 struct mptsas_portinfo *p;
1695 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001696 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001697
1698 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1699 if (!vtarget)
1700 return -ENOMEM;
1701
1702 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001703 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001704 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1705 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001706 channel = 0;
1707
Eric Moore793955f2007-01-29 09:42:20 -07001708 /*
1709 * RAID volumes placed beyond the last expected port.
1710 */
1711 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301712 if (!ioc->raid_data.pIocPg2) {
1713 kfree(vtarget);
1714 return -ENXIO;
1715 }
1716 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1717 if (id == ioc->raid_data.pIocPg2->
1718 RaidVolume[i].VolumeID) {
1719 channel = ioc->raid_data.pIocPg2->
1720 RaidVolume[i].VolumeBus;
1721 }
1722 }
1723 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001724 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001725 }
Eric Moore547f9a22006-06-27 14:42:12 -06001726
1727 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001728 mutex_lock(&ioc->sas_topology_mutex);
1729 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001730 for (i = 0; i < p->num_phys; i++) {
1731 if (p->phy_info[i].attached.sas_address !=
1732 rphy->identify.sas_address)
1733 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001734 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001735 channel = p->phy_info[i].attached.channel;
1736 mptsas_set_starget(&p->phy_info[i], starget);
1737
1738 /*
1739 * Exposing hidden raid components
1740 */
Eric Mooree80b0022007-09-14 18:49:03 -06001741 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1742 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001743 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001744 vtarget->tflags |=
1745 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001746 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001747 }
Eric Mooree80b0022007-09-14 18:49:03 -06001748 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001749 goto out;
1750 }
1751 }
Eric Mooree80b0022007-09-14 18:49:03 -06001752 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001753
1754 kfree(vtarget);
1755 return -ENXIO;
1756
1757 out:
Eric Moore793955f2007-01-29 09:42:20 -07001758 vtarget->id = id;
1759 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001760 starget->hostdata = vtarget;
1761 return 0;
1762}
1763
1764static void
1765mptsas_target_destroy(struct scsi_target *starget)
1766{
1767 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001768 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001769 struct sas_rphy *rphy;
1770 struct mptsas_portinfo *p;
1771 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301772 MPT_ADAPTER *ioc = hd->ioc;
1773 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001774
1775 if (!starget->hostdata)
1776 return;
1777
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301778 vtarget = starget->hostdata;
1779
Kashyap, Desai57e98512009-05-29 16:55:09 +05301780 mptsas_del_device_component_by_os(ioc, starget->channel,
1781 starget->id);
1782
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301783
James Bottomleye8bf3942006-07-11 17:49:34 -04001784 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001785 goto out;
1786
1787 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001788 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001789 for (i = 0; i < p->num_phys; i++) {
1790 if (p->phy_info[i].attached.sas_address !=
1791 rphy->identify.sas_address)
1792 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301793
1794 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1795 "delete device: fw_channel %d, fw_id %d, phy %d, "
1796 "sas_addr 0x%llx\n", ioc->name,
1797 p->phy_info[i].attached.channel,
1798 p->phy_info[i].attached.id,
1799 p->phy_info[i].attached.phy_id, (unsigned long long)
1800 p->phy_info[i].attached.sas_address);
1801
Eric Moore547f9a22006-06-27 14:42:12 -06001802 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001803 }
1804 }
1805
1806 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301807 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001808 kfree(starget->hostdata);
1809 starget->hostdata = NULL;
1810}
1811
1812
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001813static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001814mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001815{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001816 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001817 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001818 struct sas_rphy *rphy;
1819 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001820 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001821 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001822 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001823 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824
Eric Moorea69de502007-09-14 18:48:19 -06001825 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1826 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001827 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001828 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001829 return -ENOMEM;
1830 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001831 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001832 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001833
James Bottomleye8bf3942006-07-11 17:49:34 -04001834 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001835 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001836
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001837 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001838 mutex_lock(&ioc->sas_topology_mutex);
1839 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001840 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001841 if (p->phy_info[i].attached.sas_address !=
1842 rphy->identify.sas_address)
1843 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001844 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001845 /*
1846 * Exposing hidden raid components
1847 */
Eric Mooree80b0022007-09-14 18:49:03 -06001848 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001849 p->phy_info[i].attached.channel,
1850 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001851 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001852 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001853 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001854 }
1855 }
Eric Mooree80b0022007-09-14 18:49:03 -06001856 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001857
Eric Moorea69de502007-09-14 18:48:19 -06001858 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001859 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001860
1861 out:
Eric Moorea69de502007-09-14 18:48:19 -06001862 vdevice->vtarget->num_luns++;
1863 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001864 return 0;
1865}
1866
Eric Moore547f9a22006-06-27 14:42:12 -06001867static int
1868mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001869{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301870 MPT_SCSI_HOST *hd;
1871 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001872 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001873
Eric Moorea69de502007-09-14 18:48:19 -06001874 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001875 SCpnt->result = DID_NO_CONNECT << 16;
1876 done(SCpnt);
1877 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001878 }
Eric Moore547f9a22006-06-27 14:42:12 -06001879
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301880 hd = shost_priv(SCpnt->device->host);
1881 ioc = hd->ioc;
1882
1883 if (ioc->sas_discovery_quiesce_io)
1884 return SCSI_MLQUEUE_HOST_BUSY;
1885
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301886 if (ioc->debug_level & MPT_DEBUG_SCSI)
1887 scsi_print_command(SCpnt);
Eric Moore793955f2007-01-29 09:42:20 -07001888
Eric Moore547f9a22006-06-27 14:42:12 -06001889 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001890}
1891
Eric Moore547f9a22006-06-27 14:42:12 -06001892
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001893static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001894 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001895 .proc_name = "mptsas",
1896 .proc_info = mptscsih_proc_info,
Kashyap, Desai568da762010-03-18 19:23:50 +05301897 .name = "MPT SAS Host",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001898 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001899 .queuecommand = mptsas_qcmd,
1900 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001901 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001902 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001903 .target_destroy = mptsas_target_destroy,
1904 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001905 .change_queue_depth = mptscsih_change_queue_depth,
1906 .eh_abort_handler = mptscsih_abort,
1907 .eh_device_reset_handler = mptscsih_dev_reset,
1908 .eh_bus_reset_handler = mptscsih_bus_reset,
1909 .eh_host_reset_handler = mptscsih_host_reset,
1910 .bios_param = mptscsih_bios_param,
Kashyap, Desai9d2e9d62009-08-05 12:48:44 +05301911 .can_queue = MPT_SAS_CAN_QUEUE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001912 .this_id = -1,
1913 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1914 .max_sectors = 8192,
1915 .cmd_per_lun = 7,
1916 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301917 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001918};
1919
Christoph Hellwigb5141122005-10-28 22:07:41 +02001920static int mptsas_get_linkerrors(struct sas_phy *phy)
1921{
1922 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1923 ConfigExtendedPageHeader_t hdr;
1924 CONFIGPARMS cfg;
1925 SasPhyPage1_t *buffer;
1926 dma_addr_t dma_handle;
1927 int error;
1928
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001929 /* FIXME: only have link errors on local phys */
1930 if (!scsi_is_sas_phy_local(phy))
1931 return -EINVAL;
1932
Christoph Hellwigb5141122005-10-28 22:07:41 +02001933 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1934 hdr.ExtPageLength = 0;
1935 hdr.PageNumber = 1 /* page number 1*/;
1936 hdr.Reserved1 = 0;
1937 hdr.Reserved2 = 0;
1938 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1939 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1940
1941 cfg.cfghdr.ehdr = &hdr;
1942 cfg.physAddr = -1;
1943 cfg.pageAddr = phy->identify.phy_identifier;
1944 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1945 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301946 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwigb5141122005-10-28 22:07:41 +02001947
1948 error = mpt_config(ioc, &cfg);
1949 if (error)
1950 return error;
1951 if (!hdr.ExtPageLength)
1952 return -ENXIO;
1953
1954 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1955 &dma_handle);
1956 if (!buffer)
1957 return -ENOMEM;
1958
1959 cfg.physAddr = dma_handle;
1960 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1961
1962 error = mpt_config(ioc, &cfg);
1963 if (error)
1964 goto out_free_consistent;
1965
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301966 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001967
1968 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1969 phy->running_disparity_error_count =
1970 le32_to_cpu(buffer->RunningDisparityErrorCount);
1971 phy->loss_of_dword_sync_count =
1972 le32_to_cpu(buffer->LossDwordSynchCount);
1973 phy->phy_reset_problem_count =
1974 le32_to_cpu(buffer->PhyResetProblemCount);
1975
1976 out_free_consistent:
1977 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1978 buffer, dma_handle);
1979 return error;
1980}
1981
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001982static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1983 MPT_FRAME_HDR *reply)
1984{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301985 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001986 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301987 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001988 memcpy(ioc->sas_mgmt.reply, reply,
1989 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1990 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301991
1992 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1993 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1994 complete(&ioc->sas_mgmt.done);
1995 return 1;
1996 }
1997 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001998}
1999
2000static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
2001{
2002 MPT_ADAPTER *ioc = phy_to_ioc(phy);
2003 SasIoUnitControlRequest_t *req;
2004 SasIoUnitControlReply_t *reply;
2005 MPT_FRAME_HDR *mf;
2006 MPIHeader_t *hdr;
2007 unsigned long timeleft;
2008 int error = -ERESTARTSYS;
2009
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002010 /* FIXME: fusion doesn't allow non-local phy reset */
2011 if (!scsi_is_sas_phy_local(phy))
2012 return -EINVAL;
2013
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002014 /* not implemented for expanders */
2015 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2016 return -ENXIO;
2017
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002018 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002019 goto out;
2020
2021 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2022 if (!mf) {
2023 error = -ENOMEM;
2024 goto out_unlock;
2025 }
2026
2027 hdr = (MPIHeader_t *) mf;
2028 req = (SasIoUnitControlRequest_t *)mf;
2029 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2030 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2031 req->MsgContext = hdr->MsgContext;
2032 req->Operation = hard_reset ?
2033 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2034 req->PhyNum = phy->identify.phy_identifier;
2035
Kashyap, Desai2f187862009-05-29 16:52:37 +05302036 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002037 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2038
2039 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2040 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302041 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2042 error = -ETIME;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002043 mpt_free_msg_frame(ioc, mf);
Kashyap, Desai568da762010-03-18 19:23:50 +05302044 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2045 goto out_unlock;
2046 if (!timeleft)
2047 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002048 goto out_unlock;
2049 }
2050
2051 /* a reply frame is expected */
2052 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302053 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002054 error = -ENXIO;
2055 goto out_unlock;
2056 }
2057
2058 /* process the completed Reply Message Frame */
2059 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2060 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002061 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002062 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002063 error = -ENXIO;
2064 goto out_unlock;
2065 }
2066
2067 error = 0;
2068
2069 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302070 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002071 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002072 out:
2073 return error;
2074}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002075
Christoph Hellwige3094442006-02-16 13:25:36 +01002076static int
2077mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2078{
2079 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2080 int i, error;
2081 struct mptsas_portinfo *p;
2082 struct mptsas_enclosure enclosure_info;
2083 u64 enclosure_handle;
2084
2085 mutex_lock(&ioc->sas_topology_mutex);
2086 list_for_each_entry(p, &ioc->sas_topology, list) {
2087 for (i = 0; i < p->num_phys; i++) {
2088 if (p->phy_info[i].attached.sas_address ==
2089 rphy->identify.sas_address) {
2090 enclosure_handle = p->phy_info[i].
2091 attached.handle_enclosure;
2092 goto found_info;
2093 }
2094 }
2095 }
2096 mutex_unlock(&ioc->sas_topology_mutex);
2097 return -ENXIO;
2098
2099 found_info:
2100 mutex_unlock(&ioc->sas_topology_mutex);
2101 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002102 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002103 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2104 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2105 if (!error)
2106 *identifier = enclosure_info.enclosure_logical_id;
2107 return error;
2108}
2109
2110static int
2111mptsas_get_bay_identifier(struct sas_rphy *rphy)
2112{
2113 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2114 struct mptsas_portinfo *p;
2115 int i, rc;
2116
2117 mutex_lock(&ioc->sas_topology_mutex);
2118 list_for_each_entry(p, &ioc->sas_topology, list) {
2119 for (i = 0; i < p->num_phys; i++) {
2120 if (p->phy_info[i].attached.sas_address ==
2121 rphy->identify.sas_address) {
2122 rc = p->phy_info[i].attached.slot;
2123 goto out;
2124 }
2125 }
2126 }
2127 rc = -ENXIO;
2128 out:
2129 mutex_unlock(&ioc->sas_topology_mutex);
2130 return rc;
2131}
2132
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002133static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2134 struct request *req)
2135{
2136 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2137 MPT_FRAME_HDR *mf;
2138 SmpPassthroughRequest_t *smpreq;
2139 struct request *rsp = req->next_rq;
2140 int ret;
2141 int flagsLength;
2142 unsigned long timeleft;
2143 char *psge;
2144 dma_addr_t dma_addr_in = 0;
2145 dma_addr_t dma_addr_out = 0;
2146 u64 sas_address = 0;
2147
2148 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002149 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002150 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002151 return -EINVAL;
2152 }
2153
2154 /* do we need to support multiple segments? */
2155 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002156 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002157 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2158 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002159 return -EINVAL;
2160 }
2161
2162 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2163 if (ret)
2164 goto out;
2165
2166 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2167 if (!mf) {
2168 ret = -ENOMEM;
2169 goto out_unlock;
2170 }
2171
2172 smpreq = (SmpPassthroughRequest_t *)mf;
2173 memset(smpreq, 0, sizeof(*smpreq));
2174
Tejun Heob0790412009-05-07 22:24:42 +09002175 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002176 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2177
2178 if (rphy)
2179 sas_address = rphy->identify.sas_address;
2180 else {
2181 struct mptsas_portinfo *port_info;
2182
2183 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302184 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002185 if (port_info && port_info->phy_info)
2186 sas_address =
2187 port_info->phy_info[0].phy->identify.sas_address;
2188 mutex_unlock(&ioc->sas_topology_mutex);
2189 }
2190
2191 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2192
2193 psge = (char *)
2194 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2195
2196 /* request */
2197 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2198 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302199 MPI_SGE_FLAGS_DIRECTION)
2200 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002201 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002202
2203 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002204 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002205 if (!dma_addr_out)
2206 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302207 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302208 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002209
2210 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302211 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2212 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2213 MPI_SGE_FLAGS_IOC_TO_HOST |
2214 MPI_SGE_FLAGS_END_OF_BUFFER;
2215
2216 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002217 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002218 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002219 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002220 if (!dma_addr_in)
2221 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302222 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002223
Kashyap, Desai2f187862009-05-29 16:52:37 +05302224 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002225 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2226
2227 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302228 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2229 ret = -ETIME;
2230 mpt_free_msg_frame(ioc, mf);
2231 mf = NULL;
2232 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2233 goto unmap;
2234 if (!timeleft)
2235 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002236 goto unmap;
2237 }
2238 mf = NULL;
2239
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302240 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002241 SmpPassthroughReply_t *smprep;
2242
2243 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2244 memcpy(req->sense, smprep, sizeof(*smprep));
2245 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002246 req->resid_len = 0;
2247 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002248 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302249 printk(MYIOC_s_ERR_FMT
2250 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002251 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002252 ret = -ENXIO;
2253 }
2254unmap:
2255 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002256 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002257 PCI_DMA_BIDIRECTIONAL);
2258 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002259 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002260 PCI_DMA_BIDIRECTIONAL);
2261put_mf:
2262 if (mf)
2263 mpt_free_msg_frame(ioc, mf);
2264out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302265 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002266 mutex_unlock(&ioc->sas_mgmt.mutex);
2267out:
2268 return ret;
2269}
2270
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002271static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002272 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002273 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2274 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002275 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002276 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002277};
2278
2279static struct scsi_transport_template *mptsas_transport_template;
2280
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002281static int
2282mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2283{
2284 ConfigExtendedPageHeader_t hdr;
2285 CONFIGPARMS cfg;
2286 SasIOUnitPage0_t *buffer;
2287 dma_addr_t dma_handle;
2288 int error, i;
2289
2290 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2291 hdr.ExtPageLength = 0;
2292 hdr.PageNumber = 0;
2293 hdr.Reserved1 = 0;
2294 hdr.Reserved2 = 0;
2295 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2296 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2297
2298 cfg.cfghdr.ehdr = &hdr;
2299 cfg.physAddr = -1;
2300 cfg.pageAddr = 0;
2301 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2302 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302303 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002304
2305 error = mpt_config(ioc, &cfg);
2306 if (error)
2307 goto out;
2308 if (!hdr.ExtPageLength) {
2309 error = -ENXIO;
2310 goto out;
2311 }
2312
2313 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2314 &dma_handle);
2315 if (!buffer) {
2316 error = -ENOMEM;
2317 goto out;
2318 }
2319
2320 cfg.physAddr = dma_handle;
2321 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2322
2323 error = mpt_config(ioc, &cfg);
2324 if (error)
2325 goto out_free_consistent;
2326
2327 port_info->num_phys = buffer->NumPhys;
2328 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302329 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002330 if (!port_info->phy_info) {
2331 error = -ENOMEM;
2332 goto out_free_consistent;
2333 }
2334
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302335 ioc->nvdata_version_persistent =
2336 le16_to_cpu(buffer->NvdataVersionPersistent);
2337 ioc->nvdata_version_default =
2338 le16_to_cpu(buffer->NvdataVersionDefault);
2339
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002340 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302341 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002342 port_info->phy_info[i].phy_id = i;
2343 port_info->phy_info[i].port_id =
2344 buffer->PhyData[i].Port;
2345 port_info->phy_info[i].negotiated_link_rate =
2346 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002347 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002348 port_info->phy_info[i].handle =
2349 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002350 }
2351
2352 out_free_consistent:
2353 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2354 buffer, dma_handle);
2355 out:
2356 return error;
2357}
2358
2359static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302360mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2361{
2362 ConfigExtendedPageHeader_t hdr;
2363 CONFIGPARMS cfg;
2364 SasIOUnitPage1_t *buffer;
2365 dma_addr_t dma_handle;
2366 int error;
2367 u16 device_missing_delay;
2368
2369 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2370 memset(&cfg, 0, sizeof(CONFIGPARMS));
2371
2372 cfg.cfghdr.ehdr = &hdr;
2373 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302374 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302375 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2376 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2377 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2378 cfg.cfghdr.ehdr->PageNumber = 1;
2379
2380 error = mpt_config(ioc, &cfg);
2381 if (error)
2382 goto out;
2383 if (!hdr.ExtPageLength) {
2384 error = -ENXIO;
2385 goto out;
2386 }
2387
2388 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2389 &dma_handle);
2390 if (!buffer) {
2391 error = -ENOMEM;
2392 goto out;
2393 }
2394
2395 cfg.physAddr = dma_handle;
2396 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2397
2398 error = mpt_config(ioc, &cfg);
2399 if (error)
2400 goto out_free_consistent;
2401
2402 ioc->io_missing_delay =
2403 le16_to_cpu(buffer->IODeviceMissingDelay);
2404 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2405 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2406 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2407 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2408
2409 out_free_consistent:
2410 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2411 buffer, dma_handle);
2412 out:
2413 return error;
2414}
2415
2416static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002417mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2418 u32 form, u32 form_specific)
2419{
2420 ConfigExtendedPageHeader_t hdr;
2421 CONFIGPARMS cfg;
2422 SasPhyPage0_t *buffer;
2423 dma_addr_t dma_handle;
2424 int error;
2425
2426 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2427 hdr.ExtPageLength = 0;
2428 hdr.PageNumber = 0;
2429 hdr.Reserved1 = 0;
2430 hdr.Reserved2 = 0;
2431 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2432 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2433
2434 cfg.cfghdr.ehdr = &hdr;
2435 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302436 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002437
2438 /* Get Phy Pg 0 for each Phy. */
2439 cfg.physAddr = -1;
2440 cfg.pageAddr = form + form_specific;
2441 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2442
2443 error = mpt_config(ioc, &cfg);
2444 if (error)
2445 goto out;
2446
2447 if (!hdr.ExtPageLength) {
2448 error = -ENXIO;
2449 goto out;
2450 }
2451
2452 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2453 &dma_handle);
2454 if (!buffer) {
2455 error = -ENOMEM;
2456 goto out;
2457 }
2458
2459 cfg.physAddr = dma_handle;
2460 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2461
2462 error = mpt_config(ioc, &cfg);
2463 if (error)
2464 goto out_free_consistent;
2465
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302466 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002467
2468 phy_info->hw_link_rate = buffer->HwLinkRate;
2469 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2470 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2471 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2472
2473 out_free_consistent:
2474 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2475 buffer, dma_handle);
2476 out:
2477 return error;
2478}
2479
2480static int
2481mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2482 u32 form, u32 form_specific)
2483{
2484 ConfigExtendedPageHeader_t hdr;
2485 CONFIGPARMS cfg;
2486 SasDevicePage0_t *buffer;
2487 dma_addr_t dma_handle;
2488 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002489 int error=0;
2490
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002491 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2492 hdr.ExtPageLength = 0;
2493 hdr.PageNumber = 0;
2494 hdr.Reserved1 = 0;
2495 hdr.Reserved2 = 0;
2496 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2497 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2498
2499 cfg.cfghdr.ehdr = &hdr;
2500 cfg.pageAddr = form + form_specific;
2501 cfg.physAddr = -1;
2502 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2503 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302504 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002505
Moore, Ericdb9c9172006-03-14 09:14:18 -07002506 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002507 error = mpt_config(ioc, &cfg);
2508 if (error)
2509 goto out;
2510 if (!hdr.ExtPageLength) {
2511 error = -ENXIO;
2512 goto out;
2513 }
2514
2515 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2516 &dma_handle);
2517 if (!buffer) {
2518 error = -ENOMEM;
2519 goto out;
2520 }
2521
2522 cfg.physAddr = dma_handle;
2523 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2524
2525 error = mpt_config(ioc, &cfg);
2526 if (error)
2527 goto out_free_consistent;
2528
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302529 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002530
Kashyap, Desai2f187862009-05-29 16:52:37 +05302531 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002532 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787e2006-01-26 16:20:06 -07002533 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002534 device_info->handle_enclosure =
2535 le16_to_cpu(buffer->EnclosureHandle);
2536 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002537 device_info->phy_id = buffer->PhyNum;
2538 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002539 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002540 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002541 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002542 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2543 device_info->sas_address = le64_to_cpu(sas_address);
2544 device_info->device_info =
2545 le32_to_cpu(buffer->DeviceInfo);
2546
2547 out_free_consistent:
2548 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2549 buffer, dma_handle);
2550 out:
2551 return error;
2552}
2553
2554static int
2555mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2556 u32 form, u32 form_specific)
2557{
2558 ConfigExtendedPageHeader_t hdr;
2559 CONFIGPARMS cfg;
2560 SasExpanderPage0_t *buffer;
2561 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002562 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302563 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002564
Kashyap, Desai2f187862009-05-29 16:52:37 +05302565 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002566 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2567 hdr.ExtPageLength = 0;
2568 hdr.PageNumber = 0;
2569 hdr.Reserved1 = 0;
2570 hdr.Reserved2 = 0;
2571 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2572 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2573
2574 cfg.cfghdr.ehdr = &hdr;
2575 cfg.physAddr = -1;
2576 cfg.pageAddr = form + form_specific;
2577 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2578 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302579 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002580
Moore, Ericdb9c9172006-03-14 09:14:18 -07002581 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002582 error = mpt_config(ioc, &cfg);
2583 if (error)
2584 goto out;
2585
2586 if (!hdr.ExtPageLength) {
2587 error = -ENXIO;
2588 goto out;
2589 }
2590
2591 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2592 &dma_handle);
2593 if (!buffer) {
2594 error = -ENOMEM;
2595 goto out;
2596 }
2597
2598 cfg.physAddr = dma_handle;
2599 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2600
2601 error = mpt_config(ioc, &cfg);
2602 if (error)
2603 goto out_free_consistent;
2604
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002605 if (!buffer->NumPhys) {
2606 error = -ENODEV;
2607 goto out_free_consistent;
2608 }
2609
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002610 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302611 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002612 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302613 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002614 if (!port_info->phy_info) {
2615 error = -ENOMEM;
2616 goto out_free_consistent;
2617 }
2618
Kashyap, Desai2f187862009-05-29 16:52:37 +05302619 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002620 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002621 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002622 port_info->phy_info[i].handle =
2623 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302624 port_info->phy_info[i].identify.sas_address =
2625 le64_to_cpu(sas_address);
2626 port_info->phy_info[i].identify.handle_parent =
2627 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002628 }
Eric Moore547f9a22006-06-27 14:42:12 -06002629
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002630 out_free_consistent:
2631 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2632 buffer, dma_handle);
2633 out:
2634 return error;
2635}
2636
2637static int
2638mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2639 u32 form, u32 form_specific)
2640{
2641 ConfigExtendedPageHeader_t hdr;
2642 CONFIGPARMS cfg;
2643 SasExpanderPage1_t *buffer;
2644 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002645 int error=0;
2646
Kashyap, Desai2f187862009-05-29 16:52:37 +05302647 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002648 hdr.ExtPageLength = 0;
2649 hdr.PageNumber = 1;
2650 hdr.Reserved1 = 0;
2651 hdr.Reserved2 = 0;
2652 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2653 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2654
2655 cfg.cfghdr.ehdr = &hdr;
2656 cfg.physAddr = -1;
2657 cfg.pageAddr = form + form_specific;
2658 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2659 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302660 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002661
2662 error = mpt_config(ioc, &cfg);
2663 if (error)
2664 goto out;
2665
2666 if (!hdr.ExtPageLength) {
2667 error = -ENXIO;
2668 goto out;
2669 }
2670
2671 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2672 &dma_handle);
2673 if (!buffer) {
2674 error = -ENOMEM;
2675 goto out;
2676 }
2677
2678 cfg.physAddr = dma_handle;
2679 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2680
2681 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302682
2683 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2684 error = -ENODEV;
2685 goto out;
2686 }
2687
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002688 if (error)
2689 goto out_free_consistent;
2690
2691
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302692 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002693
2694 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002695 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002696 phy_info->port_id = buffer->PhysicalPort;
2697 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2698 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2699 phy_info->hw_link_rate = buffer->HwLinkRate;
2700 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2701 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2702
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002703 out_free_consistent:
2704 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2705 buffer, dma_handle);
2706 out:
2707 return error;
2708}
2709
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302710struct rep_manu_request{
2711 u8 smp_frame_type;
2712 u8 function;
2713 u8 reserved;
2714 u8 request_length;
2715};
2716
2717struct rep_manu_reply{
2718 u8 smp_frame_type; /* 0x41 */
2719 u8 function; /* 0x01 */
2720 u8 function_result;
2721 u8 response_length;
2722 u16 expander_change_count;
2723 u8 reserved0[2];
2724 u8 sas_format:1;
2725 u8 reserved1:7;
2726 u8 reserved2[3];
2727 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2728 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2729 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2730 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2731 u16 component_id;
2732 u8 component_revision_id;
2733 u8 reserved3;
2734 u8 vendor_specific[8];
2735};
2736
2737/**
2738 * mptsas_exp_repmanufacture_info -
2739 * @ioc: per adapter object
2740 * @sas_address: expander sas address
2741 * @edev: the sas_expander_device object
2742 *
2743 * Fills in the sas_expander_device object when SMP port is created.
2744 *
2745 * Returns 0 for success, non-zero for failure.
2746 */
2747static int
2748mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2749 u64 sas_address, struct sas_expander_device *edev)
2750{
2751 MPT_FRAME_HDR *mf;
2752 SmpPassthroughRequest_t *smpreq;
2753 SmpPassthroughReply_t *smprep;
2754 struct rep_manu_reply *manufacture_reply;
2755 struct rep_manu_request *manufacture_request;
2756 int ret;
2757 int flagsLength;
2758 unsigned long timeleft;
2759 char *psge;
2760 unsigned long flags;
2761 void *data_out = NULL;
2762 dma_addr_t data_out_dma = 0;
2763 u32 sz;
2764
2765 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2766 if (ioc->ioc_reset_in_progress) {
2767 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2768 printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2769 __func__, ioc->name);
2770 return -EFAULT;
2771 }
2772 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2773
2774 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2775 if (ret)
2776 goto out;
2777
2778 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2779 if (!mf) {
2780 ret = -ENOMEM;
2781 goto out_unlock;
2782 }
2783
2784 smpreq = (SmpPassthroughRequest_t *)mf;
2785 memset(smpreq, 0, sizeof(*smpreq));
2786
2787 sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2788
2789 data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2790 if (!data_out) {
2791 printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2792 __FILE__, __LINE__, __func__);
2793 ret = -ENOMEM;
2794 goto put_mf;
2795 }
2796
2797 manufacture_request = data_out;
2798 manufacture_request->smp_frame_type = 0x40;
2799 manufacture_request->function = 1;
2800 manufacture_request->reserved = 0;
2801 manufacture_request->request_length = 0;
2802
2803 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2804 smpreq->PhysicalPort = 0xFF;
2805 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2806 smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2807
2808 psge = (char *)
2809 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2810
2811 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2812 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2813 MPI_SGE_FLAGS_HOST_TO_IOC |
2814 MPI_SGE_FLAGS_END_OF_BUFFER;
2815 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2816 flagsLength |= sizeof(struct rep_manu_request);
2817
2818 ioc->add_sge(psge, flagsLength, data_out_dma);
2819 psge += ioc->SGE_size;
2820
2821 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2822 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2823 MPI_SGE_FLAGS_IOC_TO_HOST |
2824 MPI_SGE_FLAGS_END_OF_BUFFER;
2825 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2826 flagsLength |= sizeof(struct rep_manu_reply);
2827 ioc->add_sge(psge, flagsLength, data_out_dma +
2828 sizeof(struct rep_manu_request));
2829
2830 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2831 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2832
2833 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2834 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2835 ret = -ETIME;
2836 mpt_free_msg_frame(ioc, mf);
2837 mf = NULL;
2838 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2839 goto out_free;
2840 if (!timeleft)
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302841 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302842 goto out_free;
2843 }
2844
2845 mf = NULL;
2846
2847 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2848 u8 *tmp;
2849
2850 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2851 if (le16_to_cpu(smprep->ResponseDataLength) !=
2852 sizeof(struct rep_manu_reply))
2853 goto out_free;
2854
2855 manufacture_reply = data_out + sizeof(struct rep_manu_request);
2856 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2857 SAS_EXPANDER_VENDOR_ID_LEN);
2858 strncpy(edev->product_id, manufacture_reply->product_id,
2859 SAS_EXPANDER_PRODUCT_ID_LEN);
2860 strncpy(edev->product_rev, manufacture_reply->product_rev,
2861 SAS_EXPANDER_PRODUCT_REV_LEN);
2862 edev->level = manufacture_reply->sas_format;
2863 if (manufacture_reply->sas_format) {
2864 strncpy(edev->component_vendor_id,
2865 manufacture_reply->component_vendor_id,
2866 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2867 tmp = (u8 *)&manufacture_reply->component_id;
2868 edev->component_id = tmp[0] << 8 | tmp[1];
2869 edev->component_revision_id =
2870 manufacture_reply->component_revision_id;
2871 }
2872 } else {
2873 printk(MYIOC_s_ERR_FMT
2874 "%s: smp passthru reply failed to be returned\n",
2875 ioc->name, __func__);
2876 ret = -ENXIO;
2877 }
2878out_free:
2879 if (data_out_dma)
2880 pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2881put_mf:
2882 if (mf)
2883 mpt_free_msg_frame(ioc, mf);
2884out_unlock:
2885 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2886 mutex_unlock(&ioc->sas_mgmt.mutex);
2887out:
2888 return ret;
2889 }
2890
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002891static void
2892mptsas_parse_device_info(struct sas_identify *identify,
2893 struct mptsas_devinfo *device_info)
2894{
2895 u16 protocols;
2896
2897 identify->sas_address = device_info->sas_address;
2898 identify->phy_identifier = device_info->phy_id;
2899
2900 /*
2901 * Fill in Phy Initiator Port Protocol.
2902 * Bits 6:3, more than one bit can be set, fall through cases.
2903 */
2904 protocols = device_info->device_info & 0x78;
2905 identify->initiator_port_protocols = 0;
2906 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2907 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2908 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2909 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2910 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2911 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2912 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2913 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2914
2915 /*
2916 * Fill in Phy Target Port Protocol.
2917 * Bits 10:7, more than one bit can be set, fall through cases.
2918 */
2919 protocols = device_info->device_info & 0x780;
2920 identify->target_port_protocols = 0;
2921 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2922 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2923 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2924 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2925 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2926 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2927 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2928 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2929
2930 /*
2931 * Fill in Attached device type.
2932 */
2933 switch (device_info->device_info &
2934 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2935 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2936 identify->device_type = SAS_PHY_UNUSED;
2937 break;
2938 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2939 identify->device_type = SAS_END_DEVICE;
2940 break;
2941 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2942 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2943 break;
2944 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2945 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2946 break;
2947 }
2948}
2949
2950static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002951 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002952{
Moore, Erice6b2d762006-03-14 09:14:24 -07002953 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002954 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002955 struct sas_port *port;
2956 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002957
Eric Moore547f9a22006-06-27 14:42:12 -06002958 if (!dev) {
2959 error = -ENODEV;
2960 goto out;
2961 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002962
2963 if (!phy_info->phy) {
2964 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002965 if (!phy) {
2966 error = -ENOMEM;
2967 goto out;
2968 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002969 } else
2970 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002971
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002972 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002973
2974 /*
2975 * Set Negotiated link rate.
2976 */
2977 switch (phy_info->negotiated_link_rate) {
2978 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002979 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002980 break;
2981 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002982 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002983 break;
2984 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002985 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002986 break;
2987 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002988 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002989 break;
2990 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2991 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2992 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002993 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002994 break;
2995 }
2996
2997 /*
2998 * Set Max hardware link rate.
2999 */
3000 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3001 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003002 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003003 break;
3004 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003005 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003006 break;
3007 default:
3008 break;
3009 }
3010
3011 /*
3012 * Set Max programmed link rate.
3013 */
3014 switch (phy_info->programmed_link_rate &
3015 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3016 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003017 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003018 break;
3019 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003020 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003021 break;
3022 default:
3023 break;
3024 }
3025
3026 /*
3027 * Set Min hardware link rate.
3028 */
3029 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3030 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003031 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003032 break;
3033 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003034 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003035 break;
3036 default:
3037 break;
3038 }
3039
3040 /*
3041 * Set Min programmed link rate.
3042 */
3043 switch (phy_info->programmed_link_rate &
3044 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3045 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003046 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003047 break;
3048 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003049 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003050 break;
3051 default:
3052 break;
3053 }
3054
Moore, Erice6b2d762006-03-14 09:14:24 -07003055 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003056
Moore, Erice6b2d762006-03-14 09:14:24 -07003057 error = sas_phy_add(phy);
3058 if (error) {
3059 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06003060 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07003061 }
3062 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003063 }
3064
Eric Moore547f9a22006-06-27 14:42:12 -06003065 if (!phy_info->attached.handle ||
3066 !phy_info->port_details)
3067 goto out;
3068
3069 port = mptsas_get_port(phy_info);
3070 ioc = phy_to_ioc(phy_info->phy);
3071
3072 if (phy_info->sas_port_add_phy) {
3073
3074 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06003075 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06003076 if (!port) {
3077 error = -ENOMEM;
3078 goto out;
3079 }
3080 error = sas_port_add(port);
3081 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303082 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003083 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003084 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003085 goto out;
3086 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303087 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303088 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3089 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3090 ioc->name, port->port_identifier,
3091 (unsigned long long)phy_info->
3092 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06003093 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05303094 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3095 "sas_port_add_phy: phy_id=%d\n",
3096 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06003097 sas_port_add_phy(port, phy_info->phy);
3098 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303099 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3100 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3101 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06003102 }
Eric Moore547f9a22006-06-27 14:42:12 -06003103 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003104
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003105 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05003106 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06003107 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003108
James Bottomley2686de22006-06-30 12:54:02 -05003109 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07003110 /*
3111 * Let the hotplug_work thread handle processing
3112 * the adding/removing of devices that occur
3113 * after start of day.
3114 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303115 if (mptsas_is_end_device(&phy_info->attached) &&
3116 phy_info->attached.handle_parent) {
3117 goto out;
3118 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003119
James Bottomleyf013db32006-03-18 14:54:36 -06003120 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05003121 if (scsi_is_host_device(parent)) {
3122 struct mptsas_portinfo *port_info;
3123 int i;
3124
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303125 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05003126
3127 for (i = 0; i < port_info->num_phys; i++)
3128 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003129 identify.sas_address) {
3130 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003131 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003132 }
James Bottomley2686de22006-06-30 12:54:02 -05003133
3134 } else if (scsi_is_sas_rphy(parent)) {
3135 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3136 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003137 parent_rphy->identify.sas_address) {
3138 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003139 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003140 }
James Bottomley2686de22006-06-30 12:54:02 -05003141 }
3142
James Bottomleyf013db32006-03-18 14:54:36 -06003143 switch (identify.device_type) {
3144 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003145 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06003146 break;
3147 case SAS_EDGE_EXPANDER_DEVICE:
3148 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003149 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06003150 break;
3151 default:
3152 rphy = NULL;
3153 break;
3154 }
Eric Moore547f9a22006-06-27 14:42:12 -06003155 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303156 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003157 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003158 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003159 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003160 }
3161
Eric Moore547f9a22006-06-27 14:42:12 -06003162 rphy->identify = identify;
3163 error = sas_rphy_add(rphy);
3164 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303165 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003166 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003167 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003168 sas_rphy_free(rphy);
3169 goto out;
3170 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303171 mptsas_set_rphy(ioc, phy_info, rphy);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05303172 if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3173 identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3174 mptsas_exp_repmanufacture_info(ioc,
3175 identify.sas_address,
3176 rphy_to_expander_device(rphy));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003177 }
3178
Eric Moore547f9a22006-06-27 14:42:12 -06003179 out:
3180 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003181}
3182
3183static int
Moore, Erice6b2d762006-03-14 09:14:24 -07003184mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003185{
Moore, Erice6b2d762006-03-14 09:14:24 -07003186 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003187 int error = -ENOMEM, i;
3188
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303189 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07003190 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003191 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003192
Moore, Erice6b2d762006-03-14 09:14:24 -07003193 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003194 if (error)
3195 goto out_free_port_info;
3196
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303197 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003198 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303199 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07003200 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303201 ioc->hba_port_info = port_info = hba;
3202 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003203 list_add_tail(&port_info->list, &ioc->sas_topology);
3204 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003205 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003206 port_info->phy_info[i].negotiated_link_rate =
3207 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003208 port_info->phy_info[i].handle =
3209 hba->phy_info[i].handle;
3210 port_info->phy_info[i].port_id =
3211 hba->phy_info[i].port_id;
3212 }
Eric Moore547f9a22006-06-27 14:42:12 -06003213 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003214 kfree(hba);
3215 hba = NULL;
3216 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003217 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303218#if defined(CPQ_CIM)
3219 ioc->num_ports = port_info->num_phys;
3220#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003221 for (i = 0; i < port_info->num_phys; i++) {
3222 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3223 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3224 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303225 port_info->phy_info[i].identify.handle =
3226 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003227 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003228 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3229 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303230 port_info->phy_info[i].identify.handle);
3231 if (!ioc->hba_port_sas_addr)
3232 ioc->hba_port_sas_addr =
3233 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003234 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003235 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003236 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003237 mptsas_sas_device_pg0(ioc,
3238 &port_info->phy_info[i].attached,
3239 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3240 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3241 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003242 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003243
Eric Moore547f9a22006-06-27 14:42:12 -06003244 mptsas_setup_wide_ports(ioc, port_info);
3245
3246 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003247 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003248 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003249
3250 return 0;
3251
3252 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003253 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003254 out:
3255 return error;
3256}
3257
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303258static void
3259mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003260{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303261 struct mptsas_portinfo *parent;
3262 struct device *parent_dev;
3263 struct sas_rphy *rphy;
3264 int i;
3265 u64 sas_address; /* expander sas address */
3266 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003267
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303268 handle = port_info->phy_info[0].handle;
3269 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003270 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003271 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303272 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3273 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003274
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303275 mptsas_sas_device_pg0(ioc,
3276 &port_info->phy_info[i].identify,
3277 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3278 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3279 port_info->phy_info[i].identify.handle);
3280 port_info->phy_info[i].identify.phy_id =
3281 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003282
3283 if (port_info->phy_info[i].attached.handle) {
3284 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303285 &port_info->phy_info[i].attached,
3286 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3287 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3288 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003289 port_info->phy_info[i].attached.phy_id =
3290 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003291 }
Eric Moore547f9a22006-06-27 14:42:12 -06003292 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003293
Moore, Erice6b2d762006-03-14 09:14:24 -07003294 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303295 parent = mptsas_find_portinfo_by_handle(ioc,
3296 port_info->phy_info[0].identify.handle_parent);
3297 if (!parent) {
3298 mutex_unlock(&ioc->sas_topology_mutex);
3299 return;
3300 }
3301 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3302 i++) {
3303 if (parent->phy_info[i].attached.sas_address == sas_address) {
3304 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3305 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003306 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003307 }
3308 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303309
3310 mptsas_setup_wide_ports(ioc, port_info);
3311 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3312 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3313 ioc->sas_index, 0);
3314}
3315
3316static void
3317mptsas_expander_event_add(MPT_ADAPTER *ioc,
3318 MpiEventDataSasExpanderStatusChange_t *expander_data)
3319{
3320 struct mptsas_portinfo *port_info;
3321 int i;
3322 __le64 sas_address;
3323
3324 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3325 if (!port_info)
3326 BUG();
3327 port_info->num_phys = (expander_data->NumPhys) ?
3328 expander_data->NumPhys : 1;
3329 port_info->phy_info = kcalloc(port_info->num_phys,
3330 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3331 if (!port_info->phy_info)
3332 BUG();
3333 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3334 for (i = 0; i < port_info->num_phys; i++) {
3335 port_info->phy_info[i].portinfo = port_info;
3336 port_info->phy_info[i].handle =
3337 le16_to_cpu(expander_data->DevHandle);
3338 port_info->phy_info[i].identify.sas_address =
3339 le64_to_cpu(sas_address);
3340 port_info->phy_info[i].identify.handle_parent =
3341 le16_to_cpu(expander_data->ParentDevHandle);
3342 }
3343
3344 mutex_lock(&ioc->sas_topology_mutex);
3345 list_add_tail(&port_info->list, &ioc->sas_topology);
3346 mutex_unlock(&ioc->sas_topology_mutex);
3347
3348 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3349 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3350 (unsigned long long)sas_address);
3351
3352 mptsas_expander_refresh(ioc, port_info);
3353}
3354
3355/**
3356 * mptsas_delete_expander_siblings - remove siblings attached to expander
3357 * @ioc: Pointer to MPT_ADAPTER structure
3358 * @parent: the parent port_info object
3359 * @expander: the expander port_info object
3360 **/
3361static void
3362mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3363 *parent, struct mptsas_portinfo *expander)
3364{
3365 struct mptsas_phyinfo *phy_info;
3366 struct mptsas_portinfo *port_info;
3367 struct sas_rphy *rphy;
3368 int i;
3369
3370 phy_info = expander->phy_info;
3371 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3372 rphy = mptsas_get_rphy(phy_info);
3373 if (!rphy)
3374 continue;
3375 if (rphy->identify.device_type == SAS_END_DEVICE)
3376 mptsas_del_end_device(ioc, phy_info);
3377 }
3378
3379 phy_info = expander->phy_info;
3380 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3381 rphy = mptsas_get_rphy(phy_info);
3382 if (!rphy)
3383 continue;
3384 if (rphy->identify.device_type ==
3385 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3386 rphy->identify.device_type ==
3387 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3388 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3389 rphy->identify.sas_address);
3390 if (!port_info)
3391 continue;
3392 if (port_info == parent) /* backlink rphy */
3393 continue;
3394 /*
3395 Delete this expander even if the expdevpage is exists
3396 because the parent expander is already deleted
3397 */
3398 mptsas_expander_delete(ioc, port_info, 1);
3399 }
3400 }
3401}
3402
3403
3404/**
3405 * mptsas_expander_delete - remove this expander
3406 * @ioc: Pointer to MPT_ADAPTER structure
3407 * @port_info: expander port_info struct
3408 * @force: Flag to forcefully delete the expander
3409 *
3410 **/
3411
3412static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3413 struct mptsas_portinfo *port_info, u8 force)
3414{
3415
3416 struct mptsas_portinfo *parent;
3417 int i;
3418 u64 expander_sas_address;
3419 struct mptsas_phyinfo *phy_info;
3420 struct mptsas_portinfo buffer;
3421 struct mptsas_portinfo_details *port_details;
3422 struct sas_port *port;
3423
3424 if (!port_info)
3425 return;
3426
3427 /* see if expander is still there before deleting */
3428 mptsas_sas_expander_pg0(ioc, &buffer,
3429 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3430 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3431 port_info->phy_info[0].identify.handle);
3432
3433 if (buffer.num_phys) {
3434 kfree(buffer.phy_info);
3435 if (!force)
3436 return;
3437 }
3438
3439
3440 /*
3441 * Obtain the port_info instance to the parent port
3442 */
3443 port_details = NULL;
3444 expander_sas_address =
3445 port_info->phy_info[0].identify.sas_address;
3446 parent = mptsas_find_portinfo_by_handle(ioc,
3447 port_info->phy_info[0].identify.handle_parent);
3448 mptsas_delete_expander_siblings(ioc, parent, port_info);
3449 if (!parent)
3450 goto out;
3451
3452 /*
3453 * Delete rphys in the parent that point
3454 * to this expander.
3455 */
3456 phy_info = parent->phy_info;
3457 port = NULL;
3458 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3459 if (!phy_info->phy)
3460 continue;
3461 if (phy_info->attached.sas_address !=
3462 expander_sas_address)
3463 continue;
3464 if (!port) {
3465 port = mptsas_get_port(phy_info);
3466 port_details = phy_info->port_details;
3467 }
3468 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3469 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3470 phy_info->phy_id, phy_info->phy);
3471 sas_port_delete_phy(port, phy_info->phy);
3472 }
3473 if (port) {
3474 dev_printk(KERN_DEBUG, &port->dev,
3475 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3476 ioc->name, port->port_identifier,
3477 (unsigned long long)expander_sas_address);
3478 sas_port_delete(port);
3479 mptsas_port_delete(ioc, port_details);
3480 }
3481 out:
3482
3483 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3484 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3485 (unsigned long long)expander_sas_address);
3486
3487 /*
3488 * free link
3489 */
3490 list_del(&port_info->list);
3491 kfree(port_info->phy_info);
3492 kfree(port_info);
3493}
3494
3495
3496/**
3497 * mptsas_send_expander_event - expanders events
3498 * @ioc: Pointer to MPT_ADAPTER structure
3499 * @expander_data: event data
3500 *
3501 *
3502 * This function handles adding, removing, and refreshing
3503 * device handles within the expander objects.
3504 */
3505static void
3506mptsas_send_expander_event(struct fw_event_work *fw_event)
3507{
3508 MPT_ADAPTER *ioc;
3509 MpiEventDataSasExpanderStatusChange_t *expander_data;
3510 struct mptsas_portinfo *port_info;
3511 __le64 sas_address;
3512 int i;
3513
3514 ioc = fw_event->ioc;
3515 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3516 fw_event->event_data;
3517 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303518 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303519 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3520
3521 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3522 if (port_info) {
3523 for (i = 0; i < port_info->num_phys; i++) {
3524 port_info->phy_info[i].portinfo = port_info;
3525 port_info->phy_info[i].handle =
3526 le16_to_cpu(expander_data->DevHandle);
3527 port_info->phy_info[i].identify.sas_address =
3528 le64_to_cpu(sas_address);
3529 port_info->phy_info[i].identify.handle_parent =
3530 le16_to_cpu(expander_data->ParentDevHandle);
3531 }
3532 mptsas_expander_refresh(ioc, port_info);
3533 } else if (!port_info && expander_data->NumPhys)
3534 mptsas_expander_event_add(ioc, expander_data);
3535 } else if (expander_data->ReasonCode ==
3536 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3537 mptsas_expander_delete(ioc, port_info, 0);
3538
3539 mptsas_free_fw_event(ioc, fw_event);
3540}
3541
3542
3543/**
3544 * mptsas_expander_add -
3545 * @ioc: Pointer to MPT_ADAPTER structure
3546 * @handle:
3547 *
3548 */
3549struct mptsas_portinfo *
3550mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3551{
3552 struct mptsas_portinfo buffer, *port_info;
3553 int i;
3554
3555 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3556 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3557 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3558 return NULL;
3559
3560 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3561 if (!port_info) {
3562 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3563 "%s: exit at line=%d\n", ioc->name,
3564 __func__, __LINE__));
3565 return NULL;
3566 }
3567 port_info->num_phys = buffer.num_phys;
3568 port_info->phy_info = buffer.phy_info;
3569 for (i = 0; i < port_info->num_phys; i++)
3570 port_info->phy_info[i].portinfo = port_info;
3571 mutex_lock(&ioc->sas_topology_mutex);
3572 list_add_tail(&port_info->list, &ioc->sas_topology);
3573 mutex_unlock(&ioc->sas_topology_mutex);
3574 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3575 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3576 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3577 mptsas_expander_refresh(ioc, port_info);
3578 return port_info;
3579}
3580
3581static void
3582mptsas_send_link_status_event(struct fw_event_work *fw_event)
3583{
3584 MPT_ADAPTER *ioc;
3585 MpiEventDataSasPhyLinkStatus_t *link_data;
3586 struct mptsas_portinfo *port_info;
3587 struct mptsas_phyinfo *phy_info = NULL;
3588 __le64 sas_address;
3589 u8 phy_num;
3590 u8 link_rate;
3591
3592 ioc = fw_event->ioc;
3593 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3594
3595 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3596 sas_address = le64_to_cpu(sas_address);
3597 link_rate = link_data->LinkRates >> 4;
3598 phy_num = link_data->PhyNum;
3599
3600 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3601 if (port_info) {
3602 phy_info = &port_info->phy_info[phy_num];
3603 if (phy_info)
3604 phy_info->negotiated_link_rate = link_rate;
3605 }
3606
3607 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3608 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3609
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303610 if (!port_info) {
3611 if (ioc->old_sas_discovery_protocal) {
3612 port_info = mptsas_expander_add(ioc,
3613 le16_to_cpu(link_data->DevHandle));
3614 if (port_info)
3615 goto out;
3616 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303617 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303618 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303619
3620 if (port_info == ioc->hba_port_info)
3621 mptsas_probe_hba_phys(ioc);
3622 else
3623 mptsas_expander_refresh(ioc, port_info);
3624 } else if (phy_info && phy_info->phy) {
3625 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3626 phy_info->phy->negotiated_linkrate =
3627 SAS_PHY_DISABLED;
3628 else if (link_rate ==
3629 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3630 phy_info->phy->negotiated_linkrate =
3631 SAS_LINK_RATE_FAILED;
3632 else
3633 phy_info->phy->negotiated_linkrate =
3634 SAS_LINK_RATE_UNKNOWN;
3635 }
3636 out:
3637 mptsas_free_fw_event(ioc, fw_event);
3638}
3639
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303640static void
3641mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3642{
3643 struct mptsas_portinfo buffer, *port_info;
3644 struct mptsas_device_info *sas_info;
3645 struct mptsas_devinfo sas_device;
3646 u32 handle;
3647 VirtTarget *vtarget = NULL;
3648 struct mptsas_phyinfo *phy_info;
3649 u8 found_expander;
3650 int retval, retry_count;
3651 unsigned long flags;
3652
3653 mpt_findImVolumes(ioc);
3654
3655 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3656 if (ioc->ioc_reset_in_progress) {
3657 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3658 "%s: exiting due to a parallel reset \n", ioc->name,
3659 __func__));
3660 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3661 return;
3662 }
3663 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3664
3665 /* devices, logical volumes */
3666 mutex_lock(&ioc->sas_device_info_mutex);
3667 redo_device_scan:
3668 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303669 if (sas_info->is_cached)
3670 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303671 if (!sas_info->is_logical_volume) {
3672 sas_device.handle = 0;
3673 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303674retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303675 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303676 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3677 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3678 (sas_info->fw.channel << 8) +
3679 sas_info->fw.id);
3680
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303681 if (sas_device.handle)
3682 continue;
3683 if (retval == -EBUSY) {
3684 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3685 if (ioc->ioc_reset_in_progress) {
3686 dfailprintk(ioc,
3687 printk(MYIOC_s_DEBUG_FMT
3688 "%s: exiting due to reset\n",
3689 ioc->name, __func__));
3690 spin_unlock_irqrestore
3691 (&ioc->taskmgmt_lock, flags);
3692 mutex_unlock(&ioc->
3693 sas_device_info_mutex);
3694 return;
3695 }
3696 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3697 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303698 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303699
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303700 if (retval && (retval != -ENODEV)) {
3701 if (retry_count < 10) {
3702 retry_count++;
3703 goto retry_page;
3704 } else {
3705 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3706 "%s: Config page retry exceeded retry "
3707 "count deleting device 0x%llx\n",
3708 ioc->name, __func__,
3709 sas_info->sas_address));
3710 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303711 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303712
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303713 /* delete device */
3714 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303715 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303716
3717 if (vtarget)
3718 vtarget->deleted = 1;
3719
3720 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3721 sas_info->sas_address);
3722
3723 if (phy_info) {
3724 mptsas_del_end_device(ioc, phy_info);
3725 goto redo_device_scan;
3726 }
3727 } else
3728 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303729 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003730 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303731
3732 /* expanders */
3733 mutex_lock(&ioc->sas_topology_mutex);
3734 redo_expander_scan:
3735 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3736
3737 if (port_info->phy_info &&
3738 (!(port_info->phy_info[0].identify.device_info &
3739 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3740 continue;
3741 found_expander = 0;
3742 handle = 0xFFFF;
3743 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3744 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3745 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3746 !found_expander) {
3747
3748 handle = buffer.phy_info[0].handle;
3749 if (buffer.phy_info[0].identify.sas_address ==
3750 port_info->phy_info[0].identify.sas_address) {
3751 found_expander = 1;
3752 }
3753 kfree(buffer.phy_info);
3754 }
3755
3756 if (!found_expander) {
3757 mptsas_expander_delete(ioc, port_info, 0);
3758 goto redo_expander_scan;
3759 }
3760 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003761 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303762}
3763
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303764/**
3765 * mptsas_probe_expanders - adding expanders
3766 * @ioc: Pointer to MPT_ADAPTER structure
3767 *
3768 **/
3769static void
3770mptsas_probe_expanders(MPT_ADAPTER *ioc)
3771{
3772 struct mptsas_portinfo buffer, *port_info;
3773 u32 handle;
3774 int i;
3775
3776 handle = 0xFFFF;
3777 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3778 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3779 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3780
3781 handle = buffer.phy_info[0].handle;
3782 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3783 buffer.phy_info[0].identify.sas_address);
3784
3785 if (port_info) {
3786 /* refreshing handles */
3787 for (i = 0; i < buffer.num_phys; i++) {
3788 port_info->phy_info[i].handle = handle;
3789 port_info->phy_info[i].identify.handle_parent =
3790 buffer.phy_info[0].identify.handle_parent;
3791 }
3792 mptsas_expander_refresh(ioc, port_info);
3793 kfree(buffer.phy_info);
3794 continue;
3795 }
3796
3797 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3798 if (!port_info) {
3799 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3800 "%s: exit at line=%d\n", ioc->name,
3801 __func__, __LINE__));
3802 return;
3803 }
3804 port_info->num_phys = buffer.num_phys;
3805 port_info->phy_info = buffer.phy_info;
3806 for (i = 0; i < port_info->num_phys; i++)
3807 port_info->phy_info[i].portinfo = port_info;
3808 mutex_lock(&ioc->sas_topology_mutex);
3809 list_add_tail(&port_info->list, &ioc->sas_topology);
3810 mutex_unlock(&ioc->sas_topology_mutex);
3811 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3812 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3813 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3814 mptsas_expander_refresh(ioc, port_info);
3815 }
3816}
3817
3818static void
3819mptsas_probe_devices(MPT_ADAPTER *ioc)
3820{
3821 u16 handle;
3822 struct mptsas_devinfo sas_device;
3823 struct mptsas_phyinfo *phy_info;
3824
3825 handle = 0xFFFF;
3826 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3827 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3828
3829 handle = sas_device.handle;
3830
3831 if ((sas_device.device_info &
3832 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3833 MPI_SAS_DEVICE_INFO_STP_TARGET |
3834 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3835 continue;
3836
3837 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3838 if (!phy_info)
3839 continue;
3840
3841 if (mptsas_get_rphy(phy_info))
3842 continue;
3843
3844 mptsas_add_end_device(ioc, phy_info);
3845 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003846}
3847
Kashyap, Desai2f187862009-05-29 16:52:37 +05303848/**
3849 * mptsas_scan_sas_topology -
3850 * @ioc: Pointer to MPT_ADAPTER structure
3851 * @sas_address:
3852 *
3853 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003854static void
3855mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3856{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303857 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003858 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003859
Moore, Erice6b2d762006-03-14 09:14:24 -07003860 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303861 mptsas_probe_expanders(ioc);
3862 mptsas_probe_devices(ioc);
3863
Moore, Ericf44e5462006-03-14 09:14:21 -07003864 /*
3865 Reporting RAID volumes.
3866 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303867 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3868 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3869 return;
Eric Moore793955f2007-01-29 09:42:20 -07003870 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303871 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3872 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3873 if (sdev) {
3874 scsi_device_put(sdev);
3875 continue;
3876 }
3877 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3878 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3879 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003880 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003881 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3882 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003883}
3884
Kashyap, Desai57e98512009-05-29 16:55:09 +05303885
3886static void
3887mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3888{
3889 MPT_ADAPTER *ioc;
3890 EventDataQueueFull_t *qfull_data;
3891 struct mptsas_device_info *sas_info;
3892 struct scsi_device *sdev;
3893 int depth;
3894 int id = -1;
3895 int channel = -1;
3896 int fw_id, fw_channel;
3897 u16 current_depth;
3898
3899
3900 ioc = fw_event->ioc;
3901 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3902 fw_id = qfull_data->TargetID;
3903 fw_channel = qfull_data->Bus;
3904 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3905
3906 /* if hidden raid component, look for the volume id */
3907 mutex_lock(&ioc->sas_device_info_mutex);
3908 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3909 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3910 list) {
3911 if (sas_info->is_cached ||
3912 sas_info->is_logical_volume)
3913 continue;
3914 if (sas_info->is_hidden_raid_component &&
3915 (sas_info->fw.channel == fw_channel &&
3916 sas_info->fw.id == fw_id)) {
3917 id = sas_info->volume_id;
3918 channel = MPTSAS_RAID_CHANNEL;
3919 goto out;
3920 }
3921 }
3922 } else {
3923 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3924 list) {
3925 if (sas_info->is_cached ||
3926 sas_info->is_hidden_raid_component ||
3927 sas_info->is_logical_volume)
3928 continue;
3929 if (sas_info->fw.channel == fw_channel &&
3930 sas_info->fw.id == fw_id) {
3931 id = sas_info->os.id;
3932 channel = sas_info->os.channel;
3933 goto out;
3934 }
3935 }
3936
3937 }
3938
3939 out:
3940 mutex_unlock(&ioc->sas_device_info_mutex);
3941
3942 if (id != -1) {
3943 shost_for_each_device(sdev, ioc->sh) {
3944 if (sdev->id == id && sdev->channel == channel) {
3945 if (current_depth > sdev->queue_depth) {
3946 sdev_printk(KERN_INFO, sdev,
3947 "strange observation, the queue "
3948 "depth is (%d) meanwhile fw queue "
3949 "depth (%d)\n", sdev->queue_depth,
3950 current_depth);
3951 continue;
3952 }
3953 depth = scsi_track_queue_full(sdev,
3954 current_depth - 1);
3955 if (depth > 0)
3956 sdev_printk(KERN_INFO, sdev,
3957 "Queue depth reduced to (%d)\n",
3958 depth);
3959 else if (depth < 0)
3960 sdev_printk(KERN_INFO, sdev,
3961 "Tagged Command Queueing is being "
3962 "disabled\n");
3963 else if (depth == 0)
3964 sdev_printk(KERN_INFO, sdev,
3965 "Queue depth not changed yet\n");
3966 }
3967 }
3968 }
3969
3970 mptsas_free_fw_event(ioc, fw_event);
3971}
3972
3973
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003974static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003975mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003976{
3977 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003978 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003979 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003980
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003981 mutex_lock(&ioc->sas_topology_mutex);
3982 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3983 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003984 if (!mptsas_is_end_device(
3985 &port_info->phy_info[i].attached))
3986 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003987 if (port_info->phy_info[i].attached.sas_address
3988 != sas_address)
3989 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003990 phy_info = &port_info->phy_info[i];
3991 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003992 }
3993 }
3994 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003995 return phy_info;
3996}
3997
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303998/**
3999 * mptsas_find_phyinfo_by_phys_disk_num -
4000 * @ioc: Pointer to MPT_ADAPTER structure
4001 * @phys_disk_num:
4002 * @channel:
4003 * @id:
4004 *
4005 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07004006static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304007mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4008 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07004009{
Eric Mooreb506ade2007-01-29 09:45:37 -07004010 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304011 struct mptsas_portinfo *port_info;
4012 RaidPhysDiskPage1_t *phys_disk = NULL;
4013 int num_paths;
4014 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07004015 int i;
4016
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304017 phy_info = NULL;
4018 if (!ioc->raid_data.pIocPg3)
4019 return NULL;
4020 /* dual port support */
4021 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4022 if (!num_paths)
4023 goto out;
4024 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4025 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4026 if (!phys_disk)
4027 goto out;
4028 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4029 for (i = 0; i < num_paths; i++) {
4030 if ((phys_disk->Path[i].Flags & 1) != 0)
4031 /* entry no longer valid */
4032 continue;
4033 if ((id == phys_disk->Path[i].PhysDiskID) &&
4034 (channel == phys_disk->Path[i].PhysDiskBus)) {
4035 memcpy(&sas_address, &phys_disk->Path[i].WWID,
4036 sizeof(u64));
4037 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4038 sas_address);
4039 goto out;
4040 }
4041 }
4042
4043 out:
4044 kfree(phys_disk);
4045 if (phy_info)
4046 return phy_info;
4047
4048 /*
4049 * Extra code to handle RAID0 case, where the sas_address is not updated
4050 * in phys_disk_page_1 when hotswapped
4051 */
Eric Mooreb506ade2007-01-29 09:45:37 -07004052 mutex_lock(&ioc->sas_topology_mutex);
4053 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304054 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004055 if (!mptsas_is_end_device(
4056 &port_info->phy_info[i].attached))
4057 continue;
4058 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4059 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304060 if ((port_info->phy_info[i].attached.phys_disk_num ==
4061 phys_disk_num) &&
4062 (port_info->phy_info[i].attached.id == id) &&
4063 (port_info->phy_info[i].attached.channel ==
4064 channel))
4065 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06004066 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004067 }
4068 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004069 return phy_info;
4070}
4071
4072static void
Moore, Ericf44e5462006-03-14 09:14:21 -07004073mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4074{
Eric Mooref99be432007-01-04 20:46:54 -07004075 int rc;
4076
Moore, Ericf44e5462006-03-14 09:14:21 -07004077 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07004078 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07004079}
4080
4081static void
4082mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4083{
4084 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4085 mptsas_reprobe_lun);
4086}
4087
Eric Mooreb506ade2007-01-29 09:45:37 -07004088static void
4089mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4090{
4091 CONFIGPARMS cfg;
4092 ConfigPageHeader_t hdr;
4093 dma_addr_t dma_handle;
4094 pRaidVolumePage0_t buffer = NULL;
4095 RaidPhysDiskPage0_t phys_disk;
4096 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304097 struct mptsas_phyinfo *phy_info;
4098 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07004099
4100 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4101 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4102 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4103 cfg.pageAddr = (channel << 8) + id;
4104 cfg.cfghdr.hdr = &hdr;
4105 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai568da762010-03-18 19:23:50 +05304106 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Eric Mooreb506ade2007-01-29 09:45:37 -07004107
4108 if (mpt_config(ioc, &cfg) != 0)
4109 goto out;
4110
4111 if (!hdr.PageLength)
4112 goto out;
4113
4114 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4115 &dma_handle);
4116
4117 if (!buffer)
4118 goto out;
4119
4120 cfg.physAddr = dma_handle;
4121 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4122
4123 if (mpt_config(ioc, &cfg) != 0)
4124 goto out;
4125
4126 if (!(buffer->VolumeStatus.Flags &
4127 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4128 goto out;
4129
4130 if (!buffer->NumPhysDisks)
4131 goto out;
4132
4133 for (i = 0; i < buffer->NumPhysDisks; i++) {
4134
4135 if (mpt_raid_phys_disk_pg0(ioc,
4136 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4137 continue;
4138
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304139 if (mptsas_sas_device_pg0(ioc, &sas_device,
4140 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4141 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4142 (phys_disk.PhysDiskBus << 8) +
4143 phys_disk.PhysDiskID))
4144 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004145
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304146 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4147 sas_device.sas_address);
4148 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07004149 }
4150
4151 out:
4152 if (buffer)
4153 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4154 dma_handle);
4155}
Moore, Erice6b2d762006-03-14 09:14:24 -07004156/*
4157 * Work queue thread to handle SAS hotplug events
4158 */
Moore, Ericf44e5462006-03-14 09:14:21 -07004159static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304160mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4161 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004162{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004163 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004164 struct scsi_target * starget;
Moore, Ericc73787e2006-01-26 16:20:06 -07004165 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004166 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304167 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06004168
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304169 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004170
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304171 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004172
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304173 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004174 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004175
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304176 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4177 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4178 hot_plug_info->id) {
4179 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4180 "to add hidden disk - target_id matchs "
4181 "volume_id\n", ioc->name);
4182 mptsas_free_fw_event(ioc, fw_event);
4183 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004184 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004185 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304186 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004187
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004188 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304189 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4190 mptsas_sas_device_pg0(ioc, &sas_device,
4191 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4192 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4193 (hot_plug_info->channel << 8) +
4194 hot_plug_info->id);
Moore, Ericc73787e2006-01-26 16:20:06 -07004195
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304196 if (!sas_device.handle)
4197 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004198
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304199 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
4200 if (!phy_info)
4201 break;
4202
4203 if (mptsas_get_rphy(phy_info))
4204 break;
4205
4206 mptsas_add_end_device(ioc, phy_info);
4207 break;
4208
4209 case MPTSAS_DEL_DEVICE:
4210 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4211 hot_plug_info->sas_address);
4212 mptsas_del_end_device(ioc, phy_info);
4213 break;
4214
4215 case MPTSAS_DEL_PHYSDISK:
4216
4217 mpt_findImVolumes(ioc);
4218
4219 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304220 ioc, hot_plug_info->phys_disk_num,
4221 hot_plug_info->channel,
4222 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304223 mptsas_del_end_device(ioc, phy_info);
4224 break;
4225
4226 case MPTSAS_ADD_PHYSDISK_REPROBE:
4227
Christoph Hellwige3094442006-02-16 13:25:36 +01004228 if (mptsas_sas_device_pg0(ioc, &sas_device,
4229 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004230 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304231 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4232 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4233 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4234 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004235 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004236 }
4237
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304238 phy_info = mptsas_find_phyinfo_by_sas_address(
4239 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004240
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304241 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304242 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304243 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4244 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004245 break;
4246 }
4247
4248 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304249 if (!starget) {
4250 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4251 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4252 __func__, hot_plug_info->id, __LINE__));
4253 break;
4254 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004255
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304256 vtarget = starget->hostdata;
4257 if (!vtarget) {
4258 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4259 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4260 __func__, hot_plug_info->id, __LINE__));
4261 break;
4262 }
Eric Moore547f9a22006-06-27 14:42:12 -06004263
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304264 mpt_findImVolumes(ioc);
4265
4266 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4267 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4268 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4269 hot_plug_info->phys_disk_num, (unsigned long long)
4270 sas_device.sas_address);
4271
4272 vtarget->id = hot_plug_info->phys_disk_num;
4273 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4274 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4275 mptsas_reprobe_target(starget, 1);
4276 break;
4277
4278 case MPTSAS_DEL_PHYSDISK_REPROBE:
4279
4280 if (mptsas_sas_device_pg0(ioc, &sas_device,
4281 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4282 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4283 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304284 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304285 "%s: fw_id=%d exit at line=%d\n",
4286 ioc->name, __func__,
4287 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004288 break;
4289 }
4290
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304291 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4292 sas_device.sas_address);
4293 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304294 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304295 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4296 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004297 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004298 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004299
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304300 starget = mptsas_get_starget(phy_info);
4301 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304302 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304303 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4304 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004305 break;
4306 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004307
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304308 vtarget = starget->hostdata;
4309 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304310 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304311 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4312 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004313 break;
4314 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304315
4316 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4317 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4318 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4319 __func__, hot_plug_info->id, __LINE__));
4320 break;
4321 }
4322
4323 mpt_findImVolumes(ioc);
4324
4325 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4326 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4327 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4328 hot_plug_info->phys_disk_num, (unsigned long long)
4329 sas_device.sas_address);
4330
4331 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4332 vtarget->id = hot_plug_info->id;
4333 phy_info->attached.phys_disk_num = ~0;
4334 mptsas_reprobe_target(starget, 0);
4335 mptsas_add_device_component_by_fw(ioc,
4336 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004337 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304338
Moore, Ericc73787e2006-01-26 16:20:06 -07004339 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304340
Moore, Ericc73787e2006-01-26 16:20:06 -07004341 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304342 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4343 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4344 hot_plug_info->id);
4345 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4346 hot_plug_info->id, 0);
Moore, Ericc73787e2006-01-26 16:20:06 -07004347 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304348
Moore, Ericc73787e2006-01-26 16:20:06 -07004349 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304350
Moore, Ericc73787e2006-01-26 16:20:06 -07004351 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304352 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4353 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4354 hot_plug_info->id);
4355 scsi_remove_device(hot_plug_info->sdev);
4356 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787e2006-01-26 16:20:06 -07004357 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304358
Eric Mooreb506ade2007-01-29 09:45:37 -07004359 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304360
4361 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004362 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304363 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004364 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304365
Moore, Ericbd23e942006-04-17 12:43:04 -06004366 default:
4367 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004368 }
4369
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304370 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004371}
4372
4373static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304374mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004375{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304376 MPT_ADAPTER *ioc;
4377 struct mptsas_hotplug_event hot_plug_info;
4378 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4379 u32 device_info;
4380 u64 sas_address;
4381
4382 ioc = fw_event->ioc;
4383 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4384 fw_event->event_data;
4385 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004386
4387 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304388 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4389 MPI_SAS_DEVICE_INFO_STP_TARGET |
4390 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4391 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004392 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304393 }
4394
4395 if (sas_event_data->ReasonCode ==
4396 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4397 mptbase_sas_persist_operation(ioc,
4398 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4399 mptsas_free_fw_event(ioc, fw_event);
4400 return;
4401 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004402
Moore, Eric4b766472006-03-14 09:14:12 -07004403 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004404 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004405 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304406 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4407 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4408 hot_plug_info.channel = sas_event_data->Bus;
4409 hot_plug_info.id = sas_event_data->TargetID;
4410 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004411 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304412 sizeof(u64));
4413 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4414 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004415 if (sas_event_data->ReasonCode &
4416 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304417 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004418 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304419 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4420 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004421 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304422
Moore, Eric4b766472006-03-14 09:14:12 -07004423 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304424 mptbase_sas_persist_operation(ioc,
4425 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4426 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004427 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304428
Moore, Eric4b766472006-03-14 09:14:12 -07004429 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304430 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004431 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304432 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004433 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304434 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004435 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004436 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004437}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304438
Moore, Ericc73787e2006-01-26 16:20:06 -07004439static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304440mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787e2006-01-26 16:20:06 -07004441{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304442 MPT_ADAPTER *ioc;
4443 EVENT_DATA_RAID *raid_event_data;
4444 struct mptsas_hotplug_event hot_plug_info;
4445 int status;
4446 int state;
4447 struct scsi_device *sdev = NULL;
4448 VirtDevice *vdevice = NULL;
4449 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787e2006-01-26 16:20:06 -07004450
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304451 ioc = fw_event->ioc;
4452 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4453 status = le32_to_cpu(raid_event_data->SettingsStatus);
4454 state = (status >> 8) & 0xff;
Moore, Ericc73787e2006-01-26 16:20:06 -07004455
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304456 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4457 hot_plug_info.id = raid_event_data->VolumeID;
4458 hot_plug_info.channel = raid_event_data->VolumeBus;
4459 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4460
4461 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4462 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4463 raid_event_data->ReasonCode ==
4464 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4465 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4466 hot_plug_info.id, 0);
4467 hot_plug_info.sdev = sdev;
4468 if (sdev)
4469 vdevice = sdev->hostdata;
Moore, Ericc73787e2006-01-26 16:20:06 -07004470 }
4471
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304472 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4473 "ReasonCode=%02x\n", ioc->name, __func__,
4474 raid_event_data->ReasonCode));
Moore, Ericc73787e2006-01-26 16:20:06 -07004475
4476 switch (raid_event_data->ReasonCode) {
4477 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304478 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004479 break;
4480 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304481 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004482 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004483 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4484 switch (state) {
4485 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004486 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304487 mpt_raid_phys_disk_pg0(ioc,
4488 raid_event_data->PhysDiskNum, &phys_disk);
4489 hot_plug_info.id = phys_disk.PhysDiskID;
4490 hot_plug_info.channel = phys_disk.PhysDiskBus;
4491 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004492 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304493 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004494 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004495 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4496 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4497 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304498 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004499 break;
4500 default:
4501 break;
4502 }
4503 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07004504 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304505 if (!sdev)
4506 break;
4507 vdevice->vtarget->deleted = 1; /* block IO */
4508 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004509 break;
4510 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304511 if (sdev) {
4512 scsi_device_put(sdev);
4513 break;
4514 }
4515 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004516 break;
4517 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304518 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4519 if (!sdev)
4520 break;
4521 vdevice->vtarget->deleted = 1; /* block IO */
4522 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4523 break;
4524 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004525 switch (state) {
4526 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4527 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304528 if (!sdev)
4529 break;
4530 vdevice->vtarget->deleted = 1; /* block IO */
4531 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004532 break;
4533 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4534 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304535 if (sdev) {
4536 scsi_device_put(sdev);
4537 break;
4538 }
4539 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004540 break;
4541 default:
4542 break;
4543 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004544 break;
4545 default:
4546 break;
4547 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304548
4549 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4550 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4551 else
4552 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787e2006-01-26 16:20:06 -07004553}
4554
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304555/**
4556 * mptsas_issue_tm - send mptsas internal tm request
4557 * @ioc: Pointer to MPT_ADAPTER structure
4558 * @type: Task Management type
4559 * @channel: channel number for task management
4560 * @id: Logical Target ID for reset (if appropriate)
4561 * @lun: Logical unit for reset (if appropriate)
4562 * @task_context: Context for the task to be aborted
4563 * @timeout: timeout for task management control
4564 *
4565 * return 0 on success and -1 on failure:
4566 *
4567 */
4568static int
4569mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4570 int task_context, ulong timeout, u8 *issue_reset)
4571{
4572 MPT_FRAME_HDR *mf;
4573 SCSITaskMgmt_t *pScsiTm;
4574 int retval;
4575 unsigned long timeleft;
4576
4577 *issue_reset = 0;
4578 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4579 if (mf == NULL) {
4580 retval = -1; /* return failure */
4581 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4582 "msg frames!!\n", ioc->name));
4583 goto out;
4584 }
4585
4586 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4587 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4588 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4589 type, timeout, channel, id, (unsigned long long)lun,
4590 task_context));
4591
4592 pScsiTm = (SCSITaskMgmt_t *) mf;
4593 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4594 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4595 pScsiTm->TaskType = type;
4596 pScsiTm->MsgFlags = 0;
4597 pScsiTm->TargetID = id;
4598 pScsiTm->Bus = channel;
4599 pScsiTm->ChainOffset = 0;
4600 pScsiTm->Reserved = 0;
4601 pScsiTm->Reserved1 = 0;
4602 pScsiTm->TaskMsgContext = task_context;
4603 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4604
4605 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4606 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4607 retval = 0;
4608 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4609
4610 /* Now wait for the command to complete */
4611 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4612 timeout*HZ);
4613 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4614 retval = -1; /* return failure */
4615 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4616 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4617 mpt_free_msg_frame(ioc, mf);
4618 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4619 goto out;
4620 *issue_reset = 1;
4621 goto out;
4622 }
4623
4624 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4625 retval = -1; /* return failure */
4626 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4627 "TaskMgmt request: failed with no reply\n", ioc->name));
4628 goto out;
4629 }
4630
4631 out:
4632 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4633 return retval;
4634}
4635
4636/**
4637 * mptsas_broadcast_primative_work - Handle broadcast primitives
4638 * @work: work queue payload containing info describing the event
4639 *
4640 * this will be handled in workqueue context.
4641 */
4642static void
4643mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4644{
4645 MPT_ADAPTER *ioc = fw_event->ioc;
4646 MPT_FRAME_HDR *mf;
4647 VirtDevice *vdevice;
4648 int ii;
4649 struct scsi_cmnd *sc;
4650 SCSITaskMgmtReply_t *pScsiTmReply;
4651 u8 issue_reset;
4652 int task_context;
4653 u8 channel, id;
4654 int lun;
4655 u32 termination_count;
4656 u32 query_count;
4657
4658 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4659 "%s - enter\n", ioc->name, __func__));
4660
4661 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4662 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4663 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4664 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4665 return;
4666 }
4667
4668 issue_reset = 0;
4669 termination_count = 0;
4670 query_count = 0;
4671 mpt_findImVolumes(ioc);
4672 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4673
4674 for (ii = 0; ii < ioc->req_depth; ii++) {
4675 if (ioc->fw_events_off)
4676 goto out;
4677 sc = mptscsih_get_scsi_lookup(ioc, ii);
4678 if (!sc)
4679 continue;
4680 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4681 if (!mf)
4682 continue;
4683 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4684 vdevice = sc->device->hostdata;
4685 if (!vdevice || !vdevice->vtarget)
4686 continue;
4687 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4688 continue; /* skip hidden raid components */
4689 if (vdevice->vtarget->raidVolume)
4690 continue; /* skip hidden raid components */
4691 channel = vdevice->vtarget->channel;
4692 id = vdevice->vtarget->id;
4693 lun = vdevice->lun;
4694 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4695 channel, id, (u64)lun, task_context, 30, &issue_reset))
4696 goto out;
4697 query_count++;
4698 termination_count +=
4699 le32_to_cpu(pScsiTmReply->TerminationCount);
4700 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4701 (pScsiTmReply->ResponseCode ==
4702 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4703 pScsiTmReply->ResponseCode ==
4704 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4705 continue;
4706 if (mptsas_issue_tm(ioc,
4707 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4708 channel, id, (u64)lun, 0, 30, &issue_reset))
4709 goto out;
4710 termination_count +=
4711 le32_to_cpu(pScsiTmReply->TerminationCount);
4712 }
4713
4714 out:
4715 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4716 "%s - exit, query_count = %d termination_count = %d\n",
4717 ioc->name, __func__, query_count, termination_count));
4718
4719 ioc->broadcast_aen_busy = 0;
4720 mpt_clear_taskmgmt_in_progress_flag(ioc);
4721 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4722
4723 if (issue_reset) {
4724 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4725 ioc->name, __func__);
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05304726 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304727 }
4728 mptsas_free_fw_event(ioc, fw_event);
4729}
4730
Eric Mooreb506ade2007-01-29 09:45:37 -07004731/*
4732 * mptsas_send_ir2_event - handle exposing hidden disk when
4733 * an inactive raid volume is added
4734 *
4735 * @ioc: Pointer to MPT_ADAPTER structure
4736 * @ir2_data
4737 *
4738 */
4739static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304740mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004741{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304742 MPT_ADAPTER *ioc;
4743 struct mptsas_hotplug_event hot_plug_info;
4744 MPI_EVENT_DATA_IR2 *ir2_data;
4745 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304746 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004747
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304748 ioc = fw_event->ioc;
4749 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4750 reasonCode = ir2_data->ReasonCode;
4751
4752 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4753 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4754
4755 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4756 hot_plug_info.id = ir2_data->TargetID;
4757 hot_plug_info.channel = ir2_data->Bus;
4758 switch (reasonCode) {
4759 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4760 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4761 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304762 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4763 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4764 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4765 break;
4766 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4767 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4768 mpt_raid_phys_disk_pg0(ioc,
4769 ir2_data->PhysDiskNum, &phys_disk);
4770 hot_plug_info.id = phys_disk.PhysDiskID;
4771 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4772 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304773 default:
4774 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004775 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304776 }
4777 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4778}
Moore, Erice6b2d762006-03-14 09:14:24 -07004779
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004780static int
4781mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4782{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304783 u32 event = le32_to_cpu(reply->Event);
4784 int sz, event_data_sz;
4785 struct fw_event_work *fw_event;
4786 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004787
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05304788 if (ioc->bus_type != SAS)
4789 return 0;
4790
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304791 /* events turned off due to host reset or driver unloading */
4792 if (ioc->fw_events_off)
4793 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004794
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304795 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004796 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304797 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4798 {
4799 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4800 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4801 if (broadcast_event_data->Primitive !=
4802 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4803 return 0;
4804 if (ioc->broadcast_aen_busy)
4805 return 0;
4806 ioc->broadcast_aen_busy = 1;
4807 break;
4808 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004809 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304810 {
4811 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4812 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4813
4814 if (sas_event_data->ReasonCode ==
4815 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4816 mptsas_target_reset_queue(ioc, sas_event_data);
4817 return 0;
4818 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004819 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304820 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304821 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4822 {
4823 MpiEventDataSasExpanderStatusChange_t *expander_data =
4824 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4825
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304826 if (ioc->old_sas_discovery_protocal)
4827 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304828
4829 if (expander_data->ReasonCode ==
4830 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4831 ioc->device_missing_delay)
4832 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004833 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304834 }
4835 case MPI_EVENT_SAS_DISCOVERY:
4836 {
4837 u32 discovery_status;
4838 EventDataSasDiscovery_t *discovery_data =
4839 (EventDataSasDiscovery_t *)reply->Data;
4840
4841 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4842 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304843 if (ioc->old_sas_discovery_protocal && !discovery_status)
4844 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304845 return 0;
4846 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304847 case MPI_EVENT_INTEGRATED_RAID:
4848 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004849 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304850 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4851 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004852 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004853 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304854 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004855 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004856
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304857 event_data_sz = ((reply->MsgLength * 4) -
4858 offsetof(EventNotificationReply_t, Data));
4859 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4860 fw_event = kzalloc(sz, GFP_ATOMIC);
4861 if (!fw_event) {
4862 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4863 __func__, __LINE__);
4864 return 0;
4865 }
4866 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4867 fw_event->event = event;
4868 fw_event->ioc = ioc;
4869 mptsas_add_fw_event(ioc, fw_event, delay);
4870 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004871}
4872
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304873/* Delete a volume when no longer listed in ioc pg2
4874 */
4875static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4876{
4877 struct scsi_device *sdev;
4878 int i;
4879
4880 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4881 if (!sdev)
4882 return;
4883 if (!ioc->raid_data.pIocPg2)
4884 goto out;
4885 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4886 goto out;
4887 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4888 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4889 goto release_sdev;
4890 out:
4891 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4892 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4893 scsi_remove_device(sdev);
4894 release_sdev:
4895 scsi_device_put(sdev);
4896}
4897
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004898static int
4899mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4900{
4901 struct Scsi_Host *sh;
4902 MPT_SCSI_HOST *hd;
4903 MPT_ADAPTER *ioc;
4904 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004905 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004906 int numSGE = 0;
4907 int scale;
4908 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004909 int error=0;
4910 int r;
4911
4912 r = mpt_attach(pdev,id);
4913 if (r)
4914 return r;
4915
4916 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304917 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004918 ioc->DoneCtx = mptsasDoneCtx;
4919 ioc->TaskCtx = mptsasTaskCtx;
4920 ioc->InternalCtx = mptsasInternalCtx;
4921
4922 /* Added sanity check on readiness of the MPT adapter.
4923 */
4924 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4925 printk(MYIOC_s_WARN_FMT
4926 "Skipping because it's not operational!\n",
4927 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004928 error = -ENODEV;
4929 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004930 }
4931
4932 if (!ioc->active) {
4933 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4934 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004935 error = -ENODEV;
4936 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004937 }
4938
4939 /* Sanity check - ensure at least 1 port is INITIATOR capable
4940 */
4941 ioc_cap = 0;
4942 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4943 if (ioc->pfacts[ii].ProtocolFlags &
4944 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4945 ioc_cap++;
4946 }
4947
4948 if (!ioc_cap) {
4949 printk(MYIOC_s_WARN_FMT
4950 "Skipping ioc=%p because SCSI Initiator mode "
4951 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004952 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004953 }
4954
4955 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4956 if (!sh) {
4957 printk(MYIOC_s_WARN_FMT
4958 "Unable to register controller with SCSI subsystem\n",
4959 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004960 error = -1;
4961 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004962 }
4963
4964 spin_lock_irqsave(&ioc->FreeQlock, flags);
4965
4966 /* Attach the SCSI Host to the IOC structure
4967 */
4968 ioc->sh = sh;
4969
4970 sh->io_port = 0;
4971 sh->n_io_port = 0;
4972 sh->irq = 0;
4973
4974 /* set 16 byte cdb's */
4975 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05304976 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
4977 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07004978 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004979 sh->transportt = mptsas_transport_template;
4980
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004981 /* Required entry.
4982 */
4983 sh->unique_id = ioc->id;
4984
4985 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004986 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004987 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004988 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004989 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004990
4991 /* Verify that we won't exceed the maximum
4992 * number of chain buffers
4993 * We can optimize: ZZ = req_sz/sizeof(SGE)
4994 * For 32bit SGE's:
4995 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4996 * + (req_sz - 64)/sizeof(SGE)
4997 * A slightly different algorithm is required for
4998 * 64bit SGEs.
4999 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305000 scale = ioc->req_sz/ioc->SGE_size;
5001 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005002 numSGE = (scale - 1) *
5003 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305004 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005005 } else {
5006 numSGE = 1 + (scale - 1) *
5007 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305008 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005009 }
5010
5011 if (numSGE < sh->sg_tablesize) {
5012 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305013 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005014 "Resetting sg_tablesize to %d from %d\n",
5015 ioc->name, numSGE, sh->sg_tablesize));
5016 sh->sg_tablesize = numSGE;
5017 }
5018
Eric Mooree7eae9f2007-09-29 10:15:59 -06005019 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005020 hd->ioc = ioc;
5021
5022 /* SCSI needs scsi_cmnd lookup table!
5023 * (with size equal to req_depth*PtrSz!)
5024 */
Eric Mooree8206382007-09-29 10:16:53 -06005025 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5026 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005027 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005028 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005029 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005030 }
Eric Mooree8206382007-09-29 10:16:53 -06005031 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005032
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305033 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005034 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005035
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005036 ioc->sas_data.ptClear = mpt_pt_clear;
5037
Eric Mooredf9e0622007-01-29 09:46:21 -07005038 hd->last_queue_full = 0;
5039 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305040 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5041 mutex_init(&ioc->sas_device_info_mutex);
5042
Eric Mooredf9e0622007-01-29 09:46:21 -07005043 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5044
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005045 if (ioc->sas_data.ptClear==1) {
5046 mptbase_sas_persist_operation(
5047 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5048 }
5049
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005050 error = scsi_add_host(sh, &ioc->pcidev->dev);
5051 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005052 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5053 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005054 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005055 }
5056
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305057 /* older firmware doesn't support expander events */
5058 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5059 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005060 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305061 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005062 return 0;
5063
Eric Moore547f9a22006-06-27 14:42:12 -06005064 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005065
5066 mptscsih_remove(pdev);
5067 return error;
5068}
5069
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305070void
5071mptsas_shutdown(struct pci_dev *pdev)
5072{
5073 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5074
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305075 mptsas_fw_event_off(ioc);
5076 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305077}
5078
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005079static void __devexit mptsas_remove(struct pci_dev *pdev)
5080{
5081 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5082 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005083 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005084
Kashyap, Desai48959f12010-03-18 19:18:30 +05305085 if (!ioc->sh) {
5086 printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
5087 mpt_detach(pdev);
5088 return;
5089 }
5090
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305091 mptsas_shutdown(pdev);
5092
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305093 mptsas_del_device_components(ioc);
5094
Eric Mooreb506ade2007-01-29 09:45:37 -07005095 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005096 sas_remove_host(ioc->sh);
5097
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005098 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005099 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5100 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005101 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305102 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305103
Eric Moore547f9a22006-06-27 14:42:12 -06005104 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005105 kfree(p);
5106 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005107 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305108 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005109 mptscsih_remove(pdev);
5110}
5111
5112static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005113 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005114 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005115 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005116 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005117 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005118 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005119 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005120 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005121 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005122 PCI_ANY_ID, PCI_ANY_ID },
5123 {0} /* Terminating entry */
5124};
5125MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5126
5127
5128static struct pci_driver mptsas_driver = {
5129 .name = "mptsas",
5130 .id_table = mptsas_pci_table,
5131 .probe = mptsas_probe,
5132 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305133 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005134#ifdef CONFIG_PM
5135 .suspend = mptscsih_suspend,
5136 .resume = mptscsih_resume,
5137#endif
5138};
5139
5140static int __init
5141mptsas_init(void)
5142{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305143 int error;
5144
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005145 show_mptmod_ver(my_NAME, my_VERSION);
5146
5147 mptsas_transport_template =
5148 sas_attach_transport(&mptsas_transport_functions);
5149 if (!mptsas_transport_template)
5150 return -ENODEV;
5151
5152 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305153 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005154 mptsasInternalCtx =
5155 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005156 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305157 mptsasDeviceResetCtx =
5158 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005159
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305160 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5161 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005162
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305163 error = pci_register_driver(&mptsas_driver);
5164 if (error)
5165 sas_release_transport(mptsas_transport_template);
5166
5167 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005168}
5169
5170static void __exit
5171mptsas_exit(void)
5172{
5173 pci_unregister_driver(&mptsas_driver);
5174 sas_release_transport(mptsas_transport_template);
5175
5176 mpt_reset_deregister(mptsasDoneCtx);
5177 mpt_event_deregister(mptsasDoneCtx);
5178
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005179 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005180 mpt_deregister(mptsasInternalCtx);
5181 mpt_deregister(mptsasTaskCtx);
5182 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305183 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005184}
5185
5186module_init(mptsas_init);
5187module_exit(mptsas_exit);