blob: d4e890d8b992ec51092a5f551b9b400c9a326a5b [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;
3114 _scsih_response_code(ioc, response_bytes[3]);
3115 }
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;
3232 u32 response_code;
3233
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 */
3254 if (!sas_device_priv_data->tlr_snoop_check) {
3255 sas_device_priv_data->tlr_snoop_check++;
3256 if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) {
3257 response_code = (le32_to_cpu(mpi_reply->ResponseInfo)
3258 >> 24);
3259 if (response_code ==
3260 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
3261 sas_device_priv_data->flags &=
3262 ~MPT_DEVICE_TLR_ON;
3263 }
3264 }
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;
3274 scsi_state = mpi_reply->SCSIState;
3275 scsi_status = mpi_reply->SCSIStatus;
3276
3277 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
3278 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
3279 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
3280 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
3281 ioc_status = MPI2_IOCSTATUS_SUCCESS;
3282 }
3283
3284 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3285 struct sense_info data;
3286 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
3287 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06003288 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06003289 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06003290 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06003291 _scsih_normalize_sense(scmd->sense_buffer, &data);
3292 /* failure prediction threshold exceeded */
3293 if (data.asc == 0x5D)
3294 _scsih_smart_predicted_fault(ioc,
3295 le16_to_cpu(mpi_reply->DevHandle));
3296 }
3297
3298 switch (ioc_status) {
3299 case MPI2_IOCSTATUS_BUSY:
3300 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3301 scmd->result = SAM_STAT_BUSY;
3302 break;
3303
3304 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3305 scmd->result = DID_NO_CONNECT << 16;
3306 break;
3307
3308 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3309 if (sas_device_priv_data->block) {
3310 scmd->result = (DID_BUS_BUSY << 16);
3311 break;
3312 }
3313
3314 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3315 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3316 scmd->result = DID_RESET << 16;
3317 break;
3318
3319 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3320 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3321 scmd->result = DID_SOFT_ERROR << 16;
3322 else
3323 scmd->result = (DID_OK << 16) | scsi_status;
3324 break;
3325
3326 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3327 scmd->result = (DID_OK << 16) | scsi_status;
3328
3329 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3330 break;
3331
3332 if (xfer_cnt < scmd->underflow) {
3333 if (scsi_status == SAM_STAT_BUSY)
3334 scmd->result = SAM_STAT_BUSY;
3335 else
3336 scmd->result = DID_SOFT_ERROR << 16;
3337 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3338 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3339 scmd->result = DID_SOFT_ERROR << 16;
3340 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3341 scmd->result = DID_RESET << 16;
3342 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3343 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3344 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3345 scmd->result = (DRIVER_SENSE << 24) |
3346 SAM_STAT_CHECK_CONDITION;
3347 scmd->sense_buffer[0] = 0x70;
3348 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3349 scmd->sense_buffer[12] = 0x20;
3350 scmd->sense_buffer[13] = 0;
3351 }
3352 break;
3353
3354 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3355 scsi_set_resid(scmd, 0);
3356 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3357 case MPI2_IOCSTATUS_SUCCESS:
3358 scmd->result = (DID_OK << 16) | scsi_status;
3359 if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3360 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3361 scmd->result = DID_SOFT_ERROR << 16;
3362 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3363 scmd->result = DID_RESET << 16;
3364 break;
3365
Eric Moore3c621b32009-05-18 12:59:41 -06003366 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3367 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3368 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3369 _scsih_eedp_error_handling(scmd, ioc_status);
3370 break;
Eric Moore635374e2009-03-09 01:21:12 -06003371 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3372 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3373 case MPI2_IOCSTATUS_INVALID_SGL:
3374 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3375 case MPI2_IOCSTATUS_INVALID_FIELD:
3376 case MPI2_IOCSTATUS_INVALID_STATE:
3377 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3378 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3379 default:
3380 scmd->result = DID_SOFT_ERROR << 16;
3381 break;
3382
3383 }
3384
3385#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3386 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3387 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3388#endif
3389
3390 out:
3391 scsi_dma_unmap(scmd);
3392 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303393 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003394}
3395
3396/**
Eric Moore635374e2009-03-09 01:21:12 -06003397 * _scsih_sas_host_refresh - refreshing sas host object contents
3398 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06003399 * Context: user
3400 *
3401 * During port enable, fw will send topology events for every device. Its
3402 * possible that the handles may change from the previous setting, so this
3403 * code keeping handles updating if changed.
3404 *
3405 * Return nothing.
3406 */
3407static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303408_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06003409{
3410 u16 sz;
3411 u16 ioc_status;
3412 int i;
3413 Mpi2ConfigReply_t mpi_reply;
3414 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303415 u16 attached_handle;
Eric Moore635374e2009-03-09 01:21:12 -06003416
3417 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3418 "updating handles for sas_host(0x%016llx)\n",
3419 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3420
3421 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3422 * sizeof(Mpi2SasIOUnit0PhyData_t));
3423 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3424 if (!sas_iounit_pg0) {
3425 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3426 ioc->name, __FILE__, __LINE__, __func__);
3427 return;
3428 }
Eric Moore635374e2009-03-09 01:21:12 -06003429
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303430 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3431 sas_iounit_pg0, sz)) != 0)
3432 goto out;
3433 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
3434 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3435 goto out;
3436 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3437 if (i == 0)
3438 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3439 PhyData[0].ControllerDevHandle);
3440 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
3441 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
3442 AttachedDevHandle);
3443 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
3444 attached_handle, i, sas_iounit_pg0->PhyData[i].
3445 NegotiatedLinkRate >> 4);
3446 }
Eric Moore635374e2009-03-09 01:21:12 -06003447 out:
3448 kfree(sas_iounit_pg0);
3449}
3450
3451/**
3452 * _scsih_sas_host_add - create sas host object
3453 * @ioc: per adapter object
3454 *
3455 * Creating host side data object, stored in ioc->sas_hba
3456 *
3457 * Return nothing.
3458 */
3459static void
3460_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3461{
3462 int i;
3463 Mpi2ConfigReply_t mpi_reply;
3464 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3465 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3466 Mpi2SasPhyPage0_t phy_pg0;
3467 Mpi2SasDevicePage0_t sas_device_pg0;
3468 Mpi2SasEnclosurePage0_t enclosure_pg0;
3469 u16 ioc_status;
3470 u16 sz;
3471 u16 device_missing_delay;
3472
3473 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3474 if (!ioc->sas_hba.num_phys) {
3475 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3476 ioc->name, __FILE__, __LINE__, __func__);
3477 return;
3478 }
3479
3480 /* sas_iounit page 0 */
3481 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3482 sizeof(Mpi2SasIOUnit0PhyData_t));
3483 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3484 if (!sas_iounit_pg0) {
3485 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3486 ioc->name, __FILE__, __LINE__, __func__);
3487 return;
3488 }
3489 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3490 sas_iounit_pg0, sz))) {
3491 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3492 ioc->name, __FILE__, __LINE__, __func__);
3493 goto out;
3494 }
3495 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3496 MPI2_IOCSTATUS_MASK;
3497 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3498 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3499 ioc->name, __FILE__, __LINE__, __func__);
3500 goto out;
3501 }
3502
3503 /* sas_iounit page 1 */
3504 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3505 sizeof(Mpi2SasIOUnit1PhyData_t));
3506 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3507 if (!sas_iounit_pg1) {
3508 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3509 ioc->name, __FILE__, __LINE__, __func__);
3510 goto out;
3511 }
3512 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3513 sas_iounit_pg1, sz))) {
3514 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3515 ioc->name, __FILE__, __LINE__, __func__);
3516 goto out;
3517 }
3518 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3519 MPI2_IOCSTATUS_MASK;
3520 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3521 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3522 ioc->name, __FILE__, __LINE__, __func__);
3523 goto out;
3524 }
3525
3526 ioc->io_missing_delay =
3527 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3528 device_missing_delay =
3529 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3530 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3531 ioc->device_missing_delay = (device_missing_delay &
3532 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3533 else
3534 ioc->device_missing_delay = device_missing_delay &
3535 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3536
3537 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3538 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3539 sizeof(struct _sas_phy), GFP_KERNEL);
3540 if (!ioc->sas_hba.phy) {
3541 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3542 ioc->name, __FILE__, __LINE__, __func__);
3543 goto out;
3544 }
3545 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3546 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3547 i))) {
3548 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3549 ioc->name, __FILE__, __LINE__, __func__);
3550 goto out;
3551 }
3552 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3553 MPI2_IOCSTATUS_MASK;
3554 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3555 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3556 ioc->name, __FILE__, __LINE__, __func__);
3557 goto out;
3558 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303559
3560 if (i == 0)
3561 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3562 PhyData[0].ControllerDevHandle);
3563 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06003564 ioc->sas_hba.phy[i].phy_id = i;
3565 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3566 phy_pg0, ioc->sas_hba.parent_dev);
3567 }
3568 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303569 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06003570 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3571 ioc->name, __FILE__, __LINE__, __func__);
3572 goto out;
3573 }
Eric Moore635374e2009-03-09 01:21:12 -06003574 ioc->sas_hba.enclosure_handle =
3575 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3576 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3577 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3578 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3579 (unsigned long long) ioc->sas_hba.sas_address,
3580 ioc->sas_hba.num_phys) ;
3581
3582 if (ioc->sas_hba.enclosure_handle) {
3583 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3584 &enclosure_pg0,
3585 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3586 ioc->sas_hba.enclosure_handle))) {
3587 ioc->sas_hba.enclosure_logical_id =
3588 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3589 }
3590 }
3591
3592 out:
3593 kfree(sas_iounit_pg1);
3594 kfree(sas_iounit_pg0);
3595}
3596
3597/**
3598 * _scsih_expander_add - creating expander object
3599 * @ioc: per adapter object
3600 * @handle: expander handle
3601 *
3602 * Creating expander object, stored in ioc->sas_expander_list.
3603 *
3604 * Return 0 for success, else error.
3605 */
3606static int
3607_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3608{
3609 struct _sas_node *sas_expander;
3610 Mpi2ConfigReply_t mpi_reply;
3611 Mpi2ExpanderPage0_t expander_pg0;
3612 Mpi2ExpanderPage1_t expander_pg1;
3613 Mpi2SasEnclosurePage0_t enclosure_pg0;
3614 u32 ioc_status;
3615 u16 parent_handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303616 __le64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003617 int i;
3618 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303619 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003620 int rc = 0;
3621
3622 if (!handle)
3623 return -1;
3624
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303625 if (ioc->shost_recovery)
3626 return -1;
3627
Eric Moore635374e2009-03-09 01:21:12 -06003628 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3629 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3630 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3631 ioc->name, __FILE__, __LINE__, __func__);
3632 return -1;
3633 }
3634
3635 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3636 MPI2_IOCSTATUS_MASK;
3637 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3638 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3639 ioc->name, __FILE__, __LINE__, __func__);
3640 return -1;
3641 }
3642
3643 /* handle out of order topology events */
3644 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303645 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
3646 != 0) {
3647 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3648 ioc->name, __FILE__, __LINE__, __func__);
3649 return -1;
3650 }
3651 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06003652 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303653 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3654 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003655 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3656 if (!sas_expander) {
3657 rc = _scsih_expander_add(ioc, parent_handle);
3658 if (rc != 0)
3659 return rc;
3660 }
3661 }
3662
Eric Moore635374e2009-03-09 01:21:12 -06003663 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303664 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06003665 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3666 sas_address);
3667 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3668
3669 if (sas_expander)
3670 return 0;
3671
3672 sas_expander = kzalloc(sizeof(struct _sas_node),
3673 GFP_KERNEL);
3674 if (!sas_expander) {
3675 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3676 ioc->name, __FILE__, __LINE__, __func__);
3677 return -1;
3678 }
3679
3680 sas_expander->handle = handle;
3681 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303682 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06003683 sas_expander->sas_address = sas_address;
3684
3685 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3686 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303687 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06003688 sas_expander->sas_address, sas_expander->num_phys);
3689
3690 if (!sas_expander->num_phys)
3691 goto out_fail;
3692 sas_expander->phy = kcalloc(sas_expander->num_phys,
3693 sizeof(struct _sas_phy), GFP_KERNEL);
3694 if (!sas_expander->phy) {
3695 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3696 ioc->name, __FILE__, __LINE__, __func__);
3697 rc = -1;
3698 goto out_fail;
3699 }
3700
3701 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3702 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303703 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003704 if (!mpt2sas_port) {
3705 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3706 ioc->name, __FILE__, __LINE__, __func__);
3707 rc = -1;
3708 goto out_fail;
3709 }
3710 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3711
3712 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3713 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3714 &expander_pg1, i, handle))) {
3715 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3716 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303717 rc = -1;
3718 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003719 }
3720 sas_expander->phy[i].handle = handle;
3721 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303722
3723 if ((mpt2sas_transport_add_expander_phy(ioc,
3724 &sas_expander->phy[i], expander_pg1,
3725 sas_expander->parent_dev))) {
3726 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3727 ioc->name, __FILE__, __LINE__, __func__);
3728 rc = -1;
3729 goto out_fail;
3730 }
Eric Moore635374e2009-03-09 01:21:12 -06003731 }
3732
3733 if (sas_expander->enclosure_handle) {
3734 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3735 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3736 sas_expander->enclosure_handle))) {
3737 sas_expander->enclosure_logical_id =
3738 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3739 }
3740 }
3741
3742 _scsih_expander_node_add(ioc, sas_expander);
3743 return 0;
3744
3745 out_fail:
3746
Kashyap, Desai20f58952009-08-07 19:34:26 +05303747 if (mpt2sas_port)
3748 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303749 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003750 kfree(sas_expander);
3751 return rc;
3752}
3753
3754/**
3755 * _scsih_expander_remove - removing expander object
3756 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303757 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06003758 *
3759 * Return nothing.
3760 */
3761static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303762_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06003763{
3764 struct _sas_node *sas_expander;
3765 unsigned long flags;
3766
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303767 if (ioc->shost_recovery)
3768 return;
3769
Eric Moore635374e2009-03-09 01:21:12 -06003770 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303771 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3772 sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06003773 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3774 _scsih_expander_node_remove(ioc, sas_expander);
3775}
3776
3777/**
3778 * _scsih_add_device - creating sas device object
3779 * @ioc: per adapter object
3780 * @handle: sas device handle
3781 * @phy_num: phy number end device attached to
3782 * @is_pd: is this hidden raid component
3783 *
3784 * Creating end device object, stored in ioc->sas_device_list.
3785 *
3786 * Returns 0 for success, non-zero for failure.
3787 */
3788static int
3789_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
3790{
3791 Mpi2ConfigReply_t mpi_reply;
3792 Mpi2SasDevicePage0_t sas_device_pg0;
3793 Mpi2SasEnclosurePage0_t enclosure_pg0;
3794 struct _sas_device *sas_device;
3795 u32 ioc_status;
3796 __le64 sas_address;
3797 u32 device_info;
3798 unsigned long flags;
3799
3800 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
3801 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
3802 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3803 ioc->name, __FILE__, __LINE__, __func__);
3804 return -1;
3805 }
3806
3807 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3808 MPI2_IOCSTATUS_MASK;
3809 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3810 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3811 ioc->name, __FILE__, __LINE__, __func__);
3812 return -1;
3813 }
3814
3815 /* check if device is present */
3816 if (!(le16_to_cpu(sas_device_pg0.Flags) &
3817 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
3818 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3819 ioc->name, __FILE__, __LINE__, __func__);
3820 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
3821 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
3822 return -1;
3823 }
3824
3825 /* check if there were any issus with discovery */
3826 if (sas_device_pg0.AccessStatus ==
3827 MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
3828 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3829 ioc->name, __FILE__, __LINE__, __func__);
3830 printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
3831 ioc->name, sas_device_pg0.AccessStatus);
3832 return -1;
3833 }
3834
3835 /* check if this is end device */
3836 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
3837 if (!(_scsih_is_end_device(device_info))) {
3838 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3839 ioc->name, __FILE__, __LINE__, __func__);
3840 return -1;
3841 }
3842
3843 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3844
3845 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3846 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
3847 sas_address);
3848 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3849
3850 if (sas_device) {
3851 _scsih_ublock_io_device(ioc, handle);
3852 return 0;
3853 }
3854
3855 sas_device = kzalloc(sizeof(struct _sas_device),
3856 GFP_KERNEL);
3857 if (!sas_device) {
3858 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3859 ioc->name, __FILE__, __LINE__, __func__);
3860 return -1;
3861 }
3862
3863 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303864 if (_scsih_get_sas_address(ioc, le16_to_cpu
3865 (sas_device_pg0.ParentDevHandle),
3866 &sas_device->sas_address_parent) != 0)
3867 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3868 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06003869 sas_device->enclosure_handle =
3870 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3871 sas_device->slot =
3872 le16_to_cpu(sas_device_pg0.Slot);
3873 sas_device->device_info = device_info;
3874 sas_device->sas_address = sas_address;
3875 sas_device->hidden_raid_component = is_pd;
3876
3877 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05303878 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
3879 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3880 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06003881 sas_device->enclosure_logical_id =
3882 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06003883
3884 /* get device name */
3885 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
3886
3887 if (ioc->wait_for_port_enable_to_complete)
3888 _scsih_sas_device_init_add(ioc, sas_device);
3889 else
3890 _scsih_sas_device_add(ioc, sas_device);
3891
3892 return 0;
3893}
3894
3895/**
3896 * _scsih_remove_device - removing sas device object
3897 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303898 * @sas_device: the sas_device object
Eric Moore635374e2009-03-09 01:21:12 -06003899 *
3900 * Return nothing.
3901 */
3902static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303903_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
3904 *sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06003905{
3906 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06003907 Mpi2SasIoUnitControlReply_t mpi_reply;
3908 Mpi2SasIoUnitControlRequest_t mpi_request;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303909 u16 device_handle, handle;
Eric Moore635374e2009-03-09 01:21:12 -06003910
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303911 if (!sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06003912 return;
Eric Moore635374e2009-03-09 01:21:12 -06003913
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303914 handle = sas_device->handle;
3915 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
3916 " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
3917 (unsigned long long) sas_device->sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06003918
3919 if (sas_device->starget && sas_device->starget->hostdata) {
3920 sas_target_priv_data = sas_device->starget->hostdata;
3921 sas_target_priv_data->deleted = 1;
3922 }
Eric Moore635374e2009-03-09 01:21:12 -06003923
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303924 if (ioc->remove_host || ioc->shost_recovery || !handle)
Eric Moore635374e2009-03-09 01:21:12 -06003925 goto out;
3926
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303927 if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
3928 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303929 "target_reset handle(0x%04x)\n", ioc->name,
3930 handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303931 goto skip_tr;
3932 }
3933
Eric Moore635374e2009-03-09 01:21:12 -06003934 /* Target Reset to flush out all the outstanding IO */
3935 device_handle = (sas_device->hidden_raid_component) ?
3936 sas_device->volume_handle : handle;
3937 if (device_handle) {
3938 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
3939 "handle(0x%04x)\n", ioc->name, device_handle));
3940 mutex_lock(&ioc->tm_cmds.mutex);
3941 mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
3942 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
3943 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
3944 mutex_unlock(&ioc->tm_cmds.mutex);
3945 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
3946 "done: handle(0x%04x)\n", ioc->name, device_handle));
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303947 if (ioc->shost_recovery)
3948 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003949 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303950 skip_tr:
3951
3952 if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) {
3953 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
3954 "sas_cntrl handle(0x%04x)\n", ioc->name, handle));
3955 goto out;
3956 }
Eric Moore635374e2009-03-09 01:21:12 -06003957
3958 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
3959 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
3960 "(0x%04x)\n", ioc->name, handle));
3961 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
3962 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
3963 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
3964 mpi_request.DevHandle = handle;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303965 mpi_request.VF_ID = 0; /* TODO */
3966 mpi_request.VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003967 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
3968 &mpi_request)) != 0) {
3969 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3970 ioc->name, __FILE__, __LINE__, __func__);
3971 }
3972
3973 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
3974 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
3975 le16_to_cpu(mpi_reply.IOCStatus),
3976 le32_to_cpu(mpi_reply.IOCLogInfo)));
3977
3978 out:
Kashyap, Desai34a03be2009-08-20 13:23:19 +05303979
3980 _scsih_ublock_io_device(ioc, handle);
3981
Eric Moore635374e2009-03-09 01:21:12 -06003982 mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303983 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003984
3985 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303986 "(0x%016llx)\n", ioc->name, handle,
Eric Moore635374e2009-03-09 01:21:12 -06003987 (unsigned long long) sas_device->sas_address);
3988 _scsih_sas_device_remove(ioc, sas_device);
3989
3990 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
3991 "(0x%04x)\n", ioc->name, __func__, handle));
3992}
3993
3994#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3995/**
3996 * _scsih_sas_topology_change_event_debug - debug for topology event
3997 * @ioc: per adapter object
3998 * @event_data: event data payload
3999 * Context: user.
4000 */
4001static void
4002_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4003 Mpi2EventDataSasTopologyChangeList_t *event_data)
4004{
4005 int i;
4006 u16 handle;
4007 u16 reason_code;
4008 u8 phy_number;
4009 char *status_str = NULL;
4010 char link_rate[25];
4011
4012 switch (event_data->ExpStatus) {
4013 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
4014 status_str = "add";
4015 break;
4016 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
4017 status_str = "remove";
4018 break;
4019 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
4020 status_str = "responding";
4021 break;
4022 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
4023 status_str = "remove delay";
4024 break;
4025 default:
4026 status_str = "unknown status";
4027 break;
4028 }
4029 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
4030 ioc->name, status_str);
4031 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
4032 "start_phy(%02d), count(%d)\n",
4033 le16_to_cpu(event_data->ExpanderDevHandle),
4034 le16_to_cpu(event_data->EnclosureHandle),
4035 event_data->StartPhyNum, event_data->NumEntries);
4036 for (i = 0; i < event_data->NumEntries; i++) {
4037 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4038 if (!handle)
4039 continue;
4040 phy_number = event_data->StartPhyNum + i;
4041 reason_code = event_data->PHY[i].PhyStatus &
4042 MPI2_EVENT_SAS_TOPO_RC_MASK;
4043 switch (reason_code) {
4044 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
4045 snprintf(link_rate, 25, ": add, link(0x%02x)",
4046 (event_data->PHY[i].LinkRate >> 4));
4047 status_str = link_rate;
4048 break;
4049 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
4050 status_str = ": remove";
4051 break;
4052 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
4053 status_str = ": remove_delay";
4054 break;
4055 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
4056 snprintf(link_rate, 25, ": link(0x%02x)",
4057 (event_data->PHY[i].LinkRate >> 4));
4058 status_str = link_rate;
4059 break;
4060 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
4061 status_str = ": responding";
4062 break;
4063 default:
4064 status_str = ": unknown";
4065 break;
4066 }
4067 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n",
4068 phy_number, handle, status_str);
4069 }
4070}
4071#endif
4072
4073/**
4074 * _scsih_sas_topology_change_event - handle topology changes
4075 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304076 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004077 * Context: user.
4078 *
4079 */
4080static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304081_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06004082 struct fw_event_work *fw_event)
4083{
4084 int i;
4085 u16 parent_handle, handle;
4086 u16 reason_code;
4087 u8 phy_number;
4088 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304089 struct _sas_device *sas_device;
4090 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004091 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304092 u8 link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304093 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004094
4095#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4096 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4097 _scsih_sas_topology_change_event_debug(ioc, event_data);
4098#endif
4099
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304100 if (ioc->shost_recovery)
4101 return;
4102
Eric Moore635374e2009-03-09 01:21:12 -06004103 if (!ioc->sas_hba.num_phys)
4104 _scsih_sas_host_add(ioc);
4105 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304106 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06004107
4108 if (fw_event->ignore) {
4109 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
4110 "event\n", ioc->name));
4111 return;
4112 }
4113
4114 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
4115
4116 /* handle expander add */
4117 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
4118 if (_scsih_expander_add(ioc, parent_handle) != 0)
4119 return;
4120
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304121 spin_lock_irqsave(&ioc->sas_node_lock, flags);
4122 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
4123 parent_handle);
4124 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4125 if (sas_expander)
4126 sas_address = sas_expander->sas_address;
4127 else if (parent_handle < ioc->sas_hba.num_phys)
4128 sas_address = ioc->sas_hba.sas_address;
4129 else
4130 return;
4131
Eric Moore635374e2009-03-09 01:21:12 -06004132 /* handle siblings events */
4133 for (i = 0; i < event_data->NumEntries; i++) {
4134 if (fw_event->ignore) {
4135 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
4136 "expander event\n", ioc->name));
4137 return;
4138 }
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304139 if (ioc->shost_recovery)
4140 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05304141 phy_number = event_data->StartPhyNum + i;
4142 reason_code = event_data->PHY[i].PhyStatus &
4143 MPI2_EVENT_SAS_TOPO_RC_MASK;
4144 if ((event_data->PHY[i].PhyStatus &
4145 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
4146 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06004147 continue;
4148 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4149 if (!handle)
4150 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304151 link_rate = event_data->PHY[i].LinkRate >> 4;
Eric Moore635374e2009-03-09 01:21:12 -06004152 switch (reason_code) {
4153 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
4154 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304155
4156 mpt2sas_transport_update_links(ioc, sas_address,
4157 handle, phy_number, link_rate);
4158
4159 if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
4160 break;
Eric Moore635374e2009-03-09 01:21:12 -06004161 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
Eric Moore635374e2009-03-09 01:21:12 -06004162 _scsih_add_device(ioc, handle, phy_number, 0);
4163 }
4164 break;
4165 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304166
4167 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4168 sas_device = _scsih_sas_device_find_by_handle(ioc,
4169 handle);
4170 if (!sas_device) {
4171 spin_unlock_irqrestore(&ioc->sas_device_lock,
4172 flags);
4173 break;
4174 }
4175 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4176 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004177 break;
4178 }
4179 }
4180
4181 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304182 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
4183 sas_expander)
4184 _scsih_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06004185
4186}
4187
4188#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4189/**
4190 * _scsih_sas_device_status_change_event_debug - debug for device event
4191 * @event_data: event data payload
4192 * Context: user.
4193 *
4194 * Return nothing.
4195 */
4196static void
4197_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4198 Mpi2EventDataSasDeviceStatusChange_t *event_data)
4199{
4200 char *reason_str = NULL;
4201
4202 switch (event_data->ReasonCode) {
4203 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
4204 reason_str = "smart data";
4205 break;
4206 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
4207 reason_str = "unsupported device discovered";
4208 break;
4209 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
4210 reason_str = "internal device reset";
4211 break;
4212 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
4213 reason_str = "internal task abort";
4214 break;
4215 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
4216 reason_str = "internal task abort set";
4217 break;
4218 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
4219 reason_str = "internal clear task set";
4220 break;
4221 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
4222 reason_str = "internal query task";
4223 break;
4224 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
4225 reason_str = "sata init failure";
4226 break;
4227 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
4228 reason_str = "internal device reset complete";
4229 break;
4230 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
4231 reason_str = "internal task abort complete";
4232 break;
4233 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
4234 reason_str = "internal async notification";
4235 break;
4236 default:
4237 reason_str = "unknown reason";
4238 break;
4239 }
4240 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
4241 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
4242 reason_str, le16_to_cpu(event_data->DevHandle),
4243 (unsigned long long)le64_to_cpu(event_data->SASAddress));
4244 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
4245 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
4246 event_data->ASC, event_data->ASCQ);
4247 printk(KERN_INFO "\n");
4248}
4249#endif
4250
4251/**
4252 * _scsih_sas_device_status_change_event - handle device status change
4253 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304254 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004255 * Context: user.
4256 *
4257 * Return nothing.
4258 */
4259static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304260_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
4261 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004262{
4263#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4264 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304265 _scsih_sas_device_status_change_event_debug(ioc,
4266 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004267#endif
4268}
4269
4270#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4271/**
4272 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
4273 * @ioc: per adapter object
4274 * @event_data: event data payload
4275 * Context: user.
4276 *
4277 * Return nothing.
4278 */
4279static void
4280_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4281 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
4282{
4283 char *reason_str = NULL;
4284
4285 switch (event_data->ReasonCode) {
4286 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
4287 reason_str = "enclosure add";
4288 break;
4289 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
4290 reason_str = "enclosure remove";
4291 break;
4292 default:
4293 reason_str = "unknown reason";
4294 break;
4295 }
4296
4297 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
4298 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
4299 " number slots(%d)\n", ioc->name, reason_str,
4300 le16_to_cpu(event_data->EnclosureHandle),
4301 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
4302 le16_to_cpu(event_data->StartSlot));
4303}
4304#endif
4305
4306/**
4307 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
4308 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304309 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004310 * Context: user.
4311 *
4312 * Return nothing.
4313 */
4314static void
4315_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304316 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004317{
4318#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4319 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4320 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304321 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004322#endif
4323}
4324
4325/**
4326 * _scsih_sas_broadcast_primative_event - handle broadcast events
4327 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304328 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004329 * Context: user.
4330 *
4331 * Return nothing.
4332 */
4333static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304334_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4335 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004336{
4337 struct scsi_cmnd *scmd;
4338 u16 smid, handle;
4339 u32 lun;
4340 struct MPT2SAS_DEVICE *sas_device_priv_data;
4341 u32 termination_count;
4342 u32 query_count;
4343 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304344#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4345 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4346#endif
Eric Moore635374e2009-03-09 01:21:12 -06004347 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4348 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4349 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004350 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4351 __func__));
4352
4353 mutex_lock(&ioc->tm_cmds.mutex);
4354 termination_count = 0;
4355 query_count = 0;
4356 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304357 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06004358 scmd = _scsih_scsi_lookup_get(ioc, smid);
4359 if (!scmd)
4360 continue;
4361 sas_device_priv_data = scmd->device->hostdata;
4362 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4363 continue;
4364 /* skip hidden raid components */
4365 if (sas_device_priv_data->sas_target->flags &
4366 MPT_TARGET_FLAGS_RAID_COMPONENT)
4367 continue;
4368 /* skip volumes */
4369 if (sas_device_priv_data->sas_target->flags &
4370 MPT_TARGET_FLAGS_VOLUME)
4371 continue;
4372
4373 handle = sas_device_priv_data->sas_target->handle;
4374 lun = sas_device_priv_data->lun;
4375 query_count++;
4376
4377 mpt2sas_scsih_issue_tm(ioc, handle, lun,
4378 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
Eric Moore8901cbb2009-04-21 15:41:32 -06004379 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004380
4381 if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) &&
4382 (mpi_reply->ResponseCode ==
4383 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4384 mpi_reply->ResponseCode ==
4385 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4386 continue;
4387
4388 mpt2sas_scsih_issue_tm(ioc, handle, lun,
Eric Moore8901cbb2009-04-21 15:41:32 -06004389 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30);
4390 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004391 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4392 }
Eric Moore635374e2009-03-09 01:21:12 -06004393 ioc->broadcast_aen_busy = 0;
4394 mutex_unlock(&ioc->tm_cmds.mutex);
4395
4396 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4397 "%s - exit, query_count = %d termination_count = %d\n",
4398 ioc->name, __func__, query_count, termination_count));
4399}
4400
4401/**
4402 * _scsih_sas_discovery_event - handle discovery events
4403 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304404 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004405 * Context: user.
4406 *
4407 * Return nothing.
4408 */
4409static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304410_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4411 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004412{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304413 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4414
Eric Moore635374e2009-03-09 01:21:12 -06004415#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4416 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4417 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4418 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4419 "start" : "stop");
4420 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304421 printk("discovery_status(0x%08x)",
4422 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06004423 printk("\n");
4424 }
4425#endif
4426
4427 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4428 !ioc->sas_hba.num_phys)
4429 _scsih_sas_host_add(ioc);
4430}
4431
4432/**
4433 * _scsih_reprobe_lun - reprobing lun
4434 * @sdev: scsi device struct
4435 * @no_uld_attach: sdev->no_uld_attach flag setting
4436 *
4437 **/
4438static void
4439_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4440{
4441 int rc;
4442
4443 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4444 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4445 sdev->no_uld_attach ? "hidding" : "exposing");
4446 rc = scsi_device_reprobe(sdev);
4447}
4448
4449/**
4450 * _scsih_reprobe_target - reprobing target
4451 * @starget: scsi target struct
4452 * @no_uld_attach: sdev->no_uld_attach flag setting
4453 *
4454 * Note: no_uld_attach flag determines whether the disk device is attached
4455 * to block layer. A value of `1` means to not attach.
4456 **/
4457static void
4458_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4459{
4460 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4461
4462 if (no_uld_attach)
4463 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4464 else
4465 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4466
4467 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4468 _scsih_reprobe_lun);
4469}
4470/**
4471 * _scsih_sas_volume_add - add new volume
4472 * @ioc: per adapter object
4473 * @element: IR config element data
4474 * Context: user.
4475 *
4476 * Return nothing.
4477 */
4478static void
4479_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4480 Mpi2EventIrConfigElement_t *element)
4481{
4482 struct _raid_device *raid_device;
4483 unsigned long flags;
4484 u64 wwid;
4485 u16 handle = le16_to_cpu(element->VolDevHandle);
4486 int rc;
4487
Eric Moore635374e2009-03-09 01:21:12 -06004488 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4489 if (!wwid) {
4490 printk(MPT2SAS_ERR_FMT
4491 "failure at %s:%d/%s()!\n", ioc->name,
4492 __FILE__, __LINE__, __func__);
4493 return;
4494 }
4495
4496 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4497 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4498 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4499
4500 if (raid_device)
4501 return;
4502
4503 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4504 if (!raid_device) {
4505 printk(MPT2SAS_ERR_FMT
4506 "failure at %s:%d/%s()!\n", ioc->name,
4507 __FILE__, __LINE__, __func__);
4508 return;
4509 }
4510
4511 raid_device->id = ioc->sas_id++;
4512 raid_device->channel = RAID_CHANNEL;
4513 raid_device->handle = handle;
4514 raid_device->wwid = wwid;
4515 _scsih_raid_device_add(ioc, raid_device);
4516 if (!ioc->wait_for_port_enable_to_complete) {
4517 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4518 raid_device->id, 0);
4519 if (rc)
4520 _scsih_raid_device_remove(ioc, raid_device);
4521 } else
4522 _scsih_determine_boot_device(ioc, raid_device, 1);
4523}
4524
4525/**
4526 * _scsih_sas_volume_delete - delete volume
4527 * @ioc: per adapter object
4528 * @element: IR config element data
4529 * Context: user.
4530 *
4531 * Return nothing.
4532 */
4533static void
4534_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4535 Mpi2EventIrConfigElement_t *element)
4536{
4537 struct _raid_device *raid_device;
4538 u16 handle = le16_to_cpu(element->VolDevHandle);
4539 unsigned long flags;
4540 struct MPT2SAS_TARGET *sas_target_priv_data;
4541
Eric Moore635374e2009-03-09 01:21:12 -06004542 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4543 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4544 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4545 if (!raid_device)
4546 return;
4547 if (raid_device->starget) {
4548 sas_target_priv_data = raid_device->starget->hostdata;
4549 sas_target_priv_data->deleted = 1;
4550 scsi_remove_target(&raid_device->starget->dev);
4551 }
4552 _scsih_raid_device_remove(ioc, raid_device);
4553}
4554
4555/**
4556 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4557 * @ioc: per adapter object
4558 * @element: IR config element data
4559 * Context: user.
4560 *
4561 * Return nothing.
4562 */
4563static void
4564_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4565 Mpi2EventIrConfigElement_t *element)
4566{
4567 struct _sas_device *sas_device;
4568 unsigned long flags;
4569 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4570
4571 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4572 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4573 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4574 if (!sas_device)
4575 return;
4576
4577 /* exposing raid component */
4578 sas_device->volume_handle = 0;
4579 sas_device->volume_wwid = 0;
4580 sas_device->hidden_raid_component = 0;
4581 _scsih_reprobe_target(sas_device->starget, 0);
4582}
4583
4584/**
4585 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4586 * @ioc: per adapter object
4587 * @element: IR config element data
4588 * Context: user.
4589 *
4590 * Return nothing.
4591 */
4592static void
4593_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4594 Mpi2EventIrConfigElement_t *element)
4595{
4596 struct _sas_device *sas_device;
4597 unsigned long flags;
4598 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4599
4600 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4601 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4602 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4603 if (!sas_device)
4604 return;
4605
4606 /* hiding raid component */
4607 mpt2sas_config_get_volume_handle(ioc, handle,
4608 &sas_device->volume_handle);
4609 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4610 &sas_device->volume_wwid);
4611 sas_device->hidden_raid_component = 1;
4612 _scsih_reprobe_target(sas_device->starget, 1);
4613}
4614
4615/**
4616 * _scsih_sas_pd_delete - delete pd component
4617 * @ioc: per adapter object
4618 * @element: IR config element data
4619 * Context: user.
4620 *
4621 * Return nothing.
4622 */
4623static void
4624_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4625 Mpi2EventIrConfigElement_t *element)
4626{
4627 struct _sas_device *sas_device;
4628 unsigned long flags;
4629 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4630
4631 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4632 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4633 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4634 if (!sas_device)
4635 return;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304636 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004637}
4638
4639/**
4640 * _scsih_sas_pd_add - remove pd component
4641 * @ioc: per adapter object
4642 * @element: IR config element data
4643 * Context: user.
4644 *
4645 * Return nothing.
4646 */
4647static void
4648_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
4649 Mpi2EventIrConfigElement_t *element)
4650{
4651 struct _sas_device *sas_device;
4652 unsigned long flags;
4653 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304654 Mpi2ConfigReply_t mpi_reply;
4655 Mpi2SasDevicePage0_t sas_device_pg0;
4656 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304657 u64 sas_address;
4658 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06004659
4660 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4661 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4662 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304663 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004664 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304665 return;
4666 }
4667
4668 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4669 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4670 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4671 ioc->name, __FILE__, __LINE__, __func__);
4672 return;
4673 }
4674
4675 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4676 MPI2_IOCSTATUS_MASK;
4677 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4678 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4679 ioc->name, __FILE__, __LINE__, __func__);
4680 return;
4681 }
4682
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304683 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
4684 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
4685 mpt2sas_transport_update_links(ioc, sas_address, handle,
4686 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304687
4688 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06004689}
4690
4691#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4692/**
4693 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
4694 * @ioc: per adapter object
4695 * @event_data: event data payload
4696 * Context: user.
4697 *
4698 * Return nothing.
4699 */
4700static void
4701_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4702 Mpi2EventDataIrConfigChangeList_t *event_data)
4703{
4704 Mpi2EventIrConfigElement_t *element;
4705 u8 element_type;
4706 int i;
4707 char *reason_str = NULL, *element_str = NULL;
4708
4709 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4710
4711 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
4712 ioc->name, (le32_to_cpu(event_data->Flags) &
4713 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
4714 "foreign" : "native", event_data->NumElements);
4715 for (i = 0; i < event_data->NumElements; i++, element++) {
4716 switch (element->ReasonCode) {
4717 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
4718 reason_str = "add";
4719 break;
4720 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
4721 reason_str = "remove";
4722 break;
4723 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
4724 reason_str = "no change";
4725 break;
4726 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4727 reason_str = "hide";
4728 break;
4729 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4730 reason_str = "unhide";
4731 break;
4732 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4733 reason_str = "volume_created";
4734 break;
4735 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4736 reason_str = "volume_deleted";
4737 break;
4738 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4739 reason_str = "pd_created";
4740 break;
4741 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4742 reason_str = "pd_deleted";
4743 break;
4744 default:
4745 reason_str = "unknown reason";
4746 break;
4747 }
4748 element_type = le16_to_cpu(element->ElementFlags) &
4749 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
4750 switch (element_type) {
4751 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
4752 element_str = "volume";
4753 break;
4754 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
4755 element_str = "phys disk";
4756 break;
4757 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
4758 element_str = "hot spare";
4759 break;
4760 default:
4761 element_str = "unknown element";
4762 break;
4763 }
4764 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
4765 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
4766 reason_str, le16_to_cpu(element->VolDevHandle),
4767 le16_to_cpu(element->PhysDiskDevHandle),
4768 element->PhysDiskNum);
4769 }
4770}
4771#endif
4772
4773/**
4774 * _scsih_sas_ir_config_change_event - handle ir configuration change events
4775 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304776 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004777 * Context: user.
4778 *
4779 * Return nothing.
4780 */
4781static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304782_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
4783 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004784{
4785 Mpi2EventIrConfigElement_t *element;
4786 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304787 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304788 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004789
4790#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4791 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4792 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
4793
4794#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05304795 foreign_config = (le32_to_cpu(event_data->Flags) &
4796 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06004797
4798 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4799 for (i = 0; i < event_data->NumElements; i++, element++) {
4800
4801 switch (element->ReasonCode) {
4802 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4803 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304804 if (!foreign_config)
4805 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004806 break;
4807 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4808 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304809 if (!foreign_config)
4810 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004811 break;
4812 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4813 _scsih_sas_pd_hide(ioc, element);
4814 break;
4815 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4816 _scsih_sas_pd_expose(ioc, element);
4817 break;
4818 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4819 _scsih_sas_pd_add(ioc, element);
4820 break;
4821 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4822 _scsih_sas_pd_delete(ioc, element);
4823 break;
4824 }
4825 }
4826}
4827
4828/**
4829 * _scsih_sas_ir_volume_event - IR volume event
4830 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304831 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004832 * Context: user.
4833 *
4834 * Return nothing.
4835 */
4836static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304837_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
4838 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004839{
4840 u64 wwid;
4841 unsigned long flags;
4842 struct _raid_device *raid_device;
4843 u16 handle;
4844 u32 state;
4845 int rc;
4846 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304847 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004848
4849 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
4850 return;
4851
4852 handle = le16_to_cpu(event_data->VolDevHandle);
4853 state = le32_to_cpu(event_data->NewValue);
4854 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4855 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4856 le32_to_cpu(event_data->PreviousValue), state));
4857
4858 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4859 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4860 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4861
4862 switch (state) {
4863 case MPI2_RAID_VOL_STATE_MISSING:
4864 case MPI2_RAID_VOL_STATE_FAILED:
4865 if (!raid_device)
4866 break;
4867 if (raid_device->starget) {
4868 sas_target_priv_data = raid_device->starget->hostdata;
4869 sas_target_priv_data->deleted = 1;
4870 scsi_remove_target(&raid_device->starget->dev);
4871 }
4872 _scsih_raid_device_remove(ioc, raid_device);
4873 break;
4874
4875 case MPI2_RAID_VOL_STATE_ONLINE:
4876 case MPI2_RAID_VOL_STATE_DEGRADED:
4877 case MPI2_RAID_VOL_STATE_OPTIMAL:
4878 if (raid_device)
4879 break;
4880
4881 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4882 if (!wwid) {
4883 printk(MPT2SAS_ERR_FMT
4884 "failure at %s:%d/%s()!\n", ioc->name,
4885 __FILE__, __LINE__, __func__);
4886 break;
4887 }
4888
4889 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4890 if (!raid_device) {
4891 printk(MPT2SAS_ERR_FMT
4892 "failure at %s:%d/%s()!\n", ioc->name,
4893 __FILE__, __LINE__, __func__);
4894 break;
4895 }
4896
4897 raid_device->id = ioc->sas_id++;
4898 raid_device->channel = RAID_CHANNEL;
4899 raid_device->handle = handle;
4900 raid_device->wwid = wwid;
4901 _scsih_raid_device_add(ioc, raid_device);
4902 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4903 raid_device->id, 0);
4904 if (rc)
4905 _scsih_raid_device_remove(ioc, raid_device);
4906 break;
4907
4908 case MPI2_RAID_VOL_STATE_INITIALIZING:
4909 default:
4910 break;
4911 }
4912}
4913
4914/**
4915 * _scsih_sas_ir_physical_disk_event - PD event
4916 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304917 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004918 * Context: user.
4919 *
4920 * Return nothing.
4921 */
4922static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304923_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
4924 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004925{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304926 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06004927 u32 state;
4928 struct _sas_device *sas_device;
4929 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304930 Mpi2ConfigReply_t mpi_reply;
4931 Mpi2SasDevicePage0_t sas_device_pg0;
4932 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304933 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304934 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004935
4936 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
4937 return;
4938
4939 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
4940 state = le32_to_cpu(event_data->NewValue);
4941
4942 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4943 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4944 le32_to_cpu(event_data->PreviousValue), state));
4945
4946 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4947 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4948 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4949
4950 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06004951 case MPI2_RAID_PD_STATE_ONLINE:
4952 case MPI2_RAID_PD_STATE_DEGRADED:
4953 case MPI2_RAID_PD_STATE_REBUILDING:
4954 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304955 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004956 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304957 return;
4958 }
4959
4960 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
4961 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
4962 handle))) {
4963 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4964 ioc->name, __FILE__, __LINE__, __func__);
4965 return;
4966 }
4967
4968 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4969 MPI2_IOCSTATUS_MASK;
4970 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4971 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4972 ioc->name, __FILE__, __LINE__, __func__);
4973 return;
4974 }
4975
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304976 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
4977 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
4978 mpt2sas_transport_update_links(ioc, sas_address, handle,
4979 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304980
4981 _scsih_add_device(ioc, handle, 0, 1);
4982
Eric Moore635374e2009-03-09 01:21:12 -06004983 break;
4984
Kashyap, Desai62727a72009-08-07 19:35:18 +05304985 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06004986 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
4987 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
4988 case MPI2_RAID_PD_STATE_HOT_SPARE:
4989 default:
4990 break;
4991 }
4992}
4993
4994#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4995/**
4996 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
4997 * @ioc: per adapter object
4998 * @event_data: event data payload
4999 * Context: user.
5000 *
5001 * Return nothing.
5002 */
5003static void
5004_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
5005 Mpi2EventDataIrOperationStatus_t *event_data)
5006{
5007 char *reason_str = NULL;
5008
5009 switch (event_data->RAIDOperation) {
5010 case MPI2_EVENT_IR_RAIDOP_RESYNC:
5011 reason_str = "resync";
5012 break;
5013 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
5014 reason_str = "online capacity expansion";
5015 break;
5016 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
5017 reason_str = "consistency check";
5018 break;
5019 default:
5020 reason_str = "unknown reason";
5021 break;
5022 }
5023
5024 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
5025 "\thandle(0x%04x), percent complete(%d)\n",
5026 ioc->name, reason_str,
5027 le16_to_cpu(event_data->VolDevHandle),
5028 event_data->PercentComplete);
5029}
5030#endif
5031
5032/**
5033 * _scsih_sas_ir_operation_status_event - handle RAID operation events
5034 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305035 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005036 * Context: user.
5037 *
5038 * Return nothing.
5039 */
5040static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305041_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
5042 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005043{
5044#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5045 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305046 _scsih_sas_ir_operation_status_event_debug(ioc,
5047 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005048#endif
5049}
5050
5051/**
5052 * _scsih_task_set_full - handle task set full
5053 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305054 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005055 * Context: user.
5056 *
5057 * Throttle back qdepth.
5058 */
5059static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305060_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
5061 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005062{
5063 unsigned long flags;
5064 struct _sas_device *sas_device;
5065 static struct _raid_device *raid_device;
5066 struct scsi_device *sdev;
5067 int depth;
5068 u16 current_depth;
5069 u16 handle;
5070 int id, channel;
5071 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305072 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005073
5074 current_depth = le16_to_cpu(event_data->CurrentDepth);
5075 handle = le16_to_cpu(event_data->DevHandle);
5076 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5077 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5078 if (!sas_device) {
5079 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5080 return;
5081 }
5082 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5083 id = sas_device->id;
5084 channel = sas_device->channel;
5085 sas_address = sas_device->sas_address;
5086
5087 /* if hidden raid component, then change to volume characteristics */
5088 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
5089 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5090 raid_device = _scsih_raid_device_find_by_handle(
5091 ioc, sas_device->volume_handle);
5092 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5093 if (raid_device) {
5094 id = raid_device->id;
5095 channel = raid_device->channel;
5096 handle = raid_device->handle;
5097 sas_address = raid_device->wwid;
5098 }
5099 }
5100
5101 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
5102 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
5103 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
5104 handle, (unsigned long long)sas_address, current_depth);
5105
5106 shost_for_each_device(sdev, ioc->shost) {
5107 if (sdev->id == id && sdev->channel == channel) {
5108 if (current_depth > sdev->queue_depth) {
5109 if (ioc->logging_level &
5110 MPT_DEBUG_TASK_SET_FULL)
5111 sdev_printk(KERN_INFO, sdev, "strange "
5112 "observation, the queue depth is"
5113 " (%d) meanwhile fw queue depth "
5114 "is (%d)\n", sdev->queue_depth,
5115 current_depth);
5116 continue;
5117 }
5118 depth = scsi_track_queue_full(sdev,
5119 current_depth - 1);
5120 if (depth > 0)
5121 sdev_printk(KERN_INFO, sdev, "Queue depth "
5122 "reduced to (%d)\n", depth);
5123 else if (depth < 0)
5124 sdev_printk(KERN_INFO, sdev, "Tagged Command "
5125 "Queueing is being disabled\n");
5126 else if (depth == 0)
5127 if (ioc->logging_level &
5128 MPT_DEBUG_TASK_SET_FULL)
5129 sdev_printk(KERN_INFO, sdev,
5130 "Queue depth not changed yet\n");
5131 }
5132 }
5133}
5134
5135/**
5136 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
5137 * @ioc: per adapter object
5138 * @sas_address: sas address
5139 * @slot: enclosure slot id
5140 * @handle: device handle
5141 *
5142 * After host reset, find out whether devices are still responding.
5143 * Used in _scsi_remove_unresponsive_sas_devices.
5144 *
5145 * Return nothing.
5146 */
5147static void
5148_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5149 u16 slot, u16 handle)
5150{
5151 struct MPT2SAS_TARGET *sas_target_priv_data;
5152 struct scsi_target *starget;
5153 struct _sas_device *sas_device;
5154 unsigned long flags;
5155
5156 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5157 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
5158 if (sas_device->sas_address == sas_address &&
5159 sas_device->slot == slot && sas_device->starget) {
5160 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305161 sas_device->state = 0;
5162 starget = sas_device->starget;
5163 sas_target_priv_data = starget->hostdata;
5164 sas_target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06005165 starget_printk(KERN_INFO, sas_device->starget,
5166 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
5167 "logical id(0x%016llx), slot(%d)\n", handle,
5168 (unsigned long long)sas_device->sas_address,
5169 (unsigned long long)
5170 sas_device->enclosure_logical_id,
5171 sas_device->slot);
5172 if (sas_device->handle == handle)
5173 goto out;
5174 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5175 sas_device->handle);
5176 sas_device->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005177 sas_target_priv_data->handle = handle;
5178 goto out;
5179 }
5180 }
5181 out:
5182 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5183}
5184
5185/**
5186 * _scsih_search_responding_sas_devices -
5187 * @ioc: per adapter object
5188 *
5189 * After host reset, find out whether devices are still responding.
5190 * If not remove.
5191 *
5192 * Return nothing.
5193 */
5194static void
5195_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
5196{
5197 Mpi2SasDevicePage0_t sas_device_pg0;
5198 Mpi2ConfigReply_t mpi_reply;
5199 u16 ioc_status;
5200 __le64 sas_address;
5201 u16 handle;
5202 u32 device_info;
5203 u16 slot;
5204
5205 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5206
5207 if (list_empty(&ioc->sas_device_list))
5208 return;
5209
5210 handle = 0xFFFF;
5211 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5212 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
5213 handle))) {
5214 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5215 MPI2_IOCSTATUS_MASK;
5216 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5217 break;
5218 handle = le16_to_cpu(sas_device_pg0.DevHandle);
5219 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5220 if (!(_scsih_is_end_device(device_info)))
5221 continue;
5222 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5223 slot = le16_to_cpu(sas_device_pg0.Slot);
5224 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
5225 handle);
5226 }
5227}
5228
5229/**
5230 * _scsih_mark_responding_raid_device - mark a raid_device as responding
5231 * @ioc: per adapter object
5232 * @wwid: world wide identifier for raid volume
5233 * @handle: device handle
5234 *
5235 * After host reset, find out whether devices are still responding.
5236 * Used in _scsi_remove_unresponsive_raid_devices.
5237 *
5238 * Return nothing.
5239 */
5240static void
5241_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
5242 u16 handle)
5243{
5244 struct MPT2SAS_TARGET *sas_target_priv_data;
5245 struct scsi_target *starget;
5246 struct _raid_device *raid_device;
5247 unsigned long flags;
5248
5249 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5250 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
5251 if (raid_device->wwid == wwid && raid_device->starget) {
5252 raid_device->responding = 1;
5253 starget_printk(KERN_INFO, raid_device->starget,
5254 "handle(0x%04x), wwid(0x%016llx)\n", handle,
5255 (unsigned long long)raid_device->wwid);
5256 if (raid_device->handle == handle)
5257 goto out;
5258 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5259 raid_device->handle);
5260 raid_device->handle = handle;
5261 starget = raid_device->starget;
5262 sas_target_priv_data = starget->hostdata;
5263 sas_target_priv_data->handle = handle;
5264 goto out;
5265 }
5266 }
5267 out:
5268 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5269}
5270
5271/**
5272 * _scsih_search_responding_raid_devices -
5273 * @ioc: per adapter object
5274 *
5275 * After host reset, find out whether devices are still responding.
5276 * If not remove.
5277 *
5278 * Return nothing.
5279 */
5280static void
5281_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
5282{
5283 Mpi2RaidVolPage1_t volume_pg1;
5284 Mpi2ConfigReply_t mpi_reply;
5285 u16 ioc_status;
5286 u16 handle;
5287
5288 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5289
5290 if (list_empty(&ioc->raid_device_list))
5291 return;
5292
5293 handle = 0xFFFF;
5294 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
5295 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
5296 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5297 MPI2_IOCSTATUS_MASK;
5298 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5299 break;
5300 handle = le16_to_cpu(volume_pg1.DevHandle);
5301 _scsih_mark_responding_raid_device(ioc,
5302 le64_to_cpu(volume_pg1.WWID), handle);
5303 }
5304}
5305
5306/**
5307 * _scsih_mark_responding_expander - mark a expander as responding
5308 * @ioc: per adapter object
5309 * @sas_address: sas address
5310 * @handle:
5311 *
5312 * After host reset, find out whether devices are still responding.
5313 * Used in _scsi_remove_unresponsive_expanders.
5314 *
5315 * Return nothing.
5316 */
5317static void
5318_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5319 u16 handle)
5320{
5321 struct _sas_node *sas_expander;
5322 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305323 int i;
Eric Moore635374e2009-03-09 01:21:12 -06005324
5325 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5326 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305327 if (sas_expander->sas_address != sas_address)
5328 continue;
5329 sas_expander->responding = 1;
5330 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06005331 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305332 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
5333 " from(0x%04x) to (0x%04x)!!!\n",
5334 (unsigned long long)sas_expander->sas_address,
5335 sas_expander->handle, handle);
5336 sas_expander->handle = handle;
5337 for (i = 0 ; i < sas_expander->num_phys ; i++)
5338 sas_expander->phy[i].handle = handle;
5339 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06005340 }
5341 out:
5342 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5343}
5344
5345/**
5346 * _scsih_search_responding_expanders -
5347 * @ioc: per adapter object
5348 *
5349 * After host reset, find out whether devices are still responding.
5350 * If not remove.
5351 *
5352 * Return nothing.
5353 */
5354static void
5355_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5356{
5357 Mpi2ExpanderPage0_t expander_pg0;
5358 Mpi2ConfigReply_t mpi_reply;
5359 u16 ioc_status;
5360 __le64 sas_address;
5361 u16 handle;
5362
5363 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5364
5365 if (list_empty(&ioc->sas_expander_list))
5366 return;
5367
5368 handle = 0xFFFF;
5369 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5370 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5371
5372 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5373 MPI2_IOCSTATUS_MASK;
5374 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5375 break;
5376
5377 handle = le16_to_cpu(expander_pg0.DevHandle);
5378 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5379 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5380 "sas_addr(0x%016llx)\n", handle,
5381 (unsigned long long)sas_address);
5382 _scsih_mark_responding_expander(ioc, sas_address, handle);
5383 }
5384
5385}
5386
5387/**
5388 * _scsih_remove_unresponding_devices - removing unresponding devices
5389 * @ioc: per adapter object
5390 *
5391 * Return nothing.
5392 */
5393static void
5394_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
5395{
5396 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305397 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005398 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005399
Eric Moore635374e2009-03-09 01:21:12 -06005400
5401 list_for_each_entry_safe(sas_device, sas_device_next,
5402 &ioc->sas_device_list, list) {
5403 if (sas_device->responding) {
5404 sas_device->responding = 0;
5405 continue;
5406 }
5407 if (sas_device->starget)
5408 starget_printk(KERN_INFO, sas_device->starget,
5409 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5410 "enclosure logical id(0x%016llx), slot(%d)\n",
5411 sas_device->handle,
5412 (unsigned long long)sas_device->sas_address,
5413 (unsigned long long)
5414 sas_device->enclosure_logical_id,
5415 sas_device->slot);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305416 /* invalidate the device handle */
5417 sas_device->handle = 0;
5418 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005419 }
5420
5421 list_for_each_entry_safe(raid_device, raid_device_next,
5422 &ioc->raid_device_list, list) {
5423 if (raid_device->responding) {
5424 raid_device->responding = 0;
5425 continue;
5426 }
5427 if (raid_device->starget) {
5428 starget_printk(KERN_INFO, raid_device->starget,
5429 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5430 raid_device->handle,
5431 (unsigned long long)raid_device->wwid);
5432 scsi_remove_target(&raid_device->starget->dev);
5433 }
5434 _scsih_raid_device_remove(ioc, raid_device);
5435 }
5436
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305437 retry_expander_search:
5438 sas_expander = NULL;
5439 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005440 if (sas_expander->responding) {
5441 sas_expander->responding = 0;
5442 continue;
5443 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305444 _scsih_expander_remove(ioc, sas_expander->sas_address);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305445 goto retry_expander_search;
5446 }
5447}
5448
5449/**
5450 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5451 * @ioc: per adapter object
5452 * @reset_phase: phase
5453 *
5454 * The handler for doing any required cleanup or initialization.
5455 *
5456 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5457 * MPT2_IOC_DONE_RESET
5458 *
5459 * Return nothing.
5460 */
5461void
5462mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5463{
5464 switch (reset_phase) {
5465 case MPT2_IOC_PRE_RESET:
5466 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5467 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
5468 _scsih_fw_event_off(ioc);
5469 break;
5470 case MPT2_IOC_AFTER_RESET:
5471 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5472 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
5473 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5474 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5475 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5476 complete(&ioc->tm_cmds.done);
5477 }
5478 _scsih_fw_event_on(ioc);
5479 _scsih_flush_running_cmds(ioc);
5480 break;
5481 case MPT2_IOC_DONE_RESET:
5482 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5483 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305484 _scsih_sas_host_refresh(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305485 _scsih_search_responding_sas_devices(ioc);
5486 _scsih_search_responding_raid_devices(ioc);
5487 _scsih_search_responding_expanders(ioc);
5488 break;
5489 case MPT2_IOC_RUNNING:
5490 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5491 "MPT2_IOC_RUNNING\n", ioc->name, __func__));
5492 _scsih_remove_unresponding_devices(ioc);
5493 break;
Eric Moore635374e2009-03-09 01:21:12 -06005494 }
5495}
5496
5497/**
5498 * _firmware_event_work - delayed task for processing firmware events
5499 * @ioc: per adapter object
5500 * @work: equal to the fw_event_work object
5501 * Context: user.
5502 *
5503 * Return nothing.
5504 */
5505static void
5506_firmware_event_work(struct work_struct *work)
5507{
5508 struct fw_event_work *fw_event = container_of(work,
Eric Moore6f92a7a2009-04-21 15:43:33 -06005509 struct fw_event_work, work);
Eric Moore635374e2009-03-09 01:21:12 -06005510 unsigned long flags;
5511 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5512
Eric Moore635374e2009-03-09 01:21:12 -06005513 /* the queue is being flushed so ignore this event */
5514 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5515 if (ioc->fw_events_off || ioc->remove_host) {
5516 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5517 _scsih_fw_event_free(ioc, fw_event);
5518 return;
5519 }
5520 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5521
Eric Moore635374e2009-03-09 01:21:12 -06005522 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06005523 _scsih_fw_event_requeue(ioc, fw_event, 1000);
5524 return;
5525 }
Eric Moore635374e2009-03-09 01:21:12 -06005526
5527 switch (fw_event->event) {
5528 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305529 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005530 break;
5531 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305532 _scsih_sas_device_status_change_event(ioc,
5533 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005534 break;
5535 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305536 _scsih_sas_discovery_event(ioc,
5537 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005538 break;
5539 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305540 _scsih_sas_broadcast_primative_event(ioc,
5541 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005542 break;
5543 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5544 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305545 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005546 break;
5547 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305548 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005549 break;
5550 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305551 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005552 break;
5553 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305554 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005555 break;
5556 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305557 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005558 break;
5559 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305560 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005561 break;
5562 }
5563 _scsih_fw_event_free(ioc, fw_event);
5564}
5565
5566/**
5567 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5568 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305569 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06005570 * @reply: reply message frame(lower 32bit addr)
5571 * Context: interrupt.
5572 *
5573 * This function merely adds a new work task into ioc->firmware_event_thread.
5574 * The tasks are worked from _firmware_event_work in user context.
5575 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305576 * Return 1 meaning mf should be freed from _base_interrupt
5577 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06005578 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305579u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305580mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
5581 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06005582{
5583 struct fw_event_work *fw_event;
5584 Mpi2EventNotificationReply_t *mpi_reply;
5585 unsigned long flags;
5586 u16 event;
5587
5588 /* events turned off due to host reset or driver unloading */
5589 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5590 if (ioc->fw_events_off || ioc->remove_host) {
5591 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305592 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005593 }
5594 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5595
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305596 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06005597 event = le16_to_cpu(mpi_reply->Event);
5598
5599 switch (event) {
5600 /* handle these */
5601 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
5602 {
5603 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
5604 (Mpi2EventDataSasBroadcastPrimitive_t *)
5605 mpi_reply->EventData;
5606
5607 if (baen_data->Primitive !=
5608 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
5609 ioc->broadcast_aen_busy)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305610 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005611 ioc->broadcast_aen_busy = 1;
5612 break;
5613 }
5614
5615 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
5616 _scsih_check_topo_delete_events(ioc,
5617 (Mpi2EventDataSasTopologyChangeList_t *)
5618 mpi_reply->EventData);
5619 break;
5620
5621 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
5622 case MPI2_EVENT_IR_OPERATION_STATUS:
5623 case MPI2_EVENT_SAS_DISCOVERY:
5624 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5625 case MPI2_EVENT_IR_VOLUME:
5626 case MPI2_EVENT_IR_PHYSICAL_DISK:
5627 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
5628 case MPI2_EVENT_TASK_SET_FULL:
5629 break;
5630
5631 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305632 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005633 }
5634
5635 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
5636 if (!fw_event) {
5637 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5638 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305639 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005640 }
5641 fw_event->event_data =
5642 kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
5643 if (!fw_event->event_data) {
5644 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5645 ioc->name, __FILE__, __LINE__, __func__);
5646 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305647 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005648 }
5649
5650 memcpy(fw_event->event_data, mpi_reply->EventData,
5651 mpi_reply->EventDataLength*4);
5652 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305653 fw_event->VF_ID = mpi_reply->VF_ID;
5654 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06005655 fw_event->event = event;
5656 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305657 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005658}
5659
5660/* shost template */
5661static struct scsi_host_template scsih_driver_template = {
5662 .module = THIS_MODULE,
5663 .name = "Fusion MPT SAS Host",
5664 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06005665 .queuecommand = _scsih_qcmd,
5666 .target_alloc = _scsih_target_alloc,
5667 .slave_alloc = _scsih_slave_alloc,
5668 .slave_configure = _scsih_slave_configure,
5669 .target_destroy = _scsih_target_destroy,
5670 .slave_destroy = _scsih_slave_destroy,
5671 .change_queue_depth = _scsih_change_queue_depth,
5672 .change_queue_type = _scsih_change_queue_type,
5673 .eh_abort_handler = _scsih_abort,
5674 .eh_device_reset_handler = _scsih_dev_reset,
5675 .eh_target_reset_handler = _scsih_target_reset,
5676 .eh_host_reset_handler = _scsih_host_reset,
5677 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06005678 .can_queue = 1,
5679 .this_id = -1,
5680 .sg_tablesize = MPT2SAS_SG_DEPTH,
5681 .max_sectors = 8192,
5682 .cmd_per_lun = 7,
5683 .use_clustering = ENABLE_CLUSTERING,
5684 .shost_attrs = mpt2sas_host_attrs,
5685 .sdev_attrs = mpt2sas_dev_attrs,
5686};
5687
5688/**
5689 * _scsih_expander_node_remove - removing expander device from list.
5690 * @ioc: per adapter object
5691 * @sas_expander: the sas_device object
5692 * Context: Calling function should acquire ioc->sas_node_lock.
5693 *
5694 * Removing object and freeing associated memory from the
5695 * ioc->sas_expander_list.
5696 *
5697 * Return nothing.
5698 */
5699static void
5700_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
5701 struct _sas_node *sas_expander)
5702{
5703 struct _sas_port *mpt2sas_port;
5704 struct _sas_device *sas_device;
5705 struct _sas_node *expander_sibling;
5706 unsigned long flags;
5707
5708 if (!sas_expander)
5709 return;
5710
5711 /* remove sibling ports attached to this expander */
5712 retry_device_search:
5713 list_for_each_entry(mpt2sas_port,
5714 &sas_expander->sas_port_list, port_list) {
5715 if (mpt2sas_port->remote_identify.device_type ==
5716 SAS_END_DEVICE) {
5717 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5718 sas_device =
5719 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5720 mpt2sas_port->remote_identify.sas_address);
5721 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5722 if (!sas_device)
5723 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305724 _scsih_remove_device(ioc, sas_device);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305725 if (ioc->shost_recovery)
5726 return;
Eric Moore635374e2009-03-09 01:21:12 -06005727 goto retry_device_search;
5728 }
5729 }
5730
5731 retry_expander_search:
5732 list_for_each_entry(mpt2sas_port,
5733 &sas_expander->sas_port_list, port_list) {
5734
5735 if (mpt2sas_port->remote_identify.device_type ==
5736 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
5737 mpt2sas_port->remote_identify.device_type ==
5738 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
5739
5740 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5741 expander_sibling =
5742 mpt2sas_scsih_expander_find_by_sas_address(
5743 ioc, mpt2sas_port->remote_identify.sas_address);
5744 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5745 if (!expander_sibling)
5746 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305747 _scsih_expander_remove(ioc,
5748 expander_sibling->sas_address);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305749 if (ioc->shost_recovery)
5750 return;
Eric Moore635374e2009-03-09 01:21:12 -06005751 goto retry_expander_search;
5752 }
5753 }
5754
5755 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305756 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06005757
5758 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
5759 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
5760 sas_expander->handle, (unsigned long long)
5761 sas_expander->sas_address);
5762
5763 list_del(&sas_expander->list);
5764 kfree(sas_expander->phy);
5765 kfree(sas_expander);
5766}
5767
5768/**
Eric Moored5d135b2009-05-18 13:02:08 -06005769 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06005770 * @pdev: PCI device struct
5771 *
5772 * Return nothing.
5773 */
5774static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06005775_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06005776{
5777 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5778 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5779 struct _sas_port *mpt2sas_port;
5780 struct _sas_device *sas_device;
5781 struct _sas_node *expander_sibling;
5782 struct workqueue_struct *wq;
5783 unsigned long flags;
5784
5785 ioc->remove_host = 1;
5786 _scsih_fw_event_off(ioc);
5787
5788 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5789 wq = ioc->firmware_event_thread;
5790 ioc->firmware_event_thread = NULL;
5791 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5792 if (wq)
5793 destroy_workqueue(wq);
5794
5795 /* free ports attached to the sas_host */
5796 retry_again:
5797 list_for_each_entry(mpt2sas_port,
5798 &ioc->sas_hba.sas_port_list, port_list) {
5799 if (mpt2sas_port->remote_identify.device_type ==
5800 SAS_END_DEVICE) {
5801 sas_device =
5802 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5803 mpt2sas_port->remote_identify.sas_address);
5804 if (sas_device) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305805 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005806 goto retry_again;
5807 }
5808 } else {
5809 expander_sibling =
5810 mpt2sas_scsih_expander_find_by_sas_address(ioc,
5811 mpt2sas_port->remote_identify.sas_address);
5812 if (expander_sibling) {
5813 _scsih_expander_remove(ioc,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305814 expander_sibling->sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06005815 goto retry_again;
5816 }
5817 }
5818 }
5819
5820 /* free phys attached to the sas_host */
5821 if (ioc->sas_hba.num_phys) {
5822 kfree(ioc->sas_hba.phy);
5823 ioc->sas_hba.phy = NULL;
5824 ioc->sas_hba.num_phys = 0;
5825 }
5826
5827 sas_remove_host(shost);
5828 mpt2sas_base_detach(ioc);
5829 list_del(&ioc->list);
5830 scsi_remove_host(shost);
5831 scsi_host_put(shost);
5832}
5833
5834/**
5835 * _scsih_probe_boot_devices - reports 1st device
5836 * @ioc: per adapter object
5837 *
5838 * If specified in bios page 2, this routine reports the 1st
5839 * device scsi-ml or sas transport for persistent boot device
5840 * purposes. Please refer to function _scsih_determine_boot_device()
5841 */
5842static void
5843_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
5844{
5845 u8 is_raid;
5846 void *device;
5847 struct _sas_device *sas_device;
5848 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305849 u16 handle;
5850 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06005851 u64 sas_address;
5852 unsigned long flags;
5853 int rc;
5854
5855 device = NULL;
5856 if (ioc->req_boot_device.device) {
5857 device = ioc->req_boot_device.device;
5858 is_raid = ioc->req_boot_device.is_raid;
5859 } else if (ioc->req_alt_boot_device.device) {
5860 device = ioc->req_alt_boot_device.device;
5861 is_raid = ioc->req_alt_boot_device.is_raid;
5862 } else if (ioc->current_boot_device.device) {
5863 device = ioc->current_boot_device.device;
5864 is_raid = ioc->current_boot_device.is_raid;
5865 }
5866
5867 if (!device)
5868 return;
5869
5870 if (is_raid) {
5871 raid_device = device;
5872 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5873 raid_device->id, 0);
5874 if (rc)
5875 _scsih_raid_device_remove(ioc, raid_device);
5876 } else {
5877 sas_device = device;
5878 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305879 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06005880 sas_address = sas_device->sas_address;
5881 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5882 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5883 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5884 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305885 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06005886 _scsih_sas_device_remove(ioc, sas_device);
5887 } else if (!sas_device->starget) {
5888 mpt2sas_transport_port_remove(ioc, sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305889 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06005890 _scsih_sas_device_remove(ioc, sas_device);
5891 }
5892 }
5893}
5894
5895/**
5896 * _scsih_probe_raid - reporting raid volumes to scsi-ml
5897 * @ioc: per adapter object
5898 *
5899 * Called during initial loading of the driver.
5900 */
5901static void
5902_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
5903{
5904 struct _raid_device *raid_device, *raid_next;
5905 int rc;
5906
5907 list_for_each_entry_safe(raid_device, raid_next,
5908 &ioc->raid_device_list, list) {
5909 if (raid_device->starget)
5910 continue;
5911 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5912 raid_device->id, 0);
5913 if (rc)
5914 _scsih_raid_device_remove(ioc, raid_device);
5915 }
5916}
5917
5918/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305919 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06005920 * @ioc: per adapter object
5921 *
5922 * Called during initial loading of the driver.
5923 */
5924static void
5925_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
5926{
5927 struct _sas_device *sas_device, *next;
5928 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06005929
5930 /* SAS Device List */
5931 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
5932 list) {
5933 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5934 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5935 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5936
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305937 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
5938 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06005939 _scsih_sas_device_remove(ioc, sas_device);
5940 } else if (!sas_device->starget) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305941 mpt2sas_transport_port_remove(ioc,
5942 sas_device->sas_address,
5943 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06005944 _scsih_sas_device_remove(ioc, sas_device);
5945 }
5946 }
5947}
5948
5949/**
5950 * _scsih_probe_devices - probing for devices
5951 * @ioc: per adapter object
5952 *
5953 * Called during initial loading of the driver.
5954 */
5955static void
5956_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
5957{
5958 u16 volume_mapping_flags =
5959 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
5960 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
5961
5962 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
5963 return; /* return when IOC doesn't support initiator mode */
5964
5965 _scsih_probe_boot_devices(ioc);
5966
5967 if (ioc->ir_firmware) {
5968 if ((volume_mapping_flags &
5969 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
5970 _scsih_probe_sas(ioc);
5971 _scsih_probe_raid(ioc);
5972 } else {
5973 _scsih_probe_raid(ioc);
5974 _scsih_probe_sas(ioc);
5975 }
5976 } else
5977 _scsih_probe_sas(ioc);
5978}
5979
5980/**
Eric Moored5d135b2009-05-18 13:02:08 -06005981 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06005982 * @pdev: PCI device struct
5983 * @id: pci device id
5984 *
5985 * Returns 0 success, anything else error.
5986 */
5987static int
Eric Moored5d135b2009-05-18 13:02:08 -06005988_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06005989{
5990 struct MPT2SAS_ADAPTER *ioc;
5991 struct Scsi_Host *shost;
5992
5993 shost = scsi_host_alloc(&scsih_driver_template,
5994 sizeof(struct MPT2SAS_ADAPTER));
5995 if (!shost)
5996 return -ENODEV;
5997
5998 /* init local params */
5999 ioc = shost_priv(shost);
6000 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
6001 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06006002 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06006003 ioc->shost = shost;
6004 ioc->id = mpt_ids++;
6005 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
6006 ioc->pdev = pdev;
6007 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
6008 ioc->tm_cb_idx = tm_cb_idx;
6009 ioc->ctl_cb_idx = ctl_cb_idx;
6010 ioc->base_cb_idx = base_cb_idx;
6011 ioc->transport_cb_idx = transport_cb_idx;
6012 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306013 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
6014 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006015 ioc->logging_level = logging_level;
6016 /* misc semaphores and spin locks */
6017 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
6018 spin_lock_init(&ioc->scsi_lookup_lock);
6019 spin_lock_init(&ioc->sas_device_lock);
6020 spin_lock_init(&ioc->sas_node_lock);
6021 spin_lock_init(&ioc->fw_event_lock);
6022 spin_lock_init(&ioc->raid_device_lock);
6023
6024 INIT_LIST_HEAD(&ioc->sas_device_list);
6025 INIT_LIST_HEAD(&ioc->sas_device_init_list);
6026 INIT_LIST_HEAD(&ioc->sas_expander_list);
6027 INIT_LIST_HEAD(&ioc->fw_event_list);
6028 INIT_LIST_HEAD(&ioc->raid_device_list);
6029 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306030 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Eric Moore635374e2009-03-09 01:21:12 -06006031
6032 /* init shost parameters */
6033 shost->max_cmd_len = 16;
6034 shost->max_lun = max_lun;
6035 shost->transportt = mpt2sas_transport_template;
6036 shost->unique_id = ioc->id;
6037
6038 if ((scsi_add_host(shost, &pdev->dev))) {
6039 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6040 ioc->name, __FILE__, __LINE__, __func__);
6041 list_del(&ioc->list);
6042 goto out_add_shost_fail;
6043 }
6044
Eric Moore3c621b32009-05-18 12:59:41 -06006045 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
6046 | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306047 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06006048
Eric Moore635374e2009-03-09 01:21:12 -06006049 /* event thread */
6050 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
6051 "fw_event%d", ioc->id);
6052 ioc->firmware_event_thread = create_singlethread_workqueue(
6053 ioc->firmware_event_name);
6054 if (!ioc->firmware_event_thread) {
6055 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6056 ioc->name, __FILE__, __LINE__, __func__);
6057 goto out_thread_fail;
6058 }
6059
6060 ioc->wait_for_port_enable_to_complete = 1;
6061 if ((mpt2sas_base_attach(ioc))) {
6062 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6063 ioc->name, __FILE__, __LINE__, __func__);
6064 goto out_attach_fail;
6065 }
6066
6067 ioc->wait_for_port_enable_to_complete = 0;
6068 _scsih_probe_devices(ioc);
6069 return 0;
6070
6071 out_attach_fail:
6072 destroy_workqueue(ioc->firmware_event_thread);
6073 out_thread_fail:
6074 list_del(&ioc->list);
6075 scsi_remove_host(shost);
6076 out_add_shost_fail:
6077 return -ENODEV;
6078}
6079
6080#ifdef CONFIG_PM
6081/**
Eric Moored5d135b2009-05-18 13:02:08 -06006082 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006083 * @pdev: PCI device struct
6084 * @state: PM state change to (usually PCI_D3)
6085 *
6086 * Returns 0 success, anything else error.
6087 */
6088static int
Eric Moored5d135b2009-05-18 13:02:08 -06006089_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06006090{
6091 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6092 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6093 u32 device_state;
6094
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306095 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006096 flush_scheduled_work();
6097 scsi_block_requests(shost);
6098 device_state = pci_choose_state(pdev, state);
6099 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
6100 "operating state [D%d]\n", ioc->name, pdev,
6101 pci_name(pdev), device_state);
6102
6103 mpt2sas_base_free_resources(ioc);
6104 pci_save_state(pdev);
6105 pci_disable_device(pdev);
6106 pci_set_power_state(pdev, device_state);
6107 return 0;
6108}
6109
6110/**
Eric Moored5d135b2009-05-18 13:02:08 -06006111 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006112 * @pdev: PCI device struct
6113 *
6114 * Returns 0 success, anything else error.
6115 */
6116static int
Eric Moored5d135b2009-05-18 13:02:08 -06006117_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006118{
6119 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6120 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6121 u32 device_state = pdev->current_state;
6122 int r;
6123
6124 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
6125 "operating state [D%d]\n", ioc->name, pdev,
6126 pci_name(pdev), device_state);
6127
6128 pci_set_power_state(pdev, PCI_D0);
6129 pci_enable_wake(pdev, PCI_D0, 0);
6130 pci_restore_state(pdev);
6131 ioc->pdev = pdev;
6132 r = mpt2sas_base_map_resources(ioc);
6133 if (r)
6134 return r;
6135
6136 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
6137 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306138 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006139 return 0;
6140}
6141#endif /* CONFIG_PM */
6142
6143
6144static struct pci_driver scsih_driver = {
6145 .name = MPT2SAS_DRIVER_NAME,
6146 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06006147 .probe = _scsih_probe,
6148 .remove = __devexit_p(_scsih_remove),
Eric Moore635374e2009-03-09 01:21:12 -06006149#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06006150 .suspend = _scsih_suspend,
6151 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06006152#endif
6153};
6154
6155
6156/**
Eric Moored5d135b2009-05-18 13:02:08 -06006157 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06006158 *
6159 * Returns 0 success, anything else error.
6160 */
6161static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06006162_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06006163{
6164 int error;
6165
6166 mpt_ids = 0;
6167 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
6168 MPT2SAS_DRIVER_VERSION);
6169
6170 mpt2sas_transport_template =
6171 sas_attach_transport(&mpt2sas_transport_functions);
6172 if (!mpt2sas_transport_template)
6173 return -ENODEV;
6174
6175 mpt2sas_base_initialize_callback_handler();
6176
6177 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06006178 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06006179
6180 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06006181 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06006182
6183 /* base internal commands callback handler */
6184 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
6185
6186 /* transport internal commands callback handler */
6187 transport_cb_idx = mpt2sas_base_register_callback_handler(
6188 mpt2sas_transport_done);
6189
6190 /* configuration page API internal commands callback handler */
6191 config_cb_idx = mpt2sas_base_register_callback_handler(
6192 mpt2sas_config_done);
6193
6194 /* ctl module callback handler */
6195 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
6196
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306197 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
6198 _scsih_tm_tr_complete);
6199 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
6200 _scsih_sas_control_complete);
6201
Eric Moore635374e2009-03-09 01:21:12 -06006202 mpt2sas_ctl_init();
6203
6204 error = pci_register_driver(&scsih_driver);
6205 if (error)
6206 sas_release_transport(mpt2sas_transport_template);
6207
6208 return error;
6209}
6210
6211/**
Eric Moored5d135b2009-05-18 13:02:08 -06006212 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06006213 *
6214 * Returns 0 success, anything else error.
6215 */
6216static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06006217_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06006218{
6219 printk(KERN_INFO "mpt2sas version %s unloading\n",
6220 MPT2SAS_DRIVER_VERSION);
6221
6222 pci_unregister_driver(&scsih_driver);
6223
6224 sas_release_transport(mpt2sas_transport_template);
6225 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
6226 mpt2sas_base_release_callback_handler(tm_cb_idx);
6227 mpt2sas_base_release_callback_handler(base_cb_idx);
6228 mpt2sas_base_release_callback_handler(transport_cb_idx);
6229 mpt2sas_base_release_callback_handler(config_cb_idx);
6230 mpt2sas_base_release_callback_handler(ctl_cb_idx);
6231
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306232 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
6233 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
6234
Eric Moore635374e2009-03-09 01:21:12 -06006235 mpt2sas_ctl_exit();
6236}
6237
Eric Moored5d135b2009-05-18 13:02:08 -06006238module_init(_scsih_init);
6239module_exit(_scsih_exit);