blob: efb6270cf261beeeabb8bd804c211092b478a2d9 [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>
55
56#include "mpt2sas_base.h"
57
58MODULE_AUTHOR(MPT2SAS_AUTHOR);
59MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
60MODULE_LICENSE("GPL");
61MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
62
63#define RAID_CHANNEL 1
64
65/* forward proto's */
66static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
67 struct _sas_node *sas_expander);
68static void _firmware_event_work(struct work_struct *work);
69
70/* global parameters */
Eric Mooreba33fad2009-03-15 21:37:18 -060071LIST_HEAD(mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -060072
73/* local parameters */
Eric Moore635374e2009-03-09 01:21:12 -060074static u8 scsi_io_cb_idx = -1;
75static u8 tm_cb_idx = -1;
76static u8 ctl_cb_idx = -1;
77static u8 base_cb_idx = -1;
78static u8 transport_cb_idx = -1;
79static u8 config_cb_idx = -1;
80static int mpt_ids;
81
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053082static u8 tm_tr_cb_idx = -1 ;
83static u8 tm_sas_control_cb_idx = -1;
84
Eric Moore635374e2009-03-09 01:21:12 -060085/* command line options */
Eric Mooreba33fad2009-03-15 21:37:18 -060086static u32 logging_level;
Eric Moore635374e2009-03-09 01:21:12 -060087MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
88 "(default=0)");
89
90/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
91#define MPT2SAS_MAX_LUN (16895)
92static int max_lun = MPT2SAS_MAX_LUN;
93module_param(max_lun, int, 0);
94MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
95
96/**
97 * struct sense_info - common structure for obtaining sense keys
98 * @skey: sense key
99 * @asc: additional sense code
100 * @ascq: additional sense code qualifier
101 */
102struct sense_info {
103 u8 skey;
104 u8 asc;
105 u8 ascq;
106};
107
108
Eric Moore635374e2009-03-09 01:21:12 -0600109/**
110 * struct fw_event_work - firmware event struct
111 * @list: link list framework
112 * @work: work object (ioc->fault_reset_work_q)
113 * @ioc: per adapter object
114 * @VF_ID: virtual function id
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530115 * @VP_ID: virtual port id
Eric Moore635374e2009-03-09 01:21:12 -0600116 * @host_reset_handling: handling events during host reset
117 * @ignore: flag meaning this event has been marked to ignore
118 * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
119 * @event_data: reply event data payload follows
120 *
121 * This object stored on ioc->fw_event_list.
122 */
123struct fw_event_work {
124 struct list_head list;
Eric Moore6f92a7a2009-04-21 15:43:33 -0600125 struct work_struct work;
Eric Moore635374e2009-03-09 01:21:12 -0600126 struct MPT2SAS_ADAPTER *ioc;
127 u8 VF_ID;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530128 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600129 u8 host_reset_handling;
130 u8 ignore;
131 u16 event;
132 void *event_data;
133};
134
135/**
136 * struct _scsi_io_transfer - scsi io transfer
137 * @handle: sas device handle (assigned by firmware)
138 * @is_raid: flag set for hidden raid components
139 * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
140 * @data_length: data transfer length
141 * @data_dma: dma pointer to data
142 * @sense: sense data
143 * @lun: lun number
144 * @cdb_length: cdb length
145 * @cdb: cdb contents
Eric Moore635374e2009-03-09 01:21:12 -0600146 * @timeout: timeout for this command
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530147 * @VF_ID: virtual function id
148 * @VP_ID: virtual port id
149 * @valid_reply: flag set for reply message
Eric Moore635374e2009-03-09 01:21:12 -0600150 * @sense_length: sense length
151 * @ioc_status: ioc status
152 * @scsi_state: scsi state
153 * @scsi_status: scsi staus
154 * @log_info: log information
155 * @transfer_length: data length transfer when there is a reply message
156 *
157 * Used for sending internal scsi commands to devices within this module.
158 * Refer to _scsi_send_scsi_io().
159 */
160struct _scsi_io_transfer {
161 u16 handle;
162 u8 is_raid;
163 enum dma_data_direction dir;
164 u32 data_length;
165 dma_addr_t data_dma;
166 u8 sense[SCSI_SENSE_BUFFERSIZE];
167 u32 lun;
168 u8 cdb_length;
169 u8 cdb[32];
170 u8 timeout;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530171 u8 VF_ID;
172 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600173 u8 valid_reply;
174 /* the following bits are only valid when 'valid_reply = 1' */
175 u32 sense_length;
176 u16 ioc_status;
177 u8 scsi_state;
178 u8 scsi_status;
179 u32 log_info;
180 u32 transfer_length;
181};
182
183/*
184 * The pci device ids are defined in mpi/mpi2_cnfg.h.
185 */
186static struct pci_device_id scsih_pci_table[] = {
187 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
188 PCI_ANY_ID, PCI_ANY_ID },
189 /* Falcon ~ 2008*/
190 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
191 PCI_ANY_ID, PCI_ANY_ID },
192 /* Liberator ~ 2108 */
193 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
194 PCI_ANY_ID, PCI_ANY_ID },
195 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
196 PCI_ANY_ID, PCI_ANY_ID },
197 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
198 PCI_ANY_ID, PCI_ANY_ID },
199 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
200 PCI_ANY_ID, PCI_ANY_ID },
201 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
202 PCI_ANY_ID, PCI_ANY_ID },
203 {0} /* Terminating entry */
204};
205MODULE_DEVICE_TABLE(pci, scsih_pci_table);
206
207/**
Eric Moored5d135b2009-05-18 13:02:08 -0600208 * _scsih_set_debug_level - global setting of ioc->logging_level.
Eric Moore635374e2009-03-09 01:21:12 -0600209 *
210 * Note: The logging levels are defined in mpt2sas_debug.h.
211 */
212static int
Eric Moored5d135b2009-05-18 13:02:08 -0600213_scsih_set_debug_level(const char *val, struct kernel_param *kp)
Eric Moore635374e2009-03-09 01:21:12 -0600214{
215 int ret = param_set_int(val, kp);
216 struct MPT2SAS_ADAPTER *ioc;
217
218 if (ret)
219 return ret;
220
221 printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
Eric Mooreba33fad2009-03-15 21:37:18 -0600222 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
Eric Moore635374e2009-03-09 01:21:12 -0600223 ioc->logging_level = logging_level;
224 return 0;
225}
Eric Moored5d135b2009-05-18 13:02:08 -0600226module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
Eric Moore635374e2009-03-09 01:21:12 -0600227 &logging_level, 0644);
228
229/**
230 * _scsih_srch_boot_sas_address - search based on sas_address
231 * @sas_address: sas address
232 * @boot_device: boot device object from bios page 2
233 *
234 * Returns 1 when there's a match, 0 means no match.
235 */
236static inline int
237_scsih_srch_boot_sas_address(u64 sas_address,
238 Mpi2BootDeviceSasWwid_t *boot_device)
239{
240 return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
241}
242
243/**
244 * _scsih_srch_boot_device_name - search based on device name
245 * @device_name: device name specified in INDENTIFY fram
246 * @boot_device: boot device object from bios page 2
247 *
248 * Returns 1 when there's a match, 0 means no match.
249 */
250static inline int
251_scsih_srch_boot_device_name(u64 device_name,
252 Mpi2BootDeviceDeviceName_t *boot_device)
253{
254 return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
255}
256
257/**
258 * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
259 * @enclosure_logical_id: enclosure logical id
260 * @slot_number: slot number
261 * @boot_device: boot device object from bios page 2
262 *
263 * Returns 1 when there's a match, 0 means no match.
264 */
265static inline int
266_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
267 Mpi2BootDeviceEnclosureSlot_t *boot_device)
268{
269 return (enclosure_logical_id == le64_to_cpu(boot_device->
270 EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
271 SlotNumber)) ? 1 : 0;
272}
273
274/**
275 * _scsih_is_boot_device - search for matching boot device.
276 * @sas_address: sas address
277 * @device_name: device name specified in INDENTIFY fram
278 * @enclosure_logical_id: enclosure logical id
279 * @slot_number: slot number
280 * @form: specifies boot device form
281 * @boot_device: boot device object from bios page 2
282 *
283 * Returns 1 when there's a match, 0 means no match.
284 */
285static int
286_scsih_is_boot_device(u64 sas_address, u64 device_name,
287 u64 enclosure_logical_id, u16 slot, u8 form,
288 Mpi2BiosPage2BootDevice_t *boot_device)
289{
290 int rc = 0;
291
292 switch (form) {
293 case MPI2_BIOSPAGE2_FORM_SAS_WWID:
294 if (!sas_address)
295 break;
296 rc = _scsih_srch_boot_sas_address(
297 sas_address, &boot_device->SasWwid);
298 break;
299 case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
300 if (!enclosure_logical_id)
301 break;
302 rc = _scsih_srch_boot_encl_slot(
303 enclosure_logical_id,
304 slot, &boot_device->EnclosureSlot);
305 break;
306 case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
307 if (!device_name)
308 break;
309 rc = _scsih_srch_boot_device_name(
310 device_name, &boot_device->DeviceName);
311 break;
312 case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
313 break;
314 }
315
316 return rc;
317}
318
319/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530320 * _scsih_get_sas_address - set the sas_address for given device handle
321 * @handle: device handle
322 * @sas_address: sas address
323 *
324 * Returns 0 success, non-zero when failure
325 */
326static int
327_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
328 u64 *sas_address)
329{
330 Mpi2SasDevicePage0_t sas_device_pg0;
331 Mpi2ConfigReply_t mpi_reply;
332 u32 ioc_status;
333
334 if (handle <= ioc->sas_hba.num_phys) {
335 *sas_address = ioc->sas_hba.sas_address;
336 return 0;
337 } else
338 *sas_address = 0;
339
340 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
341 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
342 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
343 ioc->name, __FILE__, __LINE__, __func__);
344 return -ENXIO;
345 }
346
347 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
348 MPI2_IOCSTATUS_MASK;
349 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
350 printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
351 "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
352 __FILE__, __LINE__, __func__);
353 return -EIO;
354 }
355
356 *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
357 return 0;
358}
359
360/**
Eric Moore635374e2009-03-09 01:21:12 -0600361 * _scsih_determine_boot_device - determine boot device.
362 * @ioc: per adapter object
363 * @device: either sas_device or raid_device object
364 * @is_raid: [flag] 1 = raid object, 0 = sas object
365 *
366 * Determines whether this device should be first reported device to
367 * to scsi-ml or sas transport, this purpose is for persistant boot device.
368 * There are primary, alternate, and current entries in bios page 2. The order
369 * priority is primary, alternate, then current. This routine saves
370 * the corresponding device object and is_raid flag in the ioc object.
371 * The saved data to be used later in _scsih_probe_boot_devices().
372 */
373static void
374_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
375 void *device, u8 is_raid)
376{
377 struct _sas_device *sas_device;
378 struct _raid_device *raid_device;
379 u64 sas_address;
380 u64 device_name;
381 u64 enclosure_logical_id;
382 u16 slot;
383
384 /* only process this function when driver loads */
385 if (!ioc->wait_for_port_enable_to_complete)
386 return;
387
388 if (!is_raid) {
389 sas_device = device;
390 sas_address = sas_device->sas_address;
391 device_name = sas_device->device_name;
392 enclosure_logical_id = sas_device->enclosure_logical_id;
393 slot = sas_device->slot;
394 } else {
395 raid_device = device;
396 sas_address = raid_device->wwid;
397 device_name = 0;
398 enclosure_logical_id = 0;
399 slot = 0;
400 }
401
402 if (!ioc->req_boot_device.device) {
403 if (_scsih_is_boot_device(sas_address, device_name,
404 enclosure_logical_id, slot,
405 (ioc->bios_pg2.ReqBootDeviceForm &
406 MPI2_BIOSPAGE2_FORM_MASK),
407 &ioc->bios_pg2.RequestedBootDevice)) {
408 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
409 "%s: req_boot_device(0x%016llx)\n",
410 ioc->name, __func__,
411 (unsigned long long)sas_address));
412 ioc->req_boot_device.device = device;
413 ioc->req_boot_device.is_raid = is_raid;
414 }
415 }
416
417 if (!ioc->req_alt_boot_device.device) {
418 if (_scsih_is_boot_device(sas_address, device_name,
419 enclosure_logical_id, slot,
420 (ioc->bios_pg2.ReqAltBootDeviceForm &
421 MPI2_BIOSPAGE2_FORM_MASK),
422 &ioc->bios_pg2.RequestedAltBootDevice)) {
423 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
424 "%s: req_alt_boot_device(0x%016llx)\n",
425 ioc->name, __func__,
426 (unsigned long long)sas_address));
427 ioc->req_alt_boot_device.device = device;
428 ioc->req_alt_boot_device.is_raid = is_raid;
429 }
430 }
431
432 if (!ioc->current_boot_device.device) {
433 if (_scsih_is_boot_device(sas_address, device_name,
434 enclosure_logical_id, slot,
435 (ioc->bios_pg2.CurrentBootDeviceForm &
436 MPI2_BIOSPAGE2_FORM_MASK),
437 &ioc->bios_pg2.CurrentBootDevice)) {
438 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
439 "%s: current_boot_device(0x%016llx)\n",
440 ioc->name, __func__,
441 (unsigned long long)sas_address));
442 ioc->current_boot_device.device = device;
443 ioc->current_boot_device.is_raid = is_raid;
444 }
445 }
446}
447
448/**
449 * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
450 * @ioc: per adapter object
451 * @sas_address: sas address
452 * Context: Calling function should acquire ioc->sas_device_lock
453 *
454 * This searches for sas_device based on sas_address, then return sas_device
455 * object.
456 */
457struct _sas_device *
458mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
459 u64 sas_address)
460{
461 struct _sas_device *sas_device, *r;
462
463 r = NULL;
464 /* check the sas_device_init_list */
465 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
466 list) {
467 if (sas_device->sas_address != sas_address)
468 continue;
469 r = sas_device;
470 goto out;
471 }
472
473 /* then check the sas_device_list */
474 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
475 if (sas_device->sas_address != sas_address)
476 continue;
477 r = sas_device;
478 goto out;
479 }
480 out:
481 return r;
482}
483
484/**
485 * _scsih_sas_device_find_by_handle - sas device search
486 * @ioc: per adapter object
487 * @handle: sas device handle (assigned by firmware)
488 * Context: Calling function should acquire ioc->sas_device_lock
489 *
490 * This searches for sas_device based on sas_address, then return sas_device
491 * object.
492 */
493static struct _sas_device *
494_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
495{
496 struct _sas_device *sas_device, *r;
497
498 r = NULL;
499 if (ioc->wait_for_port_enable_to_complete) {
500 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
501 list) {
502 if (sas_device->handle != handle)
503 continue;
504 r = sas_device;
505 goto out;
506 }
507 } else {
508 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
509 if (sas_device->handle != handle)
510 continue;
511 r = sas_device;
512 goto out;
513 }
514 }
515
516 out:
517 return r;
518}
519
520/**
521 * _scsih_sas_device_remove - remove sas_device from list.
522 * @ioc: per adapter object
523 * @sas_device: the sas_device object
524 * Context: This function will acquire ioc->sas_device_lock.
525 *
526 * Removing object and freeing associated memory from the ioc->sas_device_list.
527 */
528static void
529_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
530 struct _sas_device *sas_device)
531{
532 unsigned long flags;
533
534 spin_lock_irqsave(&ioc->sas_device_lock, flags);
535 list_del(&sas_device->list);
536 memset(sas_device, 0, sizeof(struct _sas_device));
537 kfree(sas_device);
538 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
539}
540
541/**
542 * _scsih_sas_device_add - insert sas_device to the list.
543 * @ioc: per adapter object
544 * @sas_device: the sas_device object
545 * Context: This function will acquire ioc->sas_device_lock.
546 *
547 * Adding new object to the ioc->sas_device_list.
548 */
549static void
550_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
551 struct _sas_device *sas_device)
552{
553 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -0600554
555 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
556 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
557 sas_device->handle, (unsigned long long)sas_device->sas_address));
558
559 spin_lock_irqsave(&ioc->sas_device_lock, flags);
560 list_add_tail(&sas_device->list, &ioc->sas_device_list);
561 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
562
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530563 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
564 sas_device->sas_address_parent))
Eric Moore635374e2009-03-09 01:21:12 -0600565 _scsih_sas_device_remove(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -0600566}
567
568/**
569 * _scsih_sas_device_init_add - insert sas_device to the list.
570 * @ioc: per adapter object
571 * @sas_device: the sas_device object
572 * Context: This function will acquire ioc->sas_device_lock.
573 *
574 * Adding new object at driver load time to the ioc->sas_device_init_list.
575 */
576static void
577_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
578 struct _sas_device *sas_device)
579{
580 unsigned long flags;
581
582 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
583 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
584 sas_device->handle, (unsigned long long)sas_device->sas_address));
585
586 spin_lock_irqsave(&ioc->sas_device_lock, flags);
587 list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
588 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
589 _scsih_determine_boot_device(ioc, sas_device, 0);
590}
591
592/**
Eric Moore635374e2009-03-09 01:21:12 -0600593 * _scsih_raid_device_find_by_id - raid device search
594 * @ioc: per adapter object
595 * @id: sas device target id
596 * @channel: sas device channel
597 * Context: Calling function should acquire ioc->raid_device_lock
598 *
599 * This searches for raid_device based on target id, then return raid_device
600 * object.
601 */
602static struct _raid_device *
603_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
604{
605 struct _raid_device *raid_device, *r;
606
607 r = NULL;
608 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
609 if (raid_device->id == id && raid_device->channel == channel) {
610 r = raid_device;
611 goto out;
612 }
613 }
614
615 out:
616 return r;
617}
618
619/**
620 * _scsih_raid_device_find_by_handle - raid device search
621 * @ioc: per adapter object
622 * @handle: sas device handle (assigned by firmware)
623 * Context: Calling function should acquire ioc->raid_device_lock
624 *
625 * This searches for raid_device based on handle, then return raid_device
626 * object.
627 */
628static struct _raid_device *
629_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
630{
631 struct _raid_device *raid_device, *r;
632
633 r = NULL;
634 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
635 if (raid_device->handle != handle)
636 continue;
637 r = raid_device;
638 goto out;
639 }
640
641 out:
642 return r;
643}
644
645/**
646 * _scsih_raid_device_find_by_wwid - raid device search
647 * @ioc: per adapter object
648 * @handle: sas device handle (assigned by firmware)
649 * Context: Calling function should acquire ioc->raid_device_lock
650 *
651 * This searches for raid_device based on wwid, then return raid_device
652 * object.
653 */
654static struct _raid_device *
655_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
656{
657 struct _raid_device *raid_device, *r;
658
659 r = NULL;
660 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
661 if (raid_device->wwid != wwid)
662 continue;
663 r = raid_device;
664 goto out;
665 }
666
667 out:
668 return r;
669}
670
671/**
672 * _scsih_raid_device_add - add raid_device object
673 * @ioc: per adapter object
674 * @raid_device: raid_device object
675 *
676 * This is added to the raid_device_list link list.
677 */
678static void
679_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
680 struct _raid_device *raid_device)
681{
682 unsigned long flags;
683
684 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
685 "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
686 raid_device->handle, (unsigned long long)raid_device->wwid));
687
688 spin_lock_irqsave(&ioc->raid_device_lock, flags);
689 list_add_tail(&raid_device->list, &ioc->raid_device_list);
690 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
691}
692
693/**
694 * _scsih_raid_device_remove - delete raid_device object
695 * @ioc: per adapter object
696 * @raid_device: raid_device object
697 *
698 * This is removed from the raid_device_list link list.
699 */
700static void
701_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
702 struct _raid_device *raid_device)
703{
704 unsigned long flags;
705
706 spin_lock_irqsave(&ioc->raid_device_lock, flags);
707 list_del(&raid_device->list);
708 memset(raid_device, 0, sizeof(struct _raid_device));
709 kfree(raid_device);
710 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
711}
712
713/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530714 * mpt2sas_scsih_expander_find_by_handle - expander device search
715 * @ioc: per adapter object
716 * @handle: expander handle (assigned by firmware)
717 * Context: Calling function should acquire ioc->sas_device_lock
718 *
719 * This searches for expander device based on handle, then returns the
720 * sas_node object.
721 */
722struct _sas_node *
723mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
724{
725 struct _sas_node *sas_expander, *r;
726
727 r = NULL;
728 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
729 if (sas_expander->handle != handle)
730 continue;
731 r = sas_expander;
732 goto out;
733 }
734 out:
735 return r;
736}
737
738/**
Eric Moore635374e2009-03-09 01:21:12 -0600739 * mpt2sas_scsih_expander_find_by_sas_address - expander device search
740 * @ioc: per adapter object
741 * @sas_address: sas address
742 * Context: Calling function should acquire ioc->sas_node_lock.
743 *
744 * This searches for expander device based on sas_address, then returns the
745 * sas_node object.
746 */
747struct _sas_node *
748mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
749 u64 sas_address)
750{
751 struct _sas_node *sas_expander, *r;
752
753 r = NULL;
754 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
755 if (sas_expander->sas_address != sas_address)
756 continue;
757 r = sas_expander;
758 goto out;
759 }
760 out:
761 return r;
762}
763
764/**
765 * _scsih_expander_node_add - insert expander device to the list.
766 * @ioc: per adapter object
767 * @sas_expander: the sas_device object
768 * Context: This function will acquire ioc->sas_node_lock.
769 *
770 * Adding new object to the ioc->sas_expander_list.
771 *
772 * Return nothing.
773 */
774static void
775_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
776 struct _sas_node *sas_expander)
777{
778 unsigned long flags;
779
780 spin_lock_irqsave(&ioc->sas_node_lock, flags);
781 list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
782 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
783}
784
785/**
786 * _scsih_is_end_device - determines if device is an end device
787 * @device_info: bitfield providing information about the device.
788 * Context: none
789 *
790 * Returns 1 if end device.
791 */
792static int
793_scsih_is_end_device(u32 device_info)
794{
795 if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
796 ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
797 (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
798 (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
799 return 1;
800 else
801 return 0;
802}
803
804/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530805 * mptscsih_get_scsi_lookup - returns scmd entry
Eric Moore635374e2009-03-09 01:21:12 -0600806 * @ioc: per adapter object
807 * @smid: system request message index
Eric Moore635374e2009-03-09 01:21:12 -0600808 *
809 * Returns the smid stored scmd pointer.
810 */
811static struct scsi_cmnd *
812_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
813{
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530814 return ioc->scsi_lookup[smid - 1].scmd;
Eric Moore635374e2009-03-09 01:21:12 -0600815}
816
817/**
818 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
819 * @ioc: per adapter object
820 * @smid: system request message index
821 * @scmd: pointer to scsi command object
822 * Context: This function will acquire ioc->scsi_lookup_lock.
823 *
824 * This will search for a scmd pointer in the scsi_lookup array,
825 * returning the revelent smid. A returned value of zero means invalid.
826 */
827static u16
828_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
829 *scmd)
830{
831 u16 smid;
832 unsigned long flags;
833 int i;
834
835 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
836 smid = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530837 for (i = 0; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600838 if (ioc->scsi_lookup[i].scmd == scmd) {
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530839 smid = ioc->scsi_lookup[i].smid;
Eric Moore635374e2009-03-09 01:21:12 -0600840 goto out;
841 }
842 }
843 out:
844 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
845 return smid;
846}
847
848/**
849 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
850 * @ioc: per adapter object
851 * @id: target id
852 * @channel: channel
853 * Context: This function will acquire ioc->scsi_lookup_lock.
854 *
855 * This will search for a matching channel:id in the scsi_lookup array,
856 * returning 1 if found.
857 */
858static u8
859_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
860 int channel)
861{
862 u8 found;
863 unsigned long flags;
864 int i;
865
866 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
867 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530868 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600869 if (ioc->scsi_lookup[i].scmd &&
870 (ioc->scsi_lookup[i].scmd->device->id == id &&
871 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
872 found = 1;
873 goto out;
874 }
875 }
876 out:
877 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
878 return found;
879}
880
881/**
Eric Moore993e0da2009-05-18 13:00:45 -0600882 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
883 * @ioc: per adapter object
884 * @id: target id
885 * @lun: lun number
886 * @channel: channel
887 * Context: This function will acquire ioc->scsi_lookup_lock.
888 *
889 * This will search for a matching channel:id:lun in the scsi_lookup array,
890 * returning 1 if found.
891 */
892static u8
893_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
894 unsigned int lun, int channel)
895{
896 u8 found;
897 unsigned long flags;
898 int i;
899
900 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
901 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530902 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore993e0da2009-05-18 13:00:45 -0600903 if (ioc->scsi_lookup[i].scmd &&
904 (ioc->scsi_lookup[i].scmd->device->id == id &&
905 ioc->scsi_lookup[i].scmd->device->channel == channel &&
906 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
907 found = 1;
908 goto out;
909 }
910 }
911 out:
912 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
913 return found;
914}
915
916/**
Eric Moore635374e2009-03-09 01:21:12 -0600917 * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
918 * @ioc: per adapter object
919 * @smid: system request message index
920 *
921 * Returns phys pointer to chain buffer.
922 */
923static dma_addr_t
924_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
925{
926 return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
927 ioc->chains_needed_per_io));
928}
929
930/**
931 * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
932 * @ioc: per adapter object
933 * @smid: system request message index
934 *
935 * Returns virt pointer to chain buffer.
936 */
937static void *
938_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
939{
940 return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
941 ioc->chains_needed_per_io)));
942}
943
944/**
945 * _scsih_build_scatter_gather - main sg creation routine
946 * @ioc: per adapter object
947 * @scmd: scsi command
948 * @smid: system request message index
949 * Context: none.
950 *
951 * The main routine that builds scatter gather table from a given
952 * scsi request sent via the .queuecommand main handler.
953 *
954 * Returns 0 success, anything else error
955 */
956static int
957_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
958 struct scsi_cmnd *scmd, u16 smid)
959{
960 Mpi2SCSIIORequest_t *mpi_request;
961 dma_addr_t chain_dma;
962 struct scatterlist *sg_scmd;
963 void *sg_local, *chain;
964 u32 chain_offset;
965 u32 chain_length;
966 u32 chain_flags;
967 u32 sges_left;
968 u32 sges_in_segment;
969 u32 sgl_flags;
970 u32 sgl_flags_last_element;
971 u32 sgl_flags_end_buffer;
972
973 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
974
975 /* init scatter gather flags */
976 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
977 if (scmd->sc_data_direction == DMA_TO_DEVICE)
978 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
979 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
980 << MPI2_SGE_FLAGS_SHIFT;
981 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
982 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
983 << MPI2_SGE_FLAGS_SHIFT;
984 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
985
986 sg_scmd = scsi_sglist(scmd);
987 sges_left = scsi_dma_map(scmd);
988 if (!sges_left) {
989 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
990 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
991 return -ENOMEM;
992 }
993
994 sg_local = &mpi_request->SGL;
995 sges_in_segment = ioc->max_sges_in_main_message;
996 if (sges_left <= sges_in_segment)
997 goto fill_in_last_segment;
998
999 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
1000 (sges_in_segment * ioc->sge_size))/4;
1001
1002 /* fill in main message segment when there is a chain following */
1003 while (sges_in_segment) {
1004 if (sges_in_segment == 1)
1005 ioc->base_add_sg_single(sg_local,
1006 sgl_flags_last_element | sg_dma_len(sg_scmd),
1007 sg_dma_address(sg_scmd));
1008 else
1009 ioc->base_add_sg_single(sg_local, sgl_flags |
1010 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1011 sg_scmd = sg_next(sg_scmd);
1012 sg_local += ioc->sge_size;
1013 sges_left--;
1014 sges_in_segment--;
1015 }
1016
1017 /* initializing the chain flags and pointers */
1018 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
1019 chain = _scsih_get_chain_buffer(ioc, smid);
1020 chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
1021 do {
1022 sges_in_segment = (sges_left <=
1023 ioc->max_sges_in_chain_message) ? sges_left :
1024 ioc->max_sges_in_chain_message;
1025 chain_offset = (sges_left == sges_in_segment) ?
1026 0 : (sges_in_segment * ioc->sge_size)/4;
1027 chain_length = sges_in_segment * ioc->sge_size;
1028 if (chain_offset) {
1029 chain_offset = chain_offset <<
1030 MPI2_SGE_CHAIN_OFFSET_SHIFT;
1031 chain_length += ioc->sge_size;
1032 }
1033 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
1034 chain_length, chain_dma);
1035 sg_local = chain;
1036 if (!chain_offset)
1037 goto fill_in_last_segment;
1038
1039 /* fill in chain segments */
1040 while (sges_in_segment) {
1041 if (sges_in_segment == 1)
1042 ioc->base_add_sg_single(sg_local,
1043 sgl_flags_last_element |
1044 sg_dma_len(sg_scmd),
1045 sg_dma_address(sg_scmd));
1046 else
1047 ioc->base_add_sg_single(sg_local, sgl_flags |
1048 sg_dma_len(sg_scmd),
1049 sg_dma_address(sg_scmd));
1050 sg_scmd = sg_next(sg_scmd);
1051 sg_local += ioc->sge_size;
1052 sges_left--;
1053 sges_in_segment--;
1054 }
1055
1056 chain_dma += ioc->request_sz;
1057 chain += ioc->request_sz;
1058 } while (1);
1059
1060
1061 fill_in_last_segment:
1062
1063 /* fill the last segment */
1064 while (sges_left) {
1065 if (sges_left == 1)
1066 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1067 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1068 else
1069 ioc->base_add_sg_single(sg_local, sgl_flags |
1070 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1071 sg_scmd = sg_next(sg_scmd);
1072 sg_local += ioc->sge_size;
1073 sges_left--;
1074 }
1075
1076 return 0;
1077}
1078
1079/**
Eric Moored5d135b2009-05-18 13:02:08 -06001080 * _scsih_change_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001081 * @sdev: scsi device struct
1082 * @qdepth: requested queue depth
1083 *
1084 * Returns queue depth.
1085 */
1086static int
Eric Moored5d135b2009-05-18 13:02:08 -06001087_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Eric Moore635374e2009-03-09 01:21:12 -06001088{
1089 struct Scsi_Host *shost = sdev->host;
1090 int max_depth;
1091 int tag_type;
1092
1093 max_depth = shost->can_queue;
1094 if (!sdev->tagged_supported)
1095 max_depth = 1;
1096 if (qdepth > max_depth)
1097 qdepth = max_depth;
1098 tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
1099 scsi_adjust_queue_depth(sdev, tag_type, qdepth);
1100
1101 if (sdev->inquiry_len > 7)
1102 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1103 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1104 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1105 sdev->ordered_tags, sdev->scsi_level,
1106 (sdev->inquiry[7] & 2) >> 1);
1107
1108 return sdev->queue_depth;
1109}
1110
1111/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301112 * _scsih_change_queue_type - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001113 * @sdev: scsi device struct
1114 * @tag_type: requested tag type
1115 *
1116 * Returns queue tag type.
1117 */
1118static int
Eric Moored5d135b2009-05-18 13:02:08 -06001119_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001120{
1121 if (sdev->tagged_supported) {
1122 scsi_set_tag_type(sdev, tag_type);
1123 if (tag_type)
1124 scsi_activate_tcq(sdev, sdev->queue_depth);
1125 else
1126 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1127 } else
1128 tag_type = 0;
1129
1130 return tag_type;
1131}
1132
1133/**
Eric Moored5d135b2009-05-18 13:02:08 -06001134 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001135 * @starget: scsi target struct
1136 *
1137 * Returns 0 if ok. Any other return is assumed to be an error and
1138 * the device is ignored.
1139 */
1140static int
Eric Moored5d135b2009-05-18 13:02:08 -06001141_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001142{
1143 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1144 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1145 struct MPT2SAS_TARGET *sas_target_priv_data;
1146 struct _sas_device *sas_device;
1147 struct _raid_device *raid_device;
1148 unsigned long flags;
1149 struct sas_rphy *rphy;
1150
1151 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1152 if (!sas_target_priv_data)
1153 return -ENOMEM;
1154
1155 starget->hostdata = sas_target_priv_data;
1156 sas_target_priv_data->starget = starget;
1157 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1158
1159 /* RAID volumes */
1160 if (starget->channel == RAID_CHANNEL) {
1161 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1162 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1163 starget->channel);
1164 if (raid_device) {
1165 sas_target_priv_data->handle = raid_device->handle;
1166 sas_target_priv_data->sas_address = raid_device->wwid;
1167 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
1168 raid_device->starget = starget;
1169 }
1170 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1171 return 0;
1172 }
1173
1174 /* sas/sata devices */
1175 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1176 rphy = dev_to_rphy(starget->dev.parent);
1177 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1178 rphy->identify.sas_address);
1179
1180 if (sas_device) {
1181 sas_target_priv_data->handle = sas_device->handle;
1182 sas_target_priv_data->sas_address = sas_device->sas_address;
1183 sas_device->starget = starget;
1184 sas_device->id = starget->id;
1185 sas_device->channel = starget->channel;
1186 if (sas_device->hidden_raid_component)
1187 sas_target_priv_data->flags |=
1188 MPT_TARGET_FLAGS_RAID_COMPONENT;
1189 }
1190 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1191
1192 return 0;
1193}
1194
1195/**
Eric Moored5d135b2009-05-18 13:02:08 -06001196 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001197 * @starget: scsi target struct
1198 *
1199 * Returns nothing.
1200 */
1201static void
Eric Moored5d135b2009-05-18 13:02:08 -06001202_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001203{
1204 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1205 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1206 struct MPT2SAS_TARGET *sas_target_priv_data;
1207 struct _sas_device *sas_device;
1208 struct _raid_device *raid_device;
1209 unsigned long flags;
1210 struct sas_rphy *rphy;
1211
1212 sas_target_priv_data = starget->hostdata;
1213 if (!sas_target_priv_data)
1214 return;
1215
1216 if (starget->channel == RAID_CHANNEL) {
1217 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1218 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1219 starget->channel);
1220 if (raid_device) {
1221 raid_device->starget = NULL;
1222 raid_device->sdev = NULL;
1223 }
1224 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1225 goto out;
1226 }
1227
1228 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1229 rphy = dev_to_rphy(starget->dev.parent);
1230 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1231 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001232 if (sas_device && (sas_device->starget == starget) &&
1233 (sas_device->id == starget->id) &&
1234 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001235 sas_device->starget = NULL;
1236
1237 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1238
1239 out:
1240 kfree(sas_target_priv_data);
1241 starget->hostdata = NULL;
1242}
1243
1244/**
Eric Moored5d135b2009-05-18 13:02:08 -06001245 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001246 * @sdev: scsi device struct
1247 *
1248 * Returns 0 if ok. Any other return is assumed to be an error and
1249 * the device is ignored.
1250 */
1251static int
Eric Moored5d135b2009-05-18 13:02:08 -06001252_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001253{
1254 struct Scsi_Host *shost;
1255 struct MPT2SAS_ADAPTER *ioc;
1256 struct MPT2SAS_TARGET *sas_target_priv_data;
1257 struct MPT2SAS_DEVICE *sas_device_priv_data;
1258 struct scsi_target *starget;
1259 struct _raid_device *raid_device;
1260 struct _sas_device *sas_device;
1261 unsigned long flags;
1262
1263 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1264 if (!sas_device_priv_data)
1265 return -ENOMEM;
1266
1267 sas_device_priv_data->lun = sdev->lun;
1268 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1269
1270 starget = scsi_target(sdev);
1271 sas_target_priv_data = starget->hostdata;
1272 sas_target_priv_data->num_luns++;
1273 sas_device_priv_data->sas_target = sas_target_priv_data;
1274 sdev->hostdata = sas_device_priv_data;
1275 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1276 sdev->no_uld_attach = 1;
1277
1278 shost = dev_to_shost(&starget->dev);
1279 ioc = shost_priv(shost);
1280 if (starget->channel == RAID_CHANNEL) {
1281 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1282 raid_device = _scsih_raid_device_find_by_id(ioc,
1283 starget->id, starget->channel);
1284 if (raid_device)
1285 raid_device->sdev = sdev; /* raid is single lun */
1286 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1287 } else {
1288 /* set TLR bit for SSP devices */
1289 if (!(ioc->facts.IOCCapabilities &
1290 MPI2_IOCFACTS_CAPABILITY_TLR))
1291 goto out;
1292 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1293 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1294 sas_device_priv_data->sas_target->sas_address);
1295 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1296 if (sas_device && sas_device->device_info &
1297 MPI2_SAS_DEVICE_INFO_SSP_TARGET)
1298 sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON;
1299 }
1300
1301 out:
1302 return 0;
1303}
1304
1305/**
Eric Moored5d135b2009-05-18 13:02:08 -06001306 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001307 * @sdev: scsi device struct
1308 *
1309 * Returns nothing.
1310 */
1311static void
Eric Moored5d135b2009-05-18 13:02:08 -06001312_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001313{
1314 struct MPT2SAS_TARGET *sas_target_priv_data;
1315 struct scsi_target *starget;
1316
1317 if (!sdev->hostdata)
1318 return;
1319
1320 starget = scsi_target(sdev);
1321 sas_target_priv_data = starget->hostdata;
1322 sas_target_priv_data->num_luns--;
1323 kfree(sdev->hostdata);
1324 sdev->hostdata = NULL;
1325}
1326
1327/**
Eric Moored5d135b2009-05-18 13:02:08 -06001328 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001329 * @ioc: per adapter object
1330 * @sas_device: the sas_device object
1331 * @sdev: scsi device struct
1332 */
1333static void
Eric Moored5d135b2009-05-18 13:02:08 -06001334_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06001335 struct _sas_device *sas_device, struct scsi_device *sdev)
1336{
1337 Mpi2ConfigReply_t mpi_reply;
1338 Mpi2SasDevicePage0_t sas_device_pg0;
1339 u32 ioc_status;
1340 u16 flags;
1341 u32 device_info;
1342
1343 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
1344 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
1345 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1346 ioc->name, __FILE__, __LINE__, __func__);
1347 return;
1348 }
1349
1350 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1351 MPI2_IOCSTATUS_MASK;
1352 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1353 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1354 ioc->name, __FILE__, __LINE__, __func__);
1355 return;
1356 }
1357
1358 flags = le16_to_cpu(sas_device_pg0.Flags);
1359 device_info = le16_to_cpu(sas_device_pg0.DeviceInfo);
1360
1361 sdev_printk(KERN_INFO, sdev,
1362 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1363 "sw_preserve(%s)\n",
1364 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1365 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1366 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1367 "n",
1368 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1369 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1370 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1371}
1372
1373/**
1374 * _scsih_get_volume_capabilities - volume capabilities
1375 * @ioc: per adapter object
1376 * @sas_device: the raid_device object
1377 */
1378static void
1379_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1380 struct _raid_device *raid_device)
1381{
1382 Mpi2RaidVolPage0_t *vol_pg0;
1383 Mpi2RaidPhysDiskPage0_t pd_pg0;
1384 Mpi2SasDevicePage0_t sas_device_pg0;
1385 Mpi2ConfigReply_t mpi_reply;
1386 u16 sz;
1387 u8 num_pds;
1388
1389 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1390 &num_pds)) || !num_pds) {
1391 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1392 ioc->name, __FILE__, __LINE__, __func__);
1393 return;
1394 }
1395
1396 raid_device->num_pds = num_pds;
1397 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1398 sizeof(Mpi2RaidVol0PhysDisk_t));
1399 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1400 if (!vol_pg0) {
1401 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1402 ioc->name, __FILE__, __LINE__, __func__);
1403 return;
1404 }
1405
1406 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1407 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1408 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1409 ioc->name, __FILE__, __LINE__, __func__);
1410 kfree(vol_pg0);
1411 return;
1412 }
1413
1414 raid_device->volume_type = vol_pg0->VolumeType;
1415
1416 /* figure out what the underlying devices are by
1417 * obtaining the device_info bits for the 1st device
1418 */
1419 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1420 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1421 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1422 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1423 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1424 le16_to_cpu(pd_pg0.DevHandle)))) {
1425 raid_device->device_info =
1426 le32_to_cpu(sas_device_pg0.DeviceInfo);
1427 }
1428 }
1429
1430 kfree(vol_pg0);
1431}
1432
1433/**
Eric Moored5d135b2009-05-18 13:02:08 -06001434 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001435 * @sdev: scsi device struct
1436 *
1437 * Returns 0 if ok. Any other return is assumed to be an error and
1438 * the device is ignored.
1439 */
1440static int
Eric Moored5d135b2009-05-18 13:02:08 -06001441_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001442{
1443 struct Scsi_Host *shost = sdev->host;
1444 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1445 struct MPT2SAS_DEVICE *sas_device_priv_data;
1446 struct MPT2SAS_TARGET *sas_target_priv_data;
1447 struct _sas_device *sas_device;
1448 struct _raid_device *raid_device;
1449 unsigned long flags;
1450 int qdepth;
1451 u8 ssp_target = 0;
1452 char *ds = "";
1453 char *r_level = "";
1454
1455 qdepth = 1;
1456 sas_device_priv_data = sdev->hostdata;
1457 sas_device_priv_data->configured_lun = 1;
1458 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1459 sas_target_priv_data = sas_device_priv_data->sas_target;
1460
1461 /* raid volume handling */
1462 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1463
1464 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1465 raid_device = _scsih_raid_device_find_by_handle(ioc,
1466 sas_target_priv_data->handle);
1467 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1468 if (!raid_device) {
1469 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1470 ioc->name, __FILE__, __LINE__, __func__);
1471 return 0;
1472 }
1473
1474 _scsih_get_volume_capabilities(ioc, raid_device);
1475
1476 /* RAID Queue Depth Support
1477 * IS volume = underlying qdepth of drive type, either
1478 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
1479 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
1480 */
1481 if (raid_device->device_info &
1482 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1483 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1484 ds = "SSP";
1485 } else {
1486 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1487 if (raid_device->device_info &
1488 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1489 ds = "SATA";
1490 else
1491 ds = "STP";
1492 }
1493
1494 switch (raid_device->volume_type) {
1495 case MPI2_RAID_VOL_TYPE_RAID0:
1496 r_level = "RAID0";
1497 break;
1498 case MPI2_RAID_VOL_TYPE_RAID1E:
1499 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05301500 if (ioc->manu_pg10.OEMIdentifier &&
1501 (ioc->manu_pg10.GenericFlags0 &
1502 MFG10_GF0_R10_DISPLAY) &&
1503 !(raid_device->num_pds % 2))
1504 r_level = "RAID10";
1505 else
1506 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06001507 break;
1508 case MPI2_RAID_VOL_TYPE_RAID1:
1509 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1510 r_level = "RAID1";
1511 break;
1512 case MPI2_RAID_VOL_TYPE_RAID10:
1513 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1514 r_level = "RAID10";
1515 break;
1516 case MPI2_RAID_VOL_TYPE_UNKNOWN:
1517 default:
1518 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1519 r_level = "RAIDX";
1520 break;
1521 }
1522
1523 sdev_printk(KERN_INFO, sdev, "%s: "
1524 "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
1525 r_level, raid_device->handle,
1526 (unsigned long long)raid_device->wwid,
1527 raid_device->num_pds, ds);
Eric Moored5d135b2009-05-18 13:02:08 -06001528 _scsih_change_queue_depth(sdev, qdepth);
Eric Moore635374e2009-03-09 01:21:12 -06001529 return 0;
1530 }
1531
1532 /* non-raid handling */
1533 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1534 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1535 sas_device_priv_data->sas_target->sas_address);
1536 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1537 if (sas_device) {
1538 if (sas_target_priv_data->flags &
1539 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1540 mpt2sas_config_get_volume_handle(ioc,
1541 sas_device->handle, &sas_device->volume_handle);
1542 mpt2sas_config_get_volume_wwid(ioc,
1543 sas_device->volume_handle,
1544 &sas_device->volume_wwid);
1545 }
1546 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1547 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1548 ssp_target = 1;
1549 ds = "SSP";
1550 } else {
1551 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1552 if (sas_device->device_info &
1553 MPI2_SAS_DEVICE_INFO_STP_TARGET)
1554 ds = "STP";
1555 else if (sas_device->device_info &
1556 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1557 ds = "SATA";
1558 }
1559
1560 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
1561 "sas_addr(0x%016llx), device_name(0x%016llx)\n",
1562 ds, sas_device->handle,
1563 (unsigned long long)sas_device->sas_address,
1564 (unsigned long long)sas_device->device_name);
1565 sdev_printk(KERN_INFO, sdev, "%s: "
1566 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
1567 (unsigned long long) sas_device->enclosure_logical_id,
1568 sas_device->slot);
1569
1570 if (!ssp_target)
Eric Moored5d135b2009-05-18 13:02:08 -06001571 _scsih_display_sata_capabilities(ioc, sas_device, sdev);
Eric Moore635374e2009-03-09 01:21:12 -06001572 }
1573
Eric Moored5d135b2009-05-18 13:02:08 -06001574 _scsih_change_queue_depth(sdev, qdepth);
Eric Moore635374e2009-03-09 01:21:12 -06001575
1576 if (ssp_target)
1577 sas_read_port_mode_page(sdev);
1578 return 0;
1579}
1580
1581/**
Eric Moored5d135b2009-05-18 13:02:08 -06001582 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06001583 * @sdev: scsi device struct
1584 * @bdev: pointer to block device context
1585 * @capacity: device size (in 512 byte sectors)
1586 * @params: three element array to place output:
1587 * params[0] number of heads (max 255)
1588 * params[1] number of sectors (max 63)
1589 * params[2] number of cylinders
1590 *
1591 * Return nothing.
1592 */
1593static int
Eric Moored5d135b2009-05-18 13:02:08 -06001594_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06001595 sector_t capacity, int params[])
1596{
1597 int heads;
1598 int sectors;
1599 sector_t cylinders;
1600 ulong dummy;
1601
1602 heads = 64;
1603 sectors = 32;
1604
1605 dummy = heads * sectors;
1606 cylinders = capacity;
1607 sector_div(cylinders, dummy);
1608
1609 /*
1610 * Handle extended translation size for logical drives
1611 * > 1Gb
1612 */
1613 if ((ulong)capacity >= 0x200000) {
1614 heads = 255;
1615 sectors = 63;
1616 dummy = heads * sectors;
1617 cylinders = capacity;
1618 sector_div(cylinders, dummy);
1619 }
1620
1621 /* return result */
1622 params[0] = heads;
1623 params[1] = sectors;
1624 params[2] = cylinders;
1625
1626 return 0;
1627}
1628
1629/**
1630 * _scsih_response_code - translation of device response code
1631 * @ioc: per adapter object
1632 * @response_code: response code returned by the device
1633 *
1634 * Return nothing.
1635 */
1636static void
1637_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
1638{
1639 char *desc;
1640
1641 switch (response_code) {
1642 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1643 desc = "task management request completed";
1644 break;
1645 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1646 desc = "invalid frame";
1647 break;
1648 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1649 desc = "task management request not supported";
1650 break;
1651 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1652 desc = "task management request failed";
1653 break;
1654 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1655 desc = "task management request succeeded";
1656 break;
1657 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1658 desc = "invalid lun";
1659 break;
1660 case 0xA:
1661 desc = "overlapped tag attempted";
1662 break;
1663 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1664 desc = "task queued, however not sent to target";
1665 break;
1666 default:
1667 desc = "unknown";
1668 break;
1669 }
1670 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
1671 ioc->name, response_code, desc);
1672}
1673
1674/**
Eric Moored5d135b2009-05-18 13:02:08 -06001675 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06001676 * @ioc: per adapter object
1677 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301678 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001679 * @reply: reply message frame(lower 32bit addr)
1680 * Context: none.
1681 *
1682 * The callback handler when using scsih_issue_tm.
1683 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301684 * Return 1 meaning mf should be freed from _base_interrupt
1685 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06001686 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301687static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301688_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06001689{
1690 MPI2DefaultReply_t *mpi_reply;
1691
1692 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301693 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001694 if (ioc->tm_cmds.smid != smid)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301695 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001696 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
1697 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
1698 if (mpi_reply) {
1699 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
1700 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
1701 }
1702 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
1703 complete(&ioc->tm_cmds.done);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301704 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001705}
1706
1707/**
1708 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
1709 * @ioc: per adapter object
1710 * @handle: device handle
1711 *
1712 * During taskmangement request, we need to freeze the device queue.
1713 */
1714void
1715mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1716{
1717 struct MPT2SAS_DEVICE *sas_device_priv_data;
1718 struct scsi_device *sdev;
1719 u8 skip = 0;
1720
1721 shost_for_each_device(sdev, ioc->shost) {
1722 if (skip)
1723 continue;
1724 sas_device_priv_data = sdev->hostdata;
1725 if (!sas_device_priv_data)
1726 continue;
1727 if (sas_device_priv_data->sas_target->handle == handle) {
1728 sas_device_priv_data->sas_target->tm_busy = 1;
1729 skip = 1;
1730 ioc->ignore_loginfos = 1;
1731 }
1732 }
1733}
1734
1735/**
1736 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
1737 * @ioc: per adapter object
1738 * @handle: device handle
1739 *
1740 * During taskmangement request, we need to freeze the device queue.
1741 */
1742void
1743mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1744{
1745 struct MPT2SAS_DEVICE *sas_device_priv_data;
1746 struct scsi_device *sdev;
1747 u8 skip = 0;
1748
1749 shost_for_each_device(sdev, ioc->shost) {
1750 if (skip)
1751 continue;
1752 sas_device_priv_data = sdev->hostdata;
1753 if (!sas_device_priv_data)
1754 continue;
1755 if (sas_device_priv_data->sas_target->handle == handle) {
1756 sas_device_priv_data->sas_target->tm_busy = 0;
1757 skip = 1;
1758 ioc->ignore_loginfos = 0;
1759 }
1760 }
1761}
1762
1763/**
1764 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
1765 * @ioc: per adapter struct
1766 * @device_handle: device handle
1767 * @lun: lun number
1768 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
1769 * @smid_task: smid assigned to the task
1770 * @timeout: timeout in seconds
1771 * Context: The calling function needs to acquire the tm_cmds.mutex
1772 *
1773 * A generic API for sending task management requests to firmware.
1774 *
1775 * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling
1776 * this API.
1777 *
1778 * The callback index is set inside `ioc->tm_cb_idx`.
1779 *
1780 * Return nothing.
1781 */
1782void
1783mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
1784 u8 type, u16 smid_task, ulong timeout)
1785{
1786 Mpi2SCSITaskManagementRequest_t *mpi_request;
1787 Mpi2SCSITaskManagementReply_t *mpi_reply;
1788 u16 smid = 0;
1789 u32 ioc_state;
1790 unsigned long timeleft;
Eric Moore635374e2009-03-09 01:21:12 -06001791
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301792 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
1793 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
1794 __func__, ioc->name);
1795 return;
1796 }
1797
1798 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06001799 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1800 __func__, ioc->name);
1801 return;
1802 }
Eric Moore635374e2009-03-09 01:21:12 -06001803
1804 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
1805 if (ioc_state & MPI2_DOORBELL_USED) {
1806 dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
1807 "active!\n", ioc->name));
1808 goto issue_host_reset;
1809 }
1810
1811 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
1812 mpt2sas_base_fault_info(ioc, ioc_state &
1813 MPI2_DOORBELL_DATA_MASK);
1814 goto issue_host_reset;
1815 }
1816
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301817 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06001818 if (!smid) {
1819 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1820 ioc->name, __func__);
1821 return;
1822 }
1823
1824 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301825 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
1826 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06001827 ioc->tm_cmds.status = MPT2_CMD_PENDING;
1828 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1829 ioc->tm_cmds.smid = smid;
1830 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
1831 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1832 mpi_request->DevHandle = cpu_to_le16(handle);
1833 mpi_request->TaskType = type;
1834 mpi_request->TaskMID = cpu_to_le16(smid_task);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301835 mpi_request->VP_ID = 0; /* TODO */
1836 mpi_request->VF_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06001837 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
1838 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05301839 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301840 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06001841 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
1842 mpt2sas_scsih_clear_tm_flag(ioc, handle);
1843 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
1844 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
1845 ioc->name, __func__);
1846 _debug_dump_mf(mpi_request,
1847 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
1848 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET))
1849 goto issue_host_reset;
1850 }
1851
1852 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
1853 mpi_reply = ioc->tm_cmds.reply;
1854 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
1855 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
1856 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
1857 le32_to_cpu(mpi_reply->IOCLogInfo),
1858 le32_to_cpu(mpi_reply->TerminationCount)));
1859 if (ioc->logging_level & MPT_DEBUG_TM)
1860 _scsih_response_code(ioc, mpi_reply->ResponseCode);
1861 }
1862 return;
1863 issue_host_reset:
1864 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
1865}
1866
1867/**
Eric Moored5d135b2009-05-18 13:02:08 -06001868 * _scsih_abort - eh threads main abort routine
Eric Moore635374e2009-03-09 01:21:12 -06001869 * @sdev: scsi device struct
1870 *
1871 * Returns SUCCESS if command aborted else FAILED
1872 */
1873static int
Eric Moored5d135b2009-05-18 13:02:08 -06001874_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001875{
1876 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1877 struct MPT2SAS_DEVICE *sas_device_priv_data;
1878 u16 smid;
1879 u16 handle;
1880 int r;
1881 struct scsi_cmnd *scmd_lookup;
1882
1883 printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
1884 ioc->name, scmd);
1885 scsi_print_command(scmd);
1886
1887 sas_device_priv_data = scmd->device->hostdata;
1888 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1889 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
1890 ioc->name, scmd);
1891 scmd->result = DID_NO_CONNECT << 16;
1892 scmd->scsi_done(scmd);
1893 r = SUCCESS;
1894 goto out;
1895 }
1896
1897 /* search for the command */
1898 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
1899 if (!smid) {
1900 scmd->result = DID_RESET << 16;
1901 r = SUCCESS;
1902 goto out;
1903 }
1904
1905 /* for hidden raid components and volumes this is not supported */
1906 if (sas_device_priv_data->sas_target->flags &
1907 MPT_TARGET_FLAGS_RAID_COMPONENT ||
1908 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
1909 scmd->result = DID_RESET << 16;
1910 r = FAILED;
1911 goto out;
1912 }
1913
1914 mutex_lock(&ioc->tm_cmds.mutex);
1915 handle = sas_device_priv_data->sas_target->handle;
1916 mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
1917 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30);
1918
1919 /* sanity check - see whether command actually completed */
1920 scmd_lookup = _scsih_scsi_lookup_get(ioc, smid);
1921 if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number))
1922 r = FAILED;
1923 else
1924 r = SUCCESS;
1925 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
1926 mutex_unlock(&ioc->tm_cmds.mutex);
1927
1928 out:
1929 printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
1930 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
1931 return r;
1932}
1933
Eric Moore635374e2009-03-09 01:21:12 -06001934/**
Eric Moored5d135b2009-05-18 13:02:08 -06001935 * _scsih_dev_reset - eh threads main device reset routine
Eric Moore635374e2009-03-09 01:21:12 -06001936 * @sdev: scsi device struct
1937 *
1938 * Returns SUCCESS if command aborted else FAILED
1939 */
1940static int
Eric Moored5d135b2009-05-18 13:02:08 -06001941_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001942{
1943 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1944 struct MPT2SAS_DEVICE *sas_device_priv_data;
1945 struct _sas_device *sas_device;
1946 unsigned long flags;
1947 u16 handle;
1948 int r;
1949
Eric Moore993e0da2009-05-18 13:00:45 -06001950 printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
Eric Moore635374e2009-03-09 01:21:12 -06001951 ioc->name, scmd);
1952 scsi_print_command(scmd);
1953
1954 sas_device_priv_data = scmd->device->hostdata;
1955 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1956 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
1957 ioc->name, scmd);
1958 scmd->result = DID_NO_CONNECT << 16;
1959 scmd->scsi_done(scmd);
1960 r = SUCCESS;
1961 goto out;
1962 }
1963
1964 /* for hidden raid components obtain the volume_handle */
1965 handle = 0;
1966 if (sas_device_priv_data->sas_target->flags &
1967 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1968 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1969 sas_device = _scsih_sas_device_find_by_handle(ioc,
1970 sas_device_priv_data->sas_target->handle);
1971 if (sas_device)
1972 handle = sas_device->volume_handle;
1973 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1974 } else
1975 handle = sas_device_priv_data->sas_target->handle;
1976
1977 if (!handle) {
1978 scmd->result = DID_RESET << 16;
1979 r = FAILED;
1980 goto out;
1981 }
1982
1983 mutex_lock(&ioc->tm_cmds.mutex);
1984 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore993e0da2009-05-18 13:00:45 -06001985 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun,
1986 30);
1987
1988 /*
1989 * sanity check see whether all commands to this device been
1990 * completed
1991 */
1992 if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id,
1993 scmd->device->lun, scmd->device->channel))
1994 r = FAILED;
1995 else
1996 r = SUCCESS;
1997 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
1998 mutex_unlock(&ioc->tm_cmds.mutex);
1999
2000 out:
2001 printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
2002 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2003 return r;
2004}
2005
2006/**
Eric Moored5d135b2009-05-18 13:02:08 -06002007 * _scsih_target_reset - eh threads main target reset routine
Eric Moore993e0da2009-05-18 13:00:45 -06002008 * @sdev: scsi device struct
2009 *
2010 * Returns SUCCESS if command aborted else FAILED
2011 */
2012static int
Eric Moored5d135b2009-05-18 13:02:08 -06002013_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06002014{
2015 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2016 struct MPT2SAS_DEVICE *sas_device_priv_data;
2017 struct _sas_device *sas_device;
2018 unsigned long flags;
2019 u16 handle;
2020 int r;
2021
2022 printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
2023 ioc->name, scmd);
2024 scsi_print_command(scmd);
2025
2026 sas_device_priv_data = scmd->device->hostdata;
2027 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2028 printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
2029 ioc->name, scmd);
2030 scmd->result = DID_NO_CONNECT << 16;
2031 scmd->scsi_done(scmd);
2032 r = SUCCESS;
2033 goto out;
2034 }
2035
2036 /* for hidden raid components obtain the volume_handle */
2037 handle = 0;
2038 if (sas_device_priv_data->sas_target->flags &
2039 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2040 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2041 sas_device = _scsih_sas_device_find_by_handle(ioc,
2042 sas_device_priv_data->sas_target->handle);
2043 if (sas_device)
2044 handle = sas_device->volume_handle;
2045 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2046 } else
2047 handle = sas_device_priv_data->sas_target->handle;
2048
2049 if (!handle) {
2050 scmd->result = DID_RESET << 16;
2051 r = FAILED;
2052 goto out;
2053 }
2054
2055 mutex_lock(&ioc->tm_cmds.mutex);
2056 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore635374e2009-03-09 01:21:12 -06002057 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30);
2058
2059 /*
2060 * sanity check see whether all commands to this target been
2061 * completed
2062 */
2063 if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id,
2064 scmd->device->channel))
2065 r = FAILED;
2066 else
2067 r = SUCCESS;
2068 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2069 mutex_unlock(&ioc->tm_cmds.mutex);
2070
2071 out:
2072 printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
2073 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2074 return r;
2075}
2076
2077/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302078 * _scsih_host_reset - eh threads main host reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002079 * @sdev: scsi device struct
2080 *
2081 * Returns SUCCESS if command aborted else FAILED
2082 */
2083static int
Eric Moored5d135b2009-05-18 13:02:08 -06002084_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002085{
2086 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2087 int r, retval;
2088
2089 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2090 ioc->name, scmd);
2091 scsi_print_command(scmd);
2092
2093 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2094 FORCE_BIG_HAMMER);
2095 r = (retval < 0) ? FAILED : SUCCESS;
2096 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2097 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2098
2099 return r;
2100}
2101
2102/**
2103 * _scsih_fw_event_add - insert and queue up fw_event
2104 * @ioc: per adapter object
2105 * @fw_event: object describing the event
2106 * Context: This function will acquire ioc->fw_event_lock.
2107 *
2108 * This adds the firmware event object into link list, then queues it up to
2109 * be processed from user context.
2110 *
2111 * Return nothing.
2112 */
2113static void
2114_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2115{
2116 unsigned long flags;
2117
2118 if (ioc->firmware_event_thread == NULL)
2119 return;
2120
2121 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2122 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002123 INIT_WORK(&fw_event->work, _firmware_event_work);
2124 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002125 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2126}
2127
2128/**
2129 * _scsih_fw_event_free - delete fw_event
2130 * @ioc: per adapter object
2131 * @fw_event: object describing the event
2132 * Context: This function will acquire ioc->fw_event_lock.
2133 *
2134 * This removes firmware event object from link list, frees associated memory.
2135 *
2136 * Return nothing.
2137 */
2138static void
2139_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2140 *fw_event)
2141{
2142 unsigned long flags;
2143
2144 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2145 list_del(&fw_event->list);
2146 kfree(fw_event->event_data);
2147 kfree(fw_event);
2148 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2149}
2150
2151/**
2152 * _scsih_fw_event_add - requeue an event
2153 * @ioc: per adapter object
2154 * @fw_event: object describing the event
2155 * Context: This function will acquire ioc->fw_event_lock.
2156 *
2157 * Return nothing.
2158 */
2159static void
2160_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2161 *fw_event, unsigned long delay)
2162{
2163 unsigned long flags;
2164 if (ioc->firmware_event_thread == NULL)
2165 return;
2166
2167 spin_lock_irqsave(&ioc->fw_event_lock, flags);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002168 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002169 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2170}
2171
2172/**
2173 * _scsih_fw_event_off - turn flag off preventing event handling
2174 * @ioc: per adapter object
2175 *
2176 * Used to prevent handling of firmware events during adapter reset
2177 * driver unload.
2178 *
2179 * Return nothing.
2180 */
2181static void
2182_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc)
2183{
2184 unsigned long flags;
2185
2186 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2187 ioc->fw_events_off = 1;
2188 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2189
2190}
2191
2192/**
2193 * _scsih_fw_event_on - turn flag on allowing firmware event handling
2194 * @ioc: per adapter object
2195 *
2196 * Returns nothing.
2197 */
2198static void
2199_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc)
2200{
2201 unsigned long flags;
2202
2203 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2204 ioc->fw_events_off = 0;
2205 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2206}
2207
2208/**
2209 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2210 * @ioc: per adapter object
2211 * @handle: device handle
2212 *
2213 * During device pull we need to appropiately set the sdev state.
2214 */
2215static void
2216_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2217{
2218 struct MPT2SAS_DEVICE *sas_device_priv_data;
2219 struct scsi_device *sdev;
2220
2221 shost_for_each_device(sdev, ioc->shost) {
2222 sas_device_priv_data = sdev->hostdata;
2223 if (!sas_device_priv_data)
2224 continue;
2225 if (!sas_device_priv_data->block)
2226 continue;
2227 if (sas_device_priv_data->sas_target->handle == handle) {
2228 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2229 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2230 "handle(0x%04x)\n", ioc->name, handle));
2231 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302232 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002233 }
2234 }
2235}
2236
2237/**
2238 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2239 * @ioc: per adapter object
2240 * @handle: device handle
2241 *
2242 * During device pull we need to appropiately set the sdev state.
2243 */
2244static void
2245_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2246{
2247 struct MPT2SAS_DEVICE *sas_device_priv_data;
2248 struct scsi_device *sdev;
2249
2250 shost_for_each_device(sdev, ioc->shost) {
2251 sas_device_priv_data = sdev->hostdata;
2252 if (!sas_device_priv_data)
2253 continue;
2254 if (sas_device_priv_data->block)
2255 continue;
2256 if (sas_device_priv_data->sas_target->handle == handle) {
2257 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2258 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2259 "handle(0x%04x)\n", ioc->name, handle));
2260 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302261 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002262 }
2263 }
2264}
2265
2266/**
2267 * _scsih_block_io_to_children_attached_to_ex
2268 * @ioc: per adapter object
2269 * @sas_expander: the sas_device object
2270 *
2271 * This routine set sdev state to SDEV_BLOCK for all devices
2272 * attached to this expander. This function called when expander is
2273 * pulled.
2274 */
2275static void
2276_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2277 struct _sas_node *sas_expander)
2278{
2279 struct _sas_port *mpt2sas_port;
2280 struct _sas_device *sas_device;
2281 struct _sas_node *expander_sibling;
2282 unsigned long flags;
2283
2284 if (!sas_expander)
2285 return;
2286
2287 list_for_each_entry(mpt2sas_port,
2288 &sas_expander->sas_port_list, port_list) {
2289 if (mpt2sas_port->remote_identify.device_type ==
2290 SAS_END_DEVICE) {
2291 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2292 sas_device =
2293 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2294 mpt2sas_port->remote_identify.sas_address);
2295 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2296 if (!sas_device)
2297 continue;
2298 _scsih_block_io_device(ioc, sas_device->handle);
2299 }
2300 }
2301
2302 list_for_each_entry(mpt2sas_port,
2303 &sas_expander->sas_port_list, port_list) {
2304
2305 if (mpt2sas_port->remote_identify.device_type ==
2306 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2307 mpt2sas_port->remote_identify.device_type ==
2308 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2309
2310 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2311 expander_sibling =
2312 mpt2sas_scsih_expander_find_by_sas_address(
2313 ioc, mpt2sas_port->remote_identify.sas_address);
2314 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2315 _scsih_block_io_to_children_attached_to_ex(ioc,
2316 expander_sibling);
2317 }
2318 }
2319}
2320
2321/**
2322 * _scsih_block_io_to_children_attached_directly
2323 * @ioc: per adapter object
2324 * @event_data: topology change event data
2325 *
2326 * This routine set sdev state to SDEV_BLOCK for all devices
2327 * direct attached during device pull.
2328 */
2329static void
2330_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2331 Mpi2EventDataSasTopologyChangeList_t *event_data)
2332{
2333 int i;
2334 u16 handle;
2335 u16 reason_code;
2336 u8 phy_number;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302337 u8 link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06002338
2339 for (i = 0; i < event_data->NumEntries; i++) {
2340 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2341 if (!handle)
2342 continue;
2343 phy_number = event_data->StartPhyNum + i;
2344 reason_code = event_data->PHY[i].PhyStatus &
2345 MPI2_EVENT_SAS_TOPO_RC_MASK;
2346 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2347 _scsih_block_io_device(ioc, handle);
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302348 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) {
2349 link_rate = event_data->PHY[i].LinkRate >> 4;
2350 if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
2351 _scsih_ublock_io_device(ioc, handle);
2352 }
Eric Moore635374e2009-03-09 01:21:12 -06002353 }
2354}
2355
2356/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302357 * _scsih_tm_tr_send - send task management request
2358 * @ioc: per adapter object
2359 * @handle: device handle
2360 * Context: interrupt time.
2361 *
2362 * This code is to initiate the device removal handshake protocal
2363 * with controller firmware. This function will issue target reset
2364 * using high priority request queue. It will send a sas iounit
2365 * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
2366 *
2367 * This is designed to send muliple task management request at the same
2368 * time to the fifo. If the fifo is full, we will append the request,
2369 * and process it in a future completion.
2370 */
2371static void
2372_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2373{
2374 Mpi2SCSITaskManagementRequest_t *mpi_request;
2375 struct MPT2SAS_TARGET *sas_target_priv_data;
2376 u16 smid;
2377 struct _sas_device *sas_device;
2378 unsigned long flags;
2379 struct _tr_list *delayed_tr;
2380
2381 if (ioc->shost_recovery) {
2382 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2383 __func__, ioc->name);
2384 return;
2385 }
2386
2387 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2388 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302389 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2390
2391 /* skip is hidden raid component */
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302392 if (sas_device && sas_device->hidden_raid_component)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302393 return;
2394
2395 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
2396 if (!smid) {
2397 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
2398 if (!delayed_tr)
2399 return;
2400 INIT_LIST_HEAD(&delayed_tr->list);
2401 delayed_tr->handle = handle;
2402 delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
2403 list_add_tail(&delayed_tr->list,
2404 &ioc->delayed_tr_list);
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302405 if (sas_device && sas_device->starget) {
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302406 dewtprintk(ioc, starget_printk(KERN_INFO,
2407 sas_device->starget, "DELAYED:tr:handle(0x%04x), "
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302408 "(open)\n", handle));
2409 } else {
2410 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2411 "DELAYED:tr:handle(0x%04x), (open)\n",
2412 ioc->name, handle));
2413 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302414 return;
2415 }
2416
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302417 if (sas_device) {
2418 sas_device->state |= MPTSAS_STATE_TR_SEND;
2419 sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
2420 if (sas_device->starget && sas_device->starget->hostdata) {
2421 sas_target_priv_data = sas_device->starget->hostdata;
2422 sas_target_priv_data->tm_busy = 1;
2423 dewtprintk(ioc, starget_printk(KERN_INFO,
2424 sas_device->starget, "tr:handle(0x%04x), (open)\n",
2425 handle));
2426 }
2427 } else {
2428 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2429 "tr:handle(0x%04x), (open)\n", ioc->name, handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302430 }
2431
2432 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2433 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2434 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2435 mpi_request->DevHandle = cpu_to_le16(handle);
2436 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302437 mpt2sas_base_put_smid_hi_priority(ioc, smid);
2438}
2439
2440
2441
2442/**
2443 * _scsih_sas_control_complete - completion routine
2444 * @ioc: per adapter object
2445 * @smid: system request message index
2446 * @msix_index: MSIX table index supplied by the OS
2447 * @reply: reply message frame(lower 32bit addr)
2448 * Context: interrupt time.
2449 *
2450 * This is the sas iounit controll completion routine.
2451 * This code is part of the code to initiate the device removal
2452 * handshake protocal with controller firmware.
2453 *
2454 * Return 1 meaning mf should be freed from _base_interrupt
2455 * 0 means the mf is freed from this function.
2456 */
2457static u8
2458_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
2459 u8 msix_index, u32 reply)
2460{
2461 unsigned long flags;
2462 u16 handle;
2463 struct _sas_device *sas_device;
2464 Mpi2SasIoUnitControlReply_t *mpi_reply =
2465 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2466
2467 handle = le16_to_cpu(mpi_reply->DevHandle);
2468
2469 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2470 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302471 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2472
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302473 if (sas_device) {
2474 sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
2475 if (sas_device->starget)
2476 dewtprintk(ioc, starget_printk(KERN_INFO,
2477 sas_device->starget,
2478 "sc_complete:handle(0x%04x), "
2479 "ioc_status(0x%04x), loginfo(0x%08x)\n",
2480 handle, le16_to_cpu(mpi_reply->IOCStatus),
2481 le32_to_cpu(mpi_reply->IOCLogInfo)));
2482 } else {
2483 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302484 "sc_complete:handle(0x%04x), "
2485 "ioc_status(0x%04x), loginfo(0x%08x)\n",
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302486 ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus),
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302487 le32_to_cpu(mpi_reply->IOCLogInfo)));
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302488 }
2489
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302490 return 1;
2491}
2492
2493/**
2494 * _scsih_tm_tr_complete -
2495 * @ioc: per adapter object
2496 * @smid: system request message index
2497 * @msix_index: MSIX table index supplied by the OS
2498 * @reply: reply message frame(lower 32bit addr)
2499 * Context: interrupt time.
2500 *
2501 * This is the target reset completion routine.
2502 * This code is part of the code to initiate the device removal
2503 * handshake protocal with controller firmware.
2504 * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE)
2505 *
2506 * Return 1 meaning mf should be freed from _base_interrupt
2507 * 0 means the mf is freed from this function.
2508 */
2509static u8
2510_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
2511 u32 reply)
2512{
2513 unsigned long flags;
2514 u16 handle;
2515 struct _sas_device *sas_device;
2516 Mpi2SCSITaskManagementReply_t *mpi_reply =
2517 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2518 Mpi2SasIoUnitControlRequest_t *mpi_request;
2519 u16 smid_sas_ctrl;
2520 struct MPT2SAS_TARGET *sas_target_priv_data;
2521 struct _tr_list *delayed_tr;
2522 u8 rc;
2523
2524 handle = le16_to_cpu(mpi_reply->DevHandle);
2525 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2526 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302527 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2528
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302529 if (sas_device) {
2530 sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
2531 if (sas_device->starget) {
2532 dewtprintk(ioc, starget_printk(KERN_INFO,
2533 sas_device->starget, "tr_complete:handle(0x%04x), "
2534 "(%s) ioc_status(0x%04x), loginfo(0x%08x), "
2535 "completed(%d)\n", sas_device->handle,
2536 (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ?
2537 "open" : "active",
2538 le16_to_cpu(mpi_reply->IOCStatus),
2539 le32_to_cpu(mpi_reply->IOCLogInfo),
2540 le32_to_cpu(mpi_reply->TerminationCount)));
2541 if (sas_device->starget->hostdata) {
2542 sas_target_priv_data =
2543 sas_device->starget->hostdata;
2544 sas_target_priv_data->tm_busy = 0;
2545 }
2546 }
2547 } else {
2548 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2549 "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), "
2550 "loginfo(0x%08x), completed(%d)\n", ioc->name,
2551 handle, le16_to_cpu(mpi_reply->IOCStatus),
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302552 le32_to_cpu(mpi_reply->IOCLogInfo),
2553 le32_to_cpu(mpi_reply->TerminationCount)));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302554 }
2555
2556 if (!list_empty(&ioc->delayed_tr_list)) {
2557 delayed_tr = list_entry(ioc->delayed_tr_list.next,
2558 struct _tr_list, list);
2559 mpt2sas_base_free_smid(ioc, smid);
2560 if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL)
2561 _scsih_tm_tr_send(ioc, delayed_tr->handle);
2562 list_del(&delayed_tr->list);
2563 kfree(delayed_tr);
2564 rc = 0; /* tells base_interrupt not to free mf */
2565 } else
2566 rc = 1;
2567
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302568 if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302569 return rc;
2570
2571 if (ioc->shost_recovery) {
2572 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2573 __func__, ioc->name);
2574 return rc;
2575 }
2576
2577 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
2578 if (!smid_sas_ctrl) {
2579 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2580 ioc->name, __func__);
2581 return rc;
2582 }
2583
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302584 if (sas_device)
2585 sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
2586
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302587 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
2588 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
2589 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
2590 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
2591 mpi_request->DevHandle = mpi_reply->DevHandle;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302592 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
2593 return rc;
2594}
2595
2596/**
Eric Moore635374e2009-03-09 01:21:12 -06002597 * _scsih_check_topo_delete_events - sanity check on topo events
2598 * @ioc: per adapter object
2599 * @event_data: the event data payload
2600 *
2601 * This routine added to better handle cable breaker.
2602 *
2603 * This handles the case where driver recieves multiple expander
2604 * add and delete events in a single shot. When there is a delete event
2605 * the routine will void any pending add events waiting in the event queue.
2606 *
2607 * Return nothing.
2608 */
2609static void
2610_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
2611 Mpi2EventDataSasTopologyChangeList_t *event_data)
2612{
2613 struct fw_event_work *fw_event;
2614 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
2615 u16 expander_handle;
2616 struct _sas_node *sas_expander;
2617 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302618 int i, reason_code;
2619 u16 handle;
2620
2621 for (i = 0 ; i < event_data->NumEntries; i++) {
2622 if (event_data->PHY[i].PhyStatus &
2623 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
2624 continue;
2625 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2626 if (!handle)
2627 continue;
2628 reason_code = event_data->PHY[i].PhyStatus &
2629 MPI2_EVENT_SAS_TOPO_RC_MASK;
2630 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
2631 _scsih_tm_tr_send(ioc, handle);
2632 }
Eric Moore635374e2009-03-09 01:21:12 -06002633
2634 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
2635 if (expander_handle < ioc->sas_hba.num_phys) {
2636 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2637 return;
2638 }
2639
2640 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
2641 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
2642 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2643 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
2644 expander_handle);
2645 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2646 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
2647 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
2648 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2649
2650 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
2651 return;
2652
2653 /* mark ignore flag for pending events */
2654 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2655 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
2656 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
2657 fw_event->ignore)
2658 continue;
2659 local_event_data = fw_event->event_data;
2660 if (local_event_data->ExpStatus ==
2661 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
2662 local_event_data->ExpStatus ==
2663 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
2664 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
2665 expander_handle) {
2666 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
2667 "setting ignoring flag\n", ioc->name));
2668 fw_event->ignore = 1;
2669 }
2670 }
2671 }
2672 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2673}
2674
2675/**
Eric Moore635374e2009-03-09 01:21:12 -06002676 * _scsih_flush_running_cmds - completing outstanding commands.
2677 * @ioc: per adapter object
2678 *
2679 * The flushing out of all pending scmd commands following host reset,
2680 * where all IO is dropped to the floor.
2681 *
2682 * Return nothing.
2683 */
2684static void
2685_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
2686{
2687 struct scsi_cmnd *scmd;
2688 u16 smid;
2689 u16 count = 0;
2690
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302691 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
2692 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002693 if (!scmd)
2694 continue;
2695 count++;
2696 mpt2sas_base_free_smid(ioc, smid);
2697 scsi_dma_unmap(scmd);
2698 scmd->result = DID_RESET << 16;
2699 scmd->scsi_done(scmd);
2700 }
2701 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
2702 ioc->name, count));
2703}
2704
2705/**
Eric Moore3c621b32009-05-18 12:59:41 -06002706 * _scsih_setup_eedp - setup MPI request for EEDP transfer
2707 * @scmd: pointer to scsi command object
2708 * @mpi_request: pointer to the SCSI_IO reqest message frame
2709 *
2710 * Supporting protection 1 and 3.
2711 *
2712 * Returns nothing
2713 */
2714static void
2715_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
2716{
2717 u16 eedp_flags;
2718 unsigned char prot_op = scsi_get_prot_op(scmd);
2719 unsigned char prot_type = scsi_get_prot_type(scmd);
2720
2721 if (prot_type == SCSI_PROT_DIF_TYPE0 ||
2722 prot_type == SCSI_PROT_DIF_TYPE2 ||
2723 prot_op == SCSI_PROT_NORMAL)
2724 return;
2725
2726 if (prot_op == SCSI_PROT_READ_STRIP)
2727 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
2728 else if (prot_op == SCSI_PROT_WRITE_INSERT)
2729 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
2730 else
2731 return;
2732
2733 mpi_request->EEDPBlockSize = scmd->device->sector_size;
2734
2735 switch (prot_type) {
2736 case SCSI_PROT_DIF_TYPE1:
2737
2738 /*
2739 * enable ref/guard checking
2740 * auto increment ref tag
2741 */
2742 mpi_request->EEDPFlags = eedp_flags |
2743 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
2744 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2745 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2746 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
2747 cpu_to_be32(scsi_get_lba(scmd));
2748
2749 break;
2750
2751 case SCSI_PROT_DIF_TYPE3:
2752
2753 /*
2754 * enable guard checking
2755 */
2756 mpi_request->EEDPFlags = eedp_flags |
2757 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2758
2759 break;
2760 }
2761}
2762
2763/**
2764 * _scsih_eedp_error_handling - return sense code for EEDP errors
2765 * @scmd: pointer to scsi command object
2766 * @ioc_status: ioc status
2767 *
2768 * Returns nothing
2769 */
2770static void
2771_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
2772{
2773 u8 ascq;
2774 u8 sk;
2775 u8 host_byte;
2776
2777 switch (ioc_status) {
2778 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2779 ascq = 0x01;
2780 break;
2781 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2782 ascq = 0x02;
2783 break;
2784 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2785 ascq = 0x03;
2786 break;
2787 default:
2788 ascq = 0x00;
2789 break;
2790 }
2791
2792 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
2793 sk = ILLEGAL_REQUEST;
2794 host_byte = DID_ABORT;
2795 } else {
2796 sk = ABORTED_COMMAND;
2797 host_byte = DID_OK;
2798 }
2799
2800 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
2801 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
2802 SAM_STAT_CHECK_CONDITION;
2803}
2804
2805/**
Eric Moored5d135b2009-05-18 13:02:08 -06002806 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06002807 * @scmd: pointer to scsi command object
2808 * @done: function pointer to be invoked on completion
2809 *
2810 * The callback index is set inside `ioc->scsi_io_cb_idx`.
2811 *
2812 * Returns 0 on success. If there's a failure, return either:
2813 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
2814 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
2815 */
2816static int
Eric Moored5d135b2009-05-18 13:02:08 -06002817_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06002818{
2819 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2820 struct MPT2SAS_DEVICE *sas_device_priv_data;
2821 struct MPT2SAS_TARGET *sas_target_priv_data;
2822 Mpi2SCSIIORequest_t *mpi_request;
2823 u32 mpi_control;
2824 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06002825
2826 scmd->scsi_done = done;
2827 sas_device_priv_data = scmd->device->hostdata;
2828 if (!sas_device_priv_data) {
2829 scmd->result = DID_NO_CONNECT << 16;
2830 scmd->scsi_done(scmd);
2831 return 0;
2832 }
2833
2834 sas_target_priv_data = sas_device_priv_data->sas_target;
2835 if (!sas_target_priv_data || sas_target_priv_data->handle ==
2836 MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
2837 scmd->result = DID_NO_CONNECT << 16;
2838 scmd->scsi_done(scmd);
2839 return 0;
2840 }
2841
2842 /* see if we are busy with task managment stuff */
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302843 if (sas_target_priv_data->tm_busy)
2844 return SCSI_MLQUEUE_DEVICE_BUSY;
2845 else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06002846 return SCSI_MLQUEUE_HOST_BUSY;
Eric Moore635374e2009-03-09 01:21:12 -06002847
2848 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
2849 mpi_control = MPI2_SCSIIO_CONTROL_READ;
2850 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
2851 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
2852 else
2853 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
2854
2855 /* set tags */
2856 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
2857 if (scmd->device->tagged_supported) {
2858 if (scmd->device->ordered_tags)
2859 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
2860 else
2861 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2862 } else
2863/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
2864/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
2865 */
2866 mpi_control |= (0x500);
2867
2868 } else
2869 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2870
2871 if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
2872 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
2873
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302874 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002875 if (!smid) {
2876 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2877 ioc->name, __func__);
2878 goto out;
2879 }
2880 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2881 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06002882 _scsih_setup_eedp(scmd, mpi_request);
Eric Moore635374e2009-03-09 01:21:12 -06002883 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2884 if (sas_device_priv_data->sas_target->flags &
2885 MPT_TARGET_FLAGS_RAID_COMPONENT)
2886 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2887 else
2888 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2889 mpi_request->DevHandle =
2890 cpu_to_le16(sas_device_priv_data->sas_target->handle);
2891 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
2892 mpi_request->Control = cpu_to_le32(mpi_control);
2893 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
2894 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
2895 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
2896 mpi_request->SenseBufferLowAddress =
2897 (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
2898 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
2899 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
2900 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302901 mpi_request->VF_ID = 0; /* TODO */
2902 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06002903 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
2904 mpi_request->LUN);
2905 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
2906
2907 if (!mpi_request->DataLength) {
2908 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
2909 } else {
2910 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
2911 mpt2sas_base_free_smid(ioc, smid);
2912 goto out;
2913 }
2914 }
2915
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302916 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Eric Moore635374e2009-03-09 01:21:12 -06002917 sas_device_priv_data->sas_target->handle);
2918 return 0;
2919
2920 out:
2921 return SCSI_MLQUEUE_HOST_BUSY;
2922}
2923
2924/**
2925 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
2926 * @sense_buffer: sense data returned by target
2927 * @data: normalized skey/asc/ascq
2928 *
2929 * Return nothing.
2930 */
2931static void
2932_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
2933{
2934 if ((sense_buffer[0] & 0x7F) >= 0x72) {
2935 /* descriptor format */
2936 data->skey = sense_buffer[1] & 0x0F;
2937 data->asc = sense_buffer[2];
2938 data->ascq = sense_buffer[3];
2939 } else {
2940 /* fixed format */
2941 data->skey = sense_buffer[2] & 0x0F;
2942 data->asc = sense_buffer[12];
2943 data->ascq = sense_buffer[13];
2944 }
2945}
2946
2947#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
2948/**
2949 * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request
2950 * @ioc: per adapter object
2951 * @scmd: pointer to scsi command object
2952 * @mpi_reply: reply mf payload returned from firmware
2953 *
2954 * scsi_status - SCSI Status code returned from target device
2955 * scsi_state - state info associated with SCSI_IO determined by ioc
2956 * ioc_status - ioc supplied status info
2957 *
2958 * Return nothing.
2959 */
2960static void
2961_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
2962 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
2963{
2964 u32 response_info;
2965 u8 *response_bytes;
2966 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
2967 MPI2_IOCSTATUS_MASK;
2968 u8 scsi_state = mpi_reply->SCSIState;
2969 u8 scsi_status = mpi_reply->SCSIStatus;
2970 char *desc_ioc_state = NULL;
2971 char *desc_scsi_status = NULL;
2972 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05302973 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
2974
2975 if (log_info == 0x31170000)
2976 return;
Eric Moore635374e2009-03-09 01:21:12 -06002977
2978 switch (ioc_status) {
2979 case MPI2_IOCSTATUS_SUCCESS:
2980 desc_ioc_state = "success";
2981 break;
2982 case MPI2_IOCSTATUS_INVALID_FUNCTION:
2983 desc_ioc_state = "invalid function";
2984 break;
2985 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2986 desc_ioc_state = "scsi recovered error";
2987 break;
2988 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2989 desc_ioc_state = "scsi invalid dev handle";
2990 break;
2991 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2992 desc_ioc_state = "scsi device not there";
2993 break;
2994 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2995 desc_ioc_state = "scsi data overrun";
2996 break;
2997 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2998 desc_ioc_state = "scsi data underrun";
2999 break;
3000 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3001 desc_ioc_state = "scsi io data error";
3002 break;
3003 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3004 desc_ioc_state = "scsi protocol error";
3005 break;
3006 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3007 desc_ioc_state = "scsi task terminated";
3008 break;
3009 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3010 desc_ioc_state = "scsi residual mismatch";
3011 break;
3012 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3013 desc_ioc_state = "scsi task mgmt failed";
3014 break;
3015 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3016 desc_ioc_state = "scsi ioc terminated";
3017 break;
3018 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3019 desc_ioc_state = "scsi ext terminated";
3020 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003021 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3022 desc_ioc_state = "eedp guard error";
3023 break;
3024 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3025 desc_ioc_state = "eedp ref tag error";
3026 break;
3027 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3028 desc_ioc_state = "eedp app tag error";
3029 break;
Eric Moore635374e2009-03-09 01:21:12 -06003030 default:
3031 desc_ioc_state = "unknown";
3032 break;
3033 }
3034
3035 switch (scsi_status) {
3036 case MPI2_SCSI_STATUS_GOOD:
3037 desc_scsi_status = "good";
3038 break;
3039 case MPI2_SCSI_STATUS_CHECK_CONDITION:
3040 desc_scsi_status = "check condition";
3041 break;
3042 case MPI2_SCSI_STATUS_CONDITION_MET:
3043 desc_scsi_status = "condition met";
3044 break;
3045 case MPI2_SCSI_STATUS_BUSY:
3046 desc_scsi_status = "busy";
3047 break;
3048 case MPI2_SCSI_STATUS_INTERMEDIATE:
3049 desc_scsi_status = "intermediate";
3050 break;
3051 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
3052 desc_scsi_status = "intermediate condmet";
3053 break;
3054 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
3055 desc_scsi_status = "reservation conflict";
3056 break;
3057 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
3058 desc_scsi_status = "command terminated";
3059 break;
3060 case MPI2_SCSI_STATUS_TASK_SET_FULL:
3061 desc_scsi_status = "task set full";
3062 break;
3063 case MPI2_SCSI_STATUS_ACA_ACTIVE:
3064 desc_scsi_status = "aca active";
3065 break;
3066 case MPI2_SCSI_STATUS_TASK_ABORTED:
3067 desc_scsi_status = "task aborted";
3068 break;
3069 default:
3070 desc_scsi_status = "unknown";
3071 break;
3072 }
3073
3074 desc_scsi_state[0] = '\0';
3075 if (!scsi_state)
3076 desc_scsi_state = " ";
3077 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3078 strcat(desc_scsi_state, "response info ");
3079 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3080 strcat(desc_scsi_state, "state terminated ");
3081 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
3082 strcat(desc_scsi_state, "no status ");
3083 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
3084 strcat(desc_scsi_state, "autosense failed ");
3085 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
3086 strcat(desc_scsi_state, "autosense valid ");
3087
3088 scsi_print_command(scmd);
3089 printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
3090 "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
3091 le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
3092 ioc_status, smid);
3093 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
3094 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
3095 scsi_get_resid(scmd));
3096 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
3097 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
3098 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
3099 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
3100 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
3101 scsi_status, desc_scsi_state, scsi_state);
3102
3103 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3104 struct sense_info data;
3105 _scsih_normalize_sense(scmd->sense_buffer, &data);
3106 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
3107 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey,
3108 data.asc, data.ascq);
3109 }
3110
3111 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
3112 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
3113 response_bytes = (u8 *)&response_info;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303114 _scsih_response_code(ioc, response_bytes[0]);
Eric Moore635374e2009-03-09 01:21:12 -06003115 }
3116}
3117#endif
3118
3119/**
3120 * _scsih_smart_predicted_fault - illuminate Fault LED
3121 * @ioc: per adapter object
3122 * @handle: device handle
3123 *
3124 * Return nothing.
3125 */
3126static void
3127_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3128{
3129 Mpi2SepReply_t mpi_reply;
3130 Mpi2SepRequest_t mpi_request;
3131 struct scsi_target *starget;
3132 struct MPT2SAS_TARGET *sas_target_priv_data;
3133 Mpi2EventNotificationReply_t *event_reply;
3134 Mpi2EventDataSasDeviceStatusChange_t *event_data;
3135 struct _sas_device *sas_device;
3136 ssize_t sz;
3137 unsigned long flags;
3138
3139 /* only handle non-raid devices */
3140 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3141 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3142 if (!sas_device) {
3143 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3144 return;
3145 }
3146 starget = sas_device->starget;
3147 sas_target_priv_data = starget->hostdata;
3148
3149 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
3150 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
3151 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3152 return;
3153 }
3154 starget_printk(KERN_WARNING, starget, "predicted fault\n");
3155 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3156
3157 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
3158 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
3159 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
3160 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
3161 mpi_request.SlotStatus =
3162 MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
3163 mpi_request.DevHandle = cpu_to_le16(handle);
3164 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
3165 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
3166 &mpi_request)) != 0) {
3167 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3168 ioc->name, __FILE__, __LINE__, __func__);
3169 return;
3170 }
3171
3172 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
3173 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3174 "enclosure_processor: ioc_status (0x%04x), "
3175 "loginfo(0x%08x)\n", ioc->name,
3176 le16_to_cpu(mpi_reply.IOCStatus),
3177 le32_to_cpu(mpi_reply.IOCLogInfo)));
3178 return;
3179 }
3180 }
3181
3182 /* insert into event log */
3183 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
3184 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
3185 event_reply = kzalloc(sz, GFP_KERNEL);
3186 if (!event_reply) {
3187 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3188 ioc->name, __FILE__, __LINE__, __func__);
3189 return;
3190 }
3191
3192 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
3193 event_reply->Event =
3194 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
3195 event_reply->MsgLength = sz/4;
3196 event_reply->EventDataLength =
3197 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
3198 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
3199 event_reply->EventData;
3200 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
3201 event_data->ASC = 0x5D;
3202 event_data->DevHandle = cpu_to_le16(handle);
3203 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
3204 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
3205 kfree(event_reply);
3206}
3207
3208/**
Eric Moored5d135b2009-05-18 13:02:08 -06003209 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06003210 * @ioc: per adapter object
3211 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303212 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06003213 * @reply: reply message frame(lower 32bit addr)
3214 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303215 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06003216 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303217 * Return 1 meaning mf should be freed from _base_interrupt
3218 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06003219 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303220static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303221_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06003222{
3223 Mpi2SCSIIORequest_t *mpi_request;
3224 Mpi2SCSIIOReply_t *mpi_reply;
3225 struct scsi_cmnd *scmd;
3226 u16 ioc_status;
3227 u32 xfer_cnt;
3228 u8 scsi_state;
3229 u8 scsi_status;
3230 u32 log_info;
3231 struct MPT2SAS_DEVICE *sas_device_priv_data;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303232 u32 response_code = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003233
3234 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303235 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003236 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303237 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003238
3239 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3240
3241 if (mpi_reply == NULL) {
3242 scmd->result = DID_OK << 16;
3243 goto out;
3244 }
3245
3246 sas_device_priv_data = scmd->device->hostdata;
3247 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
3248 sas_device_priv_data->sas_target->deleted) {
3249 scmd->result = DID_NO_CONNECT << 16;
3250 goto out;
3251 }
3252
3253 /* turning off TLR */
Kashyap, Desai9982f592009-09-23 17:23:07 +05303254 scsi_state = mpi_reply->SCSIState;
3255 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3256 response_code =
3257 le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
Eric Moore635374e2009-03-09 01:21:12 -06003258 if (!sas_device_priv_data->tlr_snoop_check) {
3259 sas_device_priv_data->tlr_snoop_check++;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303260 if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
3261 response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
3262 sas_device_priv_data->flags &=
3263 ~MPT_DEVICE_TLR_ON;
Eric Moore635374e2009-03-09 01:21:12 -06003264 }
3265
3266 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
3267 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
3268 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
3269 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
3270 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3271 else
3272 log_info = 0;
3273 ioc_status &= MPI2_IOCSTATUS_MASK;
Eric Moore635374e2009-03-09 01:21:12 -06003274 scsi_status = mpi_reply->SCSIStatus;
3275
3276 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
3277 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
3278 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
3279 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
3280 ioc_status = MPI2_IOCSTATUS_SUCCESS;
3281 }
3282
3283 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3284 struct sense_info data;
3285 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
3286 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06003287 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06003288 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06003289 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06003290 _scsih_normalize_sense(scmd->sense_buffer, &data);
3291 /* failure prediction threshold exceeded */
3292 if (data.asc == 0x5D)
3293 _scsih_smart_predicted_fault(ioc,
3294 le16_to_cpu(mpi_reply->DevHandle));
3295 }
3296
3297 switch (ioc_status) {
3298 case MPI2_IOCSTATUS_BUSY:
3299 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3300 scmd->result = SAM_STAT_BUSY;
3301 break;
3302
3303 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3304 scmd->result = DID_NO_CONNECT << 16;
3305 break;
3306
3307 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3308 if (sas_device_priv_data->block) {
3309 scmd->result = (DID_BUS_BUSY << 16);
3310 break;
3311 }
3312
3313 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3314 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3315 scmd->result = DID_RESET << 16;
3316 break;
3317
3318 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3319 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3320 scmd->result = DID_SOFT_ERROR << 16;
3321 else
3322 scmd->result = (DID_OK << 16) | scsi_status;
3323 break;
3324
3325 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3326 scmd->result = (DID_OK << 16) | scsi_status;
3327
3328 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3329 break;
3330
3331 if (xfer_cnt < scmd->underflow) {
3332 if (scsi_status == SAM_STAT_BUSY)
3333 scmd->result = SAM_STAT_BUSY;
3334 else
3335 scmd->result = DID_SOFT_ERROR << 16;
3336 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3337 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3338 scmd->result = DID_SOFT_ERROR << 16;
3339 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3340 scmd->result = DID_RESET << 16;
3341 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3342 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3343 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3344 scmd->result = (DRIVER_SENSE << 24) |
3345 SAM_STAT_CHECK_CONDITION;
3346 scmd->sense_buffer[0] = 0x70;
3347 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3348 scmd->sense_buffer[12] = 0x20;
3349 scmd->sense_buffer[13] = 0;
3350 }
3351 break;
3352
3353 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3354 scsi_set_resid(scmd, 0);
3355 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3356 case MPI2_IOCSTATUS_SUCCESS:
3357 scmd->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303358 if (response_code ==
3359 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
3360 (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3361 MPI2_SCSI_STATE_NO_SCSI_STATUS)))
Eric Moore635374e2009-03-09 01:21:12 -06003362 scmd->result = DID_SOFT_ERROR << 16;
3363 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3364 scmd->result = DID_RESET << 16;
3365 break;
3366
Eric Moore3c621b32009-05-18 12:59:41 -06003367 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3368 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3369 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3370 _scsih_eedp_error_handling(scmd, ioc_status);
3371 break;
Eric Moore635374e2009-03-09 01:21:12 -06003372 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3373 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3374 case MPI2_IOCSTATUS_INVALID_SGL:
3375 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3376 case MPI2_IOCSTATUS_INVALID_FIELD:
3377 case MPI2_IOCSTATUS_INVALID_STATE:
3378 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3379 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3380 default:
3381 scmd->result = DID_SOFT_ERROR << 16;
3382 break;
3383
3384 }
3385
3386#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3387 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3388 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3389#endif
3390
3391 out:
3392 scsi_dma_unmap(scmd);
3393 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303394 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003395}
3396
3397/**
Eric Moore635374e2009-03-09 01:21:12 -06003398 * _scsih_sas_host_refresh - refreshing sas host object contents
3399 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06003400 * Context: user
3401 *
3402 * During port enable, fw will send topology events for every device. Its
3403 * possible that the handles may change from the previous setting, so this
3404 * code keeping handles updating if changed.
3405 *
3406 * Return nothing.
3407 */
3408static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303409_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06003410{
3411 u16 sz;
3412 u16 ioc_status;
3413 int i;
3414 Mpi2ConfigReply_t mpi_reply;
3415 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303416 u16 attached_handle;
Eric Moore635374e2009-03-09 01:21:12 -06003417
3418 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3419 "updating handles for sas_host(0x%016llx)\n",
3420 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3421
3422 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3423 * sizeof(Mpi2SasIOUnit0PhyData_t));
3424 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3425 if (!sas_iounit_pg0) {
3426 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3427 ioc->name, __FILE__, __LINE__, __func__);
3428 return;
3429 }
Eric Moore635374e2009-03-09 01:21:12 -06003430
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303431 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3432 sas_iounit_pg0, sz)) != 0)
3433 goto out;
3434 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
3435 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3436 goto out;
3437 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3438 if (i == 0)
3439 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3440 PhyData[0].ControllerDevHandle);
3441 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
3442 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
3443 AttachedDevHandle);
3444 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
3445 attached_handle, i, sas_iounit_pg0->PhyData[i].
3446 NegotiatedLinkRate >> 4);
3447 }
Eric Moore635374e2009-03-09 01:21:12 -06003448 out:
3449 kfree(sas_iounit_pg0);
3450}
3451
3452/**
3453 * _scsih_sas_host_add - create sas host object
3454 * @ioc: per adapter object
3455 *
3456 * Creating host side data object, stored in ioc->sas_hba
3457 *
3458 * Return nothing.
3459 */
3460static void
3461_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3462{
3463 int i;
3464 Mpi2ConfigReply_t mpi_reply;
3465 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3466 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3467 Mpi2SasPhyPage0_t phy_pg0;
3468 Mpi2SasDevicePage0_t sas_device_pg0;
3469 Mpi2SasEnclosurePage0_t enclosure_pg0;
3470 u16 ioc_status;
3471 u16 sz;
3472 u16 device_missing_delay;
3473
3474 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3475 if (!ioc->sas_hba.num_phys) {
3476 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3477 ioc->name, __FILE__, __LINE__, __func__);
3478 return;
3479 }
3480
3481 /* sas_iounit page 0 */
3482 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3483 sizeof(Mpi2SasIOUnit0PhyData_t));
3484 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3485 if (!sas_iounit_pg0) {
3486 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3487 ioc->name, __FILE__, __LINE__, __func__);
3488 return;
3489 }
3490 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3491 sas_iounit_pg0, sz))) {
3492 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3493 ioc->name, __FILE__, __LINE__, __func__);
3494 goto out;
3495 }
3496 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3497 MPI2_IOCSTATUS_MASK;
3498 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3499 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3500 ioc->name, __FILE__, __LINE__, __func__);
3501 goto out;
3502 }
3503
3504 /* sas_iounit page 1 */
3505 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3506 sizeof(Mpi2SasIOUnit1PhyData_t));
3507 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3508 if (!sas_iounit_pg1) {
3509 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3510 ioc->name, __FILE__, __LINE__, __func__);
3511 goto out;
3512 }
3513 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3514 sas_iounit_pg1, sz))) {
3515 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3516 ioc->name, __FILE__, __LINE__, __func__);
3517 goto out;
3518 }
3519 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3520 MPI2_IOCSTATUS_MASK;
3521 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3522 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3523 ioc->name, __FILE__, __LINE__, __func__);
3524 goto out;
3525 }
3526
3527 ioc->io_missing_delay =
3528 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3529 device_missing_delay =
3530 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3531 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3532 ioc->device_missing_delay = (device_missing_delay &
3533 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3534 else
3535 ioc->device_missing_delay = device_missing_delay &
3536 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3537
3538 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3539 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3540 sizeof(struct _sas_phy), GFP_KERNEL);
3541 if (!ioc->sas_hba.phy) {
3542 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3543 ioc->name, __FILE__, __LINE__, __func__);
3544 goto out;
3545 }
3546 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3547 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3548 i))) {
3549 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3550 ioc->name, __FILE__, __LINE__, __func__);
3551 goto out;
3552 }
3553 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3554 MPI2_IOCSTATUS_MASK;
3555 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3556 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3557 ioc->name, __FILE__, __LINE__, __func__);
3558 goto out;
3559 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303560
3561 if (i == 0)
3562 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3563 PhyData[0].ControllerDevHandle);
3564 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06003565 ioc->sas_hba.phy[i].phy_id = i;
3566 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3567 phy_pg0, ioc->sas_hba.parent_dev);
3568 }
3569 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303570 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06003571 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3572 ioc->name, __FILE__, __LINE__, __func__);
3573 goto out;
3574 }
Eric Moore635374e2009-03-09 01:21:12 -06003575 ioc->sas_hba.enclosure_handle =
3576 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3577 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3578 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3579 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3580 (unsigned long long) ioc->sas_hba.sas_address,
3581 ioc->sas_hba.num_phys) ;
3582
3583 if (ioc->sas_hba.enclosure_handle) {
3584 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3585 &enclosure_pg0,
3586 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3587 ioc->sas_hba.enclosure_handle))) {
3588 ioc->sas_hba.enclosure_logical_id =
3589 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3590 }
3591 }
3592
3593 out:
3594 kfree(sas_iounit_pg1);
3595 kfree(sas_iounit_pg0);
3596}
3597
3598/**
3599 * _scsih_expander_add - creating expander object
3600 * @ioc: per adapter object
3601 * @handle: expander handle
3602 *
3603 * Creating expander object, stored in ioc->sas_expander_list.
3604 *
3605 * Return 0 for success, else error.
3606 */
3607static int
3608_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3609{
3610 struct _sas_node *sas_expander;
3611 Mpi2ConfigReply_t mpi_reply;
3612 Mpi2ExpanderPage0_t expander_pg0;
3613 Mpi2ExpanderPage1_t expander_pg1;
3614 Mpi2SasEnclosurePage0_t enclosure_pg0;
3615 u32 ioc_status;
3616 u16 parent_handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303617 __le64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003618 int i;
3619 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303620 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003621 int rc = 0;
3622
3623 if (!handle)
3624 return -1;
3625
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303626 if (ioc->shost_recovery)
3627 return -1;
3628
Eric Moore635374e2009-03-09 01:21:12 -06003629 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3630 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3631 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3632 ioc->name, __FILE__, __LINE__, __func__);
3633 return -1;
3634 }
3635
3636 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3637 MPI2_IOCSTATUS_MASK;
3638 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3639 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3640 ioc->name, __FILE__, __LINE__, __func__);
3641 return -1;
3642 }
3643
3644 /* handle out of order topology events */
3645 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303646 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
3647 != 0) {
3648 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3649 ioc->name, __FILE__, __LINE__, __func__);
3650 return -1;
3651 }
3652 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06003653 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303654 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3655 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003656 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3657 if (!sas_expander) {
3658 rc = _scsih_expander_add(ioc, parent_handle);
3659 if (rc != 0)
3660 return rc;
3661 }
3662 }
3663
Eric Moore635374e2009-03-09 01:21:12 -06003664 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303665 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06003666 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3667 sas_address);
3668 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3669
3670 if (sas_expander)
3671 return 0;
3672
3673 sas_expander = kzalloc(sizeof(struct _sas_node),
3674 GFP_KERNEL);
3675 if (!sas_expander) {
3676 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3677 ioc->name, __FILE__, __LINE__, __func__);
3678 return -1;
3679 }
3680
3681 sas_expander->handle = handle;
3682 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303683 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06003684 sas_expander->sas_address = sas_address;
3685
3686 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3687 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303688 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06003689 sas_expander->sas_address, sas_expander->num_phys);
3690
3691 if (!sas_expander->num_phys)
3692 goto out_fail;
3693 sas_expander->phy = kcalloc(sas_expander->num_phys,
3694 sizeof(struct _sas_phy), GFP_KERNEL);
3695 if (!sas_expander->phy) {
3696 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3697 ioc->name, __FILE__, __LINE__, __func__);
3698 rc = -1;
3699 goto out_fail;
3700 }
3701
3702 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3703 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303704 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003705 if (!mpt2sas_port) {
3706 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3707 ioc->name, __FILE__, __LINE__, __func__);
3708 rc = -1;
3709 goto out_fail;
3710 }
3711 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3712
3713 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3714 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3715 &expander_pg1, i, handle))) {
3716 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3717 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303718 rc = -1;
3719 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003720 }
3721 sas_expander->phy[i].handle = handle;
3722 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303723
3724 if ((mpt2sas_transport_add_expander_phy(ioc,
3725 &sas_expander->phy[i], expander_pg1,
3726 sas_expander->parent_dev))) {
3727 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3728 ioc->name, __FILE__, __LINE__, __func__);
3729 rc = -1;
3730 goto out_fail;
3731 }
Eric Moore635374e2009-03-09 01:21:12 -06003732 }
3733
3734 if (sas_expander->enclosure_handle) {
3735 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3736 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3737 sas_expander->enclosure_handle))) {
3738 sas_expander->enclosure_logical_id =
3739 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3740 }
3741 }
3742
3743 _scsih_expander_node_add(ioc, sas_expander);
3744 return 0;
3745
3746 out_fail:
3747
Kashyap, Desai20f58952009-08-07 19:34:26 +05303748 if (mpt2sas_port)
3749 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303750 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003751 kfree(sas_expander);
3752 return rc;
3753}
3754
3755/**
3756 * _scsih_expander_remove - removing expander object
3757 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303758 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06003759 *
3760 * Return nothing.
3761 */
3762static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303763_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06003764{
3765 struct _sas_node *sas_expander;
3766 unsigned long flags;
3767
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303768 if (ioc->shost_recovery)
3769 return;
3770
Eric Moore635374e2009-03-09 01:21:12 -06003771 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303772 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3773 sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06003774 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3775 _scsih_expander_node_remove(ioc, sas_expander);
3776}
3777
3778/**
3779 * _scsih_add_device - creating sas device object
3780 * @ioc: per adapter object
3781 * @handle: sas device handle
3782 * @phy_num: phy number end device attached to
3783 * @is_pd: is this hidden raid component
3784 *
3785 * Creating end device object, stored in ioc->sas_device_list.
3786 *
3787 * Returns 0 for success, non-zero for failure.
3788 */
3789static int
3790_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
3791{
3792 Mpi2ConfigReply_t mpi_reply;
3793 Mpi2SasDevicePage0_t sas_device_pg0;
3794 Mpi2SasEnclosurePage0_t enclosure_pg0;
3795 struct _sas_device *sas_device;
3796 u32 ioc_status;
3797 __le64 sas_address;
3798 u32 device_info;
3799 unsigned long flags;
3800
3801 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
3802 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
3803 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3804 ioc->name, __FILE__, __LINE__, __func__);
3805 return -1;
3806 }
3807
3808 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3809 MPI2_IOCSTATUS_MASK;
3810 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3811 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3812 ioc->name, __FILE__, __LINE__, __func__);
3813 return -1;
3814 }
3815
3816 /* check if device is present */
3817 if (!(le16_to_cpu(sas_device_pg0.Flags) &
3818 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
3819 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3820 ioc->name, __FILE__, __LINE__, __func__);
3821 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
3822 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
3823 return -1;
3824 }
3825
3826 /* check if there were any issus with discovery */
3827 if (sas_device_pg0.AccessStatus ==
3828 MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
3829 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3830 ioc->name, __FILE__, __LINE__, __func__);
3831 printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
3832 ioc->name, sas_device_pg0.AccessStatus);
3833 return -1;
3834 }
3835
3836 /* check if this is end device */
3837 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
3838 if (!(_scsih_is_end_device(device_info))) {
3839 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3840 ioc->name, __FILE__, __LINE__, __func__);
3841 return -1;
3842 }
3843
3844 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3845
3846 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3847 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
3848 sas_address);
3849 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3850
3851 if (sas_device) {
3852 _scsih_ublock_io_device(ioc, handle);
3853 return 0;
3854 }
3855
3856 sas_device = kzalloc(sizeof(struct _sas_device),
3857 GFP_KERNEL);
3858 if (!sas_device) {
3859 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3860 ioc->name, __FILE__, __LINE__, __func__);
3861 return -1;
3862 }
3863
3864 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303865 if (_scsih_get_sas_address(ioc, le16_to_cpu
3866 (sas_device_pg0.ParentDevHandle),
3867 &sas_device->sas_address_parent) != 0)
3868 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3869 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06003870 sas_device->enclosure_handle =
3871 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3872 sas_device->slot =
3873 le16_to_cpu(sas_device_pg0.Slot);
3874 sas_device->device_info = device_info;
3875 sas_device->sas_address = sas_address;
3876 sas_device->hidden_raid_component = is_pd;
3877
3878 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05303879 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
3880 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3881 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06003882 sas_device->enclosure_logical_id =
3883 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06003884
3885 /* get device name */
3886 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
3887
3888 if (ioc->wait_for_port_enable_to_complete)
3889 _scsih_sas_device_init_add(ioc, sas_device);
3890 else
3891 _scsih_sas_device_add(ioc, sas_device);
3892
3893 return 0;
3894}
3895
3896/**
3897 * _scsih_remove_device - removing sas device object
3898 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303899 * @sas_device: the sas_device object
Eric Moore635374e2009-03-09 01:21:12 -06003900 *
3901 * Return nothing.
3902 */
3903static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303904_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
3905 *sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06003906{
3907 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06003908 Mpi2SasIoUnitControlReply_t mpi_reply;
3909 Mpi2SasIoUnitControlRequest_t mpi_request;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303910 u16 device_handle, handle;
Eric Moore635374e2009-03-09 01:21:12 -06003911
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303912 if (!sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06003913 return;
Eric Moore635374e2009-03-09 01:21:12 -06003914
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303915 handle = sas_device->handle;
3916 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
3917 " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
3918 (unsigned long long) sas_device->sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06003919
3920 if (sas_device->starget && sas_device->starget->hostdata) {
3921 sas_target_priv_data = sas_device->starget->hostdata;
3922 sas_target_priv_data->deleted = 1;
3923 }
Eric Moore635374e2009-03-09 01:21:12 -06003924
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303925 if (ioc->remove_host || ioc->shost_recovery || !handle)
Eric Moore635374e2009-03-09 01:21:12 -06003926 goto out;
3927
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303928 if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
3929 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303930 "target_reset handle(0x%04x)\n", ioc->name,
3931 handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303932 goto skip_tr;
3933 }
3934
Eric Moore635374e2009-03-09 01:21:12 -06003935 /* Target Reset to flush out all the outstanding IO */
3936 device_handle = (sas_device->hidden_raid_component) ?
3937 sas_device->volume_handle : handle;
3938 if (device_handle) {
3939 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
3940 "handle(0x%04x)\n", ioc->name, device_handle));
3941 mutex_lock(&ioc->tm_cmds.mutex);
3942 mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
3943 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
3944 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
3945 mutex_unlock(&ioc->tm_cmds.mutex);
3946 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
3947 "done: handle(0x%04x)\n", ioc->name, device_handle));
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303948 if (ioc->shost_recovery)
3949 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003950 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303951 skip_tr:
3952
3953 if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) {
3954 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
3955 "sas_cntrl handle(0x%04x)\n", ioc->name, handle));
3956 goto out;
3957 }
Eric Moore635374e2009-03-09 01:21:12 -06003958
3959 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
3960 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
3961 "(0x%04x)\n", ioc->name, handle));
3962 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
3963 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
3964 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
3965 mpi_request.DevHandle = handle;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303966 mpi_request.VF_ID = 0; /* TODO */
3967 mpi_request.VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003968 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
3969 &mpi_request)) != 0) {
3970 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3971 ioc->name, __FILE__, __LINE__, __func__);
3972 }
3973
3974 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
3975 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
3976 le16_to_cpu(mpi_reply.IOCStatus),
3977 le32_to_cpu(mpi_reply.IOCLogInfo)));
3978
3979 out:
Kashyap, Desai34a03be2009-08-20 13:23:19 +05303980
3981 _scsih_ublock_io_device(ioc, handle);
3982
Eric Moore635374e2009-03-09 01:21:12 -06003983 mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303984 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003985
3986 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303987 "(0x%016llx)\n", ioc->name, handle,
Eric Moore635374e2009-03-09 01:21:12 -06003988 (unsigned long long) sas_device->sas_address);
3989 _scsih_sas_device_remove(ioc, sas_device);
3990
3991 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
3992 "(0x%04x)\n", ioc->name, __func__, handle));
3993}
3994
3995#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3996/**
3997 * _scsih_sas_topology_change_event_debug - debug for topology event
3998 * @ioc: per adapter object
3999 * @event_data: event data payload
4000 * Context: user.
4001 */
4002static void
4003_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4004 Mpi2EventDataSasTopologyChangeList_t *event_data)
4005{
4006 int i;
4007 u16 handle;
4008 u16 reason_code;
4009 u8 phy_number;
4010 char *status_str = NULL;
4011 char link_rate[25];
4012
4013 switch (event_data->ExpStatus) {
4014 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
4015 status_str = "add";
4016 break;
4017 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
4018 status_str = "remove";
4019 break;
4020 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
4021 status_str = "responding";
4022 break;
4023 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
4024 status_str = "remove delay";
4025 break;
4026 default:
4027 status_str = "unknown status";
4028 break;
4029 }
4030 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
4031 ioc->name, status_str);
4032 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
4033 "start_phy(%02d), count(%d)\n",
4034 le16_to_cpu(event_data->ExpanderDevHandle),
4035 le16_to_cpu(event_data->EnclosureHandle),
4036 event_data->StartPhyNum, event_data->NumEntries);
4037 for (i = 0; i < event_data->NumEntries; i++) {
4038 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4039 if (!handle)
4040 continue;
4041 phy_number = event_data->StartPhyNum + i;
4042 reason_code = event_data->PHY[i].PhyStatus &
4043 MPI2_EVENT_SAS_TOPO_RC_MASK;
4044 switch (reason_code) {
4045 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
4046 snprintf(link_rate, 25, ": add, link(0x%02x)",
4047 (event_data->PHY[i].LinkRate >> 4));
4048 status_str = link_rate;
4049 break;
4050 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
4051 status_str = ": remove";
4052 break;
4053 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
4054 status_str = ": remove_delay";
4055 break;
4056 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
4057 snprintf(link_rate, 25, ": link(0x%02x)",
4058 (event_data->PHY[i].LinkRate >> 4));
4059 status_str = link_rate;
4060 break;
4061 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
4062 status_str = ": responding";
4063 break;
4064 default:
4065 status_str = ": unknown";
4066 break;
4067 }
4068 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n",
4069 phy_number, handle, status_str);
4070 }
4071}
4072#endif
4073
4074/**
4075 * _scsih_sas_topology_change_event - handle topology changes
4076 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304077 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004078 * Context: user.
4079 *
4080 */
4081static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304082_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06004083 struct fw_event_work *fw_event)
4084{
4085 int i;
4086 u16 parent_handle, handle;
4087 u16 reason_code;
4088 u8 phy_number;
4089 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304090 struct _sas_device *sas_device;
4091 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004092 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304093 u8 link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304094 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004095
4096#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4097 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4098 _scsih_sas_topology_change_event_debug(ioc, event_data);
4099#endif
4100
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304101 if (ioc->shost_recovery)
4102 return;
4103
Eric Moore635374e2009-03-09 01:21:12 -06004104 if (!ioc->sas_hba.num_phys)
4105 _scsih_sas_host_add(ioc);
4106 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304107 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06004108
4109 if (fw_event->ignore) {
4110 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
4111 "event\n", ioc->name));
4112 return;
4113 }
4114
4115 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
4116
4117 /* handle expander add */
4118 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
4119 if (_scsih_expander_add(ioc, parent_handle) != 0)
4120 return;
4121
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304122 spin_lock_irqsave(&ioc->sas_node_lock, flags);
4123 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
4124 parent_handle);
4125 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4126 if (sas_expander)
4127 sas_address = sas_expander->sas_address;
4128 else if (parent_handle < ioc->sas_hba.num_phys)
4129 sas_address = ioc->sas_hba.sas_address;
4130 else
4131 return;
4132
Eric Moore635374e2009-03-09 01:21:12 -06004133 /* handle siblings events */
4134 for (i = 0; i < event_data->NumEntries; i++) {
4135 if (fw_event->ignore) {
4136 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
4137 "expander event\n", ioc->name));
4138 return;
4139 }
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304140 if (ioc->shost_recovery)
4141 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05304142 phy_number = event_data->StartPhyNum + i;
4143 reason_code = event_data->PHY[i].PhyStatus &
4144 MPI2_EVENT_SAS_TOPO_RC_MASK;
4145 if ((event_data->PHY[i].PhyStatus &
4146 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
4147 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06004148 continue;
4149 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4150 if (!handle)
4151 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304152 link_rate = event_data->PHY[i].LinkRate >> 4;
Eric Moore635374e2009-03-09 01:21:12 -06004153 switch (reason_code) {
4154 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
4155 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304156
4157 mpt2sas_transport_update_links(ioc, sas_address,
4158 handle, phy_number, link_rate);
4159
4160 if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
4161 break;
Eric Moore635374e2009-03-09 01:21:12 -06004162 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
Eric Moore635374e2009-03-09 01:21:12 -06004163 _scsih_add_device(ioc, handle, phy_number, 0);
4164 }
4165 break;
4166 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304167
4168 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4169 sas_device = _scsih_sas_device_find_by_handle(ioc,
4170 handle);
4171 if (!sas_device) {
4172 spin_unlock_irqrestore(&ioc->sas_device_lock,
4173 flags);
4174 break;
4175 }
4176 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4177 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004178 break;
4179 }
4180 }
4181
4182 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304183 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
4184 sas_expander)
4185 _scsih_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06004186
4187}
4188
4189#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4190/**
4191 * _scsih_sas_device_status_change_event_debug - debug for device event
4192 * @event_data: event data payload
4193 * Context: user.
4194 *
4195 * Return nothing.
4196 */
4197static void
4198_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4199 Mpi2EventDataSasDeviceStatusChange_t *event_data)
4200{
4201 char *reason_str = NULL;
4202
4203 switch (event_data->ReasonCode) {
4204 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
4205 reason_str = "smart data";
4206 break;
4207 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
4208 reason_str = "unsupported device discovered";
4209 break;
4210 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
4211 reason_str = "internal device reset";
4212 break;
4213 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
4214 reason_str = "internal task abort";
4215 break;
4216 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
4217 reason_str = "internal task abort set";
4218 break;
4219 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
4220 reason_str = "internal clear task set";
4221 break;
4222 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
4223 reason_str = "internal query task";
4224 break;
4225 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
4226 reason_str = "sata init failure";
4227 break;
4228 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
4229 reason_str = "internal device reset complete";
4230 break;
4231 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
4232 reason_str = "internal task abort complete";
4233 break;
4234 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
4235 reason_str = "internal async notification";
4236 break;
4237 default:
4238 reason_str = "unknown reason";
4239 break;
4240 }
4241 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
4242 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
4243 reason_str, le16_to_cpu(event_data->DevHandle),
4244 (unsigned long long)le64_to_cpu(event_data->SASAddress));
4245 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
4246 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
4247 event_data->ASC, event_data->ASCQ);
4248 printk(KERN_INFO "\n");
4249}
4250#endif
4251
4252/**
4253 * _scsih_sas_device_status_change_event - handle device status change
4254 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304255 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004256 * Context: user.
4257 *
4258 * Return nothing.
4259 */
4260static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304261_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
4262 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004263{
4264#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4265 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304266 _scsih_sas_device_status_change_event_debug(ioc,
4267 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004268#endif
4269}
4270
4271#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4272/**
4273 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
4274 * @ioc: per adapter object
4275 * @event_data: event data payload
4276 * Context: user.
4277 *
4278 * Return nothing.
4279 */
4280static void
4281_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4282 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
4283{
4284 char *reason_str = NULL;
4285
4286 switch (event_data->ReasonCode) {
4287 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
4288 reason_str = "enclosure add";
4289 break;
4290 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
4291 reason_str = "enclosure remove";
4292 break;
4293 default:
4294 reason_str = "unknown reason";
4295 break;
4296 }
4297
4298 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
4299 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
4300 " number slots(%d)\n", ioc->name, reason_str,
4301 le16_to_cpu(event_data->EnclosureHandle),
4302 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
4303 le16_to_cpu(event_data->StartSlot));
4304}
4305#endif
4306
4307/**
4308 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
4309 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304310 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004311 * Context: user.
4312 *
4313 * Return nothing.
4314 */
4315static void
4316_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304317 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004318{
4319#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4320 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4321 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304322 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004323#endif
4324}
4325
4326/**
4327 * _scsih_sas_broadcast_primative_event - handle broadcast events
4328 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304329 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004330 * Context: user.
4331 *
4332 * Return nothing.
4333 */
4334static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304335_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4336 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004337{
4338 struct scsi_cmnd *scmd;
4339 u16 smid, handle;
4340 u32 lun;
4341 struct MPT2SAS_DEVICE *sas_device_priv_data;
4342 u32 termination_count;
4343 u32 query_count;
4344 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304345#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4346 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4347#endif
Eric Moore635374e2009-03-09 01:21:12 -06004348 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4349 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4350 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004351 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4352 __func__));
4353
4354 mutex_lock(&ioc->tm_cmds.mutex);
4355 termination_count = 0;
4356 query_count = 0;
4357 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304358 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06004359 scmd = _scsih_scsi_lookup_get(ioc, smid);
4360 if (!scmd)
4361 continue;
4362 sas_device_priv_data = scmd->device->hostdata;
4363 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4364 continue;
4365 /* skip hidden raid components */
4366 if (sas_device_priv_data->sas_target->flags &
4367 MPT_TARGET_FLAGS_RAID_COMPONENT)
4368 continue;
4369 /* skip volumes */
4370 if (sas_device_priv_data->sas_target->flags &
4371 MPT_TARGET_FLAGS_VOLUME)
4372 continue;
4373
4374 handle = sas_device_priv_data->sas_target->handle;
4375 lun = sas_device_priv_data->lun;
4376 query_count++;
4377
4378 mpt2sas_scsih_issue_tm(ioc, handle, lun,
4379 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
Eric Moore8901cbb2009-04-21 15:41:32 -06004380 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004381
4382 if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) &&
4383 (mpi_reply->ResponseCode ==
4384 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4385 mpi_reply->ResponseCode ==
4386 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4387 continue;
4388
4389 mpt2sas_scsih_issue_tm(ioc, handle, lun,
Eric Moore8901cbb2009-04-21 15:41:32 -06004390 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30);
4391 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004392 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4393 }
Eric Moore635374e2009-03-09 01:21:12 -06004394 ioc->broadcast_aen_busy = 0;
4395 mutex_unlock(&ioc->tm_cmds.mutex);
4396
4397 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4398 "%s - exit, query_count = %d termination_count = %d\n",
4399 ioc->name, __func__, query_count, termination_count));
4400}
4401
4402/**
4403 * _scsih_sas_discovery_event - handle discovery events
4404 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304405 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004406 * Context: user.
4407 *
4408 * Return nothing.
4409 */
4410static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304411_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4412 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004413{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304414 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4415
Eric Moore635374e2009-03-09 01:21:12 -06004416#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4417 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4418 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4419 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4420 "start" : "stop");
4421 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304422 printk("discovery_status(0x%08x)",
4423 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06004424 printk("\n");
4425 }
4426#endif
4427
4428 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4429 !ioc->sas_hba.num_phys)
4430 _scsih_sas_host_add(ioc);
4431}
4432
4433/**
4434 * _scsih_reprobe_lun - reprobing lun
4435 * @sdev: scsi device struct
4436 * @no_uld_attach: sdev->no_uld_attach flag setting
4437 *
4438 **/
4439static void
4440_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4441{
4442 int rc;
4443
4444 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4445 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4446 sdev->no_uld_attach ? "hidding" : "exposing");
4447 rc = scsi_device_reprobe(sdev);
4448}
4449
4450/**
4451 * _scsih_reprobe_target - reprobing target
4452 * @starget: scsi target struct
4453 * @no_uld_attach: sdev->no_uld_attach flag setting
4454 *
4455 * Note: no_uld_attach flag determines whether the disk device is attached
4456 * to block layer. A value of `1` means to not attach.
4457 **/
4458static void
4459_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4460{
4461 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4462
4463 if (no_uld_attach)
4464 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4465 else
4466 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4467
4468 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4469 _scsih_reprobe_lun);
4470}
4471/**
4472 * _scsih_sas_volume_add - add new volume
4473 * @ioc: per adapter object
4474 * @element: IR config element data
4475 * Context: user.
4476 *
4477 * Return nothing.
4478 */
4479static void
4480_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4481 Mpi2EventIrConfigElement_t *element)
4482{
4483 struct _raid_device *raid_device;
4484 unsigned long flags;
4485 u64 wwid;
4486 u16 handle = le16_to_cpu(element->VolDevHandle);
4487 int rc;
4488
Eric Moore635374e2009-03-09 01:21:12 -06004489 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4490 if (!wwid) {
4491 printk(MPT2SAS_ERR_FMT
4492 "failure at %s:%d/%s()!\n", ioc->name,
4493 __FILE__, __LINE__, __func__);
4494 return;
4495 }
4496
4497 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4498 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4499 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4500
4501 if (raid_device)
4502 return;
4503
4504 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4505 if (!raid_device) {
4506 printk(MPT2SAS_ERR_FMT
4507 "failure at %s:%d/%s()!\n", ioc->name,
4508 __FILE__, __LINE__, __func__);
4509 return;
4510 }
4511
4512 raid_device->id = ioc->sas_id++;
4513 raid_device->channel = RAID_CHANNEL;
4514 raid_device->handle = handle;
4515 raid_device->wwid = wwid;
4516 _scsih_raid_device_add(ioc, raid_device);
4517 if (!ioc->wait_for_port_enable_to_complete) {
4518 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4519 raid_device->id, 0);
4520 if (rc)
4521 _scsih_raid_device_remove(ioc, raid_device);
4522 } else
4523 _scsih_determine_boot_device(ioc, raid_device, 1);
4524}
4525
4526/**
4527 * _scsih_sas_volume_delete - delete volume
4528 * @ioc: per adapter object
4529 * @element: IR config element data
4530 * Context: user.
4531 *
4532 * Return nothing.
4533 */
4534static void
4535_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4536 Mpi2EventIrConfigElement_t *element)
4537{
4538 struct _raid_device *raid_device;
4539 u16 handle = le16_to_cpu(element->VolDevHandle);
4540 unsigned long flags;
4541 struct MPT2SAS_TARGET *sas_target_priv_data;
4542
Eric Moore635374e2009-03-09 01:21:12 -06004543 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4544 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4545 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4546 if (!raid_device)
4547 return;
4548 if (raid_device->starget) {
4549 sas_target_priv_data = raid_device->starget->hostdata;
4550 sas_target_priv_data->deleted = 1;
4551 scsi_remove_target(&raid_device->starget->dev);
4552 }
4553 _scsih_raid_device_remove(ioc, raid_device);
4554}
4555
4556/**
4557 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4558 * @ioc: per adapter object
4559 * @element: IR config element data
4560 * Context: user.
4561 *
4562 * Return nothing.
4563 */
4564static void
4565_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4566 Mpi2EventIrConfigElement_t *element)
4567{
4568 struct _sas_device *sas_device;
4569 unsigned long flags;
4570 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4571
4572 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4573 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4574 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4575 if (!sas_device)
4576 return;
4577
4578 /* exposing raid component */
4579 sas_device->volume_handle = 0;
4580 sas_device->volume_wwid = 0;
4581 sas_device->hidden_raid_component = 0;
4582 _scsih_reprobe_target(sas_device->starget, 0);
4583}
4584
4585/**
4586 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4587 * @ioc: per adapter object
4588 * @element: IR config element data
4589 * Context: user.
4590 *
4591 * Return nothing.
4592 */
4593static void
4594_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4595 Mpi2EventIrConfigElement_t *element)
4596{
4597 struct _sas_device *sas_device;
4598 unsigned long flags;
4599 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4600
4601 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4602 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4603 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4604 if (!sas_device)
4605 return;
4606
4607 /* hiding raid component */
4608 mpt2sas_config_get_volume_handle(ioc, handle,
4609 &sas_device->volume_handle);
4610 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4611 &sas_device->volume_wwid);
4612 sas_device->hidden_raid_component = 1;
4613 _scsih_reprobe_target(sas_device->starget, 1);
4614}
4615
4616/**
4617 * _scsih_sas_pd_delete - delete pd component
4618 * @ioc: per adapter object
4619 * @element: IR config element data
4620 * Context: user.
4621 *
4622 * Return nothing.
4623 */
4624static void
4625_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4626 Mpi2EventIrConfigElement_t *element)
4627{
4628 struct _sas_device *sas_device;
4629 unsigned long flags;
4630 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4631
4632 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4633 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4634 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4635 if (!sas_device)
4636 return;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304637 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004638}
4639
4640/**
4641 * _scsih_sas_pd_add - remove pd component
4642 * @ioc: per adapter object
4643 * @element: IR config element data
4644 * Context: user.
4645 *
4646 * Return nothing.
4647 */
4648static void
4649_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
4650 Mpi2EventIrConfigElement_t *element)
4651{
4652 struct _sas_device *sas_device;
4653 unsigned long flags;
4654 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304655 Mpi2ConfigReply_t mpi_reply;
4656 Mpi2SasDevicePage0_t sas_device_pg0;
4657 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304658 u64 sas_address;
4659 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06004660
4661 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4662 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4663 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304664 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004665 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304666 return;
4667 }
4668
4669 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4670 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4671 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4672 ioc->name, __FILE__, __LINE__, __func__);
4673 return;
4674 }
4675
4676 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4677 MPI2_IOCSTATUS_MASK;
4678 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4679 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4680 ioc->name, __FILE__, __LINE__, __func__);
4681 return;
4682 }
4683
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304684 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
4685 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
4686 mpt2sas_transport_update_links(ioc, sas_address, handle,
4687 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304688
4689 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06004690}
4691
4692#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4693/**
4694 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
4695 * @ioc: per adapter object
4696 * @event_data: event data payload
4697 * Context: user.
4698 *
4699 * Return nothing.
4700 */
4701static void
4702_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4703 Mpi2EventDataIrConfigChangeList_t *event_data)
4704{
4705 Mpi2EventIrConfigElement_t *element;
4706 u8 element_type;
4707 int i;
4708 char *reason_str = NULL, *element_str = NULL;
4709
4710 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4711
4712 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
4713 ioc->name, (le32_to_cpu(event_data->Flags) &
4714 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
4715 "foreign" : "native", event_data->NumElements);
4716 for (i = 0; i < event_data->NumElements; i++, element++) {
4717 switch (element->ReasonCode) {
4718 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
4719 reason_str = "add";
4720 break;
4721 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
4722 reason_str = "remove";
4723 break;
4724 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
4725 reason_str = "no change";
4726 break;
4727 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4728 reason_str = "hide";
4729 break;
4730 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4731 reason_str = "unhide";
4732 break;
4733 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4734 reason_str = "volume_created";
4735 break;
4736 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4737 reason_str = "volume_deleted";
4738 break;
4739 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4740 reason_str = "pd_created";
4741 break;
4742 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4743 reason_str = "pd_deleted";
4744 break;
4745 default:
4746 reason_str = "unknown reason";
4747 break;
4748 }
4749 element_type = le16_to_cpu(element->ElementFlags) &
4750 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
4751 switch (element_type) {
4752 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
4753 element_str = "volume";
4754 break;
4755 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
4756 element_str = "phys disk";
4757 break;
4758 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
4759 element_str = "hot spare";
4760 break;
4761 default:
4762 element_str = "unknown element";
4763 break;
4764 }
4765 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
4766 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
4767 reason_str, le16_to_cpu(element->VolDevHandle),
4768 le16_to_cpu(element->PhysDiskDevHandle),
4769 element->PhysDiskNum);
4770 }
4771}
4772#endif
4773
4774/**
4775 * _scsih_sas_ir_config_change_event - handle ir configuration change events
4776 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304777 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004778 * Context: user.
4779 *
4780 * Return nothing.
4781 */
4782static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304783_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
4784 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004785{
4786 Mpi2EventIrConfigElement_t *element;
4787 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304788 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304789 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004790
4791#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4792 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4793 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
4794
4795#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05304796 foreign_config = (le32_to_cpu(event_data->Flags) &
4797 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06004798
4799 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4800 for (i = 0; i < event_data->NumElements; i++, element++) {
4801
4802 switch (element->ReasonCode) {
4803 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4804 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304805 if (!foreign_config)
4806 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004807 break;
4808 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4809 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304810 if (!foreign_config)
4811 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004812 break;
4813 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4814 _scsih_sas_pd_hide(ioc, element);
4815 break;
4816 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4817 _scsih_sas_pd_expose(ioc, element);
4818 break;
4819 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4820 _scsih_sas_pd_add(ioc, element);
4821 break;
4822 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4823 _scsih_sas_pd_delete(ioc, element);
4824 break;
4825 }
4826 }
4827}
4828
4829/**
4830 * _scsih_sas_ir_volume_event - IR volume event
4831 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304832 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004833 * Context: user.
4834 *
4835 * Return nothing.
4836 */
4837static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304838_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
4839 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004840{
4841 u64 wwid;
4842 unsigned long flags;
4843 struct _raid_device *raid_device;
4844 u16 handle;
4845 u32 state;
4846 int rc;
4847 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304848 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004849
4850 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
4851 return;
4852
4853 handle = le16_to_cpu(event_data->VolDevHandle);
4854 state = le32_to_cpu(event_data->NewValue);
4855 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4856 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4857 le32_to_cpu(event_data->PreviousValue), state));
4858
4859 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4860 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4861 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4862
4863 switch (state) {
4864 case MPI2_RAID_VOL_STATE_MISSING:
4865 case MPI2_RAID_VOL_STATE_FAILED:
4866 if (!raid_device)
4867 break;
4868 if (raid_device->starget) {
4869 sas_target_priv_data = raid_device->starget->hostdata;
4870 sas_target_priv_data->deleted = 1;
4871 scsi_remove_target(&raid_device->starget->dev);
4872 }
4873 _scsih_raid_device_remove(ioc, raid_device);
4874 break;
4875
4876 case MPI2_RAID_VOL_STATE_ONLINE:
4877 case MPI2_RAID_VOL_STATE_DEGRADED:
4878 case MPI2_RAID_VOL_STATE_OPTIMAL:
4879 if (raid_device)
4880 break;
4881
4882 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4883 if (!wwid) {
4884 printk(MPT2SAS_ERR_FMT
4885 "failure at %s:%d/%s()!\n", ioc->name,
4886 __FILE__, __LINE__, __func__);
4887 break;
4888 }
4889
4890 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4891 if (!raid_device) {
4892 printk(MPT2SAS_ERR_FMT
4893 "failure at %s:%d/%s()!\n", ioc->name,
4894 __FILE__, __LINE__, __func__);
4895 break;
4896 }
4897
4898 raid_device->id = ioc->sas_id++;
4899 raid_device->channel = RAID_CHANNEL;
4900 raid_device->handle = handle;
4901 raid_device->wwid = wwid;
4902 _scsih_raid_device_add(ioc, raid_device);
4903 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4904 raid_device->id, 0);
4905 if (rc)
4906 _scsih_raid_device_remove(ioc, raid_device);
4907 break;
4908
4909 case MPI2_RAID_VOL_STATE_INITIALIZING:
4910 default:
4911 break;
4912 }
4913}
4914
4915/**
4916 * _scsih_sas_ir_physical_disk_event - PD event
4917 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304918 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004919 * Context: user.
4920 *
4921 * Return nothing.
4922 */
4923static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304924_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
4925 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004926{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304927 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06004928 u32 state;
4929 struct _sas_device *sas_device;
4930 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304931 Mpi2ConfigReply_t mpi_reply;
4932 Mpi2SasDevicePage0_t sas_device_pg0;
4933 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304934 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304935 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004936
4937 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
4938 return;
4939
4940 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
4941 state = le32_to_cpu(event_data->NewValue);
4942
4943 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4944 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4945 le32_to_cpu(event_data->PreviousValue), state));
4946
4947 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4948 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4949 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4950
4951 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06004952 case MPI2_RAID_PD_STATE_ONLINE:
4953 case MPI2_RAID_PD_STATE_DEGRADED:
4954 case MPI2_RAID_PD_STATE_REBUILDING:
4955 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304956 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004957 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304958 return;
4959 }
4960
4961 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
4962 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
4963 handle))) {
4964 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4965 ioc->name, __FILE__, __LINE__, __func__);
4966 return;
4967 }
4968
4969 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4970 MPI2_IOCSTATUS_MASK;
4971 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4972 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4973 ioc->name, __FILE__, __LINE__, __func__);
4974 return;
4975 }
4976
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304977 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
4978 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
4979 mpt2sas_transport_update_links(ioc, sas_address, handle,
4980 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304981
4982 _scsih_add_device(ioc, handle, 0, 1);
4983
Eric Moore635374e2009-03-09 01:21:12 -06004984 break;
4985
Kashyap, Desai62727a72009-08-07 19:35:18 +05304986 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06004987 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
4988 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
4989 case MPI2_RAID_PD_STATE_HOT_SPARE:
4990 default:
4991 break;
4992 }
4993}
4994
4995#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4996/**
4997 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
4998 * @ioc: per adapter object
4999 * @event_data: event data payload
5000 * Context: user.
5001 *
5002 * Return nothing.
5003 */
5004static void
5005_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
5006 Mpi2EventDataIrOperationStatus_t *event_data)
5007{
5008 char *reason_str = NULL;
5009
5010 switch (event_data->RAIDOperation) {
5011 case MPI2_EVENT_IR_RAIDOP_RESYNC:
5012 reason_str = "resync";
5013 break;
5014 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
5015 reason_str = "online capacity expansion";
5016 break;
5017 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
5018 reason_str = "consistency check";
5019 break;
5020 default:
5021 reason_str = "unknown reason";
5022 break;
5023 }
5024
5025 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
5026 "\thandle(0x%04x), percent complete(%d)\n",
5027 ioc->name, reason_str,
5028 le16_to_cpu(event_data->VolDevHandle),
5029 event_data->PercentComplete);
5030}
5031#endif
5032
5033/**
5034 * _scsih_sas_ir_operation_status_event - handle RAID operation events
5035 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305036 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005037 * Context: user.
5038 *
5039 * Return nothing.
5040 */
5041static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305042_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
5043 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005044{
5045#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5046 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305047 _scsih_sas_ir_operation_status_event_debug(ioc,
5048 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005049#endif
5050}
5051
5052/**
5053 * _scsih_task_set_full - handle task set full
5054 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305055 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005056 * Context: user.
5057 *
5058 * Throttle back qdepth.
5059 */
5060static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305061_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
5062 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005063{
5064 unsigned long flags;
5065 struct _sas_device *sas_device;
5066 static struct _raid_device *raid_device;
5067 struct scsi_device *sdev;
5068 int depth;
5069 u16 current_depth;
5070 u16 handle;
5071 int id, channel;
5072 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305073 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005074
5075 current_depth = le16_to_cpu(event_data->CurrentDepth);
5076 handle = le16_to_cpu(event_data->DevHandle);
5077 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5078 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5079 if (!sas_device) {
5080 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5081 return;
5082 }
5083 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5084 id = sas_device->id;
5085 channel = sas_device->channel;
5086 sas_address = sas_device->sas_address;
5087
5088 /* if hidden raid component, then change to volume characteristics */
5089 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
5090 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5091 raid_device = _scsih_raid_device_find_by_handle(
5092 ioc, sas_device->volume_handle);
5093 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5094 if (raid_device) {
5095 id = raid_device->id;
5096 channel = raid_device->channel;
5097 handle = raid_device->handle;
5098 sas_address = raid_device->wwid;
5099 }
5100 }
5101
5102 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
5103 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
5104 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
5105 handle, (unsigned long long)sas_address, current_depth);
5106
5107 shost_for_each_device(sdev, ioc->shost) {
5108 if (sdev->id == id && sdev->channel == channel) {
5109 if (current_depth > sdev->queue_depth) {
5110 if (ioc->logging_level &
5111 MPT_DEBUG_TASK_SET_FULL)
5112 sdev_printk(KERN_INFO, sdev, "strange "
5113 "observation, the queue depth is"
5114 " (%d) meanwhile fw queue depth "
5115 "is (%d)\n", sdev->queue_depth,
5116 current_depth);
5117 continue;
5118 }
5119 depth = scsi_track_queue_full(sdev,
5120 current_depth - 1);
5121 if (depth > 0)
5122 sdev_printk(KERN_INFO, sdev, "Queue depth "
5123 "reduced to (%d)\n", depth);
5124 else if (depth < 0)
5125 sdev_printk(KERN_INFO, sdev, "Tagged Command "
5126 "Queueing is being disabled\n");
5127 else if (depth == 0)
5128 if (ioc->logging_level &
5129 MPT_DEBUG_TASK_SET_FULL)
5130 sdev_printk(KERN_INFO, sdev,
5131 "Queue depth not changed yet\n");
5132 }
5133 }
5134}
5135
5136/**
5137 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
5138 * @ioc: per adapter object
5139 * @sas_address: sas address
5140 * @slot: enclosure slot id
5141 * @handle: device handle
5142 *
5143 * After host reset, find out whether devices are still responding.
5144 * Used in _scsi_remove_unresponsive_sas_devices.
5145 *
5146 * Return nothing.
5147 */
5148static void
5149_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5150 u16 slot, u16 handle)
5151{
5152 struct MPT2SAS_TARGET *sas_target_priv_data;
5153 struct scsi_target *starget;
5154 struct _sas_device *sas_device;
5155 unsigned long flags;
5156
5157 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5158 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
5159 if (sas_device->sas_address == sas_address &&
5160 sas_device->slot == slot && sas_device->starget) {
5161 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305162 sas_device->state = 0;
5163 starget = sas_device->starget;
5164 sas_target_priv_data = starget->hostdata;
5165 sas_target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06005166 starget_printk(KERN_INFO, sas_device->starget,
5167 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
5168 "logical id(0x%016llx), slot(%d)\n", handle,
5169 (unsigned long long)sas_device->sas_address,
5170 (unsigned long long)
5171 sas_device->enclosure_logical_id,
5172 sas_device->slot);
5173 if (sas_device->handle == handle)
5174 goto out;
5175 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5176 sas_device->handle);
5177 sas_device->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005178 sas_target_priv_data->handle = handle;
5179 goto out;
5180 }
5181 }
5182 out:
5183 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5184}
5185
5186/**
5187 * _scsih_search_responding_sas_devices -
5188 * @ioc: per adapter object
5189 *
5190 * After host reset, find out whether devices are still responding.
5191 * If not remove.
5192 *
5193 * Return nothing.
5194 */
5195static void
5196_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
5197{
5198 Mpi2SasDevicePage0_t sas_device_pg0;
5199 Mpi2ConfigReply_t mpi_reply;
5200 u16 ioc_status;
5201 __le64 sas_address;
5202 u16 handle;
5203 u32 device_info;
5204 u16 slot;
5205
5206 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5207
5208 if (list_empty(&ioc->sas_device_list))
5209 return;
5210
5211 handle = 0xFFFF;
5212 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5213 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
5214 handle))) {
5215 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5216 MPI2_IOCSTATUS_MASK;
5217 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5218 break;
5219 handle = le16_to_cpu(sas_device_pg0.DevHandle);
5220 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5221 if (!(_scsih_is_end_device(device_info)))
5222 continue;
5223 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5224 slot = le16_to_cpu(sas_device_pg0.Slot);
5225 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
5226 handle);
5227 }
5228}
5229
5230/**
5231 * _scsih_mark_responding_raid_device - mark a raid_device as responding
5232 * @ioc: per adapter object
5233 * @wwid: world wide identifier for raid volume
5234 * @handle: device handle
5235 *
5236 * After host reset, find out whether devices are still responding.
5237 * Used in _scsi_remove_unresponsive_raid_devices.
5238 *
5239 * Return nothing.
5240 */
5241static void
5242_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
5243 u16 handle)
5244{
5245 struct MPT2SAS_TARGET *sas_target_priv_data;
5246 struct scsi_target *starget;
5247 struct _raid_device *raid_device;
5248 unsigned long flags;
5249
5250 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5251 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
5252 if (raid_device->wwid == wwid && raid_device->starget) {
5253 raid_device->responding = 1;
5254 starget_printk(KERN_INFO, raid_device->starget,
5255 "handle(0x%04x), wwid(0x%016llx)\n", handle,
5256 (unsigned long long)raid_device->wwid);
5257 if (raid_device->handle == handle)
5258 goto out;
5259 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5260 raid_device->handle);
5261 raid_device->handle = handle;
5262 starget = raid_device->starget;
5263 sas_target_priv_data = starget->hostdata;
5264 sas_target_priv_data->handle = handle;
5265 goto out;
5266 }
5267 }
5268 out:
5269 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5270}
5271
5272/**
5273 * _scsih_search_responding_raid_devices -
5274 * @ioc: per adapter object
5275 *
5276 * After host reset, find out whether devices are still responding.
5277 * If not remove.
5278 *
5279 * Return nothing.
5280 */
5281static void
5282_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
5283{
5284 Mpi2RaidVolPage1_t volume_pg1;
5285 Mpi2ConfigReply_t mpi_reply;
5286 u16 ioc_status;
5287 u16 handle;
5288
5289 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5290
5291 if (list_empty(&ioc->raid_device_list))
5292 return;
5293
5294 handle = 0xFFFF;
5295 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
5296 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
5297 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5298 MPI2_IOCSTATUS_MASK;
5299 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5300 break;
5301 handle = le16_to_cpu(volume_pg1.DevHandle);
5302 _scsih_mark_responding_raid_device(ioc,
5303 le64_to_cpu(volume_pg1.WWID), handle);
5304 }
5305}
5306
5307/**
5308 * _scsih_mark_responding_expander - mark a expander as responding
5309 * @ioc: per adapter object
5310 * @sas_address: sas address
5311 * @handle:
5312 *
5313 * After host reset, find out whether devices are still responding.
5314 * Used in _scsi_remove_unresponsive_expanders.
5315 *
5316 * Return nothing.
5317 */
5318static void
5319_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5320 u16 handle)
5321{
5322 struct _sas_node *sas_expander;
5323 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305324 int i;
Eric Moore635374e2009-03-09 01:21:12 -06005325
5326 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5327 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305328 if (sas_expander->sas_address != sas_address)
5329 continue;
5330 sas_expander->responding = 1;
5331 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06005332 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305333 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
5334 " from(0x%04x) to (0x%04x)!!!\n",
5335 (unsigned long long)sas_expander->sas_address,
5336 sas_expander->handle, handle);
5337 sas_expander->handle = handle;
5338 for (i = 0 ; i < sas_expander->num_phys ; i++)
5339 sas_expander->phy[i].handle = handle;
5340 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06005341 }
5342 out:
5343 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5344}
5345
5346/**
5347 * _scsih_search_responding_expanders -
5348 * @ioc: per adapter object
5349 *
5350 * After host reset, find out whether devices are still responding.
5351 * If not remove.
5352 *
5353 * Return nothing.
5354 */
5355static void
5356_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5357{
5358 Mpi2ExpanderPage0_t expander_pg0;
5359 Mpi2ConfigReply_t mpi_reply;
5360 u16 ioc_status;
5361 __le64 sas_address;
5362 u16 handle;
5363
5364 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5365
5366 if (list_empty(&ioc->sas_expander_list))
5367 return;
5368
5369 handle = 0xFFFF;
5370 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5371 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5372
5373 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5374 MPI2_IOCSTATUS_MASK;
5375 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5376 break;
5377
5378 handle = le16_to_cpu(expander_pg0.DevHandle);
5379 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5380 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5381 "sas_addr(0x%016llx)\n", handle,
5382 (unsigned long long)sas_address);
5383 _scsih_mark_responding_expander(ioc, sas_address, handle);
5384 }
5385
5386}
5387
5388/**
5389 * _scsih_remove_unresponding_devices - removing unresponding devices
5390 * @ioc: per adapter object
5391 *
5392 * Return nothing.
5393 */
5394static void
5395_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
5396{
5397 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305398 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005399 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005400
Eric Moore635374e2009-03-09 01:21:12 -06005401
5402 list_for_each_entry_safe(sas_device, sas_device_next,
5403 &ioc->sas_device_list, list) {
5404 if (sas_device->responding) {
5405 sas_device->responding = 0;
5406 continue;
5407 }
5408 if (sas_device->starget)
5409 starget_printk(KERN_INFO, sas_device->starget,
5410 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5411 "enclosure logical id(0x%016llx), slot(%d)\n",
5412 sas_device->handle,
5413 (unsigned long long)sas_device->sas_address,
5414 (unsigned long long)
5415 sas_device->enclosure_logical_id,
5416 sas_device->slot);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305417 /* invalidate the device handle */
5418 sas_device->handle = 0;
5419 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005420 }
5421
5422 list_for_each_entry_safe(raid_device, raid_device_next,
5423 &ioc->raid_device_list, list) {
5424 if (raid_device->responding) {
5425 raid_device->responding = 0;
5426 continue;
5427 }
5428 if (raid_device->starget) {
5429 starget_printk(KERN_INFO, raid_device->starget,
5430 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5431 raid_device->handle,
5432 (unsigned long long)raid_device->wwid);
5433 scsi_remove_target(&raid_device->starget->dev);
5434 }
5435 _scsih_raid_device_remove(ioc, raid_device);
5436 }
5437
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305438 retry_expander_search:
5439 sas_expander = NULL;
5440 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005441 if (sas_expander->responding) {
5442 sas_expander->responding = 0;
5443 continue;
5444 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305445 _scsih_expander_remove(ioc, sas_expander->sas_address);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305446 goto retry_expander_search;
5447 }
5448}
5449
5450/**
5451 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5452 * @ioc: per adapter object
5453 * @reset_phase: phase
5454 *
5455 * The handler for doing any required cleanup or initialization.
5456 *
5457 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5458 * MPT2_IOC_DONE_RESET
5459 *
5460 * Return nothing.
5461 */
5462void
5463mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5464{
5465 switch (reset_phase) {
5466 case MPT2_IOC_PRE_RESET:
5467 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5468 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
5469 _scsih_fw_event_off(ioc);
5470 break;
5471 case MPT2_IOC_AFTER_RESET:
5472 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5473 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
5474 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5475 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5476 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5477 complete(&ioc->tm_cmds.done);
5478 }
5479 _scsih_fw_event_on(ioc);
5480 _scsih_flush_running_cmds(ioc);
5481 break;
5482 case MPT2_IOC_DONE_RESET:
5483 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5484 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305485 _scsih_sas_host_refresh(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305486 _scsih_search_responding_sas_devices(ioc);
5487 _scsih_search_responding_raid_devices(ioc);
5488 _scsih_search_responding_expanders(ioc);
5489 break;
5490 case MPT2_IOC_RUNNING:
5491 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5492 "MPT2_IOC_RUNNING\n", ioc->name, __func__));
5493 _scsih_remove_unresponding_devices(ioc);
5494 break;
Eric Moore635374e2009-03-09 01:21:12 -06005495 }
5496}
5497
5498/**
5499 * _firmware_event_work - delayed task for processing firmware events
5500 * @ioc: per adapter object
5501 * @work: equal to the fw_event_work object
5502 * Context: user.
5503 *
5504 * Return nothing.
5505 */
5506static void
5507_firmware_event_work(struct work_struct *work)
5508{
5509 struct fw_event_work *fw_event = container_of(work,
Eric Moore6f92a7a2009-04-21 15:43:33 -06005510 struct fw_event_work, work);
Eric Moore635374e2009-03-09 01:21:12 -06005511 unsigned long flags;
5512 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5513
Eric Moore635374e2009-03-09 01:21:12 -06005514 /* the queue is being flushed so ignore this event */
5515 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5516 if (ioc->fw_events_off || ioc->remove_host) {
5517 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5518 _scsih_fw_event_free(ioc, fw_event);
5519 return;
5520 }
5521 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5522
Eric Moore635374e2009-03-09 01:21:12 -06005523 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06005524 _scsih_fw_event_requeue(ioc, fw_event, 1000);
5525 return;
5526 }
Eric Moore635374e2009-03-09 01:21:12 -06005527
5528 switch (fw_event->event) {
5529 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305530 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005531 break;
5532 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305533 _scsih_sas_device_status_change_event(ioc,
5534 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005535 break;
5536 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305537 _scsih_sas_discovery_event(ioc,
5538 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005539 break;
5540 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305541 _scsih_sas_broadcast_primative_event(ioc,
5542 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005543 break;
5544 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5545 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305546 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005547 break;
5548 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305549 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005550 break;
5551 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305552 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005553 break;
5554 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305555 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005556 break;
5557 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305558 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005559 break;
5560 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305561 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005562 break;
5563 }
5564 _scsih_fw_event_free(ioc, fw_event);
5565}
5566
5567/**
5568 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5569 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305570 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06005571 * @reply: reply message frame(lower 32bit addr)
5572 * Context: interrupt.
5573 *
5574 * This function merely adds a new work task into ioc->firmware_event_thread.
5575 * The tasks are worked from _firmware_event_work in user context.
5576 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305577 * Return 1 meaning mf should be freed from _base_interrupt
5578 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06005579 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305580u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305581mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
5582 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06005583{
5584 struct fw_event_work *fw_event;
5585 Mpi2EventNotificationReply_t *mpi_reply;
5586 unsigned long flags;
5587 u16 event;
5588
5589 /* events turned off due to host reset or driver unloading */
5590 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5591 if (ioc->fw_events_off || ioc->remove_host) {
5592 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305593 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005594 }
5595 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5596
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305597 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06005598 event = le16_to_cpu(mpi_reply->Event);
5599
5600 switch (event) {
5601 /* handle these */
5602 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
5603 {
5604 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
5605 (Mpi2EventDataSasBroadcastPrimitive_t *)
5606 mpi_reply->EventData;
5607
5608 if (baen_data->Primitive !=
5609 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
5610 ioc->broadcast_aen_busy)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305611 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005612 ioc->broadcast_aen_busy = 1;
5613 break;
5614 }
5615
5616 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
5617 _scsih_check_topo_delete_events(ioc,
5618 (Mpi2EventDataSasTopologyChangeList_t *)
5619 mpi_reply->EventData);
5620 break;
5621
5622 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
5623 case MPI2_EVENT_IR_OPERATION_STATUS:
5624 case MPI2_EVENT_SAS_DISCOVERY:
5625 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5626 case MPI2_EVENT_IR_VOLUME:
5627 case MPI2_EVENT_IR_PHYSICAL_DISK:
5628 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
5629 case MPI2_EVENT_TASK_SET_FULL:
5630 break;
5631
5632 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305633 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005634 }
5635
5636 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
5637 if (!fw_event) {
5638 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5639 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305640 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005641 }
5642 fw_event->event_data =
5643 kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
5644 if (!fw_event->event_data) {
5645 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5646 ioc->name, __FILE__, __LINE__, __func__);
5647 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305648 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005649 }
5650
5651 memcpy(fw_event->event_data, mpi_reply->EventData,
5652 mpi_reply->EventDataLength*4);
5653 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305654 fw_event->VF_ID = mpi_reply->VF_ID;
5655 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06005656 fw_event->event = event;
5657 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305658 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005659}
5660
5661/* shost template */
5662static struct scsi_host_template scsih_driver_template = {
5663 .module = THIS_MODULE,
5664 .name = "Fusion MPT SAS Host",
5665 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06005666 .queuecommand = _scsih_qcmd,
5667 .target_alloc = _scsih_target_alloc,
5668 .slave_alloc = _scsih_slave_alloc,
5669 .slave_configure = _scsih_slave_configure,
5670 .target_destroy = _scsih_target_destroy,
5671 .slave_destroy = _scsih_slave_destroy,
5672 .change_queue_depth = _scsih_change_queue_depth,
5673 .change_queue_type = _scsih_change_queue_type,
5674 .eh_abort_handler = _scsih_abort,
5675 .eh_device_reset_handler = _scsih_dev_reset,
5676 .eh_target_reset_handler = _scsih_target_reset,
5677 .eh_host_reset_handler = _scsih_host_reset,
5678 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06005679 .can_queue = 1,
5680 .this_id = -1,
5681 .sg_tablesize = MPT2SAS_SG_DEPTH,
5682 .max_sectors = 8192,
5683 .cmd_per_lun = 7,
5684 .use_clustering = ENABLE_CLUSTERING,
5685 .shost_attrs = mpt2sas_host_attrs,
5686 .sdev_attrs = mpt2sas_dev_attrs,
5687};
5688
5689/**
5690 * _scsih_expander_node_remove - removing expander device from list.
5691 * @ioc: per adapter object
5692 * @sas_expander: the sas_device object
5693 * Context: Calling function should acquire ioc->sas_node_lock.
5694 *
5695 * Removing object and freeing associated memory from the
5696 * ioc->sas_expander_list.
5697 *
5698 * Return nothing.
5699 */
5700static void
5701_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
5702 struct _sas_node *sas_expander)
5703{
5704 struct _sas_port *mpt2sas_port;
5705 struct _sas_device *sas_device;
5706 struct _sas_node *expander_sibling;
5707 unsigned long flags;
5708
5709 if (!sas_expander)
5710 return;
5711
5712 /* remove sibling ports attached to this expander */
5713 retry_device_search:
5714 list_for_each_entry(mpt2sas_port,
5715 &sas_expander->sas_port_list, port_list) {
5716 if (mpt2sas_port->remote_identify.device_type ==
5717 SAS_END_DEVICE) {
5718 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5719 sas_device =
5720 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5721 mpt2sas_port->remote_identify.sas_address);
5722 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5723 if (!sas_device)
5724 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305725 _scsih_remove_device(ioc, sas_device);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305726 if (ioc->shost_recovery)
5727 return;
Eric Moore635374e2009-03-09 01:21:12 -06005728 goto retry_device_search;
5729 }
5730 }
5731
5732 retry_expander_search:
5733 list_for_each_entry(mpt2sas_port,
5734 &sas_expander->sas_port_list, port_list) {
5735
5736 if (mpt2sas_port->remote_identify.device_type ==
5737 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
5738 mpt2sas_port->remote_identify.device_type ==
5739 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
5740
5741 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5742 expander_sibling =
5743 mpt2sas_scsih_expander_find_by_sas_address(
5744 ioc, mpt2sas_port->remote_identify.sas_address);
5745 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5746 if (!expander_sibling)
5747 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305748 _scsih_expander_remove(ioc,
5749 expander_sibling->sas_address);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305750 if (ioc->shost_recovery)
5751 return;
Eric Moore635374e2009-03-09 01:21:12 -06005752 goto retry_expander_search;
5753 }
5754 }
5755
5756 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305757 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06005758
5759 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
5760 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
5761 sas_expander->handle, (unsigned long long)
5762 sas_expander->sas_address);
5763
5764 list_del(&sas_expander->list);
5765 kfree(sas_expander->phy);
5766 kfree(sas_expander);
5767}
5768
5769/**
Eric Moored5d135b2009-05-18 13:02:08 -06005770 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06005771 * @pdev: PCI device struct
5772 *
5773 * Return nothing.
5774 */
5775static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06005776_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06005777{
5778 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5779 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5780 struct _sas_port *mpt2sas_port;
5781 struct _sas_device *sas_device;
5782 struct _sas_node *expander_sibling;
5783 struct workqueue_struct *wq;
5784 unsigned long flags;
5785
5786 ioc->remove_host = 1;
5787 _scsih_fw_event_off(ioc);
5788
5789 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5790 wq = ioc->firmware_event_thread;
5791 ioc->firmware_event_thread = NULL;
5792 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5793 if (wq)
5794 destroy_workqueue(wq);
5795
5796 /* free ports attached to the sas_host */
5797 retry_again:
5798 list_for_each_entry(mpt2sas_port,
5799 &ioc->sas_hba.sas_port_list, port_list) {
5800 if (mpt2sas_port->remote_identify.device_type ==
5801 SAS_END_DEVICE) {
5802 sas_device =
5803 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5804 mpt2sas_port->remote_identify.sas_address);
5805 if (sas_device) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305806 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005807 goto retry_again;
5808 }
5809 } else {
5810 expander_sibling =
5811 mpt2sas_scsih_expander_find_by_sas_address(ioc,
5812 mpt2sas_port->remote_identify.sas_address);
5813 if (expander_sibling) {
5814 _scsih_expander_remove(ioc,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305815 expander_sibling->sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06005816 goto retry_again;
5817 }
5818 }
5819 }
5820
5821 /* free phys attached to the sas_host */
5822 if (ioc->sas_hba.num_phys) {
5823 kfree(ioc->sas_hba.phy);
5824 ioc->sas_hba.phy = NULL;
5825 ioc->sas_hba.num_phys = 0;
5826 }
5827
5828 sas_remove_host(shost);
5829 mpt2sas_base_detach(ioc);
5830 list_del(&ioc->list);
5831 scsi_remove_host(shost);
5832 scsi_host_put(shost);
5833}
5834
5835/**
5836 * _scsih_probe_boot_devices - reports 1st device
5837 * @ioc: per adapter object
5838 *
5839 * If specified in bios page 2, this routine reports the 1st
5840 * device scsi-ml or sas transport for persistent boot device
5841 * purposes. Please refer to function _scsih_determine_boot_device()
5842 */
5843static void
5844_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
5845{
5846 u8 is_raid;
5847 void *device;
5848 struct _sas_device *sas_device;
5849 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305850 u16 handle;
5851 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06005852 u64 sas_address;
5853 unsigned long flags;
5854 int rc;
5855
5856 device = NULL;
5857 if (ioc->req_boot_device.device) {
5858 device = ioc->req_boot_device.device;
5859 is_raid = ioc->req_boot_device.is_raid;
5860 } else if (ioc->req_alt_boot_device.device) {
5861 device = ioc->req_alt_boot_device.device;
5862 is_raid = ioc->req_alt_boot_device.is_raid;
5863 } else if (ioc->current_boot_device.device) {
5864 device = ioc->current_boot_device.device;
5865 is_raid = ioc->current_boot_device.is_raid;
5866 }
5867
5868 if (!device)
5869 return;
5870
5871 if (is_raid) {
5872 raid_device = device;
5873 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5874 raid_device->id, 0);
5875 if (rc)
5876 _scsih_raid_device_remove(ioc, raid_device);
5877 } else {
5878 sas_device = device;
5879 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305880 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06005881 sas_address = sas_device->sas_address;
5882 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5883 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5884 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5885 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305886 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06005887 _scsih_sas_device_remove(ioc, sas_device);
5888 } else if (!sas_device->starget) {
5889 mpt2sas_transport_port_remove(ioc, sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305890 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06005891 _scsih_sas_device_remove(ioc, sas_device);
5892 }
5893 }
5894}
5895
5896/**
5897 * _scsih_probe_raid - reporting raid volumes to scsi-ml
5898 * @ioc: per adapter object
5899 *
5900 * Called during initial loading of the driver.
5901 */
5902static void
5903_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
5904{
5905 struct _raid_device *raid_device, *raid_next;
5906 int rc;
5907
5908 list_for_each_entry_safe(raid_device, raid_next,
5909 &ioc->raid_device_list, list) {
5910 if (raid_device->starget)
5911 continue;
5912 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5913 raid_device->id, 0);
5914 if (rc)
5915 _scsih_raid_device_remove(ioc, raid_device);
5916 }
5917}
5918
5919/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305920 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06005921 * @ioc: per adapter object
5922 *
5923 * Called during initial loading of the driver.
5924 */
5925static void
5926_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
5927{
5928 struct _sas_device *sas_device, *next;
5929 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06005930
5931 /* SAS Device List */
5932 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
5933 list) {
5934 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5935 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5936 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5937
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305938 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
5939 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06005940 _scsih_sas_device_remove(ioc, sas_device);
5941 } else if (!sas_device->starget) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305942 mpt2sas_transport_port_remove(ioc,
5943 sas_device->sas_address,
5944 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06005945 _scsih_sas_device_remove(ioc, sas_device);
5946 }
5947 }
5948}
5949
5950/**
5951 * _scsih_probe_devices - probing for devices
5952 * @ioc: per adapter object
5953 *
5954 * Called during initial loading of the driver.
5955 */
5956static void
5957_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
5958{
5959 u16 volume_mapping_flags =
5960 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
5961 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
5962
5963 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
5964 return; /* return when IOC doesn't support initiator mode */
5965
5966 _scsih_probe_boot_devices(ioc);
5967
5968 if (ioc->ir_firmware) {
5969 if ((volume_mapping_flags &
5970 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
5971 _scsih_probe_sas(ioc);
5972 _scsih_probe_raid(ioc);
5973 } else {
5974 _scsih_probe_raid(ioc);
5975 _scsih_probe_sas(ioc);
5976 }
5977 } else
5978 _scsih_probe_sas(ioc);
5979}
5980
5981/**
Eric Moored5d135b2009-05-18 13:02:08 -06005982 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06005983 * @pdev: PCI device struct
5984 * @id: pci device id
5985 *
5986 * Returns 0 success, anything else error.
5987 */
5988static int
Eric Moored5d135b2009-05-18 13:02:08 -06005989_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06005990{
5991 struct MPT2SAS_ADAPTER *ioc;
5992 struct Scsi_Host *shost;
5993
5994 shost = scsi_host_alloc(&scsih_driver_template,
5995 sizeof(struct MPT2SAS_ADAPTER));
5996 if (!shost)
5997 return -ENODEV;
5998
5999 /* init local params */
6000 ioc = shost_priv(shost);
6001 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
6002 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06006003 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06006004 ioc->shost = shost;
6005 ioc->id = mpt_ids++;
6006 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
6007 ioc->pdev = pdev;
6008 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
6009 ioc->tm_cb_idx = tm_cb_idx;
6010 ioc->ctl_cb_idx = ctl_cb_idx;
6011 ioc->base_cb_idx = base_cb_idx;
6012 ioc->transport_cb_idx = transport_cb_idx;
6013 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306014 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
6015 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006016 ioc->logging_level = logging_level;
6017 /* misc semaphores and spin locks */
6018 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
6019 spin_lock_init(&ioc->scsi_lookup_lock);
6020 spin_lock_init(&ioc->sas_device_lock);
6021 spin_lock_init(&ioc->sas_node_lock);
6022 spin_lock_init(&ioc->fw_event_lock);
6023 spin_lock_init(&ioc->raid_device_lock);
6024
6025 INIT_LIST_HEAD(&ioc->sas_device_list);
6026 INIT_LIST_HEAD(&ioc->sas_device_init_list);
6027 INIT_LIST_HEAD(&ioc->sas_expander_list);
6028 INIT_LIST_HEAD(&ioc->fw_event_list);
6029 INIT_LIST_HEAD(&ioc->raid_device_list);
6030 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306031 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Eric Moore635374e2009-03-09 01:21:12 -06006032
6033 /* init shost parameters */
6034 shost->max_cmd_len = 16;
6035 shost->max_lun = max_lun;
6036 shost->transportt = mpt2sas_transport_template;
6037 shost->unique_id = ioc->id;
6038
6039 if ((scsi_add_host(shost, &pdev->dev))) {
6040 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6041 ioc->name, __FILE__, __LINE__, __func__);
6042 list_del(&ioc->list);
6043 goto out_add_shost_fail;
6044 }
6045
Eric Moore3c621b32009-05-18 12:59:41 -06006046 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
6047 | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306048 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06006049
Eric Moore635374e2009-03-09 01:21:12 -06006050 /* event thread */
6051 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
6052 "fw_event%d", ioc->id);
6053 ioc->firmware_event_thread = create_singlethread_workqueue(
6054 ioc->firmware_event_name);
6055 if (!ioc->firmware_event_thread) {
6056 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6057 ioc->name, __FILE__, __LINE__, __func__);
6058 goto out_thread_fail;
6059 }
6060
6061 ioc->wait_for_port_enable_to_complete = 1;
6062 if ((mpt2sas_base_attach(ioc))) {
6063 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6064 ioc->name, __FILE__, __LINE__, __func__);
6065 goto out_attach_fail;
6066 }
6067
6068 ioc->wait_for_port_enable_to_complete = 0;
6069 _scsih_probe_devices(ioc);
6070 return 0;
6071
6072 out_attach_fail:
6073 destroy_workqueue(ioc->firmware_event_thread);
6074 out_thread_fail:
6075 list_del(&ioc->list);
6076 scsi_remove_host(shost);
6077 out_add_shost_fail:
6078 return -ENODEV;
6079}
6080
6081#ifdef CONFIG_PM
6082/**
Eric Moored5d135b2009-05-18 13:02:08 -06006083 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006084 * @pdev: PCI device struct
6085 * @state: PM state change to (usually PCI_D3)
6086 *
6087 * Returns 0 success, anything else error.
6088 */
6089static int
Eric Moored5d135b2009-05-18 13:02:08 -06006090_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06006091{
6092 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6093 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6094 u32 device_state;
6095
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306096 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006097 flush_scheduled_work();
6098 scsi_block_requests(shost);
6099 device_state = pci_choose_state(pdev, state);
6100 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
6101 "operating state [D%d]\n", ioc->name, pdev,
6102 pci_name(pdev), device_state);
6103
6104 mpt2sas_base_free_resources(ioc);
6105 pci_save_state(pdev);
6106 pci_disable_device(pdev);
6107 pci_set_power_state(pdev, device_state);
6108 return 0;
6109}
6110
6111/**
Eric Moored5d135b2009-05-18 13:02:08 -06006112 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006113 * @pdev: PCI device struct
6114 *
6115 * Returns 0 success, anything else error.
6116 */
6117static int
Eric Moored5d135b2009-05-18 13:02:08 -06006118_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006119{
6120 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6121 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6122 u32 device_state = pdev->current_state;
6123 int r;
6124
6125 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
6126 "operating state [D%d]\n", ioc->name, pdev,
6127 pci_name(pdev), device_state);
6128
6129 pci_set_power_state(pdev, PCI_D0);
6130 pci_enable_wake(pdev, PCI_D0, 0);
6131 pci_restore_state(pdev);
6132 ioc->pdev = pdev;
6133 r = mpt2sas_base_map_resources(ioc);
6134 if (r)
6135 return r;
6136
6137 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
6138 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306139 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006140 return 0;
6141}
6142#endif /* CONFIG_PM */
6143
6144
6145static struct pci_driver scsih_driver = {
6146 .name = MPT2SAS_DRIVER_NAME,
6147 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06006148 .probe = _scsih_probe,
6149 .remove = __devexit_p(_scsih_remove),
Eric Moore635374e2009-03-09 01:21:12 -06006150#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06006151 .suspend = _scsih_suspend,
6152 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06006153#endif
6154};
6155
6156
6157/**
Eric Moored5d135b2009-05-18 13:02:08 -06006158 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06006159 *
6160 * Returns 0 success, anything else error.
6161 */
6162static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06006163_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06006164{
6165 int error;
6166
6167 mpt_ids = 0;
6168 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
6169 MPT2SAS_DRIVER_VERSION);
6170
6171 mpt2sas_transport_template =
6172 sas_attach_transport(&mpt2sas_transport_functions);
6173 if (!mpt2sas_transport_template)
6174 return -ENODEV;
6175
6176 mpt2sas_base_initialize_callback_handler();
6177
6178 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06006179 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06006180
6181 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06006182 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06006183
6184 /* base internal commands callback handler */
6185 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
6186
6187 /* transport internal commands callback handler */
6188 transport_cb_idx = mpt2sas_base_register_callback_handler(
6189 mpt2sas_transport_done);
6190
6191 /* configuration page API internal commands callback handler */
6192 config_cb_idx = mpt2sas_base_register_callback_handler(
6193 mpt2sas_config_done);
6194
6195 /* ctl module callback handler */
6196 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
6197
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306198 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
6199 _scsih_tm_tr_complete);
6200 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
6201 _scsih_sas_control_complete);
6202
Eric Moore635374e2009-03-09 01:21:12 -06006203 mpt2sas_ctl_init();
6204
6205 error = pci_register_driver(&scsih_driver);
6206 if (error)
6207 sas_release_transport(mpt2sas_transport_template);
6208
6209 return error;
6210}
6211
6212/**
Eric Moored5d135b2009-05-18 13:02:08 -06006213 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06006214 *
6215 * Returns 0 success, anything else error.
6216 */
6217static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06006218_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06006219{
6220 printk(KERN_INFO "mpt2sas version %s unloading\n",
6221 MPT2SAS_DRIVER_VERSION);
6222
6223 pci_unregister_driver(&scsih_driver);
6224
6225 sas_release_transport(mpt2sas_transport_template);
6226 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
6227 mpt2sas_base_release_callback_handler(tm_cb_idx);
6228 mpt2sas_base_release_callback_handler(base_cb_idx);
6229 mpt2sas_base_release_callback_handler(transport_cb_idx);
6230 mpt2sas_base_release_callback_handler(config_cb_idx);
6231 mpt2sas_base_release_callback_handler(ctl_cb_idx);
6232
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306233 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
6234 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
6235
Eric Moore635374e2009-03-09 01:21:12 -06006236 mpt2sas_ctl_exit();
6237}
6238
Eric Moored5d135b2009-05-18 13:02:08 -06006239module_init(_scsih_init);
6240module_exit(_scsih_exit);