blob: ca984cbc8e2f5045d507f68de4ca7dba60f2bb62 [file] [log] [blame]
Eric Moore635374e2009-03-09 01:21:12 -06001/*
2 * Scsi Host Layer for MPT (Message Passing Technology) based controllers
3 *
4 * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
Kashyap, Desai19d3ebe2009-09-14 11:01:36 +05305 * Copyright (C) 2007-2009 LSI Corporation
Eric Moore635374e2009-03-09 01:21:12 -06006 * (mailto:DL-MPTFusionLinux@lsi.com)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * NO WARRANTY
19 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
20 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
21 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
22 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
23 * solely responsible for determining the appropriateness of using and
24 * distributing the Program and assumes all risks associated with its
25 * exercise of rights under this Agreement, including but not limited to
26 * the risks and costs of program errors, damage to or loss of data,
27 * programs or equipment, and unavailability or interruption of operations.
28
29 * DISCLAIMER OF LIABILITY
30 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
31 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
36 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
37
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
41 * USA.
42 */
43
44#include <linux/version.h>
45#include <linux/module.h>
46#include <linux/kernel.h>
47#include <linux/init.h>
48#include <linux/errno.h>
49#include <linux/blkdev.h>
50#include <linux/sched.h>
51#include <linux/workqueue.h>
52#include <linux/delay.h>
53#include <linux/pci.h>
54#include <linux/interrupt.h>
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +053055#include <linux/raid_class.h>
Eric Moore635374e2009-03-09 01:21:12 -060056
57#include "mpt2sas_base.h"
58
59MODULE_AUTHOR(MPT2SAS_AUTHOR);
60MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
61MODULE_LICENSE("GPL");
62MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
63
64#define RAID_CHANNEL 1
65
66/* forward proto's */
67static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
68 struct _sas_node *sas_expander);
69static void _firmware_event_work(struct work_struct *work);
70
71/* global parameters */
Eric Mooreba33fad2009-03-15 21:37:18 -060072LIST_HEAD(mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -060073
74/* local parameters */
Eric Moore635374e2009-03-09 01:21:12 -060075static u8 scsi_io_cb_idx = -1;
76static u8 tm_cb_idx = -1;
77static u8 ctl_cb_idx = -1;
78static u8 base_cb_idx = -1;
79static u8 transport_cb_idx = -1;
Kashyap, Desai744090d2009-10-05 15:56:56 +053080static u8 scsih_cb_idx = -1;
Eric Moore635374e2009-03-09 01:21:12 -060081static u8 config_cb_idx = -1;
82static int mpt_ids;
83
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053084static u8 tm_tr_cb_idx = -1 ;
85static u8 tm_sas_control_cb_idx = -1;
86
Eric Moore635374e2009-03-09 01:21:12 -060087/* command line options */
Eric Mooreba33fad2009-03-15 21:37:18 -060088static u32 logging_level;
Eric Moore635374e2009-03-09 01:21:12 -060089MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
90 "(default=0)");
91
92/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
93#define MPT2SAS_MAX_LUN (16895)
94static int max_lun = MPT2SAS_MAX_LUN;
95module_param(max_lun, int, 0);
96MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
97
98/**
99 * struct sense_info - common structure for obtaining sense keys
100 * @skey: sense key
101 * @asc: additional sense code
102 * @ascq: additional sense code qualifier
103 */
104struct sense_info {
105 u8 skey;
106 u8 asc;
107 u8 ascq;
108};
109
110
Eric Moore635374e2009-03-09 01:21:12 -0600111/**
112 * struct fw_event_work - firmware event struct
113 * @list: link list framework
114 * @work: work object (ioc->fault_reset_work_q)
115 * @ioc: per adapter object
116 * @VF_ID: virtual function id
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530117 * @VP_ID: virtual port id
Eric Moore635374e2009-03-09 01:21:12 -0600118 * @host_reset_handling: handling events during host reset
119 * @ignore: flag meaning this event has been marked to ignore
120 * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
121 * @event_data: reply event data payload follows
122 *
123 * This object stored on ioc->fw_event_list.
124 */
125struct fw_event_work {
126 struct list_head list;
Eric Moore6f92a7a2009-04-21 15:43:33 -0600127 struct work_struct work;
Eric Moore635374e2009-03-09 01:21:12 -0600128 struct MPT2SAS_ADAPTER *ioc;
129 u8 VF_ID;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530130 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600131 u8 host_reset_handling;
132 u8 ignore;
133 u16 event;
134 void *event_data;
135};
136
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +0530137/* raid transport support */
138static struct raid_template *mpt2sas_raid_template;
139
Eric Moore635374e2009-03-09 01:21:12 -0600140/**
141 * struct _scsi_io_transfer - scsi io transfer
142 * @handle: sas device handle (assigned by firmware)
143 * @is_raid: flag set for hidden raid components
144 * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
145 * @data_length: data transfer length
146 * @data_dma: dma pointer to data
147 * @sense: sense data
148 * @lun: lun number
149 * @cdb_length: cdb length
150 * @cdb: cdb contents
Eric Moore635374e2009-03-09 01:21:12 -0600151 * @timeout: timeout for this command
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530152 * @VF_ID: virtual function id
153 * @VP_ID: virtual port id
154 * @valid_reply: flag set for reply message
Eric Moore635374e2009-03-09 01:21:12 -0600155 * @sense_length: sense length
156 * @ioc_status: ioc status
157 * @scsi_state: scsi state
158 * @scsi_status: scsi staus
159 * @log_info: log information
160 * @transfer_length: data length transfer when there is a reply message
161 *
162 * Used for sending internal scsi commands to devices within this module.
163 * Refer to _scsi_send_scsi_io().
164 */
165struct _scsi_io_transfer {
166 u16 handle;
167 u8 is_raid;
168 enum dma_data_direction dir;
169 u32 data_length;
170 dma_addr_t data_dma;
171 u8 sense[SCSI_SENSE_BUFFERSIZE];
172 u32 lun;
173 u8 cdb_length;
174 u8 cdb[32];
175 u8 timeout;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530176 u8 VF_ID;
177 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600178 u8 valid_reply;
179 /* the following bits are only valid when 'valid_reply = 1' */
180 u32 sense_length;
181 u16 ioc_status;
182 u8 scsi_state;
183 u8 scsi_status;
184 u32 log_info;
185 u32 transfer_length;
186};
187
188/*
189 * The pci device ids are defined in mpi/mpi2_cnfg.h.
190 */
191static struct pci_device_id scsih_pci_table[] = {
192 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
193 PCI_ANY_ID, PCI_ANY_ID },
194 /* Falcon ~ 2008*/
195 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
196 PCI_ANY_ID, PCI_ANY_ID },
197 /* Liberator ~ 2108 */
198 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
199 PCI_ANY_ID, PCI_ANY_ID },
200 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
201 PCI_ANY_ID, PCI_ANY_ID },
202 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
203 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530204 /* Meteor ~ 2116 */
Eric Moore635374e2009-03-09 01:21:12 -0600205 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
206 PCI_ANY_ID, PCI_ANY_ID },
207 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
208 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530209 /* Thunderbolt ~ 2208 */
210 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
211 PCI_ANY_ID, PCI_ANY_ID },
212 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
213 PCI_ANY_ID, PCI_ANY_ID },
214 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
215 PCI_ANY_ID, PCI_ANY_ID },
216 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
217 PCI_ANY_ID, PCI_ANY_ID },
218 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
219 PCI_ANY_ID, PCI_ANY_ID },
220 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
221 PCI_ANY_ID, PCI_ANY_ID },
222 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7,
223 PCI_ANY_ID, PCI_ANY_ID },
224 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8,
225 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore635374e2009-03-09 01:21:12 -0600226 {0} /* Terminating entry */
227};
228MODULE_DEVICE_TABLE(pci, scsih_pci_table);
229
230/**
Eric Moored5d135b2009-05-18 13:02:08 -0600231 * _scsih_set_debug_level - global setting of ioc->logging_level.
Eric Moore635374e2009-03-09 01:21:12 -0600232 *
233 * Note: The logging levels are defined in mpt2sas_debug.h.
234 */
235static int
Eric Moored5d135b2009-05-18 13:02:08 -0600236_scsih_set_debug_level(const char *val, struct kernel_param *kp)
Eric Moore635374e2009-03-09 01:21:12 -0600237{
238 int ret = param_set_int(val, kp);
239 struct MPT2SAS_ADAPTER *ioc;
240
241 if (ret)
242 return ret;
243
244 printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
Eric Mooreba33fad2009-03-15 21:37:18 -0600245 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
Eric Moore635374e2009-03-09 01:21:12 -0600246 ioc->logging_level = logging_level;
247 return 0;
248}
Eric Moored5d135b2009-05-18 13:02:08 -0600249module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
Eric Moore635374e2009-03-09 01:21:12 -0600250 &logging_level, 0644);
251
252/**
253 * _scsih_srch_boot_sas_address - search based on sas_address
254 * @sas_address: sas address
255 * @boot_device: boot device object from bios page 2
256 *
257 * Returns 1 when there's a match, 0 means no match.
258 */
259static inline int
260_scsih_srch_boot_sas_address(u64 sas_address,
261 Mpi2BootDeviceSasWwid_t *boot_device)
262{
263 return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
264}
265
266/**
267 * _scsih_srch_boot_device_name - search based on device name
268 * @device_name: device name specified in INDENTIFY fram
269 * @boot_device: boot device object from bios page 2
270 *
271 * Returns 1 when there's a match, 0 means no match.
272 */
273static inline int
274_scsih_srch_boot_device_name(u64 device_name,
275 Mpi2BootDeviceDeviceName_t *boot_device)
276{
277 return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
278}
279
280/**
281 * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
282 * @enclosure_logical_id: enclosure logical id
283 * @slot_number: slot number
284 * @boot_device: boot device object from bios page 2
285 *
286 * Returns 1 when there's a match, 0 means no match.
287 */
288static inline int
289_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
290 Mpi2BootDeviceEnclosureSlot_t *boot_device)
291{
292 return (enclosure_logical_id == le64_to_cpu(boot_device->
293 EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
294 SlotNumber)) ? 1 : 0;
295}
296
297/**
298 * _scsih_is_boot_device - search for matching boot device.
299 * @sas_address: sas address
300 * @device_name: device name specified in INDENTIFY fram
301 * @enclosure_logical_id: enclosure logical id
302 * @slot_number: slot number
303 * @form: specifies boot device form
304 * @boot_device: boot device object from bios page 2
305 *
306 * Returns 1 when there's a match, 0 means no match.
307 */
308static int
309_scsih_is_boot_device(u64 sas_address, u64 device_name,
310 u64 enclosure_logical_id, u16 slot, u8 form,
311 Mpi2BiosPage2BootDevice_t *boot_device)
312{
313 int rc = 0;
314
315 switch (form) {
316 case MPI2_BIOSPAGE2_FORM_SAS_WWID:
317 if (!sas_address)
318 break;
319 rc = _scsih_srch_boot_sas_address(
320 sas_address, &boot_device->SasWwid);
321 break;
322 case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
323 if (!enclosure_logical_id)
324 break;
325 rc = _scsih_srch_boot_encl_slot(
326 enclosure_logical_id,
327 slot, &boot_device->EnclosureSlot);
328 break;
329 case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
330 if (!device_name)
331 break;
332 rc = _scsih_srch_boot_device_name(
333 device_name, &boot_device->DeviceName);
334 break;
335 case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
336 break;
337 }
338
339 return rc;
340}
341
342/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530343 * _scsih_get_sas_address - set the sas_address for given device handle
344 * @handle: device handle
345 * @sas_address: sas address
346 *
347 * Returns 0 success, non-zero when failure
348 */
349static int
350_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
351 u64 *sas_address)
352{
353 Mpi2SasDevicePage0_t sas_device_pg0;
354 Mpi2ConfigReply_t mpi_reply;
355 u32 ioc_status;
356
357 if (handle <= ioc->sas_hba.num_phys) {
358 *sas_address = ioc->sas_hba.sas_address;
359 return 0;
360 } else
361 *sas_address = 0;
362
363 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
364 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
365 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
366 ioc->name, __FILE__, __LINE__, __func__);
367 return -ENXIO;
368 }
369
370 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
371 MPI2_IOCSTATUS_MASK;
372 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
373 printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
374 "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
375 __FILE__, __LINE__, __func__);
376 return -EIO;
377 }
378
379 *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
380 return 0;
381}
382
383/**
Eric Moore635374e2009-03-09 01:21:12 -0600384 * _scsih_determine_boot_device - determine boot device.
385 * @ioc: per adapter object
386 * @device: either sas_device or raid_device object
387 * @is_raid: [flag] 1 = raid object, 0 = sas object
388 *
389 * Determines whether this device should be first reported device to
390 * to scsi-ml or sas transport, this purpose is for persistant boot device.
391 * There are primary, alternate, and current entries in bios page 2. The order
392 * priority is primary, alternate, then current. This routine saves
393 * the corresponding device object and is_raid flag in the ioc object.
394 * The saved data to be used later in _scsih_probe_boot_devices().
395 */
396static void
397_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
398 void *device, u8 is_raid)
399{
400 struct _sas_device *sas_device;
401 struct _raid_device *raid_device;
402 u64 sas_address;
403 u64 device_name;
404 u64 enclosure_logical_id;
405 u16 slot;
406
407 /* only process this function when driver loads */
408 if (!ioc->wait_for_port_enable_to_complete)
409 return;
410
411 if (!is_raid) {
412 sas_device = device;
413 sas_address = sas_device->sas_address;
414 device_name = sas_device->device_name;
415 enclosure_logical_id = sas_device->enclosure_logical_id;
416 slot = sas_device->slot;
417 } else {
418 raid_device = device;
419 sas_address = raid_device->wwid;
420 device_name = 0;
421 enclosure_logical_id = 0;
422 slot = 0;
423 }
424
425 if (!ioc->req_boot_device.device) {
426 if (_scsih_is_boot_device(sas_address, device_name,
427 enclosure_logical_id, slot,
428 (ioc->bios_pg2.ReqBootDeviceForm &
429 MPI2_BIOSPAGE2_FORM_MASK),
430 &ioc->bios_pg2.RequestedBootDevice)) {
431 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
432 "%s: req_boot_device(0x%016llx)\n",
433 ioc->name, __func__,
434 (unsigned long long)sas_address));
435 ioc->req_boot_device.device = device;
436 ioc->req_boot_device.is_raid = is_raid;
437 }
438 }
439
440 if (!ioc->req_alt_boot_device.device) {
441 if (_scsih_is_boot_device(sas_address, device_name,
442 enclosure_logical_id, slot,
443 (ioc->bios_pg2.ReqAltBootDeviceForm &
444 MPI2_BIOSPAGE2_FORM_MASK),
445 &ioc->bios_pg2.RequestedAltBootDevice)) {
446 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
447 "%s: req_alt_boot_device(0x%016llx)\n",
448 ioc->name, __func__,
449 (unsigned long long)sas_address));
450 ioc->req_alt_boot_device.device = device;
451 ioc->req_alt_boot_device.is_raid = is_raid;
452 }
453 }
454
455 if (!ioc->current_boot_device.device) {
456 if (_scsih_is_boot_device(sas_address, device_name,
457 enclosure_logical_id, slot,
458 (ioc->bios_pg2.CurrentBootDeviceForm &
459 MPI2_BIOSPAGE2_FORM_MASK),
460 &ioc->bios_pg2.CurrentBootDevice)) {
461 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
462 "%s: current_boot_device(0x%016llx)\n",
463 ioc->name, __func__,
464 (unsigned long long)sas_address));
465 ioc->current_boot_device.device = device;
466 ioc->current_boot_device.is_raid = is_raid;
467 }
468 }
469}
470
471/**
472 * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
473 * @ioc: per adapter object
474 * @sas_address: sas address
475 * Context: Calling function should acquire ioc->sas_device_lock
476 *
477 * This searches for sas_device based on sas_address, then return sas_device
478 * object.
479 */
480struct _sas_device *
481mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
482 u64 sas_address)
483{
484 struct _sas_device *sas_device, *r;
485
486 r = NULL;
487 /* check the sas_device_init_list */
488 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
489 list) {
490 if (sas_device->sas_address != sas_address)
491 continue;
492 r = sas_device;
493 goto out;
494 }
495
496 /* then check the sas_device_list */
497 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
498 if (sas_device->sas_address != sas_address)
499 continue;
500 r = sas_device;
501 goto out;
502 }
503 out:
504 return r;
505}
506
507/**
508 * _scsih_sas_device_find_by_handle - sas device search
509 * @ioc: per adapter object
510 * @handle: sas device handle (assigned by firmware)
511 * Context: Calling function should acquire ioc->sas_device_lock
512 *
513 * This searches for sas_device based on sas_address, then return sas_device
514 * object.
515 */
516static struct _sas_device *
517_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
518{
519 struct _sas_device *sas_device, *r;
520
521 r = NULL;
522 if (ioc->wait_for_port_enable_to_complete) {
523 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
524 list) {
525 if (sas_device->handle != handle)
526 continue;
527 r = sas_device;
528 goto out;
529 }
530 } else {
531 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
532 if (sas_device->handle != handle)
533 continue;
534 r = sas_device;
535 goto out;
536 }
537 }
538
539 out:
540 return r;
541}
542
543/**
544 * _scsih_sas_device_remove - remove sas_device from list.
545 * @ioc: per adapter object
546 * @sas_device: the sas_device object
547 * Context: This function will acquire ioc->sas_device_lock.
548 *
549 * Removing object and freeing associated memory from the ioc->sas_device_list.
550 */
551static void
552_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
553 struct _sas_device *sas_device)
554{
555 unsigned long flags;
556
557 spin_lock_irqsave(&ioc->sas_device_lock, flags);
558 list_del(&sas_device->list);
559 memset(sas_device, 0, sizeof(struct _sas_device));
560 kfree(sas_device);
561 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
562}
563
564/**
565 * _scsih_sas_device_add - insert sas_device to the list.
566 * @ioc: per adapter object
567 * @sas_device: the sas_device object
568 * Context: This function will acquire ioc->sas_device_lock.
569 *
570 * Adding new object to the ioc->sas_device_list.
571 */
572static void
573_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
574 struct _sas_device *sas_device)
575{
576 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -0600577
578 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
579 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
580 sas_device->handle, (unsigned long long)sas_device->sas_address));
581
582 spin_lock_irqsave(&ioc->sas_device_lock, flags);
583 list_add_tail(&sas_device->list, &ioc->sas_device_list);
584 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
585
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530586 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
587 sas_device->sas_address_parent))
Eric Moore635374e2009-03-09 01:21:12 -0600588 _scsih_sas_device_remove(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -0600589}
590
591/**
592 * _scsih_sas_device_init_add - insert sas_device to the list.
593 * @ioc: per adapter object
594 * @sas_device: the sas_device object
595 * Context: This function will acquire ioc->sas_device_lock.
596 *
597 * Adding new object at driver load time to the ioc->sas_device_init_list.
598 */
599static void
600_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
601 struct _sas_device *sas_device)
602{
603 unsigned long flags;
604
605 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
606 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
607 sas_device->handle, (unsigned long long)sas_device->sas_address));
608
609 spin_lock_irqsave(&ioc->sas_device_lock, flags);
610 list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
611 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
612 _scsih_determine_boot_device(ioc, sas_device, 0);
613}
614
615/**
Eric Moore635374e2009-03-09 01:21:12 -0600616 * _scsih_raid_device_find_by_id - raid device search
617 * @ioc: per adapter object
618 * @id: sas device target id
619 * @channel: sas device channel
620 * Context: Calling function should acquire ioc->raid_device_lock
621 *
622 * This searches for raid_device based on target id, then return raid_device
623 * object.
624 */
625static struct _raid_device *
626_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
627{
628 struct _raid_device *raid_device, *r;
629
630 r = NULL;
631 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
632 if (raid_device->id == id && raid_device->channel == channel) {
633 r = raid_device;
634 goto out;
635 }
636 }
637
638 out:
639 return r;
640}
641
642/**
643 * _scsih_raid_device_find_by_handle - raid device search
644 * @ioc: per adapter object
645 * @handle: sas device handle (assigned by firmware)
646 * Context: Calling function should acquire ioc->raid_device_lock
647 *
648 * This searches for raid_device based on handle, then return raid_device
649 * object.
650 */
651static struct _raid_device *
652_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
653{
654 struct _raid_device *raid_device, *r;
655
656 r = NULL;
657 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
658 if (raid_device->handle != handle)
659 continue;
660 r = raid_device;
661 goto out;
662 }
663
664 out:
665 return r;
666}
667
668/**
669 * _scsih_raid_device_find_by_wwid - raid device search
670 * @ioc: per adapter object
671 * @handle: sas device handle (assigned by firmware)
672 * Context: Calling function should acquire ioc->raid_device_lock
673 *
674 * This searches for raid_device based on wwid, then return raid_device
675 * object.
676 */
677static struct _raid_device *
678_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
679{
680 struct _raid_device *raid_device, *r;
681
682 r = NULL;
683 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
684 if (raid_device->wwid != wwid)
685 continue;
686 r = raid_device;
687 goto out;
688 }
689
690 out:
691 return r;
692}
693
694/**
695 * _scsih_raid_device_add - add raid_device object
696 * @ioc: per adapter object
697 * @raid_device: raid_device object
698 *
699 * This is added to the raid_device_list link list.
700 */
701static void
702_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
703 struct _raid_device *raid_device)
704{
705 unsigned long flags;
706
707 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
708 "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
709 raid_device->handle, (unsigned long long)raid_device->wwid));
710
711 spin_lock_irqsave(&ioc->raid_device_lock, flags);
712 list_add_tail(&raid_device->list, &ioc->raid_device_list);
713 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
714}
715
716/**
717 * _scsih_raid_device_remove - delete raid_device object
718 * @ioc: per adapter object
719 * @raid_device: raid_device object
720 *
721 * This is removed from the raid_device_list link list.
722 */
723static void
724_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
725 struct _raid_device *raid_device)
726{
727 unsigned long flags;
728
729 spin_lock_irqsave(&ioc->raid_device_lock, flags);
730 list_del(&raid_device->list);
731 memset(raid_device, 0, sizeof(struct _raid_device));
732 kfree(raid_device);
733 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
734}
735
736/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530737 * mpt2sas_scsih_expander_find_by_handle - expander device search
738 * @ioc: per adapter object
739 * @handle: expander handle (assigned by firmware)
740 * Context: Calling function should acquire ioc->sas_device_lock
741 *
742 * This searches for expander device based on handle, then returns the
743 * sas_node object.
744 */
745struct _sas_node *
746mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
747{
748 struct _sas_node *sas_expander, *r;
749
750 r = NULL;
751 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
752 if (sas_expander->handle != handle)
753 continue;
754 r = sas_expander;
755 goto out;
756 }
757 out:
758 return r;
759}
760
761/**
Eric Moore635374e2009-03-09 01:21:12 -0600762 * mpt2sas_scsih_expander_find_by_sas_address - expander device search
763 * @ioc: per adapter object
764 * @sas_address: sas address
765 * Context: Calling function should acquire ioc->sas_node_lock.
766 *
767 * This searches for expander device based on sas_address, then returns the
768 * sas_node object.
769 */
770struct _sas_node *
771mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
772 u64 sas_address)
773{
774 struct _sas_node *sas_expander, *r;
775
776 r = NULL;
777 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
778 if (sas_expander->sas_address != sas_address)
779 continue;
780 r = sas_expander;
781 goto out;
782 }
783 out:
784 return r;
785}
786
787/**
788 * _scsih_expander_node_add - insert expander device to the list.
789 * @ioc: per adapter object
790 * @sas_expander: the sas_device object
791 * Context: This function will acquire ioc->sas_node_lock.
792 *
793 * Adding new object to the ioc->sas_expander_list.
794 *
795 * Return nothing.
796 */
797static void
798_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
799 struct _sas_node *sas_expander)
800{
801 unsigned long flags;
802
803 spin_lock_irqsave(&ioc->sas_node_lock, flags);
804 list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
805 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
806}
807
808/**
809 * _scsih_is_end_device - determines if device is an end device
810 * @device_info: bitfield providing information about the device.
811 * Context: none
812 *
813 * Returns 1 if end device.
814 */
815static int
816_scsih_is_end_device(u32 device_info)
817{
818 if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
819 ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
820 (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
821 (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
822 return 1;
823 else
824 return 0;
825}
826
827/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530828 * mptscsih_get_scsi_lookup - returns scmd entry
Eric Moore635374e2009-03-09 01:21:12 -0600829 * @ioc: per adapter object
830 * @smid: system request message index
Eric Moore635374e2009-03-09 01:21:12 -0600831 *
832 * Returns the smid stored scmd pointer.
833 */
834static struct scsi_cmnd *
835_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
836{
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530837 return ioc->scsi_lookup[smid - 1].scmd;
Eric Moore635374e2009-03-09 01:21:12 -0600838}
839
840/**
841 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
842 * @ioc: per adapter object
843 * @smid: system request message index
844 * @scmd: pointer to scsi command object
845 * Context: This function will acquire ioc->scsi_lookup_lock.
846 *
847 * This will search for a scmd pointer in the scsi_lookup array,
848 * returning the revelent smid. A returned value of zero means invalid.
849 */
850static u16
851_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
852 *scmd)
853{
854 u16 smid;
855 unsigned long flags;
856 int i;
857
858 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
859 smid = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530860 for (i = 0; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600861 if (ioc->scsi_lookup[i].scmd == scmd) {
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530862 smid = ioc->scsi_lookup[i].smid;
Eric Moore635374e2009-03-09 01:21:12 -0600863 goto out;
864 }
865 }
866 out:
867 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
868 return smid;
869}
870
871/**
872 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
873 * @ioc: per adapter object
874 * @id: target id
875 * @channel: channel
876 * Context: This function will acquire ioc->scsi_lookup_lock.
877 *
878 * This will search for a matching channel:id in the scsi_lookup array,
879 * returning 1 if found.
880 */
881static u8
882_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
883 int channel)
884{
885 u8 found;
886 unsigned long flags;
887 int i;
888
889 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
890 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530891 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600892 if (ioc->scsi_lookup[i].scmd &&
893 (ioc->scsi_lookup[i].scmd->device->id == id &&
894 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
895 found = 1;
896 goto out;
897 }
898 }
899 out:
900 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
901 return found;
902}
903
904/**
Eric Moore993e0da2009-05-18 13:00:45 -0600905 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
906 * @ioc: per adapter object
907 * @id: target id
908 * @lun: lun number
909 * @channel: channel
910 * Context: This function will acquire ioc->scsi_lookup_lock.
911 *
912 * This will search for a matching channel:id:lun in the scsi_lookup array,
913 * returning 1 if found.
914 */
915static u8
916_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
917 unsigned int lun, int channel)
918{
919 u8 found;
920 unsigned long flags;
921 int i;
922
923 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
924 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530925 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore993e0da2009-05-18 13:00:45 -0600926 if (ioc->scsi_lookup[i].scmd &&
927 (ioc->scsi_lookup[i].scmd->device->id == id &&
928 ioc->scsi_lookup[i].scmd->device->channel == channel &&
929 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
930 found = 1;
931 goto out;
932 }
933 }
934 out:
935 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
936 return found;
937}
938
939/**
Eric Moore635374e2009-03-09 01:21:12 -0600940 * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
941 * @ioc: per adapter object
942 * @smid: system request message index
943 *
944 * Returns phys pointer to chain buffer.
945 */
946static dma_addr_t
947_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
948{
949 return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
950 ioc->chains_needed_per_io));
951}
952
953/**
954 * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
955 * @ioc: per adapter object
956 * @smid: system request message index
957 *
958 * Returns virt pointer to chain buffer.
959 */
960static void *
961_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
962{
963 return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
964 ioc->chains_needed_per_io)));
965}
966
967/**
968 * _scsih_build_scatter_gather - main sg creation routine
969 * @ioc: per adapter object
970 * @scmd: scsi command
971 * @smid: system request message index
972 * Context: none.
973 *
974 * The main routine that builds scatter gather table from a given
975 * scsi request sent via the .queuecommand main handler.
976 *
977 * Returns 0 success, anything else error
978 */
979static int
980_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
981 struct scsi_cmnd *scmd, u16 smid)
982{
983 Mpi2SCSIIORequest_t *mpi_request;
984 dma_addr_t chain_dma;
985 struct scatterlist *sg_scmd;
986 void *sg_local, *chain;
987 u32 chain_offset;
988 u32 chain_length;
989 u32 chain_flags;
990 u32 sges_left;
991 u32 sges_in_segment;
992 u32 sgl_flags;
993 u32 sgl_flags_last_element;
994 u32 sgl_flags_end_buffer;
995
996 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
997
998 /* init scatter gather flags */
999 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
1000 if (scmd->sc_data_direction == DMA_TO_DEVICE)
1001 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
1002 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
1003 << MPI2_SGE_FLAGS_SHIFT;
1004 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
1005 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
1006 << MPI2_SGE_FLAGS_SHIFT;
1007 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1008
1009 sg_scmd = scsi_sglist(scmd);
1010 sges_left = scsi_dma_map(scmd);
1011 if (!sges_left) {
1012 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
1013 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
1014 return -ENOMEM;
1015 }
1016
1017 sg_local = &mpi_request->SGL;
1018 sges_in_segment = ioc->max_sges_in_main_message;
1019 if (sges_left <= sges_in_segment)
1020 goto fill_in_last_segment;
1021
1022 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
1023 (sges_in_segment * ioc->sge_size))/4;
1024
1025 /* fill in main message segment when there is a chain following */
1026 while (sges_in_segment) {
1027 if (sges_in_segment == 1)
1028 ioc->base_add_sg_single(sg_local,
1029 sgl_flags_last_element | sg_dma_len(sg_scmd),
1030 sg_dma_address(sg_scmd));
1031 else
1032 ioc->base_add_sg_single(sg_local, sgl_flags |
1033 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1034 sg_scmd = sg_next(sg_scmd);
1035 sg_local += ioc->sge_size;
1036 sges_left--;
1037 sges_in_segment--;
1038 }
1039
1040 /* initializing the chain flags and pointers */
1041 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
1042 chain = _scsih_get_chain_buffer(ioc, smid);
1043 chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
1044 do {
1045 sges_in_segment = (sges_left <=
1046 ioc->max_sges_in_chain_message) ? sges_left :
1047 ioc->max_sges_in_chain_message;
1048 chain_offset = (sges_left == sges_in_segment) ?
1049 0 : (sges_in_segment * ioc->sge_size)/4;
1050 chain_length = sges_in_segment * ioc->sge_size;
1051 if (chain_offset) {
1052 chain_offset = chain_offset <<
1053 MPI2_SGE_CHAIN_OFFSET_SHIFT;
1054 chain_length += ioc->sge_size;
1055 }
1056 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
1057 chain_length, chain_dma);
1058 sg_local = chain;
1059 if (!chain_offset)
1060 goto fill_in_last_segment;
1061
1062 /* fill in chain segments */
1063 while (sges_in_segment) {
1064 if (sges_in_segment == 1)
1065 ioc->base_add_sg_single(sg_local,
1066 sgl_flags_last_element |
1067 sg_dma_len(sg_scmd),
1068 sg_dma_address(sg_scmd));
1069 else
1070 ioc->base_add_sg_single(sg_local, sgl_flags |
1071 sg_dma_len(sg_scmd),
1072 sg_dma_address(sg_scmd));
1073 sg_scmd = sg_next(sg_scmd);
1074 sg_local += ioc->sge_size;
1075 sges_left--;
1076 sges_in_segment--;
1077 }
1078
1079 chain_dma += ioc->request_sz;
1080 chain += ioc->request_sz;
1081 } while (1);
1082
1083
1084 fill_in_last_segment:
1085
1086 /* fill the last segment */
1087 while (sges_left) {
1088 if (sges_left == 1)
1089 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1090 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1091 else
1092 ioc->base_add_sg_single(sg_local, sgl_flags |
1093 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1094 sg_scmd = sg_next(sg_scmd);
1095 sg_local += ioc->sge_size;
1096 sges_left--;
1097 }
1098
1099 return 0;
1100}
1101
1102/**
Eric Moored5d135b2009-05-18 13:02:08 -06001103 * _scsih_change_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001104 * @sdev: scsi device struct
1105 * @qdepth: requested queue depth
Mike Christiee881a172009-10-15 17:46:39 -07001106 * @reason: calling context
Eric Moore635374e2009-03-09 01:21:12 -06001107 *
1108 * Returns queue depth.
1109 */
1110static int
Mike Christiee881a172009-10-15 17:46:39 -07001111_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
Eric Moore635374e2009-03-09 01:21:12 -06001112{
1113 struct Scsi_Host *shost = sdev->host;
1114 int max_depth;
1115 int tag_type;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301116 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1117 struct MPT2SAS_DEVICE *sas_device_priv_data;
1118 struct MPT2SAS_TARGET *sas_target_priv_data;
1119 struct _sas_device *sas_device;
1120 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06001121
Mike Christiee881a172009-10-15 17:46:39 -07001122 if (reason != SCSI_QDEPTH_DEFAULT)
1123 return -EOPNOTSUPP;
1124
Eric Moore635374e2009-03-09 01:21:12 -06001125 max_depth = shost->can_queue;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301126
1127 /* limit max device queue for SATA to 32 */
1128 sas_device_priv_data = sdev->hostdata;
1129 if (!sas_device_priv_data)
1130 goto not_sata;
1131 sas_target_priv_data = sas_device_priv_data->sas_target;
1132 if (!sas_target_priv_data)
1133 goto not_sata;
1134 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
1135 goto not_sata;
1136 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1137 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1138 sas_device_priv_data->sas_target->sas_address);
1139 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1140 if (sas_device && sas_device->device_info &
1141 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1142 max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
1143
1144 not_sata:
1145
Eric Moore635374e2009-03-09 01:21:12 -06001146 if (!sdev->tagged_supported)
1147 max_depth = 1;
1148 if (qdepth > max_depth)
1149 qdepth = max_depth;
1150 tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
1151 scsi_adjust_queue_depth(sdev, tag_type, qdepth);
1152
1153 if (sdev->inquiry_len > 7)
1154 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1155 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1156 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1157 sdev->ordered_tags, sdev->scsi_level,
1158 (sdev->inquiry[7] & 2) >> 1);
1159
1160 return sdev->queue_depth;
1161}
1162
1163/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301164 * _scsih_change_queue_type - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001165 * @sdev: scsi device struct
1166 * @tag_type: requested tag type
1167 *
1168 * Returns queue tag type.
1169 */
1170static int
Eric Moored5d135b2009-05-18 13:02:08 -06001171_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001172{
1173 if (sdev->tagged_supported) {
1174 scsi_set_tag_type(sdev, tag_type);
1175 if (tag_type)
1176 scsi_activate_tcq(sdev, sdev->queue_depth);
1177 else
1178 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1179 } else
1180 tag_type = 0;
1181
1182 return tag_type;
1183}
1184
1185/**
Eric Moored5d135b2009-05-18 13:02:08 -06001186 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001187 * @starget: scsi target struct
1188 *
1189 * Returns 0 if ok. Any other return is assumed to be an error and
1190 * the device is ignored.
1191 */
1192static int
Eric Moored5d135b2009-05-18 13:02:08 -06001193_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001194{
1195 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1196 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1197 struct MPT2SAS_TARGET *sas_target_priv_data;
1198 struct _sas_device *sas_device;
1199 struct _raid_device *raid_device;
1200 unsigned long flags;
1201 struct sas_rphy *rphy;
1202
1203 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1204 if (!sas_target_priv_data)
1205 return -ENOMEM;
1206
1207 starget->hostdata = sas_target_priv_data;
1208 sas_target_priv_data->starget = starget;
1209 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1210
1211 /* RAID volumes */
1212 if (starget->channel == RAID_CHANNEL) {
1213 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1214 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1215 starget->channel);
1216 if (raid_device) {
1217 sas_target_priv_data->handle = raid_device->handle;
1218 sas_target_priv_data->sas_address = raid_device->wwid;
1219 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
1220 raid_device->starget = starget;
1221 }
1222 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1223 return 0;
1224 }
1225
1226 /* sas/sata devices */
1227 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1228 rphy = dev_to_rphy(starget->dev.parent);
1229 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1230 rphy->identify.sas_address);
1231
1232 if (sas_device) {
1233 sas_target_priv_data->handle = sas_device->handle;
1234 sas_target_priv_data->sas_address = sas_device->sas_address;
1235 sas_device->starget = starget;
1236 sas_device->id = starget->id;
1237 sas_device->channel = starget->channel;
1238 if (sas_device->hidden_raid_component)
1239 sas_target_priv_data->flags |=
1240 MPT_TARGET_FLAGS_RAID_COMPONENT;
1241 }
1242 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1243
1244 return 0;
1245}
1246
1247/**
Eric Moored5d135b2009-05-18 13:02:08 -06001248 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001249 * @starget: scsi target struct
1250 *
1251 * Returns nothing.
1252 */
1253static void
Eric Moored5d135b2009-05-18 13:02:08 -06001254_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001255{
1256 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1257 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1258 struct MPT2SAS_TARGET *sas_target_priv_data;
1259 struct _sas_device *sas_device;
1260 struct _raid_device *raid_device;
1261 unsigned long flags;
1262 struct sas_rphy *rphy;
1263
1264 sas_target_priv_data = starget->hostdata;
1265 if (!sas_target_priv_data)
1266 return;
1267
1268 if (starget->channel == RAID_CHANNEL) {
1269 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1270 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1271 starget->channel);
1272 if (raid_device) {
1273 raid_device->starget = NULL;
1274 raid_device->sdev = NULL;
1275 }
1276 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1277 goto out;
1278 }
1279
1280 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1281 rphy = dev_to_rphy(starget->dev.parent);
1282 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1283 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001284 if (sas_device && (sas_device->starget == starget) &&
1285 (sas_device->id == starget->id) &&
1286 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001287 sas_device->starget = NULL;
1288
1289 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1290
1291 out:
1292 kfree(sas_target_priv_data);
1293 starget->hostdata = NULL;
1294}
1295
1296/**
Eric Moored5d135b2009-05-18 13:02:08 -06001297 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001298 * @sdev: scsi device struct
1299 *
1300 * Returns 0 if ok. Any other return is assumed to be an error and
1301 * the device is ignored.
1302 */
1303static int
Eric Moored5d135b2009-05-18 13:02:08 -06001304_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001305{
1306 struct Scsi_Host *shost;
1307 struct MPT2SAS_ADAPTER *ioc;
1308 struct MPT2SAS_TARGET *sas_target_priv_data;
1309 struct MPT2SAS_DEVICE *sas_device_priv_data;
1310 struct scsi_target *starget;
1311 struct _raid_device *raid_device;
1312 struct _sas_device *sas_device;
1313 unsigned long flags;
1314
1315 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1316 if (!sas_device_priv_data)
1317 return -ENOMEM;
1318
1319 sas_device_priv_data->lun = sdev->lun;
1320 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1321
1322 starget = scsi_target(sdev);
1323 sas_target_priv_data = starget->hostdata;
1324 sas_target_priv_data->num_luns++;
1325 sas_device_priv_data->sas_target = sas_target_priv_data;
1326 sdev->hostdata = sas_device_priv_data;
1327 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1328 sdev->no_uld_attach = 1;
1329
1330 shost = dev_to_shost(&starget->dev);
1331 ioc = shost_priv(shost);
1332 if (starget->channel == RAID_CHANNEL) {
1333 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1334 raid_device = _scsih_raid_device_find_by_id(ioc,
1335 starget->id, starget->channel);
1336 if (raid_device)
1337 raid_device->sdev = sdev; /* raid is single lun */
1338 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1339 } else {
1340 /* set TLR bit for SSP devices */
1341 if (!(ioc->facts.IOCCapabilities &
1342 MPI2_IOCFACTS_CAPABILITY_TLR))
1343 goto out;
1344 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1345 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1346 sas_device_priv_data->sas_target->sas_address);
1347 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1348 if (sas_device && sas_device->device_info &
1349 MPI2_SAS_DEVICE_INFO_SSP_TARGET)
1350 sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON;
1351 }
1352
1353 out:
1354 return 0;
1355}
1356
1357/**
Eric Moored5d135b2009-05-18 13:02:08 -06001358 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001359 * @sdev: scsi device struct
1360 *
1361 * Returns nothing.
1362 */
1363static void
Eric Moored5d135b2009-05-18 13:02:08 -06001364_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001365{
1366 struct MPT2SAS_TARGET *sas_target_priv_data;
1367 struct scsi_target *starget;
1368
1369 if (!sdev->hostdata)
1370 return;
1371
1372 starget = scsi_target(sdev);
1373 sas_target_priv_data = starget->hostdata;
1374 sas_target_priv_data->num_luns--;
1375 kfree(sdev->hostdata);
1376 sdev->hostdata = NULL;
1377}
1378
1379/**
Eric Moored5d135b2009-05-18 13:02:08 -06001380 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001381 * @ioc: per adapter object
1382 * @sas_device: the sas_device object
1383 * @sdev: scsi device struct
1384 */
1385static void
Eric Moored5d135b2009-05-18 13:02:08 -06001386_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06001387 struct _sas_device *sas_device, struct scsi_device *sdev)
1388{
1389 Mpi2ConfigReply_t mpi_reply;
1390 Mpi2SasDevicePage0_t sas_device_pg0;
1391 u32 ioc_status;
1392 u16 flags;
1393 u32 device_info;
1394
1395 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
1396 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
1397 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1398 ioc->name, __FILE__, __LINE__, __func__);
1399 return;
1400 }
1401
1402 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1403 MPI2_IOCSTATUS_MASK;
1404 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1405 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1406 ioc->name, __FILE__, __LINE__, __func__);
1407 return;
1408 }
1409
1410 flags = le16_to_cpu(sas_device_pg0.Flags);
1411 device_info = le16_to_cpu(sas_device_pg0.DeviceInfo);
1412
1413 sdev_printk(KERN_INFO, sdev,
1414 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1415 "sw_preserve(%s)\n",
1416 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1417 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1418 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1419 "n",
1420 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1421 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1422 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1423}
1424
1425/**
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301426 * _scsih_is_raid - return boolean indicating device is raid volume
1427 * @dev the device struct object
1428 */
1429static int
1430_scsih_is_raid(struct device *dev)
1431{
1432 struct scsi_device *sdev = to_scsi_device(dev);
1433
1434 return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
1435}
1436
1437/**
1438 * _scsih_get_resync - get raid volume resync percent complete
1439 * @dev the device struct object
1440 */
1441static void
1442_scsih_get_resync(struct device *dev)
1443{
1444 struct scsi_device *sdev = to_scsi_device(dev);
1445 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1446 static struct _raid_device *raid_device;
1447 unsigned long flags;
1448 Mpi2RaidVolPage0_t vol_pg0;
1449 Mpi2ConfigReply_t mpi_reply;
1450 u32 volume_status_flags;
1451 u8 percent_complete = 0;
1452
1453 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1454 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1455 sdev->channel);
1456 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1457
1458 if (!raid_device)
1459 goto out;
1460
1461 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1462 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1463 sizeof(Mpi2RaidVolPage0_t))) {
1464 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1465 ioc->name, __FILE__, __LINE__, __func__);
1466 goto out;
1467 }
1468
1469 volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1470 if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
1471 percent_complete = raid_device->percent_complete;
1472 out:
1473 raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
1474}
1475
1476/**
1477 * _scsih_get_state - get raid volume level
1478 * @dev the device struct object
1479 */
1480static void
1481_scsih_get_state(struct device *dev)
1482{
1483 struct scsi_device *sdev = to_scsi_device(dev);
1484 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1485 static struct _raid_device *raid_device;
1486 unsigned long flags;
1487 Mpi2RaidVolPage0_t vol_pg0;
1488 Mpi2ConfigReply_t mpi_reply;
1489 u32 volstate;
1490 enum raid_state state = RAID_STATE_UNKNOWN;
1491
1492 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1493 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1494 sdev->channel);
1495 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1496
1497 if (!raid_device)
1498 goto out;
1499
1500 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1501 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1502 sizeof(Mpi2RaidVolPage0_t))) {
1503 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1504 ioc->name, __FILE__, __LINE__, __func__);
1505 goto out;
1506 }
1507
1508 volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1509 if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
1510 state = RAID_STATE_RESYNCING;
1511 goto out;
1512 }
1513
1514 switch (vol_pg0.VolumeState) {
1515 case MPI2_RAID_VOL_STATE_OPTIMAL:
1516 case MPI2_RAID_VOL_STATE_ONLINE:
1517 state = RAID_STATE_ACTIVE;
1518 break;
1519 case MPI2_RAID_VOL_STATE_DEGRADED:
1520 state = RAID_STATE_DEGRADED;
1521 break;
1522 case MPI2_RAID_VOL_STATE_FAILED:
1523 case MPI2_RAID_VOL_STATE_MISSING:
1524 state = RAID_STATE_OFFLINE;
1525 break;
1526 }
1527 out:
1528 raid_set_state(mpt2sas_raid_template, dev, state);
1529}
1530
1531/**
1532 * _scsih_set_level - set raid level
1533 * @sdev: scsi device struct
1534 * @raid_device: raid_device object
1535 */
1536static void
1537_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
1538{
1539 enum raid_level level = RAID_LEVEL_UNKNOWN;
1540
1541 switch (raid_device->volume_type) {
1542 case MPI2_RAID_VOL_TYPE_RAID0:
1543 level = RAID_LEVEL_0;
1544 break;
1545 case MPI2_RAID_VOL_TYPE_RAID10:
1546 level = RAID_LEVEL_10;
1547 break;
1548 case MPI2_RAID_VOL_TYPE_RAID1E:
1549 level = RAID_LEVEL_1E;
1550 break;
1551 case MPI2_RAID_VOL_TYPE_RAID1:
1552 level = RAID_LEVEL_1;
1553 break;
1554 }
1555
1556 raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
1557}
1558
1559/**
Eric Moore635374e2009-03-09 01:21:12 -06001560 * _scsih_get_volume_capabilities - volume capabilities
1561 * @ioc: per adapter object
1562 * @sas_device: the raid_device object
1563 */
1564static void
1565_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1566 struct _raid_device *raid_device)
1567{
1568 Mpi2RaidVolPage0_t *vol_pg0;
1569 Mpi2RaidPhysDiskPage0_t pd_pg0;
1570 Mpi2SasDevicePage0_t sas_device_pg0;
1571 Mpi2ConfigReply_t mpi_reply;
1572 u16 sz;
1573 u8 num_pds;
1574
1575 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1576 &num_pds)) || !num_pds) {
1577 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1578 ioc->name, __FILE__, __LINE__, __func__);
1579 return;
1580 }
1581
1582 raid_device->num_pds = num_pds;
1583 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1584 sizeof(Mpi2RaidVol0PhysDisk_t));
1585 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1586 if (!vol_pg0) {
1587 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1588 ioc->name, __FILE__, __LINE__, __func__);
1589 return;
1590 }
1591
1592 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1593 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1594 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1595 ioc->name, __FILE__, __LINE__, __func__);
1596 kfree(vol_pg0);
1597 return;
1598 }
1599
1600 raid_device->volume_type = vol_pg0->VolumeType;
1601
1602 /* figure out what the underlying devices are by
1603 * obtaining the device_info bits for the 1st device
1604 */
1605 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1606 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1607 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1608 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1609 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1610 le16_to_cpu(pd_pg0.DevHandle)))) {
1611 raid_device->device_info =
1612 le32_to_cpu(sas_device_pg0.DeviceInfo);
1613 }
1614 }
1615
1616 kfree(vol_pg0);
1617}
1618
1619/**
Eric Moored5d135b2009-05-18 13:02:08 -06001620 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001621 * @sdev: scsi device struct
1622 *
1623 * Returns 0 if ok. Any other return is assumed to be an error and
1624 * the device is ignored.
1625 */
1626static int
Eric Moored5d135b2009-05-18 13:02:08 -06001627_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001628{
1629 struct Scsi_Host *shost = sdev->host;
1630 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1631 struct MPT2SAS_DEVICE *sas_device_priv_data;
1632 struct MPT2SAS_TARGET *sas_target_priv_data;
1633 struct _sas_device *sas_device;
1634 struct _raid_device *raid_device;
1635 unsigned long flags;
1636 int qdepth;
1637 u8 ssp_target = 0;
1638 char *ds = "";
1639 char *r_level = "";
1640
1641 qdepth = 1;
1642 sas_device_priv_data = sdev->hostdata;
1643 sas_device_priv_data->configured_lun = 1;
1644 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1645 sas_target_priv_data = sas_device_priv_data->sas_target;
1646
1647 /* raid volume handling */
1648 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1649
1650 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1651 raid_device = _scsih_raid_device_find_by_handle(ioc,
1652 sas_target_priv_data->handle);
1653 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1654 if (!raid_device) {
1655 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1656 ioc->name, __FILE__, __LINE__, __func__);
1657 return 0;
1658 }
1659
1660 _scsih_get_volume_capabilities(ioc, raid_device);
1661
1662 /* RAID Queue Depth Support
1663 * IS volume = underlying qdepth of drive type, either
1664 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
1665 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
1666 */
1667 if (raid_device->device_info &
1668 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1669 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1670 ds = "SSP";
1671 } else {
1672 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1673 if (raid_device->device_info &
1674 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1675 ds = "SATA";
1676 else
1677 ds = "STP";
1678 }
1679
1680 switch (raid_device->volume_type) {
1681 case MPI2_RAID_VOL_TYPE_RAID0:
1682 r_level = "RAID0";
1683 break;
1684 case MPI2_RAID_VOL_TYPE_RAID1E:
1685 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05301686 if (ioc->manu_pg10.OEMIdentifier &&
1687 (ioc->manu_pg10.GenericFlags0 &
1688 MFG10_GF0_R10_DISPLAY) &&
1689 !(raid_device->num_pds % 2))
1690 r_level = "RAID10";
1691 else
1692 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06001693 break;
1694 case MPI2_RAID_VOL_TYPE_RAID1:
1695 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1696 r_level = "RAID1";
1697 break;
1698 case MPI2_RAID_VOL_TYPE_RAID10:
1699 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1700 r_level = "RAID10";
1701 break;
1702 case MPI2_RAID_VOL_TYPE_UNKNOWN:
1703 default:
1704 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1705 r_level = "RAIDX";
1706 break;
1707 }
1708
1709 sdev_printk(KERN_INFO, sdev, "%s: "
1710 "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
1711 r_level, raid_device->handle,
1712 (unsigned long long)raid_device->wwid,
1713 raid_device->num_pds, ds);
Mike Christiee881a172009-10-15 17:46:39 -07001714 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301715 /* raid transport support */
1716 _scsih_set_level(sdev, raid_device);
Eric Moore635374e2009-03-09 01:21:12 -06001717 return 0;
1718 }
1719
1720 /* non-raid handling */
1721 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1722 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1723 sas_device_priv_data->sas_target->sas_address);
1724 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1725 if (sas_device) {
1726 if (sas_target_priv_data->flags &
1727 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1728 mpt2sas_config_get_volume_handle(ioc,
1729 sas_device->handle, &sas_device->volume_handle);
1730 mpt2sas_config_get_volume_wwid(ioc,
1731 sas_device->volume_handle,
1732 &sas_device->volume_wwid);
1733 }
1734 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1735 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1736 ssp_target = 1;
1737 ds = "SSP";
1738 } else {
1739 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1740 if (sas_device->device_info &
1741 MPI2_SAS_DEVICE_INFO_STP_TARGET)
1742 ds = "STP";
1743 else if (sas_device->device_info &
1744 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1745 ds = "SATA";
1746 }
1747
1748 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
1749 "sas_addr(0x%016llx), device_name(0x%016llx)\n",
1750 ds, sas_device->handle,
1751 (unsigned long long)sas_device->sas_address,
1752 (unsigned long long)sas_device->device_name);
1753 sdev_printk(KERN_INFO, sdev, "%s: "
1754 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
1755 (unsigned long long) sas_device->enclosure_logical_id,
1756 sas_device->slot);
1757
1758 if (!ssp_target)
Eric Moored5d135b2009-05-18 13:02:08 -06001759 _scsih_display_sata_capabilities(ioc, sas_device, sdev);
Eric Moore635374e2009-03-09 01:21:12 -06001760 }
1761
Mike Christiee881a172009-10-15 17:46:39 -07001762 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Eric Moore635374e2009-03-09 01:21:12 -06001763
1764 if (ssp_target)
1765 sas_read_port_mode_page(sdev);
1766 return 0;
1767}
1768
1769/**
Eric Moored5d135b2009-05-18 13:02:08 -06001770 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06001771 * @sdev: scsi device struct
1772 * @bdev: pointer to block device context
1773 * @capacity: device size (in 512 byte sectors)
1774 * @params: three element array to place output:
1775 * params[0] number of heads (max 255)
1776 * params[1] number of sectors (max 63)
1777 * params[2] number of cylinders
1778 *
1779 * Return nothing.
1780 */
1781static int
Eric Moored5d135b2009-05-18 13:02:08 -06001782_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06001783 sector_t capacity, int params[])
1784{
1785 int heads;
1786 int sectors;
1787 sector_t cylinders;
1788 ulong dummy;
1789
1790 heads = 64;
1791 sectors = 32;
1792
1793 dummy = heads * sectors;
1794 cylinders = capacity;
1795 sector_div(cylinders, dummy);
1796
1797 /*
1798 * Handle extended translation size for logical drives
1799 * > 1Gb
1800 */
1801 if ((ulong)capacity >= 0x200000) {
1802 heads = 255;
1803 sectors = 63;
1804 dummy = heads * sectors;
1805 cylinders = capacity;
1806 sector_div(cylinders, dummy);
1807 }
1808
1809 /* return result */
1810 params[0] = heads;
1811 params[1] = sectors;
1812 params[2] = cylinders;
1813
1814 return 0;
1815}
1816
1817/**
1818 * _scsih_response_code - translation of device response code
1819 * @ioc: per adapter object
1820 * @response_code: response code returned by the device
1821 *
1822 * Return nothing.
1823 */
1824static void
1825_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
1826{
1827 char *desc;
1828
1829 switch (response_code) {
1830 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1831 desc = "task management request completed";
1832 break;
1833 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1834 desc = "invalid frame";
1835 break;
1836 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1837 desc = "task management request not supported";
1838 break;
1839 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1840 desc = "task management request failed";
1841 break;
1842 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1843 desc = "task management request succeeded";
1844 break;
1845 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1846 desc = "invalid lun";
1847 break;
1848 case 0xA:
1849 desc = "overlapped tag attempted";
1850 break;
1851 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1852 desc = "task queued, however not sent to target";
1853 break;
1854 default:
1855 desc = "unknown";
1856 break;
1857 }
1858 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
1859 ioc->name, response_code, desc);
1860}
1861
1862/**
Eric Moored5d135b2009-05-18 13:02:08 -06001863 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06001864 * @ioc: per adapter object
1865 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301866 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001867 * @reply: reply message frame(lower 32bit addr)
1868 * Context: none.
1869 *
1870 * The callback handler when using scsih_issue_tm.
1871 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301872 * Return 1 meaning mf should be freed from _base_interrupt
1873 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06001874 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301875static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301876_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06001877{
1878 MPI2DefaultReply_t *mpi_reply;
1879
1880 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301881 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001882 if (ioc->tm_cmds.smid != smid)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301883 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001884 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
1885 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
1886 if (mpi_reply) {
1887 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
1888 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
1889 }
1890 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
1891 complete(&ioc->tm_cmds.done);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301892 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001893}
1894
1895/**
1896 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
1897 * @ioc: per adapter object
1898 * @handle: device handle
1899 *
1900 * During taskmangement request, we need to freeze the device queue.
1901 */
1902void
1903mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1904{
1905 struct MPT2SAS_DEVICE *sas_device_priv_data;
1906 struct scsi_device *sdev;
1907 u8 skip = 0;
1908
1909 shost_for_each_device(sdev, ioc->shost) {
1910 if (skip)
1911 continue;
1912 sas_device_priv_data = sdev->hostdata;
1913 if (!sas_device_priv_data)
1914 continue;
1915 if (sas_device_priv_data->sas_target->handle == handle) {
1916 sas_device_priv_data->sas_target->tm_busy = 1;
1917 skip = 1;
1918 ioc->ignore_loginfos = 1;
1919 }
1920 }
1921}
1922
1923/**
1924 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
1925 * @ioc: per adapter object
1926 * @handle: device handle
1927 *
1928 * During taskmangement request, we need to freeze the device queue.
1929 */
1930void
1931mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1932{
1933 struct MPT2SAS_DEVICE *sas_device_priv_data;
1934 struct scsi_device *sdev;
1935 u8 skip = 0;
1936
1937 shost_for_each_device(sdev, ioc->shost) {
1938 if (skip)
1939 continue;
1940 sas_device_priv_data = sdev->hostdata;
1941 if (!sas_device_priv_data)
1942 continue;
1943 if (sas_device_priv_data->sas_target->handle == handle) {
1944 sas_device_priv_data->sas_target->tm_busy = 0;
1945 skip = 1;
1946 ioc->ignore_loginfos = 0;
1947 }
1948 }
1949}
1950
1951/**
1952 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
1953 * @ioc: per adapter struct
1954 * @device_handle: device handle
1955 * @lun: lun number
1956 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
1957 * @smid_task: smid assigned to the task
1958 * @timeout: timeout in seconds
1959 * Context: The calling function needs to acquire the tm_cmds.mutex
1960 *
1961 * A generic API for sending task management requests to firmware.
1962 *
1963 * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling
1964 * this API.
1965 *
1966 * The callback index is set inside `ioc->tm_cb_idx`.
1967 *
1968 * Return nothing.
1969 */
1970void
1971mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
1972 u8 type, u16 smid_task, ulong timeout)
1973{
1974 Mpi2SCSITaskManagementRequest_t *mpi_request;
1975 Mpi2SCSITaskManagementReply_t *mpi_reply;
1976 u16 smid = 0;
1977 u32 ioc_state;
1978 unsigned long timeleft;
Eric Moore635374e2009-03-09 01:21:12 -06001979
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301980 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
1981 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
1982 __func__, ioc->name);
1983 return;
1984 }
1985
1986 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06001987 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1988 __func__, ioc->name);
1989 return;
1990 }
Eric Moore635374e2009-03-09 01:21:12 -06001991
1992 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
1993 if (ioc_state & MPI2_DOORBELL_USED) {
1994 dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
1995 "active!\n", ioc->name));
1996 goto issue_host_reset;
1997 }
1998
1999 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
2000 mpt2sas_base_fault_info(ioc, ioc_state &
2001 MPI2_DOORBELL_DATA_MASK);
2002 goto issue_host_reset;
2003 }
2004
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302005 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06002006 if (!smid) {
2007 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2008 ioc->name, __func__);
2009 return;
2010 }
2011
2012 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302013 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
2014 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06002015 ioc->tm_cmds.status = MPT2_CMD_PENDING;
2016 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2017 ioc->tm_cmds.smid = smid;
2018 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2019 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2020 mpi_request->DevHandle = cpu_to_le16(handle);
2021 mpi_request->TaskType = type;
2022 mpi_request->TaskMID = cpu_to_le16(smid_task);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302023 mpi_request->VP_ID = 0; /* TODO */
2024 mpi_request->VF_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06002025 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
2026 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05302027 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302028 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002029 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
2030 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2031 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
2032 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
2033 ioc->name, __func__);
2034 _debug_dump_mf(mpi_request,
2035 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
2036 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET))
2037 goto issue_host_reset;
2038 }
2039
2040 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
2041 mpi_reply = ioc->tm_cmds.reply;
2042 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
2043 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
2044 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
2045 le32_to_cpu(mpi_reply->IOCLogInfo),
2046 le32_to_cpu(mpi_reply->TerminationCount)));
2047 if (ioc->logging_level & MPT_DEBUG_TM)
2048 _scsih_response_code(ioc, mpi_reply->ResponseCode);
2049 }
2050 return;
2051 issue_host_reset:
2052 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
2053}
2054
2055/**
Eric Moored5d135b2009-05-18 13:02:08 -06002056 * _scsih_abort - eh threads main abort routine
Eric Moore635374e2009-03-09 01:21:12 -06002057 * @sdev: scsi device struct
2058 *
2059 * Returns SUCCESS if command aborted else FAILED
2060 */
2061static int
Eric Moored5d135b2009-05-18 13:02:08 -06002062_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002063{
2064 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2065 struct MPT2SAS_DEVICE *sas_device_priv_data;
2066 u16 smid;
2067 u16 handle;
2068 int r;
2069 struct scsi_cmnd *scmd_lookup;
2070
2071 printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
2072 ioc->name, scmd);
2073 scsi_print_command(scmd);
2074
2075 sas_device_priv_data = scmd->device->hostdata;
2076 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2077 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
2078 ioc->name, scmd);
2079 scmd->result = DID_NO_CONNECT << 16;
2080 scmd->scsi_done(scmd);
2081 r = SUCCESS;
2082 goto out;
2083 }
2084
2085 /* search for the command */
2086 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
2087 if (!smid) {
2088 scmd->result = DID_RESET << 16;
2089 r = SUCCESS;
2090 goto out;
2091 }
2092
2093 /* for hidden raid components and volumes this is not supported */
2094 if (sas_device_priv_data->sas_target->flags &
2095 MPT_TARGET_FLAGS_RAID_COMPONENT ||
2096 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
2097 scmd->result = DID_RESET << 16;
2098 r = FAILED;
2099 goto out;
2100 }
2101
Kashyap, Desaifa7f3162009-09-23 17:26:58 +05302102 mpt2sas_halt_firmware(ioc);
2103
Eric Moore635374e2009-03-09 01:21:12 -06002104 mutex_lock(&ioc->tm_cmds.mutex);
2105 handle = sas_device_priv_data->sas_target->handle;
2106 mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
2107 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30);
2108
2109 /* sanity check - see whether command actually completed */
2110 scmd_lookup = _scsih_scsi_lookup_get(ioc, smid);
2111 if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number))
2112 r = FAILED;
2113 else
2114 r = SUCCESS;
2115 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2116 mutex_unlock(&ioc->tm_cmds.mutex);
2117
2118 out:
2119 printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
2120 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2121 return r;
2122}
2123
Eric Moore635374e2009-03-09 01:21:12 -06002124/**
Eric Moored5d135b2009-05-18 13:02:08 -06002125 * _scsih_dev_reset - eh threads main device reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002126 * @sdev: scsi device struct
2127 *
2128 * Returns SUCCESS if command aborted else FAILED
2129 */
2130static int
Eric Moored5d135b2009-05-18 13:02:08 -06002131_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002132{
2133 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2134 struct MPT2SAS_DEVICE *sas_device_priv_data;
2135 struct _sas_device *sas_device;
2136 unsigned long flags;
2137 u16 handle;
2138 int r;
2139
Eric Moore993e0da2009-05-18 13:00:45 -06002140 printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
Eric Moore635374e2009-03-09 01:21:12 -06002141 ioc->name, scmd);
2142 scsi_print_command(scmd);
2143
2144 sas_device_priv_data = scmd->device->hostdata;
2145 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2146 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
2147 ioc->name, scmd);
2148 scmd->result = DID_NO_CONNECT << 16;
2149 scmd->scsi_done(scmd);
2150 r = SUCCESS;
2151 goto out;
2152 }
2153
2154 /* for hidden raid components obtain the volume_handle */
2155 handle = 0;
2156 if (sas_device_priv_data->sas_target->flags &
2157 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2158 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2159 sas_device = _scsih_sas_device_find_by_handle(ioc,
2160 sas_device_priv_data->sas_target->handle);
2161 if (sas_device)
2162 handle = sas_device->volume_handle;
2163 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2164 } else
2165 handle = sas_device_priv_data->sas_target->handle;
2166
2167 if (!handle) {
2168 scmd->result = DID_RESET << 16;
2169 r = FAILED;
2170 goto out;
2171 }
2172
2173 mutex_lock(&ioc->tm_cmds.mutex);
2174 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore993e0da2009-05-18 13:00:45 -06002175 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun,
2176 30);
2177
2178 /*
2179 * sanity check see whether all commands to this device been
2180 * completed
2181 */
2182 if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id,
2183 scmd->device->lun, scmd->device->channel))
2184 r = FAILED;
2185 else
2186 r = SUCCESS;
2187 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2188 mutex_unlock(&ioc->tm_cmds.mutex);
2189
2190 out:
2191 printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
2192 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2193 return r;
2194}
2195
2196/**
Eric Moored5d135b2009-05-18 13:02:08 -06002197 * _scsih_target_reset - eh threads main target reset routine
Eric Moore993e0da2009-05-18 13:00:45 -06002198 * @sdev: scsi device struct
2199 *
2200 * Returns SUCCESS if command aborted else FAILED
2201 */
2202static int
Eric Moored5d135b2009-05-18 13:02:08 -06002203_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06002204{
2205 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2206 struct MPT2SAS_DEVICE *sas_device_priv_data;
2207 struct _sas_device *sas_device;
2208 unsigned long flags;
2209 u16 handle;
2210 int r;
2211
2212 printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
2213 ioc->name, scmd);
2214 scsi_print_command(scmd);
2215
2216 sas_device_priv_data = scmd->device->hostdata;
2217 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2218 printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
2219 ioc->name, scmd);
2220 scmd->result = DID_NO_CONNECT << 16;
2221 scmd->scsi_done(scmd);
2222 r = SUCCESS;
2223 goto out;
2224 }
2225
2226 /* for hidden raid components obtain the volume_handle */
2227 handle = 0;
2228 if (sas_device_priv_data->sas_target->flags &
2229 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2230 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2231 sas_device = _scsih_sas_device_find_by_handle(ioc,
2232 sas_device_priv_data->sas_target->handle);
2233 if (sas_device)
2234 handle = sas_device->volume_handle;
2235 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2236 } else
2237 handle = sas_device_priv_data->sas_target->handle;
2238
2239 if (!handle) {
2240 scmd->result = DID_RESET << 16;
2241 r = FAILED;
2242 goto out;
2243 }
2244
2245 mutex_lock(&ioc->tm_cmds.mutex);
2246 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore635374e2009-03-09 01:21:12 -06002247 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30);
2248
2249 /*
2250 * sanity check see whether all commands to this target been
2251 * completed
2252 */
2253 if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id,
2254 scmd->device->channel))
2255 r = FAILED;
2256 else
2257 r = SUCCESS;
2258 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2259 mutex_unlock(&ioc->tm_cmds.mutex);
2260
2261 out:
2262 printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
2263 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2264 return r;
2265}
2266
2267/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302268 * _scsih_host_reset - eh threads main host reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002269 * @sdev: scsi device struct
2270 *
2271 * Returns SUCCESS if command aborted else FAILED
2272 */
2273static int
Eric Moored5d135b2009-05-18 13:02:08 -06002274_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002275{
2276 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2277 int r, retval;
2278
2279 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2280 ioc->name, scmd);
2281 scsi_print_command(scmd);
2282
2283 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2284 FORCE_BIG_HAMMER);
2285 r = (retval < 0) ? FAILED : SUCCESS;
2286 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2287 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2288
2289 return r;
2290}
2291
2292/**
2293 * _scsih_fw_event_add - insert and queue up fw_event
2294 * @ioc: per adapter object
2295 * @fw_event: object describing the event
2296 * Context: This function will acquire ioc->fw_event_lock.
2297 *
2298 * This adds the firmware event object into link list, then queues it up to
2299 * be processed from user context.
2300 *
2301 * Return nothing.
2302 */
2303static void
2304_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2305{
2306 unsigned long flags;
2307
2308 if (ioc->firmware_event_thread == NULL)
2309 return;
2310
2311 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2312 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002313 INIT_WORK(&fw_event->work, _firmware_event_work);
2314 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002315 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2316}
2317
2318/**
2319 * _scsih_fw_event_free - delete fw_event
2320 * @ioc: per adapter object
2321 * @fw_event: object describing the event
2322 * Context: This function will acquire ioc->fw_event_lock.
2323 *
2324 * This removes firmware event object from link list, frees associated memory.
2325 *
2326 * Return nothing.
2327 */
2328static void
2329_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2330 *fw_event)
2331{
2332 unsigned long flags;
2333
2334 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2335 list_del(&fw_event->list);
2336 kfree(fw_event->event_data);
2337 kfree(fw_event);
2338 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2339}
2340
2341/**
2342 * _scsih_fw_event_add - requeue an event
2343 * @ioc: per adapter object
2344 * @fw_event: object describing the event
2345 * Context: This function will acquire ioc->fw_event_lock.
2346 *
2347 * Return nothing.
2348 */
2349static void
2350_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2351 *fw_event, unsigned long delay)
2352{
2353 unsigned long flags;
2354 if (ioc->firmware_event_thread == NULL)
2355 return;
2356
2357 spin_lock_irqsave(&ioc->fw_event_lock, flags);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002358 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002359 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2360}
2361
2362/**
2363 * _scsih_fw_event_off - turn flag off preventing event handling
2364 * @ioc: per adapter object
2365 *
2366 * Used to prevent handling of firmware events during adapter reset
2367 * driver unload.
2368 *
2369 * Return nothing.
2370 */
2371static void
2372_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc)
2373{
2374 unsigned long flags;
2375
2376 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2377 ioc->fw_events_off = 1;
2378 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2379
2380}
2381
2382/**
2383 * _scsih_fw_event_on - turn flag on allowing firmware event handling
2384 * @ioc: per adapter object
2385 *
2386 * Returns nothing.
2387 */
2388static void
2389_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc)
2390{
2391 unsigned long flags;
2392
2393 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2394 ioc->fw_events_off = 0;
2395 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2396}
2397
2398/**
2399 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2400 * @ioc: per adapter object
2401 * @handle: device handle
2402 *
2403 * During device pull we need to appropiately set the sdev state.
2404 */
2405static void
2406_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2407{
2408 struct MPT2SAS_DEVICE *sas_device_priv_data;
2409 struct scsi_device *sdev;
2410
2411 shost_for_each_device(sdev, ioc->shost) {
2412 sas_device_priv_data = sdev->hostdata;
2413 if (!sas_device_priv_data)
2414 continue;
2415 if (!sas_device_priv_data->block)
2416 continue;
2417 if (sas_device_priv_data->sas_target->handle == handle) {
2418 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2419 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2420 "handle(0x%04x)\n", ioc->name, handle));
2421 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302422 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002423 }
2424 }
2425}
2426
2427/**
2428 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2429 * @ioc: per adapter object
2430 * @handle: device handle
2431 *
2432 * During device pull we need to appropiately set the sdev state.
2433 */
2434static void
2435_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2436{
2437 struct MPT2SAS_DEVICE *sas_device_priv_data;
2438 struct scsi_device *sdev;
2439
2440 shost_for_each_device(sdev, ioc->shost) {
2441 sas_device_priv_data = sdev->hostdata;
2442 if (!sas_device_priv_data)
2443 continue;
2444 if (sas_device_priv_data->block)
2445 continue;
2446 if (sas_device_priv_data->sas_target->handle == handle) {
2447 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2448 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2449 "handle(0x%04x)\n", ioc->name, handle));
2450 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302451 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002452 }
2453 }
2454}
2455
2456/**
2457 * _scsih_block_io_to_children_attached_to_ex
2458 * @ioc: per adapter object
2459 * @sas_expander: the sas_device object
2460 *
2461 * This routine set sdev state to SDEV_BLOCK for all devices
2462 * attached to this expander. This function called when expander is
2463 * pulled.
2464 */
2465static void
2466_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2467 struct _sas_node *sas_expander)
2468{
2469 struct _sas_port *mpt2sas_port;
2470 struct _sas_device *sas_device;
2471 struct _sas_node *expander_sibling;
2472 unsigned long flags;
2473
2474 if (!sas_expander)
2475 return;
2476
2477 list_for_each_entry(mpt2sas_port,
2478 &sas_expander->sas_port_list, port_list) {
2479 if (mpt2sas_port->remote_identify.device_type ==
2480 SAS_END_DEVICE) {
2481 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2482 sas_device =
2483 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2484 mpt2sas_port->remote_identify.sas_address);
2485 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2486 if (!sas_device)
2487 continue;
2488 _scsih_block_io_device(ioc, sas_device->handle);
2489 }
2490 }
2491
2492 list_for_each_entry(mpt2sas_port,
2493 &sas_expander->sas_port_list, port_list) {
2494
2495 if (mpt2sas_port->remote_identify.device_type ==
2496 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2497 mpt2sas_port->remote_identify.device_type ==
2498 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2499
2500 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2501 expander_sibling =
2502 mpt2sas_scsih_expander_find_by_sas_address(
2503 ioc, mpt2sas_port->remote_identify.sas_address);
2504 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2505 _scsih_block_io_to_children_attached_to_ex(ioc,
2506 expander_sibling);
2507 }
2508 }
2509}
2510
2511/**
2512 * _scsih_block_io_to_children_attached_directly
2513 * @ioc: per adapter object
2514 * @event_data: topology change event data
2515 *
2516 * This routine set sdev state to SDEV_BLOCK for all devices
2517 * direct attached during device pull.
2518 */
2519static void
2520_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2521 Mpi2EventDataSasTopologyChangeList_t *event_data)
2522{
2523 int i;
2524 u16 handle;
2525 u16 reason_code;
2526 u8 phy_number;
2527
2528 for (i = 0; i < event_data->NumEntries; i++) {
2529 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2530 if (!handle)
2531 continue;
2532 phy_number = event_data->StartPhyNum + i;
2533 reason_code = event_data->PHY[i].PhyStatus &
2534 MPI2_EVENT_SAS_TOPO_RC_MASK;
2535 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2536 _scsih_block_io_device(ioc, handle);
2537 }
2538}
2539
2540/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302541 * _scsih_tm_tr_send - send task management request
2542 * @ioc: per adapter object
2543 * @handle: device handle
2544 * Context: interrupt time.
2545 *
2546 * This code is to initiate the device removal handshake protocal
2547 * with controller firmware. This function will issue target reset
2548 * using high priority request queue. It will send a sas iounit
2549 * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
2550 *
2551 * This is designed to send muliple task management request at the same
2552 * time to the fifo. If the fifo is full, we will append the request,
2553 * and process it in a future completion.
2554 */
2555static void
2556_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2557{
2558 Mpi2SCSITaskManagementRequest_t *mpi_request;
2559 struct MPT2SAS_TARGET *sas_target_priv_data;
2560 u16 smid;
2561 struct _sas_device *sas_device;
2562 unsigned long flags;
2563 struct _tr_list *delayed_tr;
2564
2565 if (ioc->shost_recovery) {
2566 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2567 __func__, ioc->name);
2568 return;
2569 }
2570
2571 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2572 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302573 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2574
2575 /* skip is hidden raid component */
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302576 if (sas_device && sas_device->hidden_raid_component)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302577 return;
2578
2579 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
2580 if (!smid) {
2581 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
2582 if (!delayed_tr)
2583 return;
2584 INIT_LIST_HEAD(&delayed_tr->list);
2585 delayed_tr->handle = handle;
2586 delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
2587 list_add_tail(&delayed_tr->list,
2588 &ioc->delayed_tr_list);
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302589 if (sas_device && sas_device->starget) {
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302590 dewtprintk(ioc, starget_printk(KERN_INFO,
2591 sas_device->starget, "DELAYED:tr:handle(0x%04x), "
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302592 "(open)\n", handle));
2593 } else {
2594 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2595 "DELAYED:tr:handle(0x%04x), (open)\n",
2596 ioc->name, handle));
2597 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302598 return;
2599 }
2600
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302601 if (sas_device) {
2602 sas_device->state |= MPTSAS_STATE_TR_SEND;
2603 sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
2604 if (sas_device->starget && sas_device->starget->hostdata) {
2605 sas_target_priv_data = sas_device->starget->hostdata;
2606 sas_target_priv_data->tm_busy = 1;
2607 dewtprintk(ioc, starget_printk(KERN_INFO,
2608 sas_device->starget, "tr:handle(0x%04x), (open)\n",
2609 handle));
2610 }
2611 } else {
2612 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2613 "tr:handle(0x%04x), (open)\n", ioc->name, handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302614 }
2615
2616 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2617 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2618 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2619 mpi_request->DevHandle = cpu_to_le16(handle);
2620 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302621 mpt2sas_base_put_smid_hi_priority(ioc, smid);
2622}
2623
2624
2625
2626/**
2627 * _scsih_sas_control_complete - completion routine
2628 * @ioc: per adapter object
2629 * @smid: system request message index
2630 * @msix_index: MSIX table index supplied by the OS
2631 * @reply: reply message frame(lower 32bit addr)
2632 * Context: interrupt time.
2633 *
2634 * This is the sas iounit controll completion routine.
2635 * This code is part of the code to initiate the device removal
2636 * handshake protocal with controller firmware.
2637 *
2638 * Return 1 meaning mf should be freed from _base_interrupt
2639 * 0 means the mf is freed from this function.
2640 */
2641static u8
2642_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
2643 u8 msix_index, u32 reply)
2644{
2645 unsigned long flags;
2646 u16 handle;
2647 struct _sas_device *sas_device;
2648 Mpi2SasIoUnitControlReply_t *mpi_reply =
2649 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2650
2651 handle = le16_to_cpu(mpi_reply->DevHandle);
2652
2653 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2654 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302655 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2656
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302657 if (sas_device) {
2658 sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
2659 if (sas_device->starget)
2660 dewtprintk(ioc, starget_printk(KERN_INFO,
2661 sas_device->starget,
2662 "sc_complete:handle(0x%04x), "
2663 "ioc_status(0x%04x), loginfo(0x%08x)\n",
2664 handle, le16_to_cpu(mpi_reply->IOCStatus),
2665 le32_to_cpu(mpi_reply->IOCLogInfo)));
2666 } else {
2667 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302668 "sc_complete:handle(0x%04x), "
2669 "ioc_status(0x%04x), loginfo(0x%08x)\n",
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302670 ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus),
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302671 le32_to_cpu(mpi_reply->IOCLogInfo)));
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302672 }
2673
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302674 return 1;
2675}
2676
2677/**
2678 * _scsih_tm_tr_complete -
2679 * @ioc: per adapter object
2680 * @smid: system request message index
2681 * @msix_index: MSIX table index supplied by the OS
2682 * @reply: reply message frame(lower 32bit addr)
2683 * Context: interrupt time.
2684 *
2685 * This is the target reset completion routine.
2686 * This code is part of the code to initiate the device removal
2687 * handshake protocal with controller firmware.
2688 * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE)
2689 *
2690 * Return 1 meaning mf should be freed from _base_interrupt
2691 * 0 means the mf is freed from this function.
2692 */
2693static u8
2694_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
2695 u32 reply)
2696{
2697 unsigned long flags;
2698 u16 handle;
2699 struct _sas_device *sas_device;
2700 Mpi2SCSITaskManagementReply_t *mpi_reply =
2701 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2702 Mpi2SasIoUnitControlRequest_t *mpi_request;
2703 u16 smid_sas_ctrl;
2704 struct MPT2SAS_TARGET *sas_target_priv_data;
2705 struct _tr_list *delayed_tr;
2706 u8 rc;
2707
2708 handle = le16_to_cpu(mpi_reply->DevHandle);
2709 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2710 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302711 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2712
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302713 if (sas_device) {
2714 sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
2715 if (sas_device->starget) {
2716 dewtprintk(ioc, starget_printk(KERN_INFO,
2717 sas_device->starget, "tr_complete:handle(0x%04x), "
2718 "(%s) ioc_status(0x%04x), loginfo(0x%08x), "
2719 "completed(%d)\n", sas_device->handle,
2720 (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ?
2721 "open" : "active",
2722 le16_to_cpu(mpi_reply->IOCStatus),
2723 le32_to_cpu(mpi_reply->IOCLogInfo),
2724 le32_to_cpu(mpi_reply->TerminationCount)));
2725 if (sas_device->starget->hostdata) {
2726 sas_target_priv_data =
2727 sas_device->starget->hostdata;
2728 sas_target_priv_data->tm_busy = 0;
2729 }
2730 }
2731 } else {
2732 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2733 "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), "
2734 "loginfo(0x%08x), completed(%d)\n", ioc->name,
2735 handle, le16_to_cpu(mpi_reply->IOCStatus),
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302736 le32_to_cpu(mpi_reply->IOCLogInfo),
2737 le32_to_cpu(mpi_reply->TerminationCount)));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302738 }
2739
2740 if (!list_empty(&ioc->delayed_tr_list)) {
2741 delayed_tr = list_entry(ioc->delayed_tr_list.next,
2742 struct _tr_list, list);
2743 mpt2sas_base_free_smid(ioc, smid);
2744 if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL)
2745 _scsih_tm_tr_send(ioc, delayed_tr->handle);
2746 list_del(&delayed_tr->list);
2747 kfree(delayed_tr);
2748 rc = 0; /* tells base_interrupt not to free mf */
2749 } else
2750 rc = 1;
2751
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302752 if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302753 return rc;
2754
2755 if (ioc->shost_recovery) {
2756 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2757 __func__, ioc->name);
2758 return rc;
2759 }
2760
2761 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
2762 if (!smid_sas_ctrl) {
2763 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2764 ioc->name, __func__);
2765 return rc;
2766 }
2767
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302768 if (sas_device)
2769 sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
2770
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302771 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
2772 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
2773 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
2774 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
2775 mpi_request->DevHandle = mpi_reply->DevHandle;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302776 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
2777 return rc;
2778}
2779
2780/**
Eric Moore635374e2009-03-09 01:21:12 -06002781 * _scsih_check_topo_delete_events - sanity check on topo events
2782 * @ioc: per adapter object
2783 * @event_data: the event data payload
2784 *
2785 * This routine added to better handle cable breaker.
2786 *
2787 * This handles the case where driver recieves multiple expander
2788 * add and delete events in a single shot. When there is a delete event
2789 * the routine will void any pending add events waiting in the event queue.
2790 *
2791 * Return nothing.
2792 */
2793static void
2794_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
2795 Mpi2EventDataSasTopologyChangeList_t *event_data)
2796{
2797 struct fw_event_work *fw_event;
2798 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
2799 u16 expander_handle;
2800 struct _sas_node *sas_expander;
2801 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302802 int i, reason_code;
2803 u16 handle;
2804
2805 for (i = 0 ; i < event_data->NumEntries; i++) {
2806 if (event_data->PHY[i].PhyStatus &
2807 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
2808 continue;
2809 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2810 if (!handle)
2811 continue;
2812 reason_code = event_data->PHY[i].PhyStatus &
2813 MPI2_EVENT_SAS_TOPO_RC_MASK;
2814 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
2815 _scsih_tm_tr_send(ioc, handle);
2816 }
Eric Moore635374e2009-03-09 01:21:12 -06002817
2818 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
2819 if (expander_handle < ioc->sas_hba.num_phys) {
2820 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2821 return;
2822 }
2823
2824 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
2825 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
2826 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2827 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
2828 expander_handle);
2829 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2830 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
2831 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
2832 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2833
2834 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
2835 return;
2836
2837 /* mark ignore flag for pending events */
2838 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2839 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
2840 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
2841 fw_event->ignore)
2842 continue;
2843 local_event_data = fw_event->event_data;
2844 if (local_event_data->ExpStatus ==
2845 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
2846 local_event_data->ExpStatus ==
2847 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
2848 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
2849 expander_handle) {
2850 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
2851 "setting ignoring flag\n", ioc->name));
2852 fw_event->ignore = 1;
2853 }
2854 }
2855 }
2856 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2857}
2858
2859/**
Eric Moore635374e2009-03-09 01:21:12 -06002860 * _scsih_flush_running_cmds - completing outstanding commands.
2861 * @ioc: per adapter object
2862 *
2863 * The flushing out of all pending scmd commands following host reset,
2864 * where all IO is dropped to the floor.
2865 *
2866 * Return nothing.
2867 */
2868static void
2869_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
2870{
2871 struct scsi_cmnd *scmd;
2872 u16 smid;
2873 u16 count = 0;
2874
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302875 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
2876 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002877 if (!scmd)
2878 continue;
2879 count++;
2880 mpt2sas_base_free_smid(ioc, smid);
2881 scsi_dma_unmap(scmd);
2882 scmd->result = DID_RESET << 16;
2883 scmd->scsi_done(scmd);
2884 }
2885 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
2886 ioc->name, count));
2887}
2888
2889/**
Eric Moore3c621b32009-05-18 12:59:41 -06002890 * _scsih_setup_eedp - setup MPI request for EEDP transfer
2891 * @scmd: pointer to scsi command object
2892 * @mpi_request: pointer to the SCSI_IO reqest message frame
2893 *
2894 * Supporting protection 1 and 3.
2895 *
2896 * Returns nothing
2897 */
2898static void
2899_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
2900{
2901 u16 eedp_flags;
2902 unsigned char prot_op = scsi_get_prot_op(scmd);
2903 unsigned char prot_type = scsi_get_prot_type(scmd);
2904
2905 if (prot_type == SCSI_PROT_DIF_TYPE0 ||
2906 prot_type == SCSI_PROT_DIF_TYPE2 ||
2907 prot_op == SCSI_PROT_NORMAL)
2908 return;
2909
2910 if (prot_op == SCSI_PROT_READ_STRIP)
2911 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
2912 else if (prot_op == SCSI_PROT_WRITE_INSERT)
2913 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
2914 else
2915 return;
2916
Eric Moore3c621b32009-05-18 12:59:41 -06002917 switch (prot_type) {
2918 case SCSI_PROT_DIF_TYPE1:
2919
2920 /*
2921 * enable ref/guard checking
2922 * auto increment ref tag
2923 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05302924 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
Eric Moore3c621b32009-05-18 12:59:41 -06002925 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2926 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2927 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
2928 cpu_to_be32(scsi_get_lba(scmd));
2929
2930 break;
2931
2932 case SCSI_PROT_DIF_TYPE3:
2933
2934 /*
2935 * enable guard checking
2936 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05302937 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
Eric Moore3c621b32009-05-18 12:59:41 -06002938 break;
2939 }
Kashyap, Desai463217b2009-10-05 15:53:06 +05302940 mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
2941 mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
Eric Moore3c621b32009-05-18 12:59:41 -06002942}
2943
2944/**
2945 * _scsih_eedp_error_handling - return sense code for EEDP errors
2946 * @scmd: pointer to scsi command object
2947 * @ioc_status: ioc status
2948 *
2949 * Returns nothing
2950 */
2951static void
2952_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
2953{
2954 u8 ascq;
2955 u8 sk;
2956 u8 host_byte;
2957
2958 switch (ioc_status) {
2959 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2960 ascq = 0x01;
2961 break;
2962 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2963 ascq = 0x02;
2964 break;
2965 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2966 ascq = 0x03;
2967 break;
2968 default:
2969 ascq = 0x00;
2970 break;
2971 }
2972
2973 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
2974 sk = ILLEGAL_REQUEST;
2975 host_byte = DID_ABORT;
2976 } else {
2977 sk = ABORTED_COMMAND;
2978 host_byte = DID_OK;
2979 }
2980
2981 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
2982 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
2983 SAM_STAT_CHECK_CONDITION;
2984}
2985
2986/**
Eric Moored5d135b2009-05-18 13:02:08 -06002987 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06002988 * @scmd: pointer to scsi command object
2989 * @done: function pointer to be invoked on completion
2990 *
2991 * The callback index is set inside `ioc->scsi_io_cb_idx`.
2992 *
2993 * Returns 0 on success. If there's a failure, return either:
2994 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
2995 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
2996 */
2997static int
Eric Moored5d135b2009-05-18 13:02:08 -06002998_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06002999{
3000 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
3001 struct MPT2SAS_DEVICE *sas_device_priv_data;
3002 struct MPT2SAS_TARGET *sas_target_priv_data;
3003 Mpi2SCSIIORequest_t *mpi_request;
3004 u32 mpi_control;
3005 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06003006
3007 scmd->scsi_done = done;
3008 sas_device_priv_data = scmd->device->hostdata;
3009 if (!sas_device_priv_data) {
3010 scmd->result = DID_NO_CONNECT << 16;
3011 scmd->scsi_done(scmd);
3012 return 0;
3013 }
3014
3015 sas_target_priv_data = sas_device_priv_data->sas_target;
3016 if (!sas_target_priv_data || sas_target_priv_data->handle ==
3017 MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
3018 scmd->result = DID_NO_CONNECT << 16;
3019 scmd->scsi_done(scmd);
3020 return 0;
3021 }
3022
3023 /* see if we are busy with task managment stuff */
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05303024 if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303025 return SCSI_MLQUEUE_DEVICE_BUSY;
3026 else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06003027 return SCSI_MLQUEUE_HOST_BUSY;
Eric Moore635374e2009-03-09 01:21:12 -06003028
3029 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
3030 mpi_control = MPI2_SCSIIO_CONTROL_READ;
3031 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
3032 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
3033 else
3034 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
3035
3036 /* set tags */
3037 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
3038 if (scmd->device->tagged_supported) {
3039 if (scmd->device->ordered_tags)
3040 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
3041 else
3042 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
3043 } else
3044/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
3045/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
3046 */
3047 mpi_control |= (0x500);
3048
3049 } else
3050 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
3051
3052 if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
3053 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
3054
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303055 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06003056 if (!smid) {
3057 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
3058 ioc->name, __func__);
3059 goto out;
3060 }
3061 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3062 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06003063 _scsih_setup_eedp(scmd, mpi_request);
Eric Moore635374e2009-03-09 01:21:12 -06003064 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3065 if (sas_device_priv_data->sas_target->flags &
3066 MPT_TARGET_FLAGS_RAID_COMPONENT)
3067 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3068 else
3069 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3070 mpi_request->DevHandle =
3071 cpu_to_le16(sas_device_priv_data->sas_target->handle);
3072 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
3073 mpi_request->Control = cpu_to_le32(mpi_control);
3074 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
3075 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
3076 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
3077 mpi_request->SenseBufferLowAddress =
Kashyap, Desaiec9472c2009-09-23 17:34:13 +05303078 mpt2sas_base_get_sense_buffer_dma(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003079 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
3080 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
3081 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303082 mpi_request->VF_ID = 0; /* TODO */
3083 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003084 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
3085 mpi_request->LUN);
3086 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
3087
3088 if (!mpi_request->DataLength) {
3089 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
3090 } else {
3091 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
3092 mpt2sas_base_free_smid(ioc, smid);
3093 goto out;
3094 }
3095 }
3096
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303097 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Eric Moore635374e2009-03-09 01:21:12 -06003098 sas_device_priv_data->sas_target->handle);
3099 return 0;
3100
3101 out:
3102 return SCSI_MLQUEUE_HOST_BUSY;
3103}
3104
3105/**
3106 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
3107 * @sense_buffer: sense data returned by target
3108 * @data: normalized skey/asc/ascq
3109 *
3110 * Return nothing.
3111 */
3112static void
3113_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
3114{
3115 if ((sense_buffer[0] & 0x7F) >= 0x72) {
3116 /* descriptor format */
3117 data->skey = sense_buffer[1] & 0x0F;
3118 data->asc = sense_buffer[2];
3119 data->ascq = sense_buffer[3];
3120 } else {
3121 /* fixed format */
3122 data->skey = sense_buffer[2] & 0x0F;
3123 data->asc = sense_buffer[12];
3124 data->ascq = sense_buffer[13];
3125 }
3126}
3127
3128#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3129/**
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02003130 * _scsih_scsi_ioc_info - translated non-successfull SCSI_IO request
Eric Moore635374e2009-03-09 01:21:12 -06003131 * @ioc: per adapter object
3132 * @scmd: pointer to scsi command object
3133 * @mpi_reply: reply mf payload returned from firmware
3134 *
3135 * scsi_status - SCSI Status code returned from target device
3136 * scsi_state - state info associated with SCSI_IO determined by ioc
3137 * ioc_status - ioc supplied status info
3138 *
3139 * Return nothing.
3140 */
3141static void
3142_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
3143 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
3144{
3145 u32 response_info;
3146 u8 *response_bytes;
3147 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
3148 MPI2_IOCSTATUS_MASK;
3149 u8 scsi_state = mpi_reply->SCSIState;
3150 u8 scsi_status = mpi_reply->SCSIStatus;
3151 char *desc_ioc_state = NULL;
3152 char *desc_scsi_status = NULL;
3153 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303154 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3155
3156 if (log_info == 0x31170000)
3157 return;
Eric Moore635374e2009-03-09 01:21:12 -06003158
3159 switch (ioc_status) {
3160 case MPI2_IOCSTATUS_SUCCESS:
3161 desc_ioc_state = "success";
3162 break;
3163 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3164 desc_ioc_state = "invalid function";
3165 break;
3166 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3167 desc_ioc_state = "scsi recovered error";
3168 break;
3169 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
3170 desc_ioc_state = "scsi invalid dev handle";
3171 break;
3172 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3173 desc_ioc_state = "scsi device not there";
3174 break;
3175 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3176 desc_ioc_state = "scsi data overrun";
3177 break;
3178 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3179 desc_ioc_state = "scsi data underrun";
3180 break;
3181 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3182 desc_ioc_state = "scsi io data error";
3183 break;
3184 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3185 desc_ioc_state = "scsi protocol error";
3186 break;
3187 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3188 desc_ioc_state = "scsi task terminated";
3189 break;
3190 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3191 desc_ioc_state = "scsi residual mismatch";
3192 break;
3193 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3194 desc_ioc_state = "scsi task mgmt failed";
3195 break;
3196 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3197 desc_ioc_state = "scsi ioc terminated";
3198 break;
3199 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3200 desc_ioc_state = "scsi ext terminated";
3201 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003202 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3203 desc_ioc_state = "eedp guard error";
3204 break;
3205 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3206 desc_ioc_state = "eedp ref tag error";
3207 break;
3208 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3209 desc_ioc_state = "eedp app tag error";
3210 break;
Eric Moore635374e2009-03-09 01:21:12 -06003211 default:
3212 desc_ioc_state = "unknown";
3213 break;
3214 }
3215
3216 switch (scsi_status) {
3217 case MPI2_SCSI_STATUS_GOOD:
3218 desc_scsi_status = "good";
3219 break;
3220 case MPI2_SCSI_STATUS_CHECK_CONDITION:
3221 desc_scsi_status = "check condition";
3222 break;
3223 case MPI2_SCSI_STATUS_CONDITION_MET:
3224 desc_scsi_status = "condition met";
3225 break;
3226 case MPI2_SCSI_STATUS_BUSY:
3227 desc_scsi_status = "busy";
3228 break;
3229 case MPI2_SCSI_STATUS_INTERMEDIATE:
3230 desc_scsi_status = "intermediate";
3231 break;
3232 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
3233 desc_scsi_status = "intermediate condmet";
3234 break;
3235 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
3236 desc_scsi_status = "reservation conflict";
3237 break;
3238 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
3239 desc_scsi_status = "command terminated";
3240 break;
3241 case MPI2_SCSI_STATUS_TASK_SET_FULL:
3242 desc_scsi_status = "task set full";
3243 break;
3244 case MPI2_SCSI_STATUS_ACA_ACTIVE:
3245 desc_scsi_status = "aca active";
3246 break;
3247 case MPI2_SCSI_STATUS_TASK_ABORTED:
3248 desc_scsi_status = "task aborted";
3249 break;
3250 default:
3251 desc_scsi_status = "unknown";
3252 break;
3253 }
3254
3255 desc_scsi_state[0] = '\0';
3256 if (!scsi_state)
3257 desc_scsi_state = " ";
3258 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3259 strcat(desc_scsi_state, "response info ");
3260 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3261 strcat(desc_scsi_state, "state terminated ");
3262 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
3263 strcat(desc_scsi_state, "no status ");
3264 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
3265 strcat(desc_scsi_state, "autosense failed ");
3266 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
3267 strcat(desc_scsi_state, "autosense valid ");
3268
3269 scsi_print_command(scmd);
3270 printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
3271 "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
3272 le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
3273 ioc_status, smid);
3274 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
3275 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
3276 scsi_get_resid(scmd));
3277 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
3278 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
3279 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
3280 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
3281 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
3282 scsi_status, desc_scsi_state, scsi_state);
3283
3284 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3285 struct sense_info data;
3286 _scsih_normalize_sense(scmd->sense_buffer, &data);
3287 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
3288 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey,
3289 data.asc, data.ascq);
3290 }
3291
3292 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
3293 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
3294 response_bytes = (u8 *)&response_info;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303295 _scsih_response_code(ioc, response_bytes[0]);
Eric Moore635374e2009-03-09 01:21:12 -06003296 }
3297}
3298#endif
3299
3300/**
3301 * _scsih_smart_predicted_fault - illuminate Fault LED
3302 * @ioc: per adapter object
3303 * @handle: device handle
3304 *
3305 * Return nothing.
3306 */
3307static void
3308_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3309{
3310 Mpi2SepReply_t mpi_reply;
3311 Mpi2SepRequest_t mpi_request;
3312 struct scsi_target *starget;
3313 struct MPT2SAS_TARGET *sas_target_priv_data;
3314 Mpi2EventNotificationReply_t *event_reply;
3315 Mpi2EventDataSasDeviceStatusChange_t *event_data;
3316 struct _sas_device *sas_device;
3317 ssize_t sz;
3318 unsigned long flags;
3319
3320 /* only handle non-raid devices */
3321 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3322 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3323 if (!sas_device) {
3324 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3325 return;
3326 }
3327 starget = sas_device->starget;
3328 sas_target_priv_data = starget->hostdata;
3329
3330 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
3331 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
3332 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3333 return;
3334 }
3335 starget_printk(KERN_WARNING, starget, "predicted fault\n");
3336 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3337
3338 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
3339 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
3340 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
3341 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
3342 mpi_request.SlotStatus =
3343 MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
3344 mpi_request.DevHandle = cpu_to_le16(handle);
3345 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
3346 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
3347 &mpi_request)) != 0) {
3348 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3349 ioc->name, __FILE__, __LINE__, __func__);
3350 return;
3351 }
3352
3353 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
3354 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3355 "enclosure_processor: ioc_status (0x%04x), "
3356 "loginfo(0x%08x)\n", ioc->name,
3357 le16_to_cpu(mpi_reply.IOCStatus),
3358 le32_to_cpu(mpi_reply.IOCLogInfo)));
3359 return;
3360 }
3361 }
3362
3363 /* insert into event log */
3364 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
3365 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
3366 event_reply = kzalloc(sz, GFP_KERNEL);
3367 if (!event_reply) {
3368 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3369 ioc->name, __FILE__, __LINE__, __func__);
3370 return;
3371 }
3372
3373 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
3374 event_reply->Event =
3375 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
3376 event_reply->MsgLength = sz/4;
3377 event_reply->EventDataLength =
3378 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
3379 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
3380 event_reply->EventData;
3381 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
3382 event_data->ASC = 0x5D;
3383 event_data->DevHandle = cpu_to_le16(handle);
3384 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
3385 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
3386 kfree(event_reply);
3387}
3388
3389/**
Eric Moored5d135b2009-05-18 13:02:08 -06003390 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06003391 * @ioc: per adapter object
3392 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303393 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06003394 * @reply: reply message frame(lower 32bit addr)
3395 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303396 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06003397 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303398 * Return 1 meaning mf should be freed from _base_interrupt
3399 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06003400 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303401static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303402_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06003403{
3404 Mpi2SCSIIORequest_t *mpi_request;
3405 Mpi2SCSIIOReply_t *mpi_reply;
3406 struct scsi_cmnd *scmd;
3407 u16 ioc_status;
3408 u32 xfer_cnt;
3409 u8 scsi_state;
3410 u8 scsi_status;
3411 u32 log_info;
3412 struct MPT2SAS_DEVICE *sas_device_priv_data;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303413 u32 response_code = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003414
3415 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303416 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003417 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303418 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003419
3420 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3421
3422 if (mpi_reply == NULL) {
3423 scmd->result = DID_OK << 16;
3424 goto out;
3425 }
3426
3427 sas_device_priv_data = scmd->device->hostdata;
3428 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
3429 sas_device_priv_data->sas_target->deleted) {
3430 scmd->result = DID_NO_CONNECT << 16;
3431 goto out;
3432 }
3433
3434 /* turning off TLR */
Kashyap, Desai9982f592009-09-23 17:23:07 +05303435 scsi_state = mpi_reply->SCSIState;
3436 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3437 response_code =
3438 le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
Eric Moore635374e2009-03-09 01:21:12 -06003439 if (!sas_device_priv_data->tlr_snoop_check) {
3440 sas_device_priv_data->tlr_snoop_check++;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303441 if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
3442 response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
3443 sas_device_priv_data->flags &=
3444 ~MPT_DEVICE_TLR_ON;
Eric Moore635374e2009-03-09 01:21:12 -06003445 }
3446
3447 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
3448 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
3449 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
3450 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
3451 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3452 else
3453 log_info = 0;
3454 ioc_status &= MPI2_IOCSTATUS_MASK;
Eric Moore635374e2009-03-09 01:21:12 -06003455 scsi_status = mpi_reply->SCSIStatus;
3456
3457 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
3458 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
3459 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
3460 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
3461 ioc_status = MPI2_IOCSTATUS_SUCCESS;
3462 }
3463
3464 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3465 struct sense_info data;
3466 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
3467 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06003468 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06003469 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06003470 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06003471 _scsih_normalize_sense(scmd->sense_buffer, &data);
3472 /* failure prediction threshold exceeded */
3473 if (data.asc == 0x5D)
3474 _scsih_smart_predicted_fault(ioc,
3475 le16_to_cpu(mpi_reply->DevHandle));
3476 }
3477
3478 switch (ioc_status) {
3479 case MPI2_IOCSTATUS_BUSY:
3480 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3481 scmd->result = SAM_STAT_BUSY;
3482 break;
3483
3484 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3485 scmd->result = DID_NO_CONNECT << 16;
3486 break;
3487
3488 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3489 if (sas_device_priv_data->block) {
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05303490 scmd->result = DID_TRANSPORT_DISRUPTED << 16;
3491 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003492 }
Eric Moore635374e2009-03-09 01:21:12 -06003493 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3494 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3495 scmd->result = DID_RESET << 16;
3496 break;
3497
3498 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3499 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3500 scmd->result = DID_SOFT_ERROR << 16;
3501 else
3502 scmd->result = (DID_OK << 16) | scsi_status;
3503 break;
3504
3505 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3506 scmd->result = (DID_OK << 16) | scsi_status;
3507
3508 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3509 break;
3510
3511 if (xfer_cnt < scmd->underflow) {
3512 if (scsi_status == SAM_STAT_BUSY)
3513 scmd->result = SAM_STAT_BUSY;
3514 else
3515 scmd->result = DID_SOFT_ERROR << 16;
3516 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3517 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3518 scmd->result = DID_SOFT_ERROR << 16;
3519 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3520 scmd->result = DID_RESET << 16;
3521 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3522 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3523 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3524 scmd->result = (DRIVER_SENSE << 24) |
3525 SAM_STAT_CHECK_CONDITION;
3526 scmd->sense_buffer[0] = 0x70;
3527 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3528 scmd->sense_buffer[12] = 0x20;
3529 scmd->sense_buffer[13] = 0;
3530 }
3531 break;
3532
3533 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3534 scsi_set_resid(scmd, 0);
3535 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3536 case MPI2_IOCSTATUS_SUCCESS:
3537 scmd->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303538 if (response_code ==
3539 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
3540 (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3541 MPI2_SCSI_STATE_NO_SCSI_STATUS)))
Eric Moore635374e2009-03-09 01:21:12 -06003542 scmd->result = DID_SOFT_ERROR << 16;
3543 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3544 scmd->result = DID_RESET << 16;
3545 break;
3546
Eric Moore3c621b32009-05-18 12:59:41 -06003547 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3548 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3549 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3550 _scsih_eedp_error_handling(scmd, ioc_status);
3551 break;
Eric Moore635374e2009-03-09 01:21:12 -06003552 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3553 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3554 case MPI2_IOCSTATUS_INVALID_SGL:
3555 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3556 case MPI2_IOCSTATUS_INVALID_FIELD:
3557 case MPI2_IOCSTATUS_INVALID_STATE:
3558 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3559 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3560 default:
3561 scmd->result = DID_SOFT_ERROR << 16;
3562 break;
3563
3564 }
3565
3566#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3567 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3568 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3569#endif
3570
3571 out:
3572 scsi_dma_unmap(scmd);
3573 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303574 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003575}
3576
3577/**
Eric Moore635374e2009-03-09 01:21:12 -06003578 * _scsih_sas_host_refresh - refreshing sas host object contents
3579 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06003580 * Context: user
3581 *
3582 * During port enable, fw will send topology events for every device. Its
3583 * possible that the handles may change from the previous setting, so this
3584 * code keeping handles updating if changed.
3585 *
3586 * Return nothing.
3587 */
3588static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303589_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06003590{
3591 u16 sz;
3592 u16 ioc_status;
3593 int i;
3594 Mpi2ConfigReply_t mpi_reply;
3595 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303596 u16 attached_handle;
Eric Moore635374e2009-03-09 01:21:12 -06003597
3598 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3599 "updating handles for sas_host(0x%016llx)\n",
3600 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3601
3602 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3603 * sizeof(Mpi2SasIOUnit0PhyData_t));
3604 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3605 if (!sas_iounit_pg0) {
3606 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3607 ioc->name, __FILE__, __LINE__, __func__);
3608 return;
3609 }
Eric Moore635374e2009-03-09 01:21:12 -06003610
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303611 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3612 sas_iounit_pg0, sz)) != 0)
3613 goto out;
3614 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
3615 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3616 goto out;
3617 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3618 if (i == 0)
3619 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3620 PhyData[0].ControllerDevHandle);
3621 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
3622 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
3623 AttachedDevHandle);
3624 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
3625 attached_handle, i, sas_iounit_pg0->PhyData[i].
3626 NegotiatedLinkRate >> 4);
3627 }
Eric Moore635374e2009-03-09 01:21:12 -06003628 out:
3629 kfree(sas_iounit_pg0);
3630}
3631
3632/**
3633 * _scsih_sas_host_add - create sas host object
3634 * @ioc: per adapter object
3635 *
3636 * Creating host side data object, stored in ioc->sas_hba
3637 *
3638 * Return nothing.
3639 */
3640static void
3641_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3642{
3643 int i;
3644 Mpi2ConfigReply_t mpi_reply;
3645 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3646 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3647 Mpi2SasPhyPage0_t phy_pg0;
3648 Mpi2SasDevicePage0_t sas_device_pg0;
3649 Mpi2SasEnclosurePage0_t enclosure_pg0;
3650 u16 ioc_status;
3651 u16 sz;
3652 u16 device_missing_delay;
3653
3654 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3655 if (!ioc->sas_hba.num_phys) {
3656 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3657 ioc->name, __FILE__, __LINE__, __func__);
3658 return;
3659 }
3660
3661 /* sas_iounit page 0 */
3662 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3663 sizeof(Mpi2SasIOUnit0PhyData_t));
3664 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3665 if (!sas_iounit_pg0) {
3666 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3667 ioc->name, __FILE__, __LINE__, __func__);
3668 return;
3669 }
3670 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3671 sas_iounit_pg0, sz))) {
3672 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3673 ioc->name, __FILE__, __LINE__, __func__);
3674 goto out;
3675 }
3676 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3677 MPI2_IOCSTATUS_MASK;
3678 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3679 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3680 ioc->name, __FILE__, __LINE__, __func__);
3681 goto out;
3682 }
3683
3684 /* sas_iounit page 1 */
3685 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3686 sizeof(Mpi2SasIOUnit1PhyData_t));
3687 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3688 if (!sas_iounit_pg1) {
3689 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3690 ioc->name, __FILE__, __LINE__, __func__);
3691 goto out;
3692 }
3693 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3694 sas_iounit_pg1, sz))) {
3695 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3696 ioc->name, __FILE__, __LINE__, __func__);
3697 goto out;
3698 }
3699 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3700 MPI2_IOCSTATUS_MASK;
3701 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3702 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3703 ioc->name, __FILE__, __LINE__, __func__);
3704 goto out;
3705 }
3706
3707 ioc->io_missing_delay =
3708 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3709 device_missing_delay =
3710 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3711 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3712 ioc->device_missing_delay = (device_missing_delay &
3713 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3714 else
3715 ioc->device_missing_delay = device_missing_delay &
3716 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3717
3718 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3719 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3720 sizeof(struct _sas_phy), GFP_KERNEL);
3721 if (!ioc->sas_hba.phy) {
3722 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3723 ioc->name, __FILE__, __LINE__, __func__);
3724 goto out;
3725 }
3726 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3727 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3728 i))) {
3729 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3730 ioc->name, __FILE__, __LINE__, __func__);
3731 goto out;
3732 }
3733 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3734 MPI2_IOCSTATUS_MASK;
3735 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3736 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3737 ioc->name, __FILE__, __LINE__, __func__);
3738 goto out;
3739 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303740
3741 if (i == 0)
3742 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3743 PhyData[0].ControllerDevHandle);
3744 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06003745 ioc->sas_hba.phy[i].phy_id = i;
3746 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3747 phy_pg0, ioc->sas_hba.parent_dev);
3748 }
3749 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303750 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06003751 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3752 ioc->name, __FILE__, __LINE__, __func__);
3753 goto out;
3754 }
Eric Moore635374e2009-03-09 01:21:12 -06003755 ioc->sas_hba.enclosure_handle =
3756 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3757 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3758 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3759 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3760 (unsigned long long) ioc->sas_hba.sas_address,
3761 ioc->sas_hba.num_phys) ;
3762
3763 if (ioc->sas_hba.enclosure_handle) {
3764 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3765 &enclosure_pg0,
3766 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3767 ioc->sas_hba.enclosure_handle))) {
3768 ioc->sas_hba.enclosure_logical_id =
3769 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3770 }
3771 }
3772
3773 out:
3774 kfree(sas_iounit_pg1);
3775 kfree(sas_iounit_pg0);
3776}
3777
3778/**
3779 * _scsih_expander_add - creating expander object
3780 * @ioc: per adapter object
3781 * @handle: expander handle
3782 *
3783 * Creating expander object, stored in ioc->sas_expander_list.
3784 *
3785 * Return 0 for success, else error.
3786 */
3787static int
3788_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3789{
3790 struct _sas_node *sas_expander;
3791 Mpi2ConfigReply_t mpi_reply;
3792 Mpi2ExpanderPage0_t expander_pg0;
3793 Mpi2ExpanderPage1_t expander_pg1;
3794 Mpi2SasEnclosurePage0_t enclosure_pg0;
3795 u32 ioc_status;
3796 u16 parent_handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303797 __le64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003798 int i;
3799 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303800 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003801 int rc = 0;
3802
3803 if (!handle)
3804 return -1;
3805
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303806 if (ioc->shost_recovery)
3807 return -1;
3808
Eric Moore635374e2009-03-09 01:21:12 -06003809 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3810 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3811 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3812 ioc->name, __FILE__, __LINE__, __func__);
3813 return -1;
3814 }
3815
3816 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3817 MPI2_IOCSTATUS_MASK;
3818 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3819 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3820 ioc->name, __FILE__, __LINE__, __func__);
3821 return -1;
3822 }
3823
3824 /* handle out of order topology events */
3825 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303826 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
3827 != 0) {
3828 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3829 ioc->name, __FILE__, __LINE__, __func__);
3830 return -1;
3831 }
3832 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06003833 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303834 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3835 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003836 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3837 if (!sas_expander) {
3838 rc = _scsih_expander_add(ioc, parent_handle);
3839 if (rc != 0)
3840 return rc;
3841 }
3842 }
3843
Eric Moore635374e2009-03-09 01:21:12 -06003844 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303845 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06003846 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3847 sas_address);
3848 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3849
3850 if (sas_expander)
3851 return 0;
3852
3853 sas_expander = kzalloc(sizeof(struct _sas_node),
3854 GFP_KERNEL);
3855 if (!sas_expander) {
3856 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3857 ioc->name, __FILE__, __LINE__, __func__);
3858 return -1;
3859 }
3860
3861 sas_expander->handle = handle;
3862 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303863 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06003864 sas_expander->sas_address = sas_address;
3865
3866 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3867 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303868 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06003869 sas_expander->sas_address, sas_expander->num_phys);
3870
3871 if (!sas_expander->num_phys)
3872 goto out_fail;
3873 sas_expander->phy = kcalloc(sas_expander->num_phys,
3874 sizeof(struct _sas_phy), GFP_KERNEL);
3875 if (!sas_expander->phy) {
3876 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3877 ioc->name, __FILE__, __LINE__, __func__);
3878 rc = -1;
3879 goto out_fail;
3880 }
3881
3882 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3883 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303884 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003885 if (!mpt2sas_port) {
3886 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3887 ioc->name, __FILE__, __LINE__, __func__);
3888 rc = -1;
3889 goto out_fail;
3890 }
3891 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3892
3893 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3894 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3895 &expander_pg1, i, handle))) {
3896 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3897 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303898 rc = -1;
3899 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003900 }
3901 sas_expander->phy[i].handle = handle;
3902 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303903
3904 if ((mpt2sas_transport_add_expander_phy(ioc,
3905 &sas_expander->phy[i], expander_pg1,
3906 sas_expander->parent_dev))) {
3907 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3908 ioc->name, __FILE__, __LINE__, __func__);
3909 rc = -1;
3910 goto out_fail;
3911 }
Eric Moore635374e2009-03-09 01:21:12 -06003912 }
3913
3914 if (sas_expander->enclosure_handle) {
3915 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3916 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3917 sas_expander->enclosure_handle))) {
3918 sas_expander->enclosure_logical_id =
3919 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3920 }
3921 }
3922
3923 _scsih_expander_node_add(ioc, sas_expander);
3924 return 0;
3925
3926 out_fail:
3927
Kashyap, Desai20f58952009-08-07 19:34:26 +05303928 if (mpt2sas_port)
3929 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303930 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003931 kfree(sas_expander);
3932 return rc;
3933}
3934
3935/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05303936 * _scsih_done - scsih callback handler.
3937 * @ioc: per adapter object
3938 * @smid: system request message index
3939 * @msix_index: MSIX table index supplied by the OS
3940 * @reply: reply message frame(lower 32bit addr)
3941 *
3942 * Callback handler when sending internal generated message frames.
3943 * The callback index passed is `ioc->scsih_cb_idx`
3944 *
3945 * Return 1 meaning mf should be freed from _base_interrupt
3946 * 0 means the mf is freed from this function.
3947 */
3948static u8
3949_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
3950{
3951 MPI2DefaultReply_t *mpi_reply;
3952
3953 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
3954 if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
3955 return 1;
3956 if (ioc->scsih_cmds.smid != smid)
3957 return 1;
3958 ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
3959 if (mpi_reply) {
3960 memcpy(ioc->scsih_cmds.reply, mpi_reply,
3961 mpi_reply->MsgLength*4);
3962 ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
3963 }
3964 ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
3965 complete(&ioc->scsih_cmds.done);
3966 return 1;
3967}
3968
3969/**
Eric Moore635374e2009-03-09 01:21:12 -06003970 * _scsih_expander_remove - removing expander object
3971 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303972 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06003973 *
3974 * Return nothing.
3975 */
3976static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303977_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06003978{
3979 struct _sas_node *sas_expander;
3980 unsigned long flags;
3981
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303982 if (ioc->shost_recovery)
3983 return;
3984
Eric Moore635374e2009-03-09 01:21:12 -06003985 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303986 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3987 sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06003988 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3989 _scsih_expander_node_remove(ioc, sas_expander);
3990}
3991
3992/**
3993 * _scsih_add_device - creating sas device object
3994 * @ioc: per adapter object
3995 * @handle: sas device handle
3996 * @phy_num: phy number end device attached to
3997 * @is_pd: is this hidden raid component
3998 *
3999 * Creating end device object, stored in ioc->sas_device_list.
4000 *
4001 * Returns 0 for success, non-zero for failure.
4002 */
4003static int
4004_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
4005{
4006 Mpi2ConfigReply_t mpi_reply;
4007 Mpi2SasDevicePage0_t sas_device_pg0;
4008 Mpi2SasEnclosurePage0_t enclosure_pg0;
4009 struct _sas_device *sas_device;
4010 u32 ioc_status;
4011 __le64 sas_address;
4012 u32 device_info;
4013 unsigned long flags;
4014
4015 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4016 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4017 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4018 ioc->name, __FILE__, __LINE__, __func__);
4019 return -1;
4020 }
4021
4022 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4023 MPI2_IOCSTATUS_MASK;
4024 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4025 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4026 ioc->name, __FILE__, __LINE__, __func__);
4027 return -1;
4028 }
4029
4030 /* check if device is present */
4031 if (!(le16_to_cpu(sas_device_pg0.Flags) &
4032 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
4033 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4034 ioc->name, __FILE__, __LINE__, __func__);
4035 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
4036 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
4037 return -1;
4038 }
4039
4040 /* check if there were any issus with discovery */
4041 if (sas_device_pg0.AccessStatus ==
4042 MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
4043 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4044 ioc->name, __FILE__, __LINE__, __func__);
4045 printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
4046 ioc->name, sas_device_pg0.AccessStatus);
4047 return -1;
4048 }
4049
4050 /* check if this is end device */
4051 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4052 if (!(_scsih_is_end_device(device_info))) {
4053 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4054 ioc->name, __FILE__, __LINE__, __func__);
4055 return -1;
4056 }
4057
4058 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4059
4060 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4061 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4062 sas_address);
4063 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4064
4065 if (sas_device) {
4066 _scsih_ublock_io_device(ioc, handle);
4067 return 0;
4068 }
4069
4070 sas_device = kzalloc(sizeof(struct _sas_device),
4071 GFP_KERNEL);
4072 if (!sas_device) {
4073 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4074 ioc->name, __FILE__, __LINE__, __func__);
4075 return -1;
4076 }
4077
4078 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304079 if (_scsih_get_sas_address(ioc, le16_to_cpu
4080 (sas_device_pg0.ParentDevHandle),
4081 &sas_device->sas_address_parent) != 0)
4082 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4083 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06004084 sas_device->enclosure_handle =
4085 le16_to_cpu(sas_device_pg0.EnclosureHandle);
4086 sas_device->slot =
4087 le16_to_cpu(sas_device_pg0.Slot);
4088 sas_device->device_info = device_info;
4089 sas_device->sas_address = sas_address;
4090 sas_device->hidden_raid_component = is_pd;
4091
4092 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05304093 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
4094 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4095 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06004096 sas_device->enclosure_logical_id =
4097 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06004098
4099 /* get device name */
4100 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
4101
4102 if (ioc->wait_for_port_enable_to_complete)
4103 _scsih_sas_device_init_add(ioc, sas_device);
4104 else
4105 _scsih_sas_device_add(ioc, sas_device);
4106
4107 return 0;
4108}
4109
4110/**
4111 * _scsih_remove_device - removing sas device object
4112 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304113 * @sas_device: the sas_device object
Eric Moore635374e2009-03-09 01:21:12 -06004114 *
4115 * Return nothing.
4116 */
4117static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304118_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
4119 *sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06004120{
4121 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06004122 Mpi2SasIoUnitControlReply_t mpi_reply;
4123 Mpi2SasIoUnitControlRequest_t mpi_request;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304124 u16 device_handle, handle;
Eric Moore635374e2009-03-09 01:21:12 -06004125
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304126 if (!sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06004127 return;
Eric Moore635374e2009-03-09 01:21:12 -06004128
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304129 handle = sas_device->handle;
4130 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
4131 " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
4132 (unsigned long long) sas_device->sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06004133
4134 if (sas_device->starget && sas_device->starget->hostdata) {
4135 sas_target_priv_data = sas_device->starget->hostdata;
4136 sas_target_priv_data->deleted = 1;
4137 }
Eric Moore635374e2009-03-09 01:21:12 -06004138
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304139 if (ioc->remove_host || ioc->shost_recovery || !handle)
Eric Moore635374e2009-03-09 01:21:12 -06004140 goto out;
4141
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304142 if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
4143 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304144 "target_reset handle(0x%04x)\n", ioc->name,
4145 handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304146 goto skip_tr;
4147 }
4148
Eric Moore635374e2009-03-09 01:21:12 -06004149 /* Target Reset to flush out all the outstanding IO */
4150 device_handle = (sas_device->hidden_raid_component) ?
4151 sas_device->volume_handle : handle;
4152 if (device_handle) {
4153 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
4154 "handle(0x%04x)\n", ioc->name, device_handle));
4155 mutex_lock(&ioc->tm_cmds.mutex);
4156 mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
4157 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
4158 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
4159 mutex_unlock(&ioc->tm_cmds.mutex);
4160 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
4161 "done: handle(0x%04x)\n", ioc->name, device_handle));
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304162 if (ioc->shost_recovery)
4163 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06004164 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304165 skip_tr:
4166
4167 if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) {
4168 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
4169 "sas_cntrl handle(0x%04x)\n", ioc->name, handle));
4170 goto out;
4171 }
Eric Moore635374e2009-03-09 01:21:12 -06004172
4173 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
4174 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
4175 "(0x%04x)\n", ioc->name, handle));
4176 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
4177 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
4178 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
4179 mpi_request.DevHandle = handle;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304180 mpi_request.VF_ID = 0; /* TODO */
4181 mpi_request.VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004182 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
4183 &mpi_request)) != 0) {
4184 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4185 ioc->name, __FILE__, __LINE__, __func__);
4186 }
4187
4188 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
4189 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
4190 le16_to_cpu(mpi_reply.IOCStatus),
4191 le32_to_cpu(mpi_reply.IOCLogInfo)));
4192
4193 out:
Kashyap, Desai34a03be2009-08-20 13:23:19 +05304194
4195 _scsih_ublock_io_device(ioc, handle);
4196
Eric Moore635374e2009-03-09 01:21:12 -06004197 mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304198 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004199
4200 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304201 "(0x%016llx)\n", ioc->name, handle,
Eric Moore635374e2009-03-09 01:21:12 -06004202 (unsigned long long) sas_device->sas_address);
4203 _scsih_sas_device_remove(ioc, sas_device);
4204
4205 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
4206 "(0x%04x)\n", ioc->name, __func__, handle));
4207}
4208
4209#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4210/**
4211 * _scsih_sas_topology_change_event_debug - debug for topology event
4212 * @ioc: per adapter object
4213 * @event_data: event data payload
4214 * Context: user.
4215 */
4216static void
4217_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4218 Mpi2EventDataSasTopologyChangeList_t *event_data)
4219{
4220 int i;
4221 u16 handle;
4222 u16 reason_code;
4223 u8 phy_number;
4224 char *status_str = NULL;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304225 u8 link_rate, prev_link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06004226
4227 switch (event_data->ExpStatus) {
4228 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
4229 status_str = "add";
4230 break;
4231 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
4232 status_str = "remove";
4233 break;
4234 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304235 case 0:
Eric Moore635374e2009-03-09 01:21:12 -06004236 status_str = "responding";
4237 break;
4238 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
4239 status_str = "remove delay";
4240 break;
4241 default:
4242 status_str = "unknown status";
4243 break;
4244 }
4245 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
4246 ioc->name, status_str);
4247 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
4248 "start_phy(%02d), count(%d)\n",
4249 le16_to_cpu(event_data->ExpanderDevHandle),
4250 le16_to_cpu(event_data->EnclosureHandle),
4251 event_data->StartPhyNum, event_data->NumEntries);
4252 for (i = 0; i < event_data->NumEntries; i++) {
4253 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4254 if (!handle)
4255 continue;
4256 phy_number = event_data->StartPhyNum + i;
4257 reason_code = event_data->PHY[i].PhyStatus &
4258 MPI2_EVENT_SAS_TOPO_RC_MASK;
4259 switch (reason_code) {
4260 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304261 status_str = "target add";
Eric Moore635374e2009-03-09 01:21:12 -06004262 break;
4263 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304264 status_str = "target remove";
Eric Moore635374e2009-03-09 01:21:12 -06004265 break;
4266 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304267 status_str = "delay target remove";
Eric Moore635374e2009-03-09 01:21:12 -06004268 break;
4269 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304270 status_str = "link rate change";
Eric Moore635374e2009-03-09 01:21:12 -06004271 break;
4272 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304273 status_str = "target responding";
Eric Moore635374e2009-03-09 01:21:12 -06004274 break;
4275 default:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304276 status_str = "unknown";
Eric Moore635374e2009-03-09 01:21:12 -06004277 break;
4278 }
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304279 link_rate = event_data->PHY[i].LinkRate >> 4;
4280 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
4281 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:"
4282 " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
4283 handle, status_str, link_rate, prev_link_rate);
4284
Eric Moore635374e2009-03-09 01:21:12 -06004285 }
4286}
4287#endif
4288
4289/**
4290 * _scsih_sas_topology_change_event - handle topology changes
4291 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304292 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004293 * Context: user.
4294 *
4295 */
4296static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304297_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06004298 struct fw_event_work *fw_event)
4299{
4300 int i;
4301 u16 parent_handle, handle;
4302 u16 reason_code;
4303 u8 phy_number;
4304 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304305 struct _sas_device *sas_device;
4306 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004307 unsigned long flags;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304308 u8 link_rate, prev_link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304309 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004310
4311#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4312 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4313 _scsih_sas_topology_change_event_debug(ioc, event_data);
4314#endif
4315
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304316 if (ioc->shost_recovery)
4317 return;
4318
Eric Moore635374e2009-03-09 01:21:12 -06004319 if (!ioc->sas_hba.num_phys)
4320 _scsih_sas_host_add(ioc);
4321 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304322 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06004323
4324 if (fw_event->ignore) {
4325 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
4326 "event\n", ioc->name));
4327 return;
4328 }
4329
4330 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
4331
4332 /* handle expander add */
4333 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
4334 if (_scsih_expander_add(ioc, parent_handle) != 0)
4335 return;
4336
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304337 spin_lock_irqsave(&ioc->sas_node_lock, flags);
4338 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
4339 parent_handle);
4340 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4341 if (sas_expander)
4342 sas_address = sas_expander->sas_address;
4343 else if (parent_handle < ioc->sas_hba.num_phys)
4344 sas_address = ioc->sas_hba.sas_address;
4345 else
4346 return;
4347
Eric Moore635374e2009-03-09 01:21:12 -06004348 /* handle siblings events */
4349 for (i = 0; i < event_data->NumEntries; i++) {
4350 if (fw_event->ignore) {
4351 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
4352 "expander event\n", ioc->name));
4353 return;
4354 }
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304355 if (ioc->shost_recovery)
4356 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05304357 phy_number = event_data->StartPhyNum + i;
4358 reason_code = event_data->PHY[i].PhyStatus &
4359 MPI2_EVENT_SAS_TOPO_RC_MASK;
4360 if ((event_data->PHY[i].PhyStatus &
4361 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
4362 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06004363 continue;
4364 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4365 if (!handle)
4366 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304367 link_rate = event_data->PHY[i].LinkRate >> 4;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304368 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Eric Moore635374e2009-03-09 01:21:12 -06004369 switch (reason_code) {
4370 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304371
4372 if (link_rate == prev_link_rate)
4373 break;
4374
4375 mpt2sas_transport_update_links(ioc, sas_address,
4376 handle, phy_number, link_rate);
4377
4378 if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
4379 _scsih_ublock_io_device(ioc, handle);
4380 break;
Eric Moore635374e2009-03-09 01:21:12 -06004381 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304382
4383 mpt2sas_transport_update_links(ioc, sas_address,
4384 handle, phy_number, link_rate);
4385
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304386 _scsih_add_device(ioc, handle, phy_number, 0);
Eric Moore635374e2009-03-09 01:21:12 -06004387 break;
4388 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304389
4390 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4391 sas_device = _scsih_sas_device_find_by_handle(ioc,
4392 handle);
4393 if (!sas_device) {
4394 spin_unlock_irqrestore(&ioc->sas_device_lock,
4395 flags);
4396 break;
4397 }
4398 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4399 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004400 break;
4401 }
4402 }
4403
4404 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304405 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
4406 sas_expander)
4407 _scsih_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06004408
4409}
4410
4411#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4412/**
4413 * _scsih_sas_device_status_change_event_debug - debug for device event
4414 * @event_data: event data payload
4415 * Context: user.
4416 *
4417 * Return nothing.
4418 */
4419static void
4420_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4421 Mpi2EventDataSasDeviceStatusChange_t *event_data)
4422{
4423 char *reason_str = NULL;
4424
4425 switch (event_data->ReasonCode) {
4426 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
4427 reason_str = "smart data";
4428 break;
4429 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
4430 reason_str = "unsupported device discovered";
4431 break;
4432 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
4433 reason_str = "internal device reset";
4434 break;
4435 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
4436 reason_str = "internal task abort";
4437 break;
4438 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
4439 reason_str = "internal task abort set";
4440 break;
4441 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
4442 reason_str = "internal clear task set";
4443 break;
4444 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
4445 reason_str = "internal query task";
4446 break;
4447 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
4448 reason_str = "sata init failure";
4449 break;
4450 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
4451 reason_str = "internal device reset complete";
4452 break;
4453 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
4454 reason_str = "internal task abort complete";
4455 break;
4456 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
4457 reason_str = "internal async notification";
4458 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05304459 case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
4460 reason_str = "expander reduced functionality";
4461 break;
4462 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
4463 reason_str = "expander reduced functionality complete";
4464 break;
Eric Moore635374e2009-03-09 01:21:12 -06004465 default:
4466 reason_str = "unknown reason";
4467 break;
4468 }
4469 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
4470 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
4471 reason_str, le16_to_cpu(event_data->DevHandle),
4472 (unsigned long long)le64_to_cpu(event_data->SASAddress));
4473 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
4474 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
4475 event_data->ASC, event_data->ASCQ);
4476 printk(KERN_INFO "\n");
4477}
4478#endif
4479
4480/**
4481 * _scsih_sas_device_status_change_event - handle device status change
4482 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304483 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004484 * Context: user.
4485 *
4486 * Return nothing.
4487 */
4488static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304489_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
4490 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004491{
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304492 struct MPT2SAS_TARGET *target_priv_data;
4493 struct _sas_device *sas_device;
4494 __le64 sas_address;
4495 unsigned long flags;
4496 Mpi2EventDataSasDeviceStatusChange_t *event_data =
4497 fw_event->event_data;
4498
Eric Moore635374e2009-03-09 01:21:12 -06004499#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4500 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304501 _scsih_sas_device_status_change_event_debug(ioc,
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304502 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004503#endif
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304504
4505 if (!(event_data->ReasonCode ==
4506 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
4507 event_data->ReasonCode ==
4508 MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET))
4509 return;
4510
4511 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4512 sas_address = le64_to_cpu(event_data->SASAddress);
4513 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4514 sas_address);
4515 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4516
4517 if (!sas_device || !sas_device->starget)
4518 return;
4519
4520 target_priv_data = sas_device->starget->hostdata;
4521 if (!target_priv_data)
4522 return;
4523
4524 if (event_data->ReasonCode ==
4525 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
4526 target_priv_data->tm_busy = 1;
4527 else
4528 target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004529}
4530
4531#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4532/**
4533 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
4534 * @ioc: per adapter object
4535 * @event_data: event data payload
4536 * Context: user.
4537 *
4538 * Return nothing.
4539 */
4540static void
4541_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4542 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
4543{
4544 char *reason_str = NULL;
4545
4546 switch (event_data->ReasonCode) {
4547 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
4548 reason_str = "enclosure add";
4549 break;
4550 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
4551 reason_str = "enclosure remove";
4552 break;
4553 default:
4554 reason_str = "unknown reason";
4555 break;
4556 }
4557
4558 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
4559 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
4560 " number slots(%d)\n", ioc->name, reason_str,
4561 le16_to_cpu(event_data->EnclosureHandle),
4562 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
4563 le16_to_cpu(event_data->StartSlot));
4564}
4565#endif
4566
4567/**
4568 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
4569 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304570 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004571 * Context: user.
4572 *
4573 * Return nothing.
4574 */
4575static void
4576_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304577 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004578{
4579#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4580 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4581 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304582 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004583#endif
4584}
4585
4586/**
4587 * _scsih_sas_broadcast_primative_event - handle broadcast events
4588 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304589 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004590 * Context: user.
4591 *
4592 * Return nothing.
4593 */
4594static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304595_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4596 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004597{
4598 struct scsi_cmnd *scmd;
4599 u16 smid, handle;
4600 u32 lun;
4601 struct MPT2SAS_DEVICE *sas_device_priv_data;
4602 u32 termination_count;
4603 u32 query_count;
4604 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304605#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4606 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4607#endif
Kashyap, Desai463217b2009-10-05 15:53:06 +05304608 u16 ioc_status;
Eric Moore635374e2009-03-09 01:21:12 -06004609 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4610 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4611 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004612 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4613 __func__));
4614
4615 mutex_lock(&ioc->tm_cmds.mutex);
4616 termination_count = 0;
4617 query_count = 0;
4618 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304619 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06004620 scmd = _scsih_scsi_lookup_get(ioc, smid);
4621 if (!scmd)
4622 continue;
4623 sas_device_priv_data = scmd->device->hostdata;
4624 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4625 continue;
4626 /* skip hidden raid components */
4627 if (sas_device_priv_data->sas_target->flags &
4628 MPT_TARGET_FLAGS_RAID_COMPONENT)
4629 continue;
4630 /* skip volumes */
4631 if (sas_device_priv_data->sas_target->flags &
4632 MPT_TARGET_FLAGS_VOLUME)
4633 continue;
4634
4635 handle = sas_device_priv_data->sas_target->handle;
4636 lun = sas_device_priv_data->lun;
4637 query_count++;
4638
4639 mpt2sas_scsih_issue_tm(ioc, handle, lun,
4640 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
Eric Moore8901cbb2009-04-21 15:41:32 -06004641 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Kashyap, Desai463217b2009-10-05 15:53:06 +05304642 ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
4643 & MPI2_IOCSTATUS_MASK;
4644 if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) &&
Eric Moore635374e2009-03-09 01:21:12 -06004645 (mpi_reply->ResponseCode ==
4646 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4647 mpi_reply->ResponseCode ==
4648 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4649 continue;
4650
4651 mpt2sas_scsih_issue_tm(ioc, handle, lun,
Eric Moore8901cbb2009-04-21 15:41:32 -06004652 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30);
4653 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004654 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4655 }
Eric Moore635374e2009-03-09 01:21:12 -06004656 ioc->broadcast_aen_busy = 0;
4657 mutex_unlock(&ioc->tm_cmds.mutex);
4658
4659 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4660 "%s - exit, query_count = %d termination_count = %d\n",
4661 ioc->name, __func__, query_count, termination_count));
4662}
4663
4664/**
4665 * _scsih_sas_discovery_event - handle discovery events
4666 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304667 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004668 * Context: user.
4669 *
4670 * Return nothing.
4671 */
4672static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304673_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4674 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004675{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304676 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4677
Eric Moore635374e2009-03-09 01:21:12 -06004678#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4679 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4680 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4681 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4682 "start" : "stop");
4683 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304684 printk("discovery_status(0x%08x)",
4685 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06004686 printk("\n");
4687 }
4688#endif
4689
4690 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4691 !ioc->sas_hba.num_phys)
4692 _scsih_sas_host_add(ioc);
4693}
4694
4695/**
4696 * _scsih_reprobe_lun - reprobing lun
4697 * @sdev: scsi device struct
4698 * @no_uld_attach: sdev->no_uld_attach flag setting
4699 *
4700 **/
4701static void
4702_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4703{
4704 int rc;
4705
4706 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4707 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4708 sdev->no_uld_attach ? "hidding" : "exposing");
4709 rc = scsi_device_reprobe(sdev);
4710}
4711
4712/**
4713 * _scsih_reprobe_target - reprobing target
4714 * @starget: scsi target struct
4715 * @no_uld_attach: sdev->no_uld_attach flag setting
4716 *
4717 * Note: no_uld_attach flag determines whether the disk device is attached
4718 * to block layer. A value of `1` means to not attach.
4719 **/
4720static void
4721_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4722{
4723 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4724
4725 if (no_uld_attach)
4726 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4727 else
4728 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4729
4730 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4731 _scsih_reprobe_lun);
4732}
4733/**
4734 * _scsih_sas_volume_add - add new volume
4735 * @ioc: per adapter object
4736 * @element: IR config element data
4737 * Context: user.
4738 *
4739 * Return nothing.
4740 */
4741static void
4742_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4743 Mpi2EventIrConfigElement_t *element)
4744{
4745 struct _raid_device *raid_device;
4746 unsigned long flags;
4747 u64 wwid;
4748 u16 handle = le16_to_cpu(element->VolDevHandle);
4749 int rc;
4750
Eric Moore635374e2009-03-09 01:21:12 -06004751 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4752 if (!wwid) {
4753 printk(MPT2SAS_ERR_FMT
4754 "failure at %s:%d/%s()!\n", ioc->name,
4755 __FILE__, __LINE__, __func__);
4756 return;
4757 }
4758
4759 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4760 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4761 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4762
4763 if (raid_device)
4764 return;
4765
4766 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4767 if (!raid_device) {
4768 printk(MPT2SAS_ERR_FMT
4769 "failure at %s:%d/%s()!\n", ioc->name,
4770 __FILE__, __LINE__, __func__);
4771 return;
4772 }
4773
4774 raid_device->id = ioc->sas_id++;
4775 raid_device->channel = RAID_CHANNEL;
4776 raid_device->handle = handle;
4777 raid_device->wwid = wwid;
4778 _scsih_raid_device_add(ioc, raid_device);
4779 if (!ioc->wait_for_port_enable_to_complete) {
4780 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4781 raid_device->id, 0);
4782 if (rc)
4783 _scsih_raid_device_remove(ioc, raid_device);
4784 } else
4785 _scsih_determine_boot_device(ioc, raid_device, 1);
4786}
4787
4788/**
4789 * _scsih_sas_volume_delete - delete volume
4790 * @ioc: per adapter object
4791 * @element: IR config element data
4792 * Context: user.
4793 *
4794 * Return nothing.
4795 */
4796static void
4797_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4798 Mpi2EventIrConfigElement_t *element)
4799{
4800 struct _raid_device *raid_device;
4801 u16 handle = le16_to_cpu(element->VolDevHandle);
4802 unsigned long flags;
4803 struct MPT2SAS_TARGET *sas_target_priv_data;
4804
Eric Moore635374e2009-03-09 01:21:12 -06004805 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4806 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4807 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4808 if (!raid_device)
4809 return;
4810 if (raid_device->starget) {
4811 sas_target_priv_data = raid_device->starget->hostdata;
4812 sas_target_priv_data->deleted = 1;
4813 scsi_remove_target(&raid_device->starget->dev);
4814 }
4815 _scsih_raid_device_remove(ioc, raid_device);
4816}
4817
4818/**
4819 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4820 * @ioc: per adapter object
4821 * @element: IR config element data
4822 * Context: user.
4823 *
4824 * Return nothing.
4825 */
4826static void
4827_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4828 Mpi2EventIrConfigElement_t *element)
4829{
4830 struct _sas_device *sas_device;
4831 unsigned long flags;
4832 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4833
4834 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4835 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4836 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4837 if (!sas_device)
4838 return;
4839
4840 /* exposing raid component */
4841 sas_device->volume_handle = 0;
4842 sas_device->volume_wwid = 0;
4843 sas_device->hidden_raid_component = 0;
4844 _scsih_reprobe_target(sas_device->starget, 0);
4845}
4846
4847/**
4848 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4849 * @ioc: per adapter object
4850 * @element: IR config element data
4851 * Context: user.
4852 *
4853 * Return nothing.
4854 */
4855static void
4856_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4857 Mpi2EventIrConfigElement_t *element)
4858{
4859 struct _sas_device *sas_device;
4860 unsigned long flags;
4861 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4862
4863 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4864 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4865 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4866 if (!sas_device)
4867 return;
4868
4869 /* hiding raid component */
4870 mpt2sas_config_get_volume_handle(ioc, handle,
4871 &sas_device->volume_handle);
4872 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4873 &sas_device->volume_wwid);
4874 sas_device->hidden_raid_component = 1;
4875 _scsih_reprobe_target(sas_device->starget, 1);
4876}
4877
4878/**
4879 * _scsih_sas_pd_delete - delete pd component
4880 * @ioc: per adapter object
4881 * @element: IR config element data
4882 * Context: user.
4883 *
4884 * Return nothing.
4885 */
4886static void
4887_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4888 Mpi2EventIrConfigElement_t *element)
4889{
4890 struct _sas_device *sas_device;
4891 unsigned long flags;
4892 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4893
4894 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4895 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4896 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4897 if (!sas_device)
4898 return;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304899 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004900}
4901
4902/**
4903 * _scsih_sas_pd_add - remove pd component
4904 * @ioc: per adapter object
4905 * @element: IR config element data
4906 * Context: user.
4907 *
4908 * Return nothing.
4909 */
4910static void
4911_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
4912 Mpi2EventIrConfigElement_t *element)
4913{
4914 struct _sas_device *sas_device;
4915 unsigned long flags;
4916 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304917 Mpi2ConfigReply_t mpi_reply;
4918 Mpi2SasDevicePage0_t sas_device_pg0;
4919 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304920 u64 sas_address;
4921 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06004922
4923 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4924 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4925 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304926 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004927 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304928 return;
4929 }
4930
4931 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4932 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4933 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4934 ioc->name, __FILE__, __LINE__, __func__);
4935 return;
4936 }
4937
4938 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4939 MPI2_IOCSTATUS_MASK;
4940 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4941 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4942 ioc->name, __FILE__, __LINE__, __func__);
4943 return;
4944 }
4945
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304946 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
4947 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
4948 mpt2sas_transport_update_links(ioc, sas_address, handle,
4949 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304950
4951 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06004952}
4953
4954#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4955/**
4956 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
4957 * @ioc: per adapter object
4958 * @event_data: event data payload
4959 * Context: user.
4960 *
4961 * Return nothing.
4962 */
4963static void
4964_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4965 Mpi2EventDataIrConfigChangeList_t *event_data)
4966{
4967 Mpi2EventIrConfigElement_t *element;
4968 u8 element_type;
4969 int i;
4970 char *reason_str = NULL, *element_str = NULL;
4971
4972 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4973
4974 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
4975 ioc->name, (le32_to_cpu(event_data->Flags) &
4976 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
4977 "foreign" : "native", event_data->NumElements);
4978 for (i = 0; i < event_data->NumElements; i++, element++) {
4979 switch (element->ReasonCode) {
4980 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
4981 reason_str = "add";
4982 break;
4983 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
4984 reason_str = "remove";
4985 break;
4986 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
4987 reason_str = "no change";
4988 break;
4989 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4990 reason_str = "hide";
4991 break;
4992 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4993 reason_str = "unhide";
4994 break;
4995 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4996 reason_str = "volume_created";
4997 break;
4998 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4999 reason_str = "volume_deleted";
5000 break;
5001 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
5002 reason_str = "pd_created";
5003 break;
5004 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
5005 reason_str = "pd_deleted";
5006 break;
5007 default:
5008 reason_str = "unknown reason";
5009 break;
5010 }
5011 element_type = le16_to_cpu(element->ElementFlags) &
5012 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
5013 switch (element_type) {
5014 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
5015 element_str = "volume";
5016 break;
5017 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
5018 element_str = "phys disk";
5019 break;
5020 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
5021 element_str = "hot spare";
5022 break;
5023 default:
5024 element_str = "unknown element";
5025 break;
5026 }
5027 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
5028 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
5029 reason_str, le16_to_cpu(element->VolDevHandle),
5030 le16_to_cpu(element->PhysDiskDevHandle),
5031 element->PhysDiskNum);
5032 }
5033}
5034#endif
5035
5036/**
5037 * _scsih_sas_ir_config_change_event - handle ir configuration change events
5038 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305039 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005040 * Context: user.
5041 *
5042 * Return nothing.
5043 */
5044static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305045_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
5046 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005047{
5048 Mpi2EventIrConfigElement_t *element;
5049 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305050 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305051 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005052
5053#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5054 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5055 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
5056
5057#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05305058 foreign_config = (le32_to_cpu(event_data->Flags) &
5059 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06005060
5061 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
5062 for (i = 0; i < event_data->NumElements; i++, element++) {
5063
5064 switch (element->ReasonCode) {
5065 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
5066 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305067 if (!foreign_config)
5068 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06005069 break;
5070 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
5071 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305072 if (!foreign_config)
5073 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06005074 break;
5075 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
5076 _scsih_sas_pd_hide(ioc, element);
5077 break;
5078 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
5079 _scsih_sas_pd_expose(ioc, element);
5080 break;
5081 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
5082 _scsih_sas_pd_add(ioc, element);
5083 break;
5084 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
5085 _scsih_sas_pd_delete(ioc, element);
5086 break;
5087 }
5088 }
5089}
5090
5091/**
5092 * _scsih_sas_ir_volume_event - IR volume event
5093 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305094 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005095 * Context: user.
5096 *
5097 * Return nothing.
5098 */
5099static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305100_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
5101 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005102{
5103 u64 wwid;
5104 unsigned long flags;
5105 struct _raid_device *raid_device;
5106 u16 handle;
5107 u32 state;
5108 int rc;
5109 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305110 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005111
5112 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
5113 return;
5114
5115 handle = le16_to_cpu(event_data->VolDevHandle);
5116 state = le32_to_cpu(event_data->NewValue);
5117 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
5118 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
5119 le32_to_cpu(event_data->PreviousValue), state));
5120
5121 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5122 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5123 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5124
5125 switch (state) {
5126 case MPI2_RAID_VOL_STATE_MISSING:
5127 case MPI2_RAID_VOL_STATE_FAILED:
5128 if (!raid_device)
5129 break;
5130 if (raid_device->starget) {
5131 sas_target_priv_data = raid_device->starget->hostdata;
5132 sas_target_priv_data->deleted = 1;
5133 scsi_remove_target(&raid_device->starget->dev);
5134 }
5135 _scsih_raid_device_remove(ioc, raid_device);
5136 break;
5137
5138 case MPI2_RAID_VOL_STATE_ONLINE:
5139 case MPI2_RAID_VOL_STATE_DEGRADED:
5140 case MPI2_RAID_VOL_STATE_OPTIMAL:
5141 if (raid_device)
5142 break;
5143
5144 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
5145 if (!wwid) {
5146 printk(MPT2SAS_ERR_FMT
5147 "failure at %s:%d/%s()!\n", ioc->name,
5148 __FILE__, __LINE__, __func__);
5149 break;
5150 }
5151
5152 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
5153 if (!raid_device) {
5154 printk(MPT2SAS_ERR_FMT
5155 "failure at %s:%d/%s()!\n", ioc->name,
5156 __FILE__, __LINE__, __func__);
5157 break;
5158 }
5159
5160 raid_device->id = ioc->sas_id++;
5161 raid_device->channel = RAID_CHANNEL;
5162 raid_device->handle = handle;
5163 raid_device->wwid = wwid;
5164 _scsih_raid_device_add(ioc, raid_device);
5165 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5166 raid_device->id, 0);
5167 if (rc)
5168 _scsih_raid_device_remove(ioc, raid_device);
5169 break;
5170
5171 case MPI2_RAID_VOL_STATE_INITIALIZING:
5172 default:
5173 break;
5174 }
5175}
5176
5177/**
5178 * _scsih_sas_ir_physical_disk_event - PD event
5179 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305180 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005181 * Context: user.
5182 *
5183 * Return nothing.
5184 */
5185static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305186_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
5187 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005188{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305189 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06005190 u32 state;
5191 struct _sas_device *sas_device;
5192 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305193 Mpi2ConfigReply_t mpi_reply;
5194 Mpi2SasDevicePage0_t sas_device_pg0;
5195 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305196 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305197 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06005198
5199 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
5200 return;
5201
5202 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
5203 state = le32_to_cpu(event_data->NewValue);
5204
5205 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
5206 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
5207 le32_to_cpu(event_data->PreviousValue), state));
5208
5209 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5210 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5211 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5212
5213 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06005214 case MPI2_RAID_PD_STATE_ONLINE:
5215 case MPI2_RAID_PD_STATE_DEGRADED:
5216 case MPI2_RAID_PD_STATE_REBUILDING:
5217 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305218 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06005219 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305220 return;
5221 }
5222
5223 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5224 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
5225 handle))) {
5226 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5227 ioc->name, __FILE__, __LINE__, __func__);
5228 return;
5229 }
5230
5231 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5232 MPI2_IOCSTATUS_MASK;
5233 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5234 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5235 ioc->name, __FILE__, __LINE__, __func__);
5236 return;
5237 }
5238
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305239 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
5240 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
5241 mpt2sas_transport_update_links(ioc, sas_address, handle,
5242 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305243
5244 _scsih_add_device(ioc, handle, 0, 1);
5245
Eric Moore635374e2009-03-09 01:21:12 -06005246 break;
5247
Kashyap, Desai62727a72009-08-07 19:35:18 +05305248 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06005249 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
5250 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
5251 case MPI2_RAID_PD_STATE_HOT_SPARE:
5252 default:
5253 break;
5254 }
5255}
5256
5257#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5258/**
5259 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
5260 * @ioc: per adapter object
5261 * @event_data: event data payload
5262 * Context: user.
5263 *
5264 * Return nothing.
5265 */
5266static void
5267_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
5268 Mpi2EventDataIrOperationStatus_t *event_data)
5269{
5270 char *reason_str = NULL;
5271
5272 switch (event_data->RAIDOperation) {
5273 case MPI2_EVENT_IR_RAIDOP_RESYNC:
5274 reason_str = "resync";
5275 break;
5276 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
5277 reason_str = "online capacity expansion";
5278 break;
5279 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
5280 reason_str = "consistency check";
5281 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305282 case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
5283 reason_str = "background init";
5284 break;
5285 case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
5286 reason_str = "make data consistent";
Eric Moore635374e2009-03-09 01:21:12 -06005287 break;
5288 }
5289
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305290 if (!reason_str)
5291 return;
5292
Eric Moore635374e2009-03-09 01:21:12 -06005293 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
5294 "\thandle(0x%04x), percent complete(%d)\n",
5295 ioc->name, reason_str,
5296 le16_to_cpu(event_data->VolDevHandle),
5297 event_data->PercentComplete);
5298}
5299#endif
5300
5301/**
5302 * _scsih_sas_ir_operation_status_event - handle RAID operation events
5303 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305304 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005305 * Context: user.
5306 *
5307 * Return nothing.
5308 */
5309static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305310_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
5311 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005312{
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305313 Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data;
5314 static struct _raid_device *raid_device;
5315 unsigned long flags;
5316 u16 handle;
5317
Eric Moore635374e2009-03-09 01:21:12 -06005318#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5319 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305320 _scsih_sas_ir_operation_status_event_debug(ioc,
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305321 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005322#endif
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305323
5324 /* code added for raid transport support */
5325 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
5326
5327 handle = le16_to_cpu(event_data->VolDevHandle);
5328
5329 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5330 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5331 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5332
5333 if (!raid_device)
5334 return;
5335
5336 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
5337 raid_device->percent_complete =
5338 event_data->PercentComplete;
5339 }
Eric Moore635374e2009-03-09 01:21:12 -06005340}
5341
5342/**
5343 * _scsih_task_set_full - handle task set full
5344 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305345 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005346 * Context: user.
5347 *
5348 * Throttle back qdepth.
5349 */
5350static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305351_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
5352 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005353{
5354 unsigned long flags;
5355 struct _sas_device *sas_device;
5356 static struct _raid_device *raid_device;
5357 struct scsi_device *sdev;
5358 int depth;
5359 u16 current_depth;
5360 u16 handle;
5361 int id, channel;
5362 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305363 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005364
5365 current_depth = le16_to_cpu(event_data->CurrentDepth);
5366 handle = le16_to_cpu(event_data->DevHandle);
5367 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5368 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5369 if (!sas_device) {
5370 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5371 return;
5372 }
5373 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5374 id = sas_device->id;
5375 channel = sas_device->channel;
5376 sas_address = sas_device->sas_address;
5377
5378 /* if hidden raid component, then change to volume characteristics */
5379 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
5380 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5381 raid_device = _scsih_raid_device_find_by_handle(
5382 ioc, sas_device->volume_handle);
5383 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5384 if (raid_device) {
5385 id = raid_device->id;
5386 channel = raid_device->channel;
5387 handle = raid_device->handle;
5388 sas_address = raid_device->wwid;
5389 }
5390 }
5391
5392 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
5393 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
5394 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
5395 handle, (unsigned long long)sas_address, current_depth);
5396
5397 shost_for_each_device(sdev, ioc->shost) {
5398 if (sdev->id == id && sdev->channel == channel) {
5399 if (current_depth > sdev->queue_depth) {
5400 if (ioc->logging_level &
5401 MPT_DEBUG_TASK_SET_FULL)
5402 sdev_printk(KERN_INFO, sdev, "strange "
5403 "observation, the queue depth is"
5404 " (%d) meanwhile fw queue depth "
5405 "is (%d)\n", sdev->queue_depth,
5406 current_depth);
5407 continue;
5408 }
5409 depth = scsi_track_queue_full(sdev,
5410 current_depth - 1);
5411 if (depth > 0)
5412 sdev_printk(KERN_INFO, sdev, "Queue depth "
5413 "reduced to (%d)\n", depth);
5414 else if (depth < 0)
5415 sdev_printk(KERN_INFO, sdev, "Tagged Command "
5416 "Queueing is being disabled\n");
5417 else if (depth == 0)
5418 if (ioc->logging_level &
5419 MPT_DEBUG_TASK_SET_FULL)
5420 sdev_printk(KERN_INFO, sdev,
5421 "Queue depth not changed yet\n");
5422 }
5423 }
5424}
5425
5426/**
5427 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
5428 * @ioc: per adapter object
5429 * @sas_address: sas address
5430 * @slot: enclosure slot id
5431 * @handle: device handle
5432 *
5433 * After host reset, find out whether devices are still responding.
5434 * Used in _scsi_remove_unresponsive_sas_devices.
5435 *
5436 * Return nothing.
5437 */
5438static void
5439_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5440 u16 slot, u16 handle)
5441{
5442 struct MPT2SAS_TARGET *sas_target_priv_data;
5443 struct scsi_target *starget;
5444 struct _sas_device *sas_device;
5445 unsigned long flags;
5446
5447 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5448 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
5449 if (sas_device->sas_address == sas_address &&
5450 sas_device->slot == slot && sas_device->starget) {
5451 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305452 sas_device->state = 0;
5453 starget = sas_device->starget;
5454 sas_target_priv_data = starget->hostdata;
5455 sas_target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06005456 starget_printk(KERN_INFO, sas_device->starget,
5457 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
5458 "logical id(0x%016llx), slot(%d)\n", handle,
5459 (unsigned long long)sas_device->sas_address,
5460 (unsigned long long)
5461 sas_device->enclosure_logical_id,
5462 sas_device->slot);
5463 if (sas_device->handle == handle)
5464 goto out;
5465 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5466 sas_device->handle);
5467 sas_device->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005468 sas_target_priv_data->handle = handle;
5469 goto out;
5470 }
5471 }
5472 out:
5473 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5474}
5475
5476/**
5477 * _scsih_search_responding_sas_devices -
5478 * @ioc: per adapter object
5479 *
5480 * After host reset, find out whether devices are still responding.
5481 * If not remove.
5482 *
5483 * Return nothing.
5484 */
5485static void
5486_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
5487{
5488 Mpi2SasDevicePage0_t sas_device_pg0;
5489 Mpi2ConfigReply_t mpi_reply;
5490 u16 ioc_status;
5491 __le64 sas_address;
5492 u16 handle;
5493 u32 device_info;
5494 u16 slot;
5495
5496 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5497
5498 if (list_empty(&ioc->sas_device_list))
5499 return;
5500
5501 handle = 0xFFFF;
5502 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5503 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
5504 handle))) {
5505 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5506 MPI2_IOCSTATUS_MASK;
5507 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5508 break;
5509 handle = le16_to_cpu(sas_device_pg0.DevHandle);
5510 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5511 if (!(_scsih_is_end_device(device_info)))
5512 continue;
5513 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5514 slot = le16_to_cpu(sas_device_pg0.Slot);
5515 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
5516 handle);
5517 }
5518}
5519
5520/**
5521 * _scsih_mark_responding_raid_device - mark a raid_device as responding
5522 * @ioc: per adapter object
5523 * @wwid: world wide identifier for raid volume
5524 * @handle: device handle
5525 *
5526 * After host reset, find out whether devices are still responding.
5527 * Used in _scsi_remove_unresponsive_raid_devices.
5528 *
5529 * Return nothing.
5530 */
5531static void
5532_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
5533 u16 handle)
5534{
5535 struct MPT2SAS_TARGET *sas_target_priv_data;
5536 struct scsi_target *starget;
5537 struct _raid_device *raid_device;
5538 unsigned long flags;
5539
5540 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5541 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
5542 if (raid_device->wwid == wwid && raid_device->starget) {
5543 raid_device->responding = 1;
5544 starget_printk(KERN_INFO, raid_device->starget,
5545 "handle(0x%04x), wwid(0x%016llx)\n", handle,
5546 (unsigned long long)raid_device->wwid);
5547 if (raid_device->handle == handle)
5548 goto out;
5549 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5550 raid_device->handle);
5551 raid_device->handle = handle;
5552 starget = raid_device->starget;
5553 sas_target_priv_data = starget->hostdata;
5554 sas_target_priv_data->handle = handle;
5555 goto out;
5556 }
5557 }
5558 out:
5559 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5560}
5561
5562/**
5563 * _scsih_search_responding_raid_devices -
5564 * @ioc: per adapter object
5565 *
5566 * After host reset, find out whether devices are still responding.
5567 * If not remove.
5568 *
5569 * Return nothing.
5570 */
5571static void
5572_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
5573{
5574 Mpi2RaidVolPage1_t volume_pg1;
5575 Mpi2ConfigReply_t mpi_reply;
5576 u16 ioc_status;
5577 u16 handle;
5578
5579 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5580
5581 if (list_empty(&ioc->raid_device_list))
5582 return;
5583
5584 handle = 0xFFFF;
5585 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
5586 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
5587 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5588 MPI2_IOCSTATUS_MASK;
5589 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5590 break;
5591 handle = le16_to_cpu(volume_pg1.DevHandle);
5592 _scsih_mark_responding_raid_device(ioc,
5593 le64_to_cpu(volume_pg1.WWID), handle);
5594 }
5595}
5596
5597/**
5598 * _scsih_mark_responding_expander - mark a expander as responding
5599 * @ioc: per adapter object
5600 * @sas_address: sas address
5601 * @handle:
5602 *
5603 * After host reset, find out whether devices are still responding.
5604 * Used in _scsi_remove_unresponsive_expanders.
5605 *
5606 * Return nothing.
5607 */
5608static void
5609_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5610 u16 handle)
5611{
5612 struct _sas_node *sas_expander;
5613 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305614 int i;
Eric Moore635374e2009-03-09 01:21:12 -06005615
5616 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5617 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305618 if (sas_expander->sas_address != sas_address)
5619 continue;
5620 sas_expander->responding = 1;
5621 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06005622 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305623 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
5624 " from(0x%04x) to (0x%04x)!!!\n",
5625 (unsigned long long)sas_expander->sas_address,
5626 sas_expander->handle, handle);
5627 sas_expander->handle = handle;
5628 for (i = 0 ; i < sas_expander->num_phys ; i++)
5629 sas_expander->phy[i].handle = handle;
5630 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06005631 }
5632 out:
5633 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5634}
5635
5636/**
5637 * _scsih_search_responding_expanders -
5638 * @ioc: per adapter object
5639 *
5640 * After host reset, find out whether devices are still responding.
5641 * If not remove.
5642 *
5643 * Return nothing.
5644 */
5645static void
5646_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5647{
5648 Mpi2ExpanderPage0_t expander_pg0;
5649 Mpi2ConfigReply_t mpi_reply;
5650 u16 ioc_status;
5651 __le64 sas_address;
5652 u16 handle;
5653
5654 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5655
5656 if (list_empty(&ioc->sas_expander_list))
5657 return;
5658
5659 handle = 0xFFFF;
5660 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5661 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5662
5663 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5664 MPI2_IOCSTATUS_MASK;
5665 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5666 break;
5667
5668 handle = le16_to_cpu(expander_pg0.DevHandle);
5669 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5670 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5671 "sas_addr(0x%016llx)\n", handle,
5672 (unsigned long long)sas_address);
5673 _scsih_mark_responding_expander(ioc, sas_address, handle);
5674 }
5675
5676}
5677
5678/**
5679 * _scsih_remove_unresponding_devices - removing unresponding devices
5680 * @ioc: per adapter object
5681 *
5682 * Return nothing.
5683 */
5684static void
5685_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
5686{
5687 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305688 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005689 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005690
Eric Moore635374e2009-03-09 01:21:12 -06005691
5692 list_for_each_entry_safe(sas_device, sas_device_next,
5693 &ioc->sas_device_list, list) {
5694 if (sas_device->responding) {
5695 sas_device->responding = 0;
5696 continue;
5697 }
5698 if (sas_device->starget)
5699 starget_printk(KERN_INFO, sas_device->starget,
5700 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5701 "enclosure logical id(0x%016llx), slot(%d)\n",
5702 sas_device->handle,
5703 (unsigned long long)sas_device->sas_address,
5704 (unsigned long long)
5705 sas_device->enclosure_logical_id,
5706 sas_device->slot);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305707 /* invalidate the device handle */
5708 sas_device->handle = 0;
5709 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005710 }
5711
5712 list_for_each_entry_safe(raid_device, raid_device_next,
5713 &ioc->raid_device_list, list) {
5714 if (raid_device->responding) {
5715 raid_device->responding = 0;
5716 continue;
5717 }
5718 if (raid_device->starget) {
5719 starget_printk(KERN_INFO, raid_device->starget,
5720 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5721 raid_device->handle,
5722 (unsigned long long)raid_device->wwid);
5723 scsi_remove_target(&raid_device->starget->dev);
5724 }
5725 _scsih_raid_device_remove(ioc, raid_device);
5726 }
5727
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305728 retry_expander_search:
5729 sas_expander = NULL;
5730 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005731 if (sas_expander->responding) {
5732 sas_expander->responding = 0;
5733 continue;
5734 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305735 _scsih_expander_remove(ioc, sas_expander->sas_address);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305736 goto retry_expander_search;
5737 }
5738}
5739
5740/**
5741 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5742 * @ioc: per adapter object
5743 * @reset_phase: phase
5744 *
5745 * The handler for doing any required cleanup or initialization.
5746 *
5747 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5748 * MPT2_IOC_DONE_RESET
5749 *
5750 * Return nothing.
5751 */
5752void
5753mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5754{
5755 switch (reset_phase) {
5756 case MPT2_IOC_PRE_RESET:
5757 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5758 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
5759 _scsih_fw_event_off(ioc);
5760 break;
5761 case MPT2_IOC_AFTER_RESET:
5762 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5763 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
5764 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5765 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5766 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5767 complete(&ioc->tm_cmds.done);
5768 }
5769 _scsih_fw_event_on(ioc);
5770 _scsih_flush_running_cmds(ioc);
5771 break;
5772 case MPT2_IOC_DONE_RESET:
5773 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5774 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305775 _scsih_sas_host_refresh(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305776 _scsih_search_responding_sas_devices(ioc);
5777 _scsih_search_responding_raid_devices(ioc);
5778 _scsih_search_responding_expanders(ioc);
5779 break;
5780 case MPT2_IOC_RUNNING:
5781 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5782 "MPT2_IOC_RUNNING\n", ioc->name, __func__));
5783 _scsih_remove_unresponding_devices(ioc);
5784 break;
Eric Moore635374e2009-03-09 01:21:12 -06005785 }
5786}
5787
5788/**
5789 * _firmware_event_work - delayed task for processing firmware events
5790 * @ioc: per adapter object
5791 * @work: equal to the fw_event_work object
5792 * Context: user.
5793 *
5794 * Return nothing.
5795 */
5796static void
5797_firmware_event_work(struct work_struct *work)
5798{
5799 struct fw_event_work *fw_event = container_of(work,
Eric Moore6f92a7a2009-04-21 15:43:33 -06005800 struct fw_event_work, work);
Eric Moore635374e2009-03-09 01:21:12 -06005801 unsigned long flags;
5802 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5803
Eric Moore635374e2009-03-09 01:21:12 -06005804 /* the queue is being flushed so ignore this event */
5805 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5806 if (ioc->fw_events_off || ioc->remove_host) {
5807 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5808 _scsih_fw_event_free(ioc, fw_event);
5809 return;
5810 }
5811 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5812
Eric Moore635374e2009-03-09 01:21:12 -06005813 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06005814 _scsih_fw_event_requeue(ioc, fw_event, 1000);
5815 return;
5816 }
Eric Moore635374e2009-03-09 01:21:12 -06005817
5818 switch (fw_event->event) {
5819 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305820 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005821 break;
5822 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305823 _scsih_sas_device_status_change_event(ioc,
5824 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005825 break;
5826 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305827 _scsih_sas_discovery_event(ioc,
5828 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005829 break;
5830 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305831 _scsih_sas_broadcast_primative_event(ioc,
5832 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005833 break;
5834 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5835 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305836 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005837 break;
5838 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305839 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005840 break;
5841 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305842 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005843 break;
5844 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305845 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005846 break;
5847 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305848 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005849 break;
5850 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305851 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005852 break;
5853 }
5854 _scsih_fw_event_free(ioc, fw_event);
5855}
5856
5857/**
5858 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5859 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305860 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06005861 * @reply: reply message frame(lower 32bit addr)
5862 * Context: interrupt.
5863 *
5864 * This function merely adds a new work task into ioc->firmware_event_thread.
5865 * The tasks are worked from _firmware_event_work in user context.
5866 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305867 * Return 1 meaning mf should be freed from _base_interrupt
5868 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06005869 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305870u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305871mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
5872 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06005873{
5874 struct fw_event_work *fw_event;
5875 Mpi2EventNotificationReply_t *mpi_reply;
5876 unsigned long flags;
5877 u16 event;
5878
5879 /* events turned off due to host reset or driver unloading */
5880 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5881 if (ioc->fw_events_off || ioc->remove_host) {
5882 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305883 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005884 }
5885 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5886
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305887 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06005888 event = le16_to_cpu(mpi_reply->Event);
5889
5890 switch (event) {
5891 /* handle these */
5892 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
5893 {
5894 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
5895 (Mpi2EventDataSasBroadcastPrimitive_t *)
5896 mpi_reply->EventData;
5897
5898 if (baen_data->Primitive !=
5899 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
5900 ioc->broadcast_aen_busy)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305901 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005902 ioc->broadcast_aen_busy = 1;
5903 break;
5904 }
5905
5906 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
5907 _scsih_check_topo_delete_events(ioc,
5908 (Mpi2EventDataSasTopologyChangeList_t *)
5909 mpi_reply->EventData);
5910 break;
5911
5912 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
5913 case MPI2_EVENT_IR_OPERATION_STATUS:
5914 case MPI2_EVENT_SAS_DISCOVERY:
5915 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5916 case MPI2_EVENT_IR_VOLUME:
5917 case MPI2_EVENT_IR_PHYSICAL_DISK:
5918 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
5919 case MPI2_EVENT_TASK_SET_FULL:
5920 break;
5921
5922 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305923 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005924 }
5925
5926 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
5927 if (!fw_event) {
5928 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5929 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305930 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005931 }
5932 fw_event->event_data =
5933 kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
5934 if (!fw_event->event_data) {
5935 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5936 ioc->name, __FILE__, __LINE__, __func__);
5937 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305938 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005939 }
5940
5941 memcpy(fw_event->event_data, mpi_reply->EventData,
5942 mpi_reply->EventDataLength*4);
5943 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305944 fw_event->VF_ID = mpi_reply->VF_ID;
5945 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06005946 fw_event->event = event;
5947 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305948 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005949}
5950
5951/* shost template */
5952static struct scsi_host_template scsih_driver_template = {
5953 .module = THIS_MODULE,
5954 .name = "Fusion MPT SAS Host",
5955 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06005956 .queuecommand = _scsih_qcmd,
5957 .target_alloc = _scsih_target_alloc,
5958 .slave_alloc = _scsih_slave_alloc,
5959 .slave_configure = _scsih_slave_configure,
5960 .target_destroy = _scsih_target_destroy,
5961 .slave_destroy = _scsih_slave_destroy,
5962 .change_queue_depth = _scsih_change_queue_depth,
5963 .change_queue_type = _scsih_change_queue_type,
5964 .eh_abort_handler = _scsih_abort,
5965 .eh_device_reset_handler = _scsih_dev_reset,
5966 .eh_target_reset_handler = _scsih_target_reset,
5967 .eh_host_reset_handler = _scsih_host_reset,
5968 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06005969 .can_queue = 1,
5970 .this_id = -1,
5971 .sg_tablesize = MPT2SAS_SG_DEPTH,
5972 .max_sectors = 8192,
5973 .cmd_per_lun = 7,
5974 .use_clustering = ENABLE_CLUSTERING,
5975 .shost_attrs = mpt2sas_host_attrs,
5976 .sdev_attrs = mpt2sas_dev_attrs,
5977};
5978
5979/**
5980 * _scsih_expander_node_remove - removing expander device from list.
5981 * @ioc: per adapter object
5982 * @sas_expander: the sas_device object
5983 * Context: Calling function should acquire ioc->sas_node_lock.
5984 *
5985 * Removing object and freeing associated memory from the
5986 * ioc->sas_expander_list.
5987 *
5988 * Return nothing.
5989 */
5990static void
5991_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
5992 struct _sas_node *sas_expander)
5993{
5994 struct _sas_port *mpt2sas_port;
5995 struct _sas_device *sas_device;
5996 struct _sas_node *expander_sibling;
5997 unsigned long flags;
5998
5999 if (!sas_expander)
6000 return;
6001
6002 /* remove sibling ports attached to this expander */
6003 retry_device_search:
6004 list_for_each_entry(mpt2sas_port,
6005 &sas_expander->sas_port_list, port_list) {
6006 if (mpt2sas_port->remote_identify.device_type ==
6007 SAS_END_DEVICE) {
6008 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6009 sas_device =
6010 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
6011 mpt2sas_port->remote_identify.sas_address);
6012 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6013 if (!sas_device)
6014 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306015 _scsih_remove_device(ioc, sas_device);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05306016 if (ioc->shost_recovery)
6017 return;
Eric Moore635374e2009-03-09 01:21:12 -06006018 goto retry_device_search;
6019 }
6020 }
6021
6022 retry_expander_search:
6023 list_for_each_entry(mpt2sas_port,
6024 &sas_expander->sas_port_list, port_list) {
6025
6026 if (mpt2sas_port->remote_identify.device_type ==
6027 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
6028 mpt2sas_port->remote_identify.device_type ==
6029 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
6030
6031 spin_lock_irqsave(&ioc->sas_node_lock, flags);
6032 expander_sibling =
6033 mpt2sas_scsih_expander_find_by_sas_address(
6034 ioc, mpt2sas_port->remote_identify.sas_address);
6035 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
6036 if (!expander_sibling)
6037 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306038 _scsih_expander_remove(ioc,
6039 expander_sibling->sas_address);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05306040 if (ioc->shost_recovery)
6041 return;
Eric Moore635374e2009-03-09 01:21:12 -06006042 goto retry_expander_search;
6043 }
6044 }
6045
6046 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306047 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006048
6049 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
6050 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
6051 sas_expander->handle, (unsigned long long)
6052 sas_expander->sas_address);
6053
6054 list_del(&sas_expander->list);
6055 kfree(sas_expander->phy);
6056 kfree(sas_expander);
6057}
6058
6059/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05306060 * _scsih_ir_shutdown - IR shutdown notification
6061 * @ioc: per adapter object
6062 *
6063 * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
6064 * the host system is shutting down.
6065 *
6066 * Return nothing.
6067 */
6068static void
6069_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
6070{
6071 Mpi2RaidActionRequest_t *mpi_request;
6072 Mpi2RaidActionReply_t *mpi_reply;
6073 u16 smid;
6074
6075 /* is IR firmware build loaded ? */
6076 if (!ioc->ir_firmware)
6077 return;
6078
6079 /* are there any volumes ? */
6080 if (list_empty(&ioc->raid_device_list))
6081 return;
6082
6083 mutex_lock(&ioc->scsih_cmds.mutex);
6084
6085 if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
6086 printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
6087 ioc->name, __func__);
6088 goto out;
6089 }
6090 ioc->scsih_cmds.status = MPT2_CMD_PENDING;
6091
6092 smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
6093 if (!smid) {
6094 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
6095 ioc->name, __func__);
6096 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
6097 goto out;
6098 }
6099
6100 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
6101 ioc->scsih_cmds.smid = smid;
6102 memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
6103
6104 mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
6105 mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
6106
6107 printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
6108 init_completion(&ioc->scsih_cmds.done);
6109 mpt2sas_base_put_smid_default(ioc, smid);
6110 wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
6111
6112 if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
6113 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
6114 ioc->name, __func__);
6115 goto out;
6116 }
6117
6118 if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
6119 mpi_reply = ioc->scsih_cmds.reply;
6120
6121 printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
6122 "ioc_status(0x%04x), loginfo(0x%08x)\n",
6123 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
6124 le32_to_cpu(mpi_reply->IOCLogInfo));
6125 }
6126
6127 out:
6128 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
6129 mutex_unlock(&ioc->scsih_cmds.mutex);
6130}
6131
6132/**
6133 * _scsih_shutdown - routine call during system shutdown
6134 * @pdev: PCI device struct
6135 *
6136 * Return nothing.
6137 */
6138static void
6139_scsih_shutdown(struct pci_dev *pdev)
6140{
6141 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6142 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6143
6144 _scsih_ir_shutdown(ioc);
6145 mpt2sas_base_detach(ioc);
6146}
6147
6148/**
Eric Moored5d135b2009-05-18 13:02:08 -06006149 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06006150 * @pdev: PCI device struct
6151 *
Kashyap, Desai744090d2009-10-05 15:56:56 +05306152 * Routine called when unloading the driver.
Eric Moore635374e2009-03-09 01:21:12 -06006153 * Return nothing.
6154 */
6155static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06006156_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006157{
6158 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6159 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6160 struct _sas_port *mpt2sas_port;
6161 struct _sas_device *sas_device;
6162 struct _sas_node *expander_sibling;
Kashyap, Desaid7384b22009-12-16 18:50:06 +05306163 struct _raid_device *raid_device, *next;
6164 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06006165 struct workqueue_struct *wq;
6166 unsigned long flags;
6167
6168 ioc->remove_host = 1;
6169 _scsih_fw_event_off(ioc);
6170
6171 spin_lock_irqsave(&ioc->fw_event_lock, flags);
6172 wq = ioc->firmware_event_thread;
6173 ioc->firmware_event_thread = NULL;
6174 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
6175 if (wq)
6176 destroy_workqueue(wq);
6177
Kashyap, Desaid7384b22009-12-16 18:50:06 +05306178 /* release all the volumes */
6179 list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
6180 list) {
6181 if (raid_device->starget) {
6182 sas_target_priv_data =
6183 raid_device->starget->hostdata;
6184 sas_target_priv_data->deleted = 1;
6185 scsi_remove_target(&raid_device->starget->dev);
6186 }
6187 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
6188 "(0x%016llx)\n", ioc->name, raid_device->handle,
6189 (unsigned long long) raid_device->wwid);
6190 _scsih_raid_device_remove(ioc, raid_device);
6191 }
6192
Eric Moore635374e2009-03-09 01:21:12 -06006193 /* free ports attached to the sas_host */
6194 retry_again:
6195 list_for_each_entry(mpt2sas_port,
6196 &ioc->sas_hba.sas_port_list, port_list) {
6197 if (mpt2sas_port->remote_identify.device_type ==
6198 SAS_END_DEVICE) {
6199 sas_device =
6200 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
6201 mpt2sas_port->remote_identify.sas_address);
6202 if (sas_device) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306203 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06006204 goto retry_again;
6205 }
6206 } else {
6207 expander_sibling =
6208 mpt2sas_scsih_expander_find_by_sas_address(ioc,
6209 mpt2sas_port->remote_identify.sas_address);
6210 if (expander_sibling) {
6211 _scsih_expander_remove(ioc,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306212 expander_sibling->sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06006213 goto retry_again;
6214 }
6215 }
6216 }
6217
6218 /* free phys attached to the sas_host */
6219 if (ioc->sas_hba.num_phys) {
6220 kfree(ioc->sas_hba.phy);
6221 ioc->sas_hba.phy = NULL;
6222 ioc->sas_hba.num_phys = 0;
6223 }
6224
6225 sas_remove_host(shost);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306226 _scsih_shutdown(pdev);
Eric Moore635374e2009-03-09 01:21:12 -06006227 list_del(&ioc->list);
6228 scsi_remove_host(shost);
6229 scsi_host_put(shost);
6230}
6231
6232/**
6233 * _scsih_probe_boot_devices - reports 1st device
6234 * @ioc: per adapter object
6235 *
6236 * If specified in bios page 2, this routine reports the 1st
6237 * device scsi-ml or sas transport for persistent boot device
6238 * purposes. Please refer to function _scsih_determine_boot_device()
6239 */
6240static void
6241_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
6242{
6243 u8 is_raid;
6244 void *device;
6245 struct _sas_device *sas_device;
6246 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306247 u16 handle;
6248 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06006249 u64 sas_address;
6250 unsigned long flags;
6251 int rc;
6252
6253 device = NULL;
6254 if (ioc->req_boot_device.device) {
6255 device = ioc->req_boot_device.device;
6256 is_raid = ioc->req_boot_device.is_raid;
6257 } else if (ioc->req_alt_boot_device.device) {
6258 device = ioc->req_alt_boot_device.device;
6259 is_raid = ioc->req_alt_boot_device.is_raid;
6260 } else if (ioc->current_boot_device.device) {
6261 device = ioc->current_boot_device.device;
6262 is_raid = ioc->current_boot_device.is_raid;
6263 }
6264
6265 if (!device)
6266 return;
6267
6268 if (is_raid) {
6269 raid_device = device;
6270 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6271 raid_device->id, 0);
6272 if (rc)
6273 _scsih_raid_device_remove(ioc, raid_device);
6274 } else {
6275 sas_device = device;
6276 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306277 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06006278 sas_address = sas_device->sas_address;
6279 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6280 list_move_tail(&sas_device->list, &ioc->sas_device_list);
6281 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6282 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306283 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06006284 _scsih_sas_device_remove(ioc, sas_device);
6285 } else if (!sas_device->starget) {
6286 mpt2sas_transport_port_remove(ioc, sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306287 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006288 _scsih_sas_device_remove(ioc, sas_device);
6289 }
6290 }
6291}
6292
6293/**
6294 * _scsih_probe_raid - reporting raid volumes to scsi-ml
6295 * @ioc: per adapter object
6296 *
6297 * Called during initial loading of the driver.
6298 */
6299static void
6300_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
6301{
6302 struct _raid_device *raid_device, *raid_next;
6303 int rc;
6304
6305 list_for_each_entry_safe(raid_device, raid_next,
6306 &ioc->raid_device_list, list) {
6307 if (raid_device->starget)
6308 continue;
6309 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6310 raid_device->id, 0);
6311 if (rc)
6312 _scsih_raid_device_remove(ioc, raid_device);
6313 }
6314}
6315
6316/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306317 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06006318 * @ioc: per adapter object
6319 *
6320 * Called during initial loading of the driver.
6321 */
6322static void
6323_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
6324{
6325 struct _sas_device *sas_device, *next;
6326 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06006327
6328 /* SAS Device List */
6329 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
6330 list) {
6331 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6332 list_move_tail(&sas_device->list, &ioc->sas_device_list);
6333 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6334
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306335 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
6336 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06006337 _scsih_sas_device_remove(ioc, sas_device);
6338 } else if (!sas_device->starget) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306339 mpt2sas_transport_port_remove(ioc,
6340 sas_device->sas_address,
6341 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006342 _scsih_sas_device_remove(ioc, sas_device);
6343 }
6344 }
6345}
6346
6347/**
6348 * _scsih_probe_devices - probing for devices
6349 * @ioc: per adapter object
6350 *
6351 * Called during initial loading of the driver.
6352 */
6353static void
6354_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
6355{
6356 u16 volume_mapping_flags =
6357 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
6358 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
6359
6360 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
6361 return; /* return when IOC doesn't support initiator mode */
6362
6363 _scsih_probe_boot_devices(ioc);
6364
6365 if (ioc->ir_firmware) {
6366 if ((volume_mapping_flags &
6367 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
6368 _scsih_probe_sas(ioc);
6369 _scsih_probe_raid(ioc);
6370 } else {
6371 _scsih_probe_raid(ioc);
6372 _scsih_probe_sas(ioc);
6373 }
6374 } else
6375 _scsih_probe_sas(ioc);
6376}
6377
6378/**
Eric Moored5d135b2009-05-18 13:02:08 -06006379 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06006380 * @pdev: PCI device struct
6381 * @id: pci device id
6382 *
6383 * Returns 0 success, anything else error.
6384 */
6385static int
Eric Moored5d135b2009-05-18 13:02:08 -06006386_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06006387{
6388 struct MPT2SAS_ADAPTER *ioc;
6389 struct Scsi_Host *shost;
6390
6391 shost = scsi_host_alloc(&scsih_driver_template,
6392 sizeof(struct MPT2SAS_ADAPTER));
6393 if (!shost)
6394 return -ENODEV;
6395
6396 /* init local params */
6397 ioc = shost_priv(shost);
6398 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
6399 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06006400 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06006401 ioc->shost = shost;
6402 ioc->id = mpt_ids++;
6403 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
6404 ioc->pdev = pdev;
6405 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
6406 ioc->tm_cb_idx = tm_cb_idx;
6407 ioc->ctl_cb_idx = ctl_cb_idx;
6408 ioc->base_cb_idx = base_cb_idx;
6409 ioc->transport_cb_idx = transport_cb_idx;
Kashyap, Desai744090d2009-10-05 15:56:56 +05306410 ioc->scsih_cb_idx = scsih_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006411 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306412 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
6413 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006414 ioc->logging_level = logging_level;
6415 /* misc semaphores and spin locks */
6416 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
6417 spin_lock_init(&ioc->scsi_lookup_lock);
6418 spin_lock_init(&ioc->sas_device_lock);
6419 spin_lock_init(&ioc->sas_node_lock);
6420 spin_lock_init(&ioc->fw_event_lock);
6421 spin_lock_init(&ioc->raid_device_lock);
6422
6423 INIT_LIST_HEAD(&ioc->sas_device_list);
6424 INIT_LIST_HEAD(&ioc->sas_device_init_list);
6425 INIT_LIST_HEAD(&ioc->sas_expander_list);
6426 INIT_LIST_HEAD(&ioc->fw_event_list);
6427 INIT_LIST_HEAD(&ioc->raid_device_list);
6428 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306429 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Eric Moore635374e2009-03-09 01:21:12 -06006430
6431 /* init shost parameters */
6432 shost->max_cmd_len = 16;
6433 shost->max_lun = max_lun;
6434 shost->transportt = mpt2sas_transport_template;
6435 shost->unique_id = ioc->id;
6436
6437 if ((scsi_add_host(shost, &pdev->dev))) {
6438 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6439 ioc->name, __FILE__, __LINE__, __func__);
6440 list_del(&ioc->list);
6441 goto out_add_shost_fail;
6442 }
6443
Eric Moore3c621b32009-05-18 12:59:41 -06006444 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
6445 | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306446 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06006447
Eric Moore635374e2009-03-09 01:21:12 -06006448 /* event thread */
6449 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
6450 "fw_event%d", ioc->id);
6451 ioc->firmware_event_thread = create_singlethread_workqueue(
6452 ioc->firmware_event_name);
6453 if (!ioc->firmware_event_thread) {
6454 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6455 ioc->name, __FILE__, __LINE__, __func__);
6456 goto out_thread_fail;
6457 }
6458
6459 ioc->wait_for_port_enable_to_complete = 1;
6460 if ((mpt2sas_base_attach(ioc))) {
6461 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6462 ioc->name, __FILE__, __LINE__, __func__);
6463 goto out_attach_fail;
6464 }
6465
6466 ioc->wait_for_port_enable_to_complete = 0;
6467 _scsih_probe_devices(ioc);
6468 return 0;
6469
6470 out_attach_fail:
6471 destroy_workqueue(ioc->firmware_event_thread);
6472 out_thread_fail:
6473 list_del(&ioc->list);
6474 scsi_remove_host(shost);
6475 out_add_shost_fail:
6476 return -ENODEV;
6477}
6478
6479#ifdef CONFIG_PM
6480/**
Eric Moored5d135b2009-05-18 13:02:08 -06006481 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006482 * @pdev: PCI device struct
6483 * @state: PM state change to (usually PCI_D3)
6484 *
6485 * Returns 0 success, anything else error.
6486 */
6487static int
Eric Moored5d135b2009-05-18 13:02:08 -06006488_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06006489{
6490 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6491 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6492 u32 device_state;
6493
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306494 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006495 flush_scheduled_work();
6496 scsi_block_requests(shost);
6497 device_state = pci_choose_state(pdev, state);
6498 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
6499 "operating state [D%d]\n", ioc->name, pdev,
6500 pci_name(pdev), device_state);
6501
6502 mpt2sas_base_free_resources(ioc);
6503 pci_save_state(pdev);
6504 pci_disable_device(pdev);
6505 pci_set_power_state(pdev, device_state);
6506 return 0;
6507}
6508
6509/**
Eric Moored5d135b2009-05-18 13:02:08 -06006510 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006511 * @pdev: PCI device struct
6512 *
6513 * Returns 0 success, anything else error.
6514 */
6515static int
Eric Moored5d135b2009-05-18 13:02:08 -06006516_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006517{
6518 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6519 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6520 u32 device_state = pdev->current_state;
6521 int r;
6522
6523 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
6524 "operating state [D%d]\n", ioc->name, pdev,
6525 pci_name(pdev), device_state);
6526
6527 pci_set_power_state(pdev, PCI_D0);
6528 pci_enable_wake(pdev, PCI_D0, 0);
6529 pci_restore_state(pdev);
6530 ioc->pdev = pdev;
6531 r = mpt2sas_base_map_resources(ioc);
6532 if (r)
6533 return r;
6534
6535 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
6536 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306537 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006538 return 0;
6539}
6540#endif /* CONFIG_PM */
6541
6542
6543static struct pci_driver scsih_driver = {
6544 .name = MPT2SAS_DRIVER_NAME,
6545 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06006546 .probe = _scsih_probe,
6547 .remove = __devexit_p(_scsih_remove),
Kashyap, Desai744090d2009-10-05 15:56:56 +05306548 .shutdown = _scsih_shutdown,
Eric Moore635374e2009-03-09 01:21:12 -06006549#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06006550 .suspend = _scsih_suspend,
6551 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06006552#endif
6553};
6554
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306555/* raid transport support */
6556static struct raid_function_template mpt2sas_raid_functions = {
6557 .cookie = &scsih_driver_template,
6558 .is_raid = _scsih_is_raid,
6559 .get_resync = _scsih_get_resync,
6560 .get_state = _scsih_get_state,
6561};
Eric Moore635374e2009-03-09 01:21:12 -06006562
6563/**
Eric Moored5d135b2009-05-18 13:02:08 -06006564 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06006565 *
6566 * Returns 0 success, anything else error.
6567 */
6568static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06006569_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06006570{
6571 int error;
6572
6573 mpt_ids = 0;
6574 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
6575 MPT2SAS_DRIVER_VERSION);
6576
6577 mpt2sas_transport_template =
6578 sas_attach_transport(&mpt2sas_transport_functions);
6579 if (!mpt2sas_transport_template)
6580 return -ENODEV;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306581 /* raid transport support */
6582 mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
6583 if (!mpt2sas_raid_template) {
6584 sas_release_transport(mpt2sas_transport_template);
6585 return -ENODEV;
6586 }
Eric Moore635374e2009-03-09 01:21:12 -06006587
6588 mpt2sas_base_initialize_callback_handler();
6589
6590 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06006591 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06006592
6593 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06006594 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06006595
6596 /* base internal commands callback handler */
6597 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
6598
6599 /* transport internal commands callback handler */
6600 transport_cb_idx = mpt2sas_base_register_callback_handler(
6601 mpt2sas_transport_done);
6602
Kashyap, Desai744090d2009-10-05 15:56:56 +05306603 /* scsih internal commands callback handler */
6604 scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
6605
Eric Moore635374e2009-03-09 01:21:12 -06006606 /* configuration page API internal commands callback handler */
6607 config_cb_idx = mpt2sas_base_register_callback_handler(
6608 mpt2sas_config_done);
6609
6610 /* ctl module callback handler */
6611 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
6612
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306613 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
6614 _scsih_tm_tr_complete);
6615 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
6616 _scsih_sas_control_complete);
6617
Eric Moore635374e2009-03-09 01:21:12 -06006618 mpt2sas_ctl_init();
6619
6620 error = pci_register_driver(&scsih_driver);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306621 if (error) {
6622 /* raid transport support */
6623 raid_class_release(mpt2sas_raid_template);
Eric Moore635374e2009-03-09 01:21:12 -06006624 sas_release_transport(mpt2sas_transport_template);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306625 }
Eric Moore635374e2009-03-09 01:21:12 -06006626
6627 return error;
6628}
6629
6630/**
Eric Moored5d135b2009-05-18 13:02:08 -06006631 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06006632 *
6633 * Returns 0 success, anything else error.
6634 */
6635static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06006636_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06006637{
6638 printk(KERN_INFO "mpt2sas version %s unloading\n",
6639 MPT2SAS_DRIVER_VERSION);
6640
6641 pci_unregister_driver(&scsih_driver);
6642
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306643 mpt2sas_ctl_exit();
6644
Eric Moore635374e2009-03-09 01:21:12 -06006645 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
6646 mpt2sas_base_release_callback_handler(tm_cb_idx);
6647 mpt2sas_base_release_callback_handler(base_cb_idx);
6648 mpt2sas_base_release_callback_handler(transport_cb_idx);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306649 mpt2sas_base_release_callback_handler(scsih_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06006650 mpt2sas_base_release_callback_handler(config_cb_idx);
6651 mpt2sas_base_release_callback_handler(ctl_cb_idx);
6652
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306653 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
6654 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
6655
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306656 /* raid transport support */
6657 raid_class_release(mpt2sas_raid_template);
6658 sas_release_transport(mpt2sas_transport_template);
6659
Eric Moore635374e2009-03-09 01:21:12 -06006660}
6661
Eric Moored5d135b2009-05-18 13:02:08 -06006662module_init(_scsih_init);
6663module_exit(_scsih_exit);