blob: 8822cda852ba09ba41c038657a02a724d70efc22 [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);
2389 if (!sas_device) {
2390 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2391 printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
2392 ioc->name, __func__);
2393 return;
2394 }
2395 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2396
2397 /* skip is hidden raid component */
2398 if (sas_device->hidden_raid_component)
2399 return;
2400
2401 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
2402 if (!smid) {
2403 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
2404 if (!delayed_tr)
2405 return;
2406 INIT_LIST_HEAD(&delayed_tr->list);
2407 delayed_tr->handle = handle;
2408 delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
2409 list_add_tail(&delayed_tr->list,
2410 &ioc->delayed_tr_list);
2411 if (sas_device->starget)
2412 dewtprintk(ioc, starget_printk(KERN_INFO,
2413 sas_device->starget, "DELAYED:tr:handle(0x%04x), "
2414 "(open)\n", sas_device->handle));
2415 return;
2416 }
2417
2418 if (sas_device->starget && sas_device->starget->hostdata) {
2419 sas_target_priv_data = sas_device->starget->hostdata;
2420 sas_target_priv_data->tm_busy = 1;
2421 dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
2422 "tr:handle(0x%04x), (open)\n", sas_device->handle));
2423 }
2424
2425 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2426 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2427 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2428 mpi_request->DevHandle = cpu_to_le16(handle);
2429 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
2430 sas_device->state |= MPTSAS_STATE_TR_SEND;
2431 sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
2432 mpt2sas_base_put_smid_hi_priority(ioc, smid);
2433}
2434
2435
2436
2437/**
2438 * _scsih_sas_control_complete - completion routine
2439 * @ioc: per adapter object
2440 * @smid: system request message index
2441 * @msix_index: MSIX table index supplied by the OS
2442 * @reply: reply message frame(lower 32bit addr)
2443 * Context: interrupt time.
2444 *
2445 * This is the sas iounit controll completion routine.
2446 * This code is part of the code to initiate the device removal
2447 * handshake protocal with controller firmware.
2448 *
2449 * Return 1 meaning mf should be freed from _base_interrupt
2450 * 0 means the mf is freed from this function.
2451 */
2452static u8
2453_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
2454 u8 msix_index, u32 reply)
2455{
2456 unsigned long flags;
2457 u16 handle;
2458 struct _sas_device *sas_device;
2459 Mpi2SasIoUnitControlReply_t *mpi_reply =
2460 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2461
2462 handle = le16_to_cpu(mpi_reply->DevHandle);
2463
2464 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2465 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
2466 if (!sas_device) {
2467 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2468 printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
2469 ioc->name, __func__);
2470 return 1;
2471 }
2472 sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
2473 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2474
2475 if (sas_device->starget)
2476 dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
2477 "sc_complete:handle(0x%04x), "
2478 "ioc_status(0x%04x), loginfo(0x%08x)\n",
2479 handle, le16_to_cpu(mpi_reply->IOCStatus),
2480 le32_to_cpu(mpi_reply->IOCLogInfo)));
2481 return 1;
2482}
2483
2484/**
2485 * _scsih_tm_tr_complete -
2486 * @ioc: per adapter object
2487 * @smid: system request message index
2488 * @msix_index: MSIX table index supplied by the OS
2489 * @reply: reply message frame(lower 32bit addr)
2490 * Context: interrupt time.
2491 *
2492 * This is the target reset completion routine.
2493 * This code is part of the code to initiate the device removal
2494 * handshake protocal with controller firmware.
2495 * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE)
2496 *
2497 * Return 1 meaning mf should be freed from _base_interrupt
2498 * 0 means the mf is freed from this function.
2499 */
2500static u8
2501_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
2502 u32 reply)
2503{
2504 unsigned long flags;
2505 u16 handle;
2506 struct _sas_device *sas_device;
2507 Mpi2SCSITaskManagementReply_t *mpi_reply =
2508 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2509 Mpi2SasIoUnitControlRequest_t *mpi_request;
2510 u16 smid_sas_ctrl;
2511 struct MPT2SAS_TARGET *sas_target_priv_data;
2512 struct _tr_list *delayed_tr;
2513 u8 rc;
2514
2515 handle = le16_to_cpu(mpi_reply->DevHandle);
2516 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2517 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
2518 if (!sas_device) {
2519 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2520 printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
2521 ioc->name, __func__);
2522 return 1;
2523 }
2524 sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
2525 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2526
2527 if (sas_device->starget)
2528 dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
2529 "tr_complete:handle(0x%04x), (%s) ioc_status(0x%04x), "
2530 "loginfo(0x%08x), completed(%d)\n",
2531 sas_device->handle, (sas_device->state &
2532 MPT2SAS_REQ_SAS_CNTRL) ? "open" : "active",
2533 le16_to_cpu(mpi_reply->IOCStatus),
2534 le32_to_cpu(mpi_reply->IOCLogInfo),
2535 le32_to_cpu(mpi_reply->TerminationCount)));
2536
2537 if (sas_device->starget && sas_device->starget->hostdata) {
2538 sas_target_priv_data = sas_device->starget->hostdata;
2539 sas_target_priv_data->tm_busy = 0;
2540 }
2541
2542 if (!list_empty(&ioc->delayed_tr_list)) {
2543 delayed_tr = list_entry(ioc->delayed_tr_list.next,
2544 struct _tr_list, list);
2545 mpt2sas_base_free_smid(ioc, smid);
2546 if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL)
2547 _scsih_tm_tr_send(ioc, delayed_tr->handle);
2548 list_del(&delayed_tr->list);
2549 kfree(delayed_tr);
2550 rc = 0; /* tells base_interrupt not to free mf */
2551 } else
2552 rc = 1;
2553
2554
2555 if (!(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
2556 return rc;
2557
2558 if (ioc->shost_recovery) {
2559 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2560 __func__, ioc->name);
2561 return rc;
2562 }
2563
2564 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
2565 if (!smid_sas_ctrl) {
2566 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2567 ioc->name, __func__);
2568 return rc;
2569 }
2570
2571 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
2572 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
2573 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
2574 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
2575 mpi_request->DevHandle = mpi_reply->DevHandle;
2576 sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
2577 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
2578 return rc;
2579}
2580
2581/**
Eric Moore635374e2009-03-09 01:21:12 -06002582 * _scsih_check_topo_delete_events - sanity check on topo events
2583 * @ioc: per adapter object
2584 * @event_data: the event data payload
2585 *
2586 * This routine added to better handle cable breaker.
2587 *
2588 * This handles the case where driver recieves multiple expander
2589 * add and delete events in a single shot. When there is a delete event
2590 * the routine will void any pending add events waiting in the event queue.
2591 *
2592 * Return nothing.
2593 */
2594static void
2595_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
2596 Mpi2EventDataSasTopologyChangeList_t *event_data)
2597{
2598 struct fw_event_work *fw_event;
2599 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
2600 u16 expander_handle;
2601 struct _sas_node *sas_expander;
2602 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302603 int i, reason_code;
2604 u16 handle;
2605
2606 for (i = 0 ; i < event_data->NumEntries; i++) {
2607 if (event_data->PHY[i].PhyStatus &
2608 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
2609 continue;
2610 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2611 if (!handle)
2612 continue;
2613 reason_code = event_data->PHY[i].PhyStatus &
2614 MPI2_EVENT_SAS_TOPO_RC_MASK;
2615 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
2616 _scsih_tm_tr_send(ioc, handle);
2617 }
Eric Moore635374e2009-03-09 01:21:12 -06002618
2619 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
2620 if (expander_handle < ioc->sas_hba.num_phys) {
2621 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2622 return;
2623 }
2624
2625 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
2626 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
2627 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2628 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
2629 expander_handle);
2630 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2631 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
2632 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
2633 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2634
2635 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
2636 return;
2637
2638 /* mark ignore flag for pending events */
2639 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2640 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
2641 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
2642 fw_event->ignore)
2643 continue;
2644 local_event_data = fw_event->event_data;
2645 if (local_event_data->ExpStatus ==
2646 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
2647 local_event_data->ExpStatus ==
2648 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
2649 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
2650 expander_handle) {
2651 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
2652 "setting ignoring flag\n", ioc->name));
2653 fw_event->ignore = 1;
2654 }
2655 }
2656 }
2657 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2658}
2659
2660/**
Eric Moore635374e2009-03-09 01:21:12 -06002661 * _scsih_flush_running_cmds - completing outstanding commands.
2662 * @ioc: per adapter object
2663 *
2664 * The flushing out of all pending scmd commands following host reset,
2665 * where all IO is dropped to the floor.
2666 *
2667 * Return nothing.
2668 */
2669static void
2670_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
2671{
2672 struct scsi_cmnd *scmd;
2673 u16 smid;
2674 u16 count = 0;
2675
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302676 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
2677 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002678 if (!scmd)
2679 continue;
2680 count++;
2681 mpt2sas_base_free_smid(ioc, smid);
2682 scsi_dma_unmap(scmd);
2683 scmd->result = DID_RESET << 16;
2684 scmd->scsi_done(scmd);
2685 }
2686 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
2687 ioc->name, count));
2688}
2689
2690/**
Eric Moore3c621b32009-05-18 12:59:41 -06002691 * _scsih_setup_eedp - setup MPI request for EEDP transfer
2692 * @scmd: pointer to scsi command object
2693 * @mpi_request: pointer to the SCSI_IO reqest message frame
2694 *
2695 * Supporting protection 1 and 3.
2696 *
2697 * Returns nothing
2698 */
2699static void
2700_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
2701{
2702 u16 eedp_flags;
2703 unsigned char prot_op = scsi_get_prot_op(scmd);
2704 unsigned char prot_type = scsi_get_prot_type(scmd);
2705
2706 if (prot_type == SCSI_PROT_DIF_TYPE0 ||
2707 prot_type == SCSI_PROT_DIF_TYPE2 ||
2708 prot_op == SCSI_PROT_NORMAL)
2709 return;
2710
2711 if (prot_op == SCSI_PROT_READ_STRIP)
2712 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
2713 else if (prot_op == SCSI_PROT_WRITE_INSERT)
2714 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
2715 else
2716 return;
2717
2718 mpi_request->EEDPBlockSize = scmd->device->sector_size;
2719
2720 switch (prot_type) {
2721 case SCSI_PROT_DIF_TYPE1:
2722
2723 /*
2724 * enable ref/guard checking
2725 * auto increment ref tag
2726 */
2727 mpi_request->EEDPFlags = eedp_flags |
2728 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
2729 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2730 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2731 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
2732 cpu_to_be32(scsi_get_lba(scmd));
2733
2734 break;
2735
2736 case SCSI_PROT_DIF_TYPE3:
2737
2738 /*
2739 * enable guard checking
2740 */
2741 mpi_request->EEDPFlags = eedp_flags |
2742 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2743
2744 break;
2745 }
2746}
2747
2748/**
2749 * _scsih_eedp_error_handling - return sense code for EEDP errors
2750 * @scmd: pointer to scsi command object
2751 * @ioc_status: ioc status
2752 *
2753 * Returns nothing
2754 */
2755static void
2756_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
2757{
2758 u8 ascq;
2759 u8 sk;
2760 u8 host_byte;
2761
2762 switch (ioc_status) {
2763 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2764 ascq = 0x01;
2765 break;
2766 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2767 ascq = 0x02;
2768 break;
2769 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2770 ascq = 0x03;
2771 break;
2772 default:
2773 ascq = 0x00;
2774 break;
2775 }
2776
2777 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
2778 sk = ILLEGAL_REQUEST;
2779 host_byte = DID_ABORT;
2780 } else {
2781 sk = ABORTED_COMMAND;
2782 host_byte = DID_OK;
2783 }
2784
2785 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
2786 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
2787 SAM_STAT_CHECK_CONDITION;
2788}
2789
2790/**
Eric Moored5d135b2009-05-18 13:02:08 -06002791 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06002792 * @scmd: pointer to scsi command object
2793 * @done: function pointer to be invoked on completion
2794 *
2795 * The callback index is set inside `ioc->scsi_io_cb_idx`.
2796 *
2797 * Returns 0 on success. If there's a failure, return either:
2798 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
2799 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
2800 */
2801static int
Eric Moored5d135b2009-05-18 13:02:08 -06002802_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06002803{
2804 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2805 struct MPT2SAS_DEVICE *sas_device_priv_data;
2806 struct MPT2SAS_TARGET *sas_target_priv_data;
2807 Mpi2SCSIIORequest_t *mpi_request;
2808 u32 mpi_control;
2809 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06002810
2811 scmd->scsi_done = done;
2812 sas_device_priv_data = scmd->device->hostdata;
2813 if (!sas_device_priv_data) {
2814 scmd->result = DID_NO_CONNECT << 16;
2815 scmd->scsi_done(scmd);
2816 return 0;
2817 }
2818
2819 sas_target_priv_data = sas_device_priv_data->sas_target;
2820 if (!sas_target_priv_data || sas_target_priv_data->handle ==
2821 MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
2822 scmd->result = DID_NO_CONNECT << 16;
2823 scmd->scsi_done(scmd);
2824 return 0;
2825 }
2826
2827 /* see if we are busy with task managment stuff */
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302828 if (sas_target_priv_data->tm_busy)
2829 return SCSI_MLQUEUE_DEVICE_BUSY;
2830 else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06002831 return SCSI_MLQUEUE_HOST_BUSY;
Eric Moore635374e2009-03-09 01:21:12 -06002832
2833 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
2834 mpi_control = MPI2_SCSIIO_CONTROL_READ;
2835 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
2836 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
2837 else
2838 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
2839
2840 /* set tags */
2841 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
2842 if (scmd->device->tagged_supported) {
2843 if (scmd->device->ordered_tags)
2844 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
2845 else
2846 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2847 } else
2848/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
2849/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
2850 */
2851 mpi_control |= (0x500);
2852
2853 } else
2854 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2855
2856 if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
2857 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
2858
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302859 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002860 if (!smid) {
2861 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2862 ioc->name, __func__);
2863 goto out;
2864 }
2865 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2866 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06002867 _scsih_setup_eedp(scmd, mpi_request);
Eric Moore635374e2009-03-09 01:21:12 -06002868 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2869 if (sas_device_priv_data->sas_target->flags &
2870 MPT_TARGET_FLAGS_RAID_COMPONENT)
2871 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2872 else
2873 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2874 mpi_request->DevHandle =
2875 cpu_to_le16(sas_device_priv_data->sas_target->handle);
2876 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
2877 mpi_request->Control = cpu_to_le32(mpi_control);
2878 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
2879 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
2880 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
2881 mpi_request->SenseBufferLowAddress =
2882 (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
2883 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
2884 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
2885 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302886 mpi_request->VF_ID = 0; /* TODO */
2887 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06002888 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
2889 mpi_request->LUN);
2890 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
2891
2892 if (!mpi_request->DataLength) {
2893 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
2894 } else {
2895 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
2896 mpt2sas_base_free_smid(ioc, smid);
2897 goto out;
2898 }
2899 }
2900
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302901 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Eric Moore635374e2009-03-09 01:21:12 -06002902 sas_device_priv_data->sas_target->handle);
2903 return 0;
2904
2905 out:
2906 return SCSI_MLQUEUE_HOST_BUSY;
2907}
2908
2909/**
2910 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
2911 * @sense_buffer: sense data returned by target
2912 * @data: normalized skey/asc/ascq
2913 *
2914 * Return nothing.
2915 */
2916static void
2917_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
2918{
2919 if ((sense_buffer[0] & 0x7F) >= 0x72) {
2920 /* descriptor format */
2921 data->skey = sense_buffer[1] & 0x0F;
2922 data->asc = sense_buffer[2];
2923 data->ascq = sense_buffer[3];
2924 } else {
2925 /* fixed format */
2926 data->skey = sense_buffer[2] & 0x0F;
2927 data->asc = sense_buffer[12];
2928 data->ascq = sense_buffer[13];
2929 }
2930}
2931
2932#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
2933/**
2934 * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request
2935 * @ioc: per adapter object
2936 * @scmd: pointer to scsi command object
2937 * @mpi_reply: reply mf payload returned from firmware
2938 *
2939 * scsi_status - SCSI Status code returned from target device
2940 * scsi_state - state info associated with SCSI_IO determined by ioc
2941 * ioc_status - ioc supplied status info
2942 *
2943 * Return nothing.
2944 */
2945static void
2946_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
2947 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
2948{
2949 u32 response_info;
2950 u8 *response_bytes;
2951 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
2952 MPI2_IOCSTATUS_MASK;
2953 u8 scsi_state = mpi_reply->SCSIState;
2954 u8 scsi_status = mpi_reply->SCSIStatus;
2955 char *desc_ioc_state = NULL;
2956 char *desc_scsi_status = NULL;
2957 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05302958 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
2959
2960 if (log_info == 0x31170000)
2961 return;
Eric Moore635374e2009-03-09 01:21:12 -06002962
2963 switch (ioc_status) {
2964 case MPI2_IOCSTATUS_SUCCESS:
2965 desc_ioc_state = "success";
2966 break;
2967 case MPI2_IOCSTATUS_INVALID_FUNCTION:
2968 desc_ioc_state = "invalid function";
2969 break;
2970 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2971 desc_ioc_state = "scsi recovered error";
2972 break;
2973 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2974 desc_ioc_state = "scsi invalid dev handle";
2975 break;
2976 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2977 desc_ioc_state = "scsi device not there";
2978 break;
2979 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2980 desc_ioc_state = "scsi data overrun";
2981 break;
2982 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2983 desc_ioc_state = "scsi data underrun";
2984 break;
2985 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2986 desc_ioc_state = "scsi io data error";
2987 break;
2988 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2989 desc_ioc_state = "scsi protocol error";
2990 break;
2991 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2992 desc_ioc_state = "scsi task terminated";
2993 break;
2994 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2995 desc_ioc_state = "scsi residual mismatch";
2996 break;
2997 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2998 desc_ioc_state = "scsi task mgmt failed";
2999 break;
3000 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3001 desc_ioc_state = "scsi ioc terminated";
3002 break;
3003 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3004 desc_ioc_state = "scsi ext terminated";
3005 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003006 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3007 desc_ioc_state = "eedp guard error";
3008 break;
3009 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3010 desc_ioc_state = "eedp ref tag error";
3011 break;
3012 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3013 desc_ioc_state = "eedp app tag error";
3014 break;
Eric Moore635374e2009-03-09 01:21:12 -06003015 default:
3016 desc_ioc_state = "unknown";
3017 break;
3018 }
3019
3020 switch (scsi_status) {
3021 case MPI2_SCSI_STATUS_GOOD:
3022 desc_scsi_status = "good";
3023 break;
3024 case MPI2_SCSI_STATUS_CHECK_CONDITION:
3025 desc_scsi_status = "check condition";
3026 break;
3027 case MPI2_SCSI_STATUS_CONDITION_MET:
3028 desc_scsi_status = "condition met";
3029 break;
3030 case MPI2_SCSI_STATUS_BUSY:
3031 desc_scsi_status = "busy";
3032 break;
3033 case MPI2_SCSI_STATUS_INTERMEDIATE:
3034 desc_scsi_status = "intermediate";
3035 break;
3036 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
3037 desc_scsi_status = "intermediate condmet";
3038 break;
3039 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
3040 desc_scsi_status = "reservation conflict";
3041 break;
3042 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
3043 desc_scsi_status = "command terminated";
3044 break;
3045 case MPI2_SCSI_STATUS_TASK_SET_FULL:
3046 desc_scsi_status = "task set full";
3047 break;
3048 case MPI2_SCSI_STATUS_ACA_ACTIVE:
3049 desc_scsi_status = "aca active";
3050 break;
3051 case MPI2_SCSI_STATUS_TASK_ABORTED:
3052 desc_scsi_status = "task aborted";
3053 break;
3054 default:
3055 desc_scsi_status = "unknown";
3056 break;
3057 }
3058
3059 desc_scsi_state[0] = '\0';
3060 if (!scsi_state)
3061 desc_scsi_state = " ";
3062 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3063 strcat(desc_scsi_state, "response info ");
3064 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3065 strcat(desc_scsi_state, "state terminated ");
3066 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
3067 strcat(desc_scsi_state, "no status ");
3068 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
3069 strcat(desc_scsi_state, "autosense failed ");
3070 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
3071 strcat(desc_scsi_state, "autosense valid ");
3072
3073 scsi_print_command(scmd);
3074 printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
3075 "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
3076 le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
3077 ioc_status, smid);
3078 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
3079 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
3080 scsi_get_resid(scmd));
3081 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
3082 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
3083 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
3084 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
3085 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
3086 scsi_status, desc_scsi_state, scsi_state);
3087
3088 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3089 struct sense_info data;
3090 _scsih_normalize_sense(scmd->sense_buffer, &data);
3091 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
3092 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey,
3093 data.asc, data.ascq);
3094 }
3095
3096 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
3097 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
3098 response_bytes = (u8 *)&response_info;
3099 _scsih_response_code(ioc, response_bytes[3]);
3100 }
3101}
3102#endif
3103
3104/**
3105 * _scsih_smart_predicted_fault - illuminate Fault LED
3106 * @ioc: per adapter object
3107 * @handle: device handle
3108 *
3109 * Return nothing.
3110 */
3111static void
3112_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3113{
3114 Mpi2SepReply_t mpi_reply;
3115 Mpi2SepRequest_t mpi_request;
3116 struct scsi_target *starget;
3117 struct MPT2SAS_TARGET *sas_target_priv_data;
3118 Mpi2EventNotificationReply_t *event_reply;
3119 Mpi2EventDataSasDeviceStatusChange_t *event_data;
3120 struct _sas_device *sas_device;
3121 ssize_t sz;
3122 unsigned long flags;
3123
3124 /* only handle non-raid devices */
3125 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3126 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3127 if (!sas_device) {
3128 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3129 return;
3130 }
3131 starget = sas_device->starget;
3132 sas_target_priv_data = starget->hostdata;
3133
3134 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
3135 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
3136 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3137 return;
3138 }
3139 starget_printk(KERN_WARNING, starget, "predicted fault\n");
3140 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3141
3142 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
3143 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
3144 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
3145 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
3146 mpi_request.SlotStatus =
3147 MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
3148 mpi_request.DevHandle = cpu_to_le16(handle);
3149 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
3150 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
3151 &mpi_request)) != 0) {
3152 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3153 ioc->name, __FILE__, __LINE__, __func__);
3154 return;
3155 }
3156
3157 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
3158 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3159 "enclosure_processor: ioc_status (0x%04x), "
3160 "loginfo(0x%08x)\n", ioc->name,
3161 le16_to_cpu(mpi_reply.IOCStatus),
3162 le32_to_cpu(mpi_reply.IOCLogInfo)));
3163 return;
3164 }
3165 }
3166
3167 /* insert into event log */
3168 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
3169 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
3170 event_reply = kzalloc(sz, GFP_KERNEL);
3171 if (!event_reply) {
3172 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3173 ioc->name, __FILE__, __LINE__, __func__);
3174 return;
3175 }
3176
3177 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
3178 event_reply->Event =
3179 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
3180 event_reply->MsgLength = sz/4;
3181 event_reply->EventDataLength =
3182 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
3183 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
3184 event_reply->EventData;
3185 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
3186 event_data->ASC = 0x5D;
3187 event_data->DevHandle = cpu_to_le16(handle);
3188 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
3189 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
3190 kfree(event_reply);
3191}
3192
3193/**
Eric Moored5d135b2009-05-18 13:02:08 -06003194 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06003195 * @ioc: per adapter object
3196 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303197 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06003198 * @reply: reply message frame(lower 32bit addr)
3199 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303200 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06003201 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303202 * Return 1 meaning mf should be freed from _base_interrupt
3203 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06003204 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303205static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303206_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06003207{
3208 Mpi2SCSIIORequest_t *mpi_request;
3209 Mpi2SCSIIOReply_t *mpi_reply;
3210 struct scsi_cmnd *scmd;
3211 u16 ioc_status;
3212 u32 xfer_cnt;
3213 u8 scsi_state;
3214 u8 scsi_status;
3215 u32 log_info;
3216 struct MPT2SAS_DEVICE *sas_device_priv_data;
3217 u32 response_code;
3218
3219 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303220 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003221 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303222 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003223
3224 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3225
3226 if (mpi_reply == NULL) {
3227 scmd->result = DID_OK << 16;
3228 goto out;
3229 }
3230
3231 sas_device_priv_data = scmd->device->hostdata;
3232 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
3233 sas_device_priv_data->sas_target->deleted) {
3234 scmd->result = DID_NO_CONNECT << 16;
3235 goto out;
3236 }
3237
3238 /* turning off TLR */
3239 if (!sas_device_priv_data->tlr_snoop_check) {
3240 sas_device_priv_data->tlr_snoop_check++;
3241 if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) {
3242 response_code = (le32_to_cpu(mpi_reply->ResponseInfo)
3243 >> 24);
3244 if (response_code ==
3245 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
3246 sas_device_priv_data->flags &=
3247 ~MPT_DEVICE_TLR_ON;
3248 }
3249 }
3250
3251 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
3252 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
3253 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
3254 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
3255 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3256 else
3257 log_info = 0;
3258 ioc_status &= MPI2_IOCSTATUS_MASK;
3259 scsi_state = mpi_reply->SCSIState;
3260 scsi_status = mpi_reply->SCSIStatus;
3261
3262 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
3263 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
3264 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
3265 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
3266 ioc_status = MPI2_IOCSTATUS_SUCCESS;
3267 }
3268
3269 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3270 struct sense_info data;
3271 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
3272 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06003273 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06003274 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06003275 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06003276 _scsih_normalize_sense(scmd->sense_buffer, &data);
3277 /* failure prediction threshold exceeded */
3278 if (data.asc == 0x5D)
3279 _scsih_smart_predicted_fault(ioc,
3280 le16_to_cpu(mpi_reply->DevHandle));
3281 }
3282
3283 switch (ioc_status) {
3284 case MPI2_IOCSTATUS_BUSY:
3285 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3286 scmd->result = SAM_STAT_BUSY;
3287 break;
3288
3289 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3290 scmd->result = DID_NO_CONNECT << 16;
3291 break;
3292
3293 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3294 if (sas_device_priv_data->block) {
3295 scmd->result = (DID_BUS_BUSY << 16);
3296 break;
3297 }
3298
3299 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3300 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3301 scmd->result = DID_RESET << 16;
3302 break;
3303
3304 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3305 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3306 scmd->result = DID_SOFT_ERROR << 16;
3307 else
3308 scmd->result = (DID_OK << 16) | scsi_status;
3309 break;
3310
3311 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3312 scmd->result = (DID_OK << 16) | scsi_status;
3313
3314 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3315 break;
3316
3317 if (xfer_cnt < scmd->underflow) {
3318 if (scsi_status == SAM_STAT_BUSY)
3319 scmd->result = SAM_STAT_BUSY;
3320 else
3321 scmd->result = DID_SOFT_ERROR << 16;
3322 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3323 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3324 scmd->result = DID_SOFT_ERROR << 16;
3325 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3326 scmd->result = DID_RESET << 16;
3327 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3328 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3329 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3330 scmd->result = (DRIVER_SENSE << 24) |
3331 SAM_STAT_CHECK_CONDITION;
3332 scmd->sense_buffer[0] = 0x70;
3333 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3334 scmd->sense_buffer[12] = 0x20;
3335 scmd->sense_buffer[13] = 0;
3336 }
3337 break;
3338
3339 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3340 scsi_set_resid(scmd, 0);
3341 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3342 case MPI2_IOCSTATUS_SUCCESS:
3343 scmd->result = (DID_OK << 16) | scsi_status;
3344 if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3345 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3346 scmd->result = DID_SOFT_ERROR << 16;
3347 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3348 scmd->result = DID_RESET << 16;
3349 break;
3350
Eric Moore3c621b32009-05-18 12:59:41 -06003351 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3352 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3353 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3354 _scsih_eedp_error_handling(scmd, ioc_status);
3355 break;
Eric Moore635374e2009-03-09 01:21:12 -06003356 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3357 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3358 case MPI2_IOCSTATUS_INVALID_SGL:
3359 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3360 case MPI2_IOCSTATUS_INVALID_FIELD:
3361 case MPI2_IOCSTATUS_INVALID_STATE:
3362 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3363 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3364 default:
3365 scmd->result = DID_SOFT_ERROR << 16;
3366 break;
3367
3368 }
3369
3370#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3371 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3372 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3373#endif
3374
3375 out:
3376 scsi_dma_unmap(scmd);
3377 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303378 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003379}
3380
3381/**
Eric Moore635374e2009-03-09 01:21:12 -06003382 * _scsih_sas_host_refresh - refreshing sas host object contents
3383 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06003384 * Context: user
3385 *
3386 * During port enable, fw will send topology events for every device. Its
3387 * possible that the handles may change from the previous setting, so this
3388 * code keeping handles updating if changed.
3389 *
3390 * Return nothing.
3391 */
3392static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303393_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06003394{
3395 u16 sz;
3396 u16 ioc_status;
3397 int i;
3398 Mpi2ConfigReply_t mpi_reply;
3399 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303400 u16 attached_handle;
Eric Moore635374e2009-03-09 01:21:12 -06003401
3402 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3403 "updating handles for sas_host(0x%016llx)\n",
3404 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3405
3406 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3407 * sizeof(Mpi2SasIOUnit0PhyData_t));
3408 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3409 if (!sas_iounit_pg0) {
3410 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3411 ioc->name, __FILE__, __LINE__, __func__);
3412 return;
3413 }
Eric Moore635374e2009-03-09 01:21:12 -06003414
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303415 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3416 sas_iounit_pg0, sz)) != 0)
3417 goto out;
3418 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
3419 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3420 goto out;
3421 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3422 if (i == 0)
3423 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3424 PhyData[0].ControllerDevHandle);
3425 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
3426 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
3427 AttachedDevHandle);
3428 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
3429 attached_handle, i, sas_iounit_pg0->PhyData[i].
3430 NegotiatedLinkRate >> 4);
3431 }
Eric Moore635374e2009-03-09 01:21:12 -06003432 out:
3433 kfree(sas_iounit_pg0);
3434}
3435
3436/**
3437 * _scsih_sas_host_add - create sas host object
3438 * @ioc: per adapter object
3439 *
3440 * Creating host side data object, stored in ioc->sas_hba
3441 *
3442 * Return nothing.
3443 */
3444static void
3445_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3446{
3447 int i;
3448 Mpi2ConfigReply_t mpi_reply;
3449 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3450 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3451 Mpi2SasPhyPage0_t phy_pg0;
3452 Mpi2SasDevicePage0_t sas_device_pg0;
3453 Mpi2SasEnclosurePage0_t enclosure_pg0;
3454 u16 ioc_status;
3455 u16 sz;
3456 u16 device_missing_delay;
3457
3458 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3459 if (!ioc->sas_hba.num_phys) {
3460 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3461 ioc->name, __FILE__, __LINE__, __func__);
3462 return;
3463 }
3464
3465 /* sas_iounit page 0 */
3466 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3467 sizeof(Mpi2SasIOUnit0PhyData_t));
3468 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3469 if (!sas_iounit_pg0) {
3470 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3471 ioc->name, __FILE__, __LINE__, __func__);
3472 return;
3473 }
3474 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3475 sas_iounit_pg0, sz))) {
3476 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3477 ioc->name, __FILE__, __LINE__, __func__);
3478 goto out;
3479 }
3480 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3481 MPI2_IOCSTATUS_MASK;
3482 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3483 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3484 ioc->name, __FILE__, __LINE__, __func__);
3485 goto out;
3486 }
3487
3488 /* sas_iounit page 1 */
3489 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3490 sizeof(Mpi2SasIOUnit1PhyData_t));
3491 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3492 if (!sas_iounit_pg1) {
3493 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3494 ioc->name, __FILE__, __LINE__, __func__);
3495 goto out;
3496 }
3497 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3498 sas_iounit_pg1, sz))) {
3499 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3500 ioc->name, __FILE__, __LINE__, __func__);
3501 goto out;
3502 }
3503 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3504 MPI2_IOCSTATUS_MASK;
3505 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3506 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3507 ioc->name, __FILE__, __LINE__, __func__);
3508 goto out;
3509 }
3510
3511 ioc->io_missing_delay =
3512 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3513 device_missing_delay =
3514 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3515 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3516 ioc->device_missing_delay = (device_missing_delay &
3517 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3518 else
3519 ioc->device_missing_delay = device_missing_delay &
3520 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3521
3522 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3523 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3524 sizeof(struct _sas_phy), GFP_KERNEL);
3525 if (!ioc->sas_hba.phy) {
3526 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3527 ioc->name, __FILE__, __LINE__, __func__);
3528 goto out;
3529 }
3530 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3531 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3532 i))) {
3533 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3534 ioc->name, __FILE__, __LINE__, __func__);
3535 goto out;
3536 }
3537 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3538 MPI2_IOCSTATUS_MASK;
3539 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3540 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3541 ioc->name, __FILE__, __LINE__, __func__);
3542 goto out;
3543 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303544
3545 if (i == 0)
3546 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3547 PhyData[0].ControllerDevHandle);
3548 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06003549 ioc->sas_hba.phy[i].phy_id = i;
3550 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3551 phy_pg0, ioc->sas_hba.parent_dev);
3552 }
3553 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303554 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06003555 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3556 ioc->name, __FILE__, __LINE__, __func__);
3557 goto out;
3558 }
Eric Moore635374e2009-03-09 01:21:12 -06003559 ioc->sas_hba.enclosure_handle =
3560 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3561 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3562 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3563 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3564 (unsigned long long) ioc->sas_hba.sas_address,
3565 ioc->sas_hba.num_phys) ;
3566
3567 if (ioc->sas_hba.enclosure_handle) {
3568 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3569 &enclosure_pg0,
3570 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3571 ioc->sas_hba.enclosure_handle))) {
3572 ioc->sas_hba.enclosure_logical_id =
3573 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3574 }
3575 }
3576
3577 out:
3578 kfree(sas_iounit_pg1);
3579 kfree(sas_iounit_pg0);
3580}
3581
3582/**
3583 * _scsih_expander_add - creating expander object
3584 * @ioc: per adapter object
3585 * @handle: expander handle
3586 *
3587 * Creating expander object, stored in ioc->sas_expander_list.
3588 *
3589 * Return 0 for success, else error.
3590 */
3591static int
3592_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3593{
3594 struct _sas_node *sas_expander;
3595 Mpi2ConfigReply_t mpi_reply;
3596 Mpi2ExpanderPage0_t expander_pg0;
3597 Mpi2ExpanderPage1_t expander_pg1;
3598 Mpi2SasEnclosurePage0_t enclosure_pg0;
3599 u32 ioc_status;
3600 u16 parent_handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303601 __le64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003602 int i;
3603 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303604 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003605 int rc = 0;
3606
3607 if (!handle)
3608 return -1;
3609
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303610 if (ioc->shost_recovery)
3611 return -1;
3612
Eric Moore635374e2009-03-09 01:21:12 -06003613 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3614 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3615 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3616 ioc->name, __FILE__, __LINE__, __func__);
3617 return -1;
3618 }
3619
3620 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3621 MPI2_IOCSTATUS_MASK;
3622 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3623 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3624 ioc->name, __FILE__, __LINE__, __func__);
3625 return -1;
3626 }
3627
3628 /* handle out of order topology events */
3629 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303630 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
3631 != 0) {
3632 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3633 ioc->name, __FILE__, __LINE__, __func__);
3634 return -1;
3635 }
3636 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06003637 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303638 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3639 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003640 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3641 if (!sas_expander) {
3642 rc = _scsih_expander_add(ioc, parent_handle);
3643 if (rc != 0)
3644 return rc;
3645 }
3646 }
3647
Eric Moore635374e2009-03-09 01:21:12 -06003648 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303649 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06003650 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3651 sas_address);
3652 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3653
3654 if (sas_expander)
3655 return 0;
3656
3657 sas_expander = kzalloc(sizeof(struct _sas_node),
3658 GFP_KERNEL);
3659 if (!sas_expander) {
3660 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3661 ioc->name, __FILE__, __LINE__, __func__);
3662 return -1;
3663 }
3664
3665 sas_expander->handle = handle;
3666 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303667 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06003668 sas_expander->sas_address = sas_address;
3669
3670 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3671 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303672 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06003673 sas_expander->sas_address, sas_expander->num_phys);
3674
3675 if (!sas_expander->num_phys)
3676 goto out_fail;
3677 sas_expander->phy = kcalloc(sas_expander->num_phys,
3678 sizeof(struct _sas_phy), GFP_KERNEL);
3679 if (!sas_expander->phy) {
3680 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3681 ioc->name, __FILE__, __LINE__, __func__);
3682 rc = -1;
3683 goto out_fail;
3684 }
3685
3686 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3687 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303688 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003689 if (!mpt2sas_port) {
3690 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3691 ioc->name, __FILE__, __LINE__, __func__);
3692 rc = -1;
3693 goto out_fail;
3694 }
3695 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3696
3697 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3698 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3699 &expander_pg1, i, handle))) {
3700 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3701 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303702 rc = -1;
3703 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003704 }
3705 sas_expander->phy[i].handle = handle;
3706 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303707
3708 if ((mpt2sas_transport_add_expander_phy(ioc,
3709 &sas_expander->phy[i], expander_pg1,
3710 sas_expander->parent_dev))) {
3711 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3712 ioc->name, __FILE__, __LINE__, __func__);
3713 rc = -1;
3714 goto out_fail;
3715 }
Eric Moore635374e2009-03-09 01:21:12 -06003716 }
3717
3718 if (sas_expander->enclosure_handle) {
3719 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3720 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3721 sas_expander->enclosure_handle))) {
3722 sas_expander->enclosure_logical_id =
3723 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3724 }
3725 }
3726
3727 _scsih_expander_node_add(ioc, sas_expander);
3728 return 0;
3729
3730 out_fail:
3731
Kashyap, Desai20f58952009-08-07 19:34:26 +05303732 if (mpt2sas_port)
3733 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303734 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003735 kfree(sas_expander);
3736 return rc;
3737}
3738
3739/**
3740 * _scsih_expander_remove - removing expander object
3741 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303742 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06003743 *
3744 * Return nothing.
3745 */
3746static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303747_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06003748{
3749 struct _sas_node *sas_expander;
3750 unsigned long flags;
3751
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303752 if (ioc->shost_recovery)
3753 return;
3754
Eric Moore635374e2009-03-09 01:21:12 -06003755 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303756 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3757 sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06003758 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3759 _scsih_expander_node_remove(ioc, sas_expander);
3760}
3761
3762/**
3763 * _scsih_add_device - creating sas device object
3764 * @ioc: per adapter object
3765 * @handle: sas device handle
3766 * @phy_num: phy number end device attached to
3767 * @is_pd: is this hidden raid component
3768 *
3769 * Creating end device object, stored in ioc->sas_device_list.
3770 *
3771 * Returns 0 for success, non-zero for failure.
3772 */
3773static int
3774_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
3775{
3776 Mpi2ConfigReply_t mpi_reply;
3777 Mpi2SasDevicePage0_t sas_device_pg0;
3778 Mpi2SasEnclosurePage0_t enclosure_pg0;
3779 struct _sas_device *sas_device;
3780 u32 ioc_status;
3781 __le64 sas_address;
3782 u32 device_info;
3783 unsigned long flags;
3784
3785 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
3786 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
3787 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3788 ioc->name, __FILE__, __LINE__, __func__);
3789 return -1;
3790 }
3791
3792 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3793 MPI2_IOCSTATUS_MASK;
3794 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3795 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3796 ioc->name, __FILE__, __LINE__, __func__);
3797 return -1;
3798 }
3799
3800 /* check if device is present */
3801 if (!(le16_to_cpu(sas_device_pg0.Flags) &
3802 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
3803 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3804 ioc->name, __FILE__, __LINE__, __func__);
3805 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
3806 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
3807 return -1;
3808 }
3809
3810 /* check if there were any issus with discovery */
3811 if (sas_device_pg0.AccessStatus ==
3812 MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
3813 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3814 ioc->name, __FILE__, __LINE__, __func__);
3815 printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
3816 ioc->name, sas_device_pg0.AccessStatus);
3817 return -1;
3818 }
3819
3820 /* check if this is end device */
3821 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
3822 if (!(_scsih_is_end_device(device_info))) {
3823 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3824 ioc->name, __FILE__, __LINE__, __func__);
3825 return -1;
3826 }
3827
3828 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3829
3830 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3831 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
3832 sas_address);
3833 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3834
3835 if (sas_device) {
3836 _scsih_ublock_io_device(ioc, handle);
3837 return 0;
3838 }
3839
3840 sas_device = kzalloc(sizeof(struct _sas_device),
3841 GFP_KERNEL);
3842 if (!sas_device) {
3843 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3844 ioc->name, __FILE__, __LINE__, __func__);
3845 return -1;
3846 }
3847
3848 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303849 if (_scsih_get_sas_address(ioc, le16_to_cpu
3850 (sas_device_pg0.ParentDevHandle),
3851 &sas_device->sas_address_parent) != 0)
3852 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3853 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06003854 sas_device->enclosure_handle =
3855 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3856 sas_device->slot =
3857 le16_to_cpu(sas_device_pg0.Slot);
3858 sas_device->device_info = device_info;
3859 sas_device->sas_address = sas_address;
3860 sas_device->hidden_raid_component = is_pd;
3861
3862 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05303863 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
3864 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3865 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06003866 sas_device->enclosure_logical_id =
3867 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06003868
3869 /* get device name */
3870 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
3871
3872 if (ioc->wait_for_port_enable_to_complete)
3873 _scsih_sas_device_init_add(ioc, sas_device);
3874 else
3875 _scsih_sas_device_add(ioc, sas_device);
3876
3877 return 0;
3878}
3879
3880/**
3881 * _scsih_remove_device - removing sas device object
3882 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303883 * @sas_device: the sas_device object
Eric Moore635374e2009-03-09 01:21:12 -06003884 *
3885 * Return nothing.
3886 */
3887static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303888_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
3889 *sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06003890{
3891 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06003892 Mpi2SasIoUnitControlReply_t mpi_reply;
3893 Mpi2SasIoUnitControlRequest_t mpi_request;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303894 u16 device_handle, handle;
Eric Moore635374e2009-03-09 01:21:12 -06003895
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303896 if (!sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06003897 return;
Eric Moore635374e2009-03-09 01:21:12 -06003898
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303899 handle = sas_device->handle;
3900 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
3901 " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
3902 (unsigned long long) sas_device->sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06003903
3904 if (sas_device->starget && sas_device->starget->hostdata) {
3905 sas_target_priv_data = sas_device->starget->hostdata;
3906 sas_target_priv_data->deleted = 1;
3907 }
Eric Moore635374e2009-03-09 01:21:12 -06003908
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303909 if (ioc->remove_host || ioc->shost_recovery || !handle)
Eric Moore635374e2009-03-09 01:21:12 -06003910 goto out;
3911
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303912 if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
3913 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303914 "target_reset handle(0x%04x)\n", ioc->name,
3915 handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303916 goto skip_tr;
3917 }
3918
Eric Moore635374e2009-03-09 01:21:12 -06003919 /* Target Reset to flush out all the outstanding IO */
3920 device_handle = (sas_device->hidden_raid_component) ?
3921 sas_device->volume_handle : handle;
3922 if (device_handle) {
3923 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
3924 "handle(0x%04x)\n", ioc->name, device_handle));
3925 mutex_lock(&ioc->tm_cmds.mutex);
3926 mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
3927 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
3928 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
3929 mutex_unlock(&ioc->tm_cmds.mutex);
3930 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
3931 "done: handle(0x%04x)\n", ioc->name, device_handle));
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303932 if (ioc->shost_recovery)
3933 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003934 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303935 skip_tr:
3936
3937 if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) {
3938 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
3939 "sas_cntrl handle(0x%04x)\n", ioc->name, handle));
3940 goto out;
3941 }
Eric Moore635374e2009-03-09 01:21:12 -06003942
3943 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
3944 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
3945 "(0x%04x)\n", ioc->name, handle));
3946 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
3947 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
3948 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
3949 mpi_request.DevHandle = handle;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303950 mpi_request.VF_ID = 0; /* TODO */
3951 mpi_request.VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003952 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
3953 &mpi_request)) != 0) {
3954 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3955 ioc->name, __FILE__, __LINE__, __func__);
3956 }
3957
3958 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
3959 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
3960 le16_to_cpu(mpi_reply.IOCStatus),
3961 le32_to_cpu(mpi_reply.IOCLogInfo)));
3962
3963 out:
Kashyap, Desai34a03be2009-08-20 13:23:19 +05303964
3965 _scsih_ublock_io_device(ioc, handle);
3966
Eric Moore635374e2009-03-09 01:21:12 -06003967 mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303968 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003969
3970 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303971 "(0x%016llx)\n", ioc->name, handle,
Eric Moore635374e2009-03-09 01:21:12 -06003972 (unsigned long long) sas_device->sas_address);
3973 _scsih_sas_device_remove(ioc, sas_device);
3974
3975 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
3976 "(0x%04x)\n", ioc->name, __func__, handle));
3977}
3978
3979#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3980/**
3981 * _scsih_sas_topology_change_event_debug - debug for topology event
3982 * @ioc: per adapter object
3983 * @event_data: event data payload
3984 * Context: user.
3985 */
3986static void
3987_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
3988 Mpi2EventDataSasTopologyChangeList_t *event_data)
3989{
3990 int i;
3991 u16 handle;
3992 u16 reason_code;
3993 u8 phy_number;
3994 char *status_str = NULL;
3995 char link_rate[25];
3996
3997 switch (event_data->ExpStatus) {
3998 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
3999 status_str = "add";
4000 break;
4001 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
4002 status_str = "remove";
4003 break;
4004 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
4005 status_str = "responding";
4006 break;
4007 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
4008 status_str = "remove delay";
4009 break;
4010 default:
4011 status_str = "unknown status";
4012 break;
4013 }
4014 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
4015 ioc->name, status_str);
4016 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
4017 "start_phy(%02d), count(%d)\n",
4018 le16_to_cpu(event_data->ExpanderDevHandle),
4019 le16_to_cpu(event_data->EnclosureHandle),
4020 event_data->StartPhyNum, event_data->NumEntries);
4021 for (i = 0; i < event_data->NumEntries; i++) {
4022 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4023 if (!handle)
4024 continue;
4025 phy_number = event_data->StartPhyNum + i;
4026 reason_code = event_data->PHY[i].PhyStatus &
4027 MPI2_EVENT_SAS_TOPO_RC_MASK;
4028 switch (reason_code) {
4029 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
4030 snprintf(link_rate, 25, ": add, link(0x%02x)",
4031 (event_data->PHY[i].LinkRate >> 4));
4032 status_str = link_rate;
4033 break;
4034 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
4035 status_str = ": remove";
4036 break;
4037 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
4038 status_str = ": remove_delay";
4039 break;
4040 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
4041 snprintf(link_rate, 25, ": link(0x%02x)",
4042 (event_data->PHY[i].LinkRate >> 4));
4043 status_str = link_rate;
4044 break;
4045 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
4046 status_str = ": responding";
4047 break;
4048 default:
4049 status_str = ": unknown";
4050 break;
4051 }
4052 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n",
4053 phy_number, handle, status_str);
4054 }
4055}
4056#endif
4057
4058/**
4059 * _scsih_sas_topology_change_event - handle topology changes
4060 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304061 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004062 * Context: user.
4063 *
4064 */
4065static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304066_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06004067 struct fw_event_work *fw_event)
4068{
4069 int i;
4070 u16 parent_handle, handle;
4071 u16 reason_code;
4072 u8 phy_number;
4073 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304074 struct _sas_device *sas_device;
4075 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004076 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304077 u8 link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304078 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004079
4080#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4081 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4082 _scsih_sas_topology_change_event_debug(ioc, event_data);
4083#endif
4084
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304085 if (ioc->shost_recovery)
4086 return;
4087
Eric Moore635374e2009-03-09 01:21:12 -06004088 if (!ioc->sas_hba.num_phys)
4089 _scsih_sas_host_add(ioc);
4090 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304091 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06004092
4093 if (fw_event->ignore) {
4094 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
4095 "event\n", ioc->name));
4096 return;
4097 }
4098
4099 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
4100
4101 /* handle expander add */
4102 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
4103 if (_scsih_expander_add(ioc, parent_handle) != 0)
4104 return;
4105
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304106 spin_lock_irqsave(&ioc->sas_node_lock, flags);
4107 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
4108 parent_handle);
4109 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4110 if (sas_expander)
4111 sas_address = sas_expander->sas_address;
4112 else if (parent_handle < ioc->sas_hba.num_phys)
4113 sas_address = ioc->sas_hba.sas_address;
4114 else
4115 return;
4116
Eric Moore635374e2009-03-09 01:21:12 -06004117 /* handle siblings events */
4118 for (i = 0; i < event_data->NumEntries; i++) {
4119 if (fw_event->ignore) {
4120 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
4121 "expander event\n", ioc->name));
4122 return;
4123 }
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304124 if (ioc->shost_recovery)
4125 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05304126 phy_number = event_data->StartPhyNum + i;
4127 reason_code = event_data->PHY[i].PhyStatus &
4128 MPI2_EVENT_SAS_TOPO_RC_MASK;
4129 if ((event_data->PHY[i].PhyStatus &
4130 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
4131 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06004132 continue;
4133 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4134 if (!handle)
4135 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304136 link_rate = event_data->PHY[i].LinkRate >> 4;
Eric Moore635374e2009-03-09 01:21:12 -06004137 switch (reason_code) {
4138 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
4139 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304140
4141 mpt2sas_transport_update_links(ioc, sas_address,
4142 handle, phy_number, link_rate);
4143
4144 if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
4145 break;
Eric Moore635374e2009-03-09 01:21:12 -06004146 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
Eric Moore635374e2009-03-09 01:21:12 -06004147 _scsih_add_device(ioc, handle, phy_number, 0);
4148 }
4149 break;
4150 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304151
4152 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4153 sas_device = _scsih_sas_device_find_by_handle(ioc,
4154 handle);
4155 if (!sas_device) {
4156 spin_unlock_irqrestore(&ioc->sas_device_lock,
4157 flags);
4158 break;
4159 }
4160 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4161 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004162 break;
4163 }
4164 }
4165
4166 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304167 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
4168 sas_expander)
4169 _scsih_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06004170
4171}
4172
4173#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4174/**
4175 * _scsih_sas_device_status_change_event_debug - debug for device event
4176 * @event_data: event data payload
4177 * Context: user.
4178 *
4179 * Return nothing.
4180 */
4181static void
4182_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4183 Mpi2EventDataSasDeviceStatusChange_t *event_data)
4184{
4185 char *reason_str = NULL;
4186
4187 switch (event_data->ReasonCode) {
4188 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
4189 reason_str = "smart data";
4190 break;
4191 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
4192 reason_str = "unsupported device discovered";
4193 break;
4194 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
4195 reason_str = "internal device reset";
4196 break;
4197 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
4198 reason_str = "internal task abort";
4199 break;
4200 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
4201 reason_str = "internal task abort set";
4202 break;
4203 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
4204 reason_str = "internal clear task set";
4205 break;
4206 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
4207 reason_str = "internal query task";
4208 break;
4209 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
4210 reason_str = "sata init failure";
4211 break;
4212 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
4213 reason_str = "internal device reset complete";
4214 break;
4215 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
4216 reason_str = "internal task abort complete";
4217 break;
4218 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
4219 reason_str = "internal async notification";
4220 break;
4221 default:
4222 reason_str = "unknown reason";
4223 break;
4224 }
4225 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
4226 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
4227 reason_str, le16_to_cpu(event_data->DevHandle),
4228 (unsigned long long)le64_to_cpu(event_data->SASAddress));
4229 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
4230 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
4231 event_data->ASC, event_data->ASCQ);
4232 printk(KERN_INFO "\n");
4233}
4234#endif
4235
4236/**
4237 * _scsih_sas_device_status_change_event - handle device status change
4238 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304239 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004240 * Context: user.
4241 *
4242 * Return nothing.
4243 */
4244static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304245_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
4246 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004247{
4248#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4249 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304250 _scsih_sas_device_status_change_event_debug(ioc,
4251 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004252#endif
4253}
4254
4255#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4256/**
4257 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
4258 * @ioc: per adapter object
4259 * @event_data: event data payload
4260 * Context: user.
4261 *
4262 * Return nothing.
4263 */
4264static void
4265_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4266 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
4267{
4268 char *reason_str = NULL;
4269
4270 switch (event_data->ReasonCode) {
4271 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
4272 reason_str = "enclosure add";
4273 break;
4274 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
4275 reason_str = "enclosure remove";
4276 break;
4277 default:
4278 reason_str = "unknown reason";
4279 break;
4280 }
4281
4282 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
4283 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
4284 " number slots(%d)\n", ioc->name, reason_str,
4285 le16_to_cpu(event_data->EnclosureHandle),
4286 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
4287 le16_to_cpu(event_data->StartSlot));
4288}
4289#endif
4290
4291/**
4292 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
4293 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304294 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004295 * Context: user.
4296 *
4297 * Return nothing.
4298 */
4299static void
4300_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304301 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004302{
4303#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4304 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4305 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304306 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004307#endif
4308}
4309
4310/**
4311 * _scsih_sas_broadcast_primative_event - handle broadcast events
4312 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304313 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004314 * Context: user.
4315 *
4316 * Return nothing.
4317 */
4318static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304319_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4320 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004321{
4322 struct scsi_cmnd *scmd;
4323 u16 smid, handle;
4324 u32 lun;
4325 struct MPT2SAS_DEVICE *sas_device_priv_data;
4326 u32 termination_count;
4327 u32 query_count;
4328 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304329#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4330 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4331#endif
Eric Moore635374e2009-03-09 01:21:12 -06004332 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4333 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4334 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004335 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4336 __func__));
4337
4338 mutex_lock(&ioc->tm_cmds.mutex);
4339 termination_count = 0;
4340 query_count = 0;
4341 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304342 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06004343 scmd = _scsih_scsi_lookup_get(ioc, smid);
4344 if (!scmd)
4345 continue;
4346 sas_device_priv_data = scmd->device->hostdata;
4347 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4348 continue;
4349 /* skip hidden raid components */
4350 if (sas_device_priv_data->sas_target->flags &
4351 MPT_TARGET_FLAGS_RAID_COMPONENT)
4352 continue;
4353 /* skip volumes */
4354 if (sas_device_priv_data->sas_target->flags &
4355 MPT_TARGET_FLAGS_VOLUME)
4356 continue;
4357
4358 handle = sas_device_priv_data->sas_target->handle;
4359 lun = sas_device_priv_data->lun;
4360 query_count++;
4361
4362 mpt2sas_scsih_issue_tm(ioc, handle, lun,
4363 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
Eric Moore8901cbb2009-04-21 15:41:32 -06004364 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004365
4366 if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) &&
4367 (mpi_reply->ResponseCode ==
4368 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4369 mpi_reply->ResponseCode ==
4370 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4371 continue;
4372
4373 mpt2sas_scsih_issue_tm(ioc, handle, lun,
Eric Moore8901cbb2009-04-21 15:41:32 -06004374 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30);
4375 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004376 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4377 }
Eric Moore635374e2009-03-09 01:21:12 -06004378 ioc->broadcast_aen_busy = 0;
4379 mutex_unlock(&ioc->tm_cmds.mutex);
4380
4381 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4382 "%s - exit, query_count = %d termination_count = %d\n",
4383 ioc->name, __func__, query_count, termination_count));
4384}
4385
4386/**
4387 * _scsih_sas_discovery_event - handle discovery events
4388 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304389 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004390 * Context: user.
4391 *
4392 * Return nothing.
4393 */
4394static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304395_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4396 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004397{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304398 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4399
Eric Moore635374e2009-03-09 01:21:12 -06004400#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4401 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4402 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4403 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4404 "start" : "stop");
4405 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304406 printk("discovery_status(0x%08x)",
4407 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06004408 printk("\n");
4409 }
4410#endif
4411
4412 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4413 !ioc->sas_hba.num_phys)
4414 _scsih_sas_host_add(ioc);
4415}
4416
4417/**
4418 * _scsih_reprobe_lun - reprobing lun
4419 * @sdev: scsi device struct
4420 * @no_uld_attach: sdev->no_uld_attach flag setting
4421 *
4422 **/
4423static void
4424_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4425{
4426 int rc;
4427
4428 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4429 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4430 sdev->no_uld_attach ? "hidding" : "exposing");
4431 rc = scsi_device_reprobe(sdev);
4432}
4433
4434/**
4435 * _scsih_reprobe_target - reprobing target
4436 * @starget: scsi target struct
4437 * @no_uld_attach: sdev->no_uld_attach flag setting
4438 *
4439 * Note: no_uld_attach flag determines whether the disk device is attached
4440 * to block layer. A value of `1` means to not attach.
4441 **/
4442static void
4443_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4444{
4445 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4446
4447 if (no_uld_attach)
4448 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4449 else
4450 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4451
4452 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4453 _scsih_reprobe_lun);
4454}
4455/**
4456 * _scsih_sas_volume_add - add new volume
4457 * @ioc: per adapter object
4458 * @element: IR config element data
4459 * Context: user.
4460 *
4461 * Return nothing.
4462 */
4463static void
4464_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4465 Mpi2EventIrConfigElement_t *element)
4466{
4467 struct _raid_device *raid_device;
4468 unsigned long flags;
4469 u64 wwid;
4470 u16 handle = le16_to_cpu(element->VolDevHandle);
4471 int rc;
4472
Eric Moore635374e2009-03-09 01:21:12 -06004473 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4474 if (!wwid) {
4475 printk(MPT2SAS_ERR_FMT
4476 "failure at %s:%d/%s()!\n", ioc->name,
4477 __FILE__, __LINE__, __func__);
4478 return;
4479 }
4480
4481 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4482 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4483 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4484
4485 if (raid_device)
4486 return;
4487
4488 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4489 if (!raid_device) {
4490 printk(MPT2SAS_ERR_FMT
4491 "failure at %s:%d/%s()!\n", ioc->name,
4492 __FILE__, __LINE__, __func__);
4493 return;
4494 }
4495
4496 raid_device->id = ioc->sas_id++;
4497 raid_device->channel = RAID_CHANNEL;
4498 raid_device->handle = handle;
4499 raid_device->wwid = wwid;
4500 _scsih_raid_device_add(ioc, raid_device);
4501 if (!ioc->wait_for_port_enable_to_complete) {
4502 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4503 raid_device->id, 0);
4504 if (rc)
4505 _scsih_raid_device_remove(ioc, raid_device);
4506 } else
4507 _scsih_determine_boot_device(ioc, raid_device, 1);
4508}
4509
4510/**
4511 * _scsih_sas_volume_delete - delete volume
4512 * @ioc: per adapter object
4513 * @element: IR config element data
4514 * Context: user.
4515 *
4516 * Return nothing.
4517 */
4518static void
4519_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4520 Mpi2EventIrConfigElement_t *element)
4521{
4522 struct _raid_device *raid_device;
4523 u16 handle = le16_to_cpu(element->VolDevHandle);
4524 unsigned long flags;
4525 struct MPT2SAS_TARGET *sas_target_priv_data;
4526
Eric Moore635374e2009-03-09 01:21:12 -06004527 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4528 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4529 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4530 if (!raid_device)
4531 return;
4532 if (raid_device->starget) {
4533 sas_target_priv_data = raid_device->starget->hostdata;
4534 sas_target_priv_data->deleted = 1;
4535 scsi_remove_target(&raid_device->starget->dev);
4536 }
4537 _scsih_raid_device_remove(ioc, raid_device);
4538}
4539
4540/**
4541 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4542 * @ioc: per adapter object
4543 * @element: IR config element data
4544 * Context: user.
4545 *
4546 * Return nothing.
4547 */
4548static void
4549_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4550 Mpi2EventIrConfigElement_t *element)
4551{
4552 struct _sas_device *sas_device;
4553 unsigned long flags;
4554 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4555
4556 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4557 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4558 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4559 if (!sas_device)
4560 return;
4561
4562 /* exposing raid component */
4563 sas_device->volume_handle = 0;
4564 sas_device->volume_wwid = 0;
4565 sas_device->hidden_raid_component = 0;
4566 _scsih_reprobe_target(sas_device->starget, 0);
4567}
4568
4569/**
4570 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4571 * @ioc: per adapter object
4572 * @element: IR config element data
4573 * Context: user.
4574 *
4575 * Return nothing.
4576 */
4577static void
4578_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4579 Mpi2EventIrConfigElement_t *element)
4580{
4581 struct _sas_device *sas_device;
4582 unsigned long flags;
4583 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4584
4585 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4586 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4587 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4588 if (!sas_device)
4589 return;
4590
4591 /* hiding raid component */
4592 mpt2sas_config_get_volume_handle(ioc, handle,
4593 &sas_device->volume_handle);
4594 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4595 &sas_device->volume_wwid);
4596 sas_device->hidden_raid_component = 1;
4597 _scsih_reprobe_target(sas_device->starget, 1);
4598}
4599
4600/**
4601 * _scsih_sas_pd_delete - delete pd component
4602 * @ioc: per adapter object
4603 * @element: IR config element data
4604 * Context: user.
4605 *
4606 * Return nothing.
4607 */
4608static void
4609_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4610 Mpi2EventIrConfigElement_t *element)
4611{
4612 struct _sas_device *sas_device;
4613 unsigned long flags;
4614 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4615
4616 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4617 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4618 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4619 if (!sas_device)
4620 return;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304621 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004622}
4623
4624/**
4625 * _scsih_sas_pd_add - remove pd component
4626 * @ioc: per adapter object
4627 * @element: IR config element data
4628 * Context: user.
4629 *
4630 * Return nothing.
4631 */
4632static void
4633_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
4634 Mpi2EventIrConfigElement_t *element)
4635{
4636 struct _sas_device *sas_device;
4637 unsigned long flags;
4638 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304639 Mpi2ConfigReply_t mpi_reply;
4640 Mpi2SasDevicePage0_t sas_device_pg0;
4641 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304642 u64 sas_address;
4643 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06004644
4645 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4646 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4647 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304648 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004649 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304650 return;
4651 }
4652
4653 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4654 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4655 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4656 ioc->name, __FILE__, __LINE__, __func__);
4657 return;
4658 }
4659
4660 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4661 MPI2_IOCSTATUS_MASK;
4662 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4663 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4664 ioc->name, __FILE__, __LINE__, __func__);
4665 return;
4666 }
4667
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304668 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
4669 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
4670 mpt2sas_transport_update_links(ioc, sas_address, handle,
4671 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304672
4673 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06004674}
4675
4676#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4677/**
4678 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
4679 * @ioc: per adapter object
4680 * @event_data: event data payload
4681 * Context: user.
4682 *
4683 * Return nothing.
4684 */
4685static void
4686_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4687 Mpi2EventDataIrConfigChangeList_t *event_data)
4688{
4689 Mpi2EventIrConfigElement_t *element;
4690 u8 element_type;
4691 int i;
4692 char *reason_str = NULL, *element_str = NULL;
4693
4694 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4695
4696 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
4697 ioc->name, (le32_to_cpu(event_data->Flags) &
4698 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
4699 "foreign" : "native", event_data->NumElements);
4700 for (i = 0; i < event_data->NumElements; i++, element++) {
4701 switch (element->ReasonCode) {
4702 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
4703 reason_str = "add";
4704 break;
4705 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
4706 reason_str = "remove";
4707 break;
4708 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
4709 reason_str = "no change";
4710 break;
4711 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4712 reason_str = "hide";
4713 break;
4714 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4715 reason_str = "unhide";
4716 break;
4717 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4718 reason_str = "volume_created";
4719 break;
4720 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4721 reason_str = "volume_deleted";
4722 break;
4723 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4724 reason_str = "pd_created";
4725 break;
4726 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4727 reason_str = "pd_deleted";
4728 break;
4729 default:
4730 reason_str = "unknown reason";
4731 break;
4732 }
4733 element_type = le16_to_cpu(element->ElementFlags) &
4734 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
4735 switch (element_type) {
4736 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
4737 element_str = "volume";
4738 break;
4739 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
4740 element_str = "phys disk";
4741 break;
4742 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
4743 element_str = "hot spare";
4744 break;
4745 default:
4746 element_str = "unknown element";
4747 break;
4748 }
4749 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
4750 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
4751 reason_str, le16_to_cpu(element->VolDevHandle),
4752 le16_to_cpu(element->PhysDiskDevHandle),
4753 element->PhysDiskNum);
4754 }
4755}
4756#endif
4757
4758/**
4759 * _scsih_sas_ir_config_change_event - handle ir configuration change events
4760 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304761 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004762 * Context: user.
4763 *
4764 * Return nothing.
4765 */
4766static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304767_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
4768 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004769{
4770 Mpi2EventIrConfigElement_t *element;
4771 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304772 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304773 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004774
4775#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4776 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4777 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
4778
4779#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05304780 foreign_config = (le32_to_cpu(event_data->Flags) &
4781 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06004782
4783 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4784 for (i = 0; i < event_data->NumElements; i++, element++) {
4785
4786 switch (element->ReasonCode) {
4787 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4788 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304789 if (!foreign_config)
4790 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004791 break;
4792 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4793 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304794 if (!foreign_config)
4795 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004796 break;
4797 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4798 _scsih_sas_pd_hide(ioc, element);
4799 break;
4800 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4801 _scsih_sas_pd_expose(ioc, element);
4802 break;
4803 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4804 _scsih_sas_pd_add(ioc, element);
4805 break;
4806 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4807 _scsih_sas_pd_delete(ioc, element);
4808 break;
4809 }
4810 }
4811}
4812
4813/**
4814 * _scsih_sas_ir_volume_event - IR volume event
4815 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304816 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004817 * Context: user.
4818 *
4819 * Return nothing.
4820 */
4821static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304822_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
4823 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004824{
4825 u64 wwid;
4826 unsigned long flags;
4827 struct _raid_device *raid_device;
4828 u16 handle;
4829 u32 state;
4830 int rc;
4831 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304832 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004833
4834 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
4835 return;
4836
4837 handle = le16_to_cpu(event_data->VolDevHandle);
4838 state = le32_to_cpu(event_data->NewValue);
4839 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4840 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4841 le32_to_cpu(event_data->PreviousValue), state));
4842
4843 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4844 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4845 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4846
4847 switch (state) {
4848 case MPI2_RAID_VOL_STATE_MISSING:
4849 case MPI2_RAID_VOL_STATE_FAILED:
4850 if (!raid_device)
4851 break;
4852 if (raid_device->starget) {
4853 sas_target_priv_data = raid_device->starget->hostdata;
4854 sas_target_priv_data->deleted = 1;
4855 scsi_remove_target(&raid_device->starget->dev);
4856 }
4857 _scsih_raid_device_remove(ioc, raid_device);
4858 break;
4859
4860 case MPI2_RAID_VOL_STATE_ONLINE:
4861 case MPI2_RAID_VOL_STATE_DEGRADED:
4862 case MPI2_RAID_VOL_STATE_OPTIMAL:
4863 if (raid_device)
4864 break;
4865
4866 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4867 if (!wwid) {
4868 printk(MPT2SAS_ERR_FMT
4869 "failure at %s:%d/%s()!\n", ioc->name,
4870 __FILE__, __LINE__, __func__);
4871 break;
4872 }
4873
4874 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4875 if (!raid_device) {
4876 printk(MPT2SAS_ERR_FMT
4877 "failure at %s:%d/%s()!\n", ioc->name,
4878 __FILE__, __LINE__, __func__);
4879 break;
4880 }
4881
4882 raid_device->id = ioc->sas_id++;
4883 raid_device->channel = RAID_CHANNEL;
4884 raid_device->handle = handle;
4885 raid_device->wwid = wwid;
4886 _scsih_raid_device_add(ioc, raid_device);
4887 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4888 raid_device->id, 0);
4889 if (rc)
4890 _scsih_raid_device_remove(ioc, raid_device);
4891 break;
4892
4893 case MPI2_RAID_VOL_STATE_INITIALIZING:
4894 default:
4895 break;
4896 }
4897}
4898
4899/**
4900 * _scsih_sas_ir_physical_disk_event - PD event
4901 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304902 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004903 * Context: user.
4904 *
4905 * Return nothing.
4906 */
4907static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304908_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
4909 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004910{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304911 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06004912 u32 state;
4913 struct _sas_device *sas_device;
4914 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304915 Mpi2ConfigReply_t mpi_reply;
4916 Mpi2SasDevicePage0_t sas_device_pg0;
4917 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304918 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304919 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004920
4921 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
4922 return;
4923
4924 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
4925 state = le32_to_cpu(event_data->NewValue);
4926
4927 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4928 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4929 le32_to_cpu(event_data->PreviousValue), state));
4930
4931 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4932 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4933 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4934
4935 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06004936 case MPI2_RAID_PD_STATE_ONLINE:
4937 case MPI2_RAID_PD_STATE_DEGRADED:
4938 case MPI2_RAID_PD_STATE_REBUILDING:
4939 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304940 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004941 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304942 return;
4943 }
4944
4945 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
4946 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
4947 handle))) {
4948 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4949 ioc->name, __FILE__, __LINE__, __func__);
4950 return;
4951 }
4952
4953 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4954 MPI2_IOCSTATUS_MASK;
4955 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4956 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4957 ioc->name, __FILE__, __LINE__, __func__);
4958 return;
4959 }
4960
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304961 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
4962 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
4963 mpt2sas_transport_update_links(ioc, sas_address, handle,
4964 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304965
4966 _scsih_add_device(ioc, handle, 0, 1);
4967
Eric Moore635374e2009-03-09 01:21:12 -06004968 break;
4969
Kashyap, Desai62727a72009-08-07 19:35:18 +05304970 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06004971 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
4972 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
4973 case MPI2_RAID_PD_STATE_HOT_SPARE:
4974 default:
4975 break;
4976 }
4977}
4978
4979#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4980/**
4981 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
4982 * @ioc: per adapter object
4983 * @event_data: event data payload
4984 * Context: user.
4985 *
4986 * Return nothing.
4987 */
4988static void
4989_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
4990 Mpi2EventDataIrOperationStatus_t *event_data)
4991{
4992 char *reason_str = NULL;
4993
4994 switch (event_data->RAIDOperation) {
4995 case MPI2_EVENT_IR_RAIDOP_RESYNC:
4996 reason_str = "resync";
4997 break;
4998 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
4999 reason_str = "online capacity expansion";
5000 break;
5001 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
5002 reason_str = "consistency check";
5003 break;
5004 default:
5005 reason_str = "unknown reason";
5006 break;
5007 }
5008
5009 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
5010 "\thandle(0x%04x), percent complete(%d)\n",
5011 ioc->name, reason_str,
5012 le16_to_cpu(event_data->VolDevHandle),
5013 event_data->PercentComplete);
5014}
5015#endif
5016
5017/**
5018 * _scsih_sas_ir_operation_status_event - handle RAID operation events
5019 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305020 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005021 * Context: user.
5022 *
5023 * Return nothing.
5024 */
5025static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305026_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
5027 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005028{
5029#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5030 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305031 _scsih_sas_ir_operation_status_event_debug(ioc,
5032 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005033#endif
5034}
5035
5036/**
5037 * _scsih_task_set_full - handle task set full
5038 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305039 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005040 * Context: user.
5041 *
5042 * Throttle back qdepth.
5043 */
5044static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305045_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
5046 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005047{
5048 unsigned long flags;
5049 struct _sas_device *sas_device;
5050 static struct _raid_device *raid_device;
5051 struct scsi_device *sdev;
5052 int depth;
5053 u16 current_depth;
5054 u16 handle;
5055 int id, channel;
5056 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305057 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005058
5059 current_depth = le16_to_cpu(event_data->CurrentDepth);
5060 handle = le16_to_cpu(event_data->DevHandle);
5061 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5062 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5063 if (!sas_device) {
5064 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5065 return;
5066 }
5067 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5068 id = sas_device->id;
5069 channel = sas_device->channel;
5070 sas_address = sas_device->sas_address;
5071
5072 /* if hidden raid component, then change to volume characteristics */
5073 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
5074 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5075 raid_device = _scsih_raid_device_find_by_handle(
5076 ioc, sas_device->volume_handle);
5077 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5078 if (raid_device) {
5079 id = raid_device->id;
5080 channel = raid_device->channel;
5081 handle = raid_device->handle;
5082 sas_address = raid_device->wwid;
5083 }
5084 }
5085
5086 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
5087 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
5088 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
5089 handle, (unsigned long long)sas_address, current_depth);
5090
5091 shost_for_each_device(sdev, ioc->shost) {
5092 if (sdev->id == id && sdev->channel == channel) {
5093 if (current_depth > sdev->queue_depth) {
5094 if (ioc->logging_level &
5095 MPT_DEBUG_TASK_SET_FULL)
5096 sdev_printk(KERN_INFO, sdev, "strange "
5097 "observation, the queue depth is"
5098 " (%d) meanwhile fw queue depth "
5099 "is (%d)\n", sdev->queue_depth,
5100 current_depth);
5101 continue;
5102 }
5103 depth = scsi_track_queue_full(sdev,
5104 current_depth - 1);
5105 if (depth > 0)
5106 sdev_printk(KERN_INFO, sdev, "Queue depth "
5107 "reduced to (%d)\n", depth);
5108 else if (depth < 0)
5109 sdev_printk(KERN_INFO, sdev, "Tagged Command "
5110 "Queueing is being disabled\n");
5111 else if (depth == 0)
5112 if (ioc->logging_level &
5113 MPT_DEBUG_TASK_SET_FULL)
5114 sdev_printk(KERN_INFO, sdev,
5115 "Queue depth not changed yet\n");
5116 }
5117 }
5118}
5119
5120/**
5121 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
5122 * @ioc: per adapter object
5123 * @sas_address: sas address
5124 * @slot: enclosure slot id
5125 * @handle: device handle
5126 *
5127 * After host reset, find out whether devices are still responding.
5128 * Used in _scsi_remove_unresponsive_sas_devices.
5129 *
5130 * Return nothing.
5131 */
5132static void
5133_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5134 u16 slot, u16 handle)
5135{
5136 struct MPT2SAS_TARGET *sas_target_priv_data;
5137 struct scsi_target *starget;
5138 struct _sas_device *sas_device;
5139 unsigned long flags;
5140
5141 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5142 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
5143 if (sas_device->sas_address == sas_address &&
5144 sas_device->slot == slot && sas_device->starget) {
5145 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305146 sas_device->state = 0;
5147 starget = sas_device->starget;
5148 sas_target_priv_data = starget->hostdata;
5149 sas_target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06005150 starget_printk(KERN_INFO, sas_device->starget,
5151 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
5152 "logical id(0x%016llx), slot(%d)\n", handle,
5153 (unsigned long long)sas_device->sas_address,
5154 (unsigned long long)
5155 sas_device->enclosure_logical_id,
5156 sas_device->slot);
5157 if (sas_device->handle == handle)
5158 goto out;
5159 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5160 sas_device->handle);
5161 sas_device->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005162 sas_target_priv_data->handle = handle;
5163 goto out;
5164 }
5165 }
5166 out:
5167 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5168}
5169
5170/**
5171 * _scsih_search_responding_sas_devices -
5172 * @ioc: per adapter object
5173 *
5174 * After host reset, find out whether devices are still responding.
5175 * If not remove.
5176 *
5177 * Return nothing.
5178 */
5179static void
5180_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
5181{
5182 Mpi2SasDevicePage0_t sas_device_pg0;
5183 Mpi2ConfigReply_t mpi_reply;
5184 u16 ioc_status;
5185 __le64 sas_address;
5186 u16 handle;
5187 u32 device_info;
5188 u16 slot;
5189
5190 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5191
5192 if (list_empty(&ioc->sas_device_list))
5193 return;
5194
5195 handle = 0xFFFF;
5196 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5197 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
5198 handle))) {
5199 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5200 MPI2_IOCSTATUS_MASK;
5201 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5202 break;
5203 handle = le16_to_cpu(sas_device_pg0.DevHandle);
5204 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5205 if (!(_scsih_is_end_device(device_info)))
5206 continue;
5207 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5208 slot = le16_to_cpu(sas_device_pg0.Slot);
5209 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
5210 handle);
5211 }
5212}
5213
5214/**
5215 * _scsih_mark_responding_raid_device - mark a raid_device as responding
5216 * @ioc: per adapter object
5217 * @wwid: world wide identifier for raid volume
5218 * @handle: device handle
5219 *
5220 * After host reset, find out whether devices are still responding.
5221 * Used in _scsi_remove_unresponsive_raid_devices.
5222 *
5223 * Return nothing.
5224 */
5225static void
5226_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
5227 u16 handle)
5228{
5229 struct MPT2SAS_TARGET *sas_target_priv_data;
5230 struct scsi_target *starget;
5231 struct _raid_device *raid_device;
5232 unsigned long flags;
5233
5234 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5235 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
5236 if (raid_device->wwid == wwid && raid_device->starget) {
5237 raid_device->responding = 1;
5238 starget_printk(KERN_INFO, raid_device->starget,
5239 "handle(0x%04x), wwid(0x%016llx)\n", handle,
5240 (unsigned long long)raid_device->wwid);
5241 if (raid_device->handle == handle)
5242 goto out;
5243 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5244 raid_device->handle);
5245 raid_device->handle = handle;
5246 starget = raid_device->starget;
5247 sas_target_priv_data = starget->hostdata;
5248 sas_target_priv_data->handle = handle;
5249 goto out;
5250 }
5251 }
5252 out:
5253 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5254}
5255
5256/**
5257 * _scsih_search_responding_raid_devices -
5258 * @ioc: per adapter object
5259 *
5260 * After host reset, find out whether devices are still responding.
5261 * If not remove.
5262 *
5263 * Return nothing.
5264 */
5265static void
5266_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
5267{
5268 Mpi2RaidVolPage1_t volume_pg1;
5269 Mpi2ConfigReply_t mpi_reply;
5270 u16 ioc_status;
5271 u16 handle;
5272
5273 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5274
5275 if (list_empty(&ioc->raid_device_list))
5276 return;
5277
5278 handle = 0xFFFF;
5279 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
5280 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
5281 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5282 MPI2_IOCSTATUS_MASK;
5283 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5284 break;
5285 handle = le16_to_cpu(volume_pg1.DevHandle);
5286 _scsih_mark_responding_raid_device(ioc,
5287 le64_to_cpu(volume_pg1.WWID), handle);
5288 }
5289}
5290
5291/**
5292 * _scsih_mark_responding_expander - mark a expander as responding
5293 * @ioc: per adapter object
5294 * @sas_address: sas address
5295 * @handle:
5296 *
5297 * After host reset, find out whether devices are still responding.
5298 * Used in _scsi_remove_unresponsive_expanders.
5299 *
5300 * Return nothing.
5301 */
5302static void
5303_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5304 u16 handle)
5305{
5306 struct _sas_node *sas_expander;
5307 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305308 int i;
Eric Moore635374e2009-03-09 01:21:12 -06005309
5310 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5311 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305312 if (sas_expander->sas_address != sas_address)
5313 continue;
5314 sas_expander->responding = 1;
5315 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06005316 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305317 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
5318 " from(0x%04x) to (0x%04x)!!!\n",
5319 (unsigned long long)sas_expander->sas_address,
5320 sas_expander->handle, handle);
5321 sas_expander->handle = handle;
5322 for (i = 0 ; i < sas_expander->num_phys ; i++)
5323 sas_expander->phy[i].handle = handle;
5324 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06005325 }
5326 out:
5327 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5328}
5329
5330/**
5331 * _scsih_search_responding_expanders -
5332 * @ioc: per adapter object
5333 *
5334 * After host reset, find out whether devices are still responding.
5335 * If not remove.
5336 *
5337 * Return nothing.
5338 */
5339static void
5340_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5341{
5342 Mpi2ExpanderPage0_t expander_pg0;
5343 Mpi2ConfigReply_t mpi_reply;
5344 u16 ioc_status;
5345 __le64 sas_address;
5346 u16 handle;
5347
5348 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5349
5350 if (list_empty(&ioc->sas_expander_list))
5351 return;
5352
5353 handle = 0xFFFF;
5354 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5355 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5356
5357 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5358 MPI2_IOCSTATUS_MASK;
5359 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5360 break;
5361
5362 handle = le16_to_cpu(expander_pg0.DevHandle);
5363 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5364 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5365 "sas_addr(0x%016llx)\n", handle,
5366 (unsigned long long)sas_address);
5367 _scsih_mark_responding_expander(ioc, sas_address, handle);
5368 }
5369
5370}
5371
5372/**
5373 * _scsih_remove_unresponding_devices - removing unresponding devices
5374 * @ioc: per adapter object
5375 *
5376 * Return nothing.
5377 */
5378static void
5379_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
5380{
5381 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305382 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005383 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005384
Eric Moore635374e2009-03-09 01:21:12 -06005385
5386 list_for_each_entry_safe(sas_device, sas_device_next,
5387 &ioc->sas_device_list, list) {
5388 if (sas_device->responding) {
5389 sas_device->responding = 0;
5390 continue;
5391 }
5392 if (sas_device->starget)
5393 starget_printk(KERN_INFO, sas_device->starget,
5394 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5395 "enclosure logical id(0x%016llx), slot(%d)\n",
5396 sas_device->handle,
5397 (unsigned long long)sas_device->sas_address,
5398 (unsigned long long)
5399 sas_device->enclosure_logical_id,
5400 sas_device->slot);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305401 /* invalidate the device handle */
5402 sas_device->handle = 0;
5403 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005404 }
5405
5406 list_for_each_entry_safe(raid_device, raid_device_next,
5407 &ioc->raid_device_list, list) {
5408 if (raid_device->responding) {
5409 raid_device->responding = 0;
5410 continue;
5411 }
5412 if (raid_device->starget) {
5413 starget_printk(KERN_INFO, raid_device->starget,
5414 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5415 raid_device->handle,
5416 (unsigned long long)raid_device->wwid);
5417 scsi_remove_target(&raid_device->starget->dev);
5418 }
5419 _scsih_raid_device_remove(ioc, raid_device);
5420 }
5421
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305422 retry_expander_search:
5423 sas_expander = NULL;
5424 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005425 if (sas_expander->responding) {
5426 sas_expander->responding = 0;
5427 continue;
5428 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305429 _scsih_expander_remove(ioc, sas_expander->sas_address);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305430 goto retry_expander_search;
5431 }
5432}
5433
5434/**
5435 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5436 * @ioc: per adapter object
5437 * @reset_phase: phase
5438 *
5439 * The handler for doing any required cleanup or initialization.
5440 *
5441 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5442 * MPT2_IOC_DONE_RESET
5443 *
5444 * Return nothing.
5445 */
5446void
5447mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5448{
5449 switch (reset_phase) {
5450 case MPT2_IOC_PRE_RESET:
5451 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5452 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
5453 _scsih_fw_event_off(ioc);
5454 break;
5455 case MPT2_IOC_AFTER_RESET:
5456 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5457 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
5458 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5459 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5460 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5461 complete(&ioc->tm_cmds.done);
5462 }
5463 _scsih_fw_event_on(ioc);
5464 _scsih_flush_running_cmds(ioc);
5465 break;
5466 case MPT2_IOC_DONE_RESET:
5467 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5468 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305469 _scsih_sas_host_refresh(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305470 _scsih_search_responding_sas_devices(ioc);
5471 _scsih_search_responding_raid_devices(ioc);
5472 _scsih_search_responding_expanders(ioc);
5473 break;
5474 case MPT2_IOC_RUNNING:
5475 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5476 "MPT2_IOC_RUNNING\n", ioc->name, __func__));
5477 _scsih_remove_unresponding_devices(ioc);
5478 break;
Eric Moore635374e2009-03-09 01:21:12 -06005479 }
5480}
5481
5482/**
5483 * _firmware_event_work - delayed task for processing firmware events
5484 * @ioc: per adapter object
5485 * @work: equal to the fw_event_work object
5486 * Context: user.
5487 *
5488 * Return nothing.
5489 */
5490static void
5491_firmware_event_work(struct work_struct *work)
5492{
5493 struct fw_event_work *fw_event = container_of(work,
Eric Moore6f92a7a2009-04-21 15:43:33 -06005494 struct fw_event_work, work);
Eric Moore635374e2009-03-09 01:21:12 -06005495 unsigned long flags;
5496 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5497
Eric Moore635374e2009-03-09 01:21:12 -06005498 /* the queue is being flushed so ignore this event */
5499 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5500 if (ioc->fw_events_off || ioc->remove_host) {
5501 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5502 _scsih_fw_event_free(ioc, fw_event);
5503 return;
5504 }
5505 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5506
Eric Moore635374e2009-03-09 01:21:12 -06005507 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06005508 _scsih_fw_event_requeue(ioc, fw_event, 1000);
5509 return;
5510 }
Eric Moore635374e2009-03-09 01:21:12 -06005511
5512 switch (fw_event->event) {
5513 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305514 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005515 break;
5516 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305517 _scsih_sas_device_status_change_event(ioc,
5518 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005519 break;
5520 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305521 _scsih_sas_discovery_event(ioc,
5522 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005523 break;
5524 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305525 _scsih_sas_broadcast_primative_event(ioc,
5526 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005527 break;
5528 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5529 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305530 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005531 break;
5532 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305533 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005534 break;
5535 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305536 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005537 break;
5538 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305539 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005540 break;
5541 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305542 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005543 break;
5544 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305545 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005546 break;
5547 }
5548 _scsih_fw_event_free(ioc, fw_event);
5549}
5550
5551/**
5552 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5553 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305554 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06005555 * @reply: reply message frame(lower 32bit addr)
5556 * Context: interrupt.
5557 *
5558 * This function merely adds a new work task into ioc->firmware_event_thread.
5559 * The tasks are worked from _firmware_event_work in user context.
5560 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305561 * Return 1 meaning mf should be freed from _base_interrupt
5562 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06005563 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305564u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305565mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
5566 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06005567{
5568 struct fw_event_work *fw_event;
5569 Mpi2EventNotificationReply_t *mpi_reply;
5570 unsigned long flags;
5571 u16 event;
5572
5573 /* events turned off due to host reset or driver unloading */
5574 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5575 if (ioc->fw_events_off || ioc->remove_host) {
5576 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305577 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005578 }
5579 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5580
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305581 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06005582 event = le16_to_cpu(mpi_reply->Event);
5583
5584 switch (event) {
5585 /* handle these */
5586 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
5587 {
5588 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
5589 (Mpi2EventDataSasBroadcastPrimitive_t *)
5590 mpi_reply->EventData;
5591
5592 if (baen_data->Primitive !=
5593 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
5594 ioc->broadcast_aen_busy)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305595 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005596 ioc->broadcast_aen_busy = 1;
5597 break;
5598 }
5599
5600 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
5601 _scsih_check_topo_delete_events(ioc,
5602 (Mpi2EventDataSasTopologyChangeList_t *)
5603 mpi_reply->EventData);
5604 break;
5605
5606 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
5607 case MPI2_EVENT_IR_OPERATION_STATUS:
5608 case MPI2_EVENT_SAS_DISCOVERY:
5609 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5610 case MPI2_EVENT_IR_VOLUME:
5611 case MPI2_EVENT_IR_PHYSICAL_DISK:
5612 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
5613 case MPI2_EVENT_TASK_SET_FULL:
5614 break;
5615
5616 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305617 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005618 }
5619
5620 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
5621 if (!fw_event) {
5622 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5623 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305624 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005625 }
5626 fw_event->event_data =
5627 kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
5628 if (!fw_event->event_data) {
5629 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5630 ioc->name, __FILE__, __LINE__, __func__);
5631 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305632 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005633 }
5634
5635 memcpy(fw_event->event_data, mpi_reply->EventData,
5636 mpi_reply->EventDataLength*4);
5637 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305638 fw_event->VF_ID = mpi_reply->VF_ID;
5639 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06005640 fw_event->event = event;
5641 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305642 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005643}
5644
5645/* shost template */
5646static struct scsi_host_template scsih_driver_template = {
5647 .module = THIS_MODULE,
5648 .name = "Fusion MPT SAS Host",
5649 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06005650 .queuecommand = _scsih_qcmd,
5651 .target_alloc = _scsih_target_alloc,
5652 .slave_alloc = _scsih_slave_alloc,
5653 .slave_configure = _scsih_slave_configure,
5654 .target_destroy = _scsih_target_destroy,
5655 .slave_destroy = _scsih_slave_destroy,
5656 .change_queue_depth = _scsih_change_queue_depth,
5657 .change_queue_type = _scsih_change_queue_type,
5658 .eh_abort_handler = _scsih_abort,
5659 .eh_device_reset_handler = _scsih_dev_reset,
5660 .eh_target_reset_handler = _scsih_target_reset,
5661 .eh_host_reset_handler = _scsih_host_reset,
5662 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06005663 .can_queue = 1,
5664 .this_id = -1,
5665 .sg_tablesize = MPT2SAS_SG_DEPTH,
5666 .max_sectors = 8192,
5667 .cmd_per_lun = 7,
5668 .use_clustering = ENABLE_CLUSTERING,
5669 .shost_attrs = mpt2sas_host_attrs,
5670 .sdev_attrs = mpt2sas_dev_attrs,
5671};
5672
5673/**
5674 * _scsih_expander_node_remove - removing expander device from list.
5675 * @ioc: per adapter object
5676 * @sas_expander: the sas_device object
5677 * Context: Calling function should acquire ioc->sas_node_lock.
5678 *
5679 * Removing object and freeing associated memory from the
5680 * ioc->sas_expander_list.
5681 *
5682 * Return nothing.
5683 */
5684static void
5685_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
5686 struct _sas_node *sas_expander)
5687{
5688 struct _sas_port *mpt2sas_port;
5689 struct _sas_device *sas_device;
5690 struct _sas_node *expander_sibling;
5691 unsigned long flags;
5692
5693 if (!sas_expander)
5694 return;
5695
5696 /* remove sibling ports attached to this expander */
5697 retry_device_search:
5698 list_for_each_entry(mpt2sas_port,
5699 &sas_expander->sas_port_list, port_list) {
5700 if (mpt2sas_port->remote_identify.device_type ==
5701 SAS_END_DEVICE) {
5702 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5703 sas_device =
5704 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5705 mpt2sas_port->remote_identify.sas_address);
5706 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5707 if (!sas_device)
5708 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305709 _scsih_remove_device(ioc, sas_device);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305710 if (ioc->shost_recovery)
5711 return;
Eric Moore635374e2009-03-09 01:21:12 -06005712 goto retry_device_search;
5713 }
5714 }
5715
5716 retry_expander_search:
5717 list_for_each_entry(mpt2sas_port,
5718 &sas_expander->sas_port_list, port_list) {
5719
5720 if (mpt2sas_port->remote_identify.device_type ==
5721 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
5722 mpt2sas_port->remote_identify.device_type ==
5723 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
5724
5725 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5726 expander_sibling =
5727 mpt2sas_scsih_expander_find_by_sas_address(
5728 ioc, mpt2sas_port->remote_identify.sas_address);
5729 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5730 if (!expander_sibling)
5731 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305732 _scsih_expander_remove(ioc,
5733 expander_sibling->sas_address);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305734 if (ioc->shost_recovery)
5735 return;
Eric Moore635374e2009-03-09 01:21:12 -06005736 goto retry_expander_search;
5737 }
5738 }
5739
5740 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305741 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06005742
5743 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
5744 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
5745 sas_expander->handle, (unsigned long long)
5746 sas_expander->sas_address);
5747
5748 list_del(&sas_expander->list);
5749 kfree(sas_expander->phy);
5750 kfree(sas_expander);
5751}
5752
5753/**
Eric Moored5d135b2009-05-18 13:02:08 -06005754 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06005755 * @pdev: PCI device struct
5756 *
5757 * Return nothing.
5758 */
5759static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06005760_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06005761{
5762 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5763 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5764 struct _sas_port *mpt2sas_port;
5765 struct _sas_device *sas_device;
5766 struct _sas_node *expander_sibling;
5767 struct workqueue_struct *wq;
5768 unsigned long flags;
5769
5770 ioc->remove_host = 1;
5771 _scsih_fw_event_off(ioc);
5772
5773 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5774 wq = ioc->firmware_event_thread;
5775 ioc->firmware_event_thread = NULL;
5776 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5777 if (wq)
5778 destroy_workqueue(wq);
5779
5780 /* free ports attached to the sas_host */
5781 retry_again:
5782 list_for_each_entry(mpt2sas_port,
5783 &ioc->sas_hba.sas_port_list, port_list) {
5784 if (mpt2sas_port->remote_identify.device_type ==
5785 SAS_END_DEVICE) {
5786 sas_device =
5787 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5788 mpt2sas_port->remote_identify.sas_address);
5789 if (sas_device) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305790 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005791 goto retry_again;
5792 }
5793 } else {
5794 expander_sibling =
5795 mpt2sas_scsih_expander_find_by_sas_address(ioc,
5796 mpt2sas_port->remote_identify.sas_address);
5797 if (expander_sibling) {
5798 _scsih_expander_remove(ioc,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305799 expander_sibling->sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06005800 goto retry_again;
5801 }
5802 }
5803 }
5804
5805 /* free phys attached to the sas_host */
5806 if (ioc->sas_hba.num_phys) {
5807 kfree(ioc->sas_hba.phy);
5808 ioc->sas_hba.phy = NULL;
5809 ioc->sas_hba.num_phys = 0;
5810 }
5811
5812 sas_remove_host(shost);
5813 mpt2sas_base_detach(ioc);
5814 list_del(&ioc->list);
5815 scsi_remove_host(shost);
5816 scsi_host_put(shost);
5817}
5818
5819/**
5820 * _scsih_probe_boot_devices - reports 1st device
5821 * @ioc: per adapter object
5822 *
5823 * If specified in bios page 2, this routine reports the 1st
5824 * device scsi-ml or sas transport for persistent boot device
5825 * purposes. Please refer to function _scsih_determine_boot_device()
5826 */
5827static void
5828_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
5829{
5830 u8 is_raid;
5831 void *device;
5832 struct _sas_device *sas_device;
5833 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305834 u16 handle;
5835 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06005836 u64 sas_address;
5837 unsigned long flags;
5838 int rc;
5839
5840 device = NULL;
5841 if (ioc->req_boot_device.device) {
5842 device = ioc->req_boot_device.device;
5843 is_raid = ioc->req_boot_device.is_raid;
5844 } else if (ioc->req_alt_boot_device.device) {
5845 device = ioc->req_alt_boot_device.device;
5846 is_raid = ioc->req_alt_boot_device.is_raid;
5847 } else if (ioc->current_boot_device.device) {
5848 device = ioc->current_boot_device.device;
5849 is_raid = ioc->current_boot_device.is_raid;
5850 }
5851
5852 if (!device)
5853 return;
5854
5855 if (is_raid) {
5856 raid_device = device;
5857 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5858 raid_device->id, 0);
5859 if (rc)
5860 _scsih_raid_device_remove(ioc, raid_device);
5861 } else {
5862 sas_device = device;
5863 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305864 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06005865 sas_address = sas_device->sas_address;
5866 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5867 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5868 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5869 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305870 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06005871 _scsih_sas_device_remove(ioc, sas_device);
5872 } else if (!sas_device->starget) {
5873 mpt2sas_transport_port_remove(ioc, sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305874 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06005875 _scsih_sas_device_remove(ioc, sas_device);
5876 }
5877 }
5878}
5879
5880/**
5881 * _scsih_probe_raid - reporting raid volumes to scsi-ml
5882 * @ioc: per adapter object
5883 *
5884 * Called during initial loading of the driver.
5885 */
5886static void
5887_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
5888{
5889 struct _raid_device *raid_device, *raid_next;
5890 int rc;
5891
5892 list_for_each_entry_safe(raid_device, raid_next,
5893 &ioc->raid_device_list, list) {
5894 if (raid_device->starget)
5895 continue;
5896 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5897 raid_device->id, 0);
5898 if (rc)
5899 _scsih_raid_device_remove(ioc, raid_device);
5900 }
5901}
5902
5903/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305904 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06005905 * @ioc: per adapter object
5906 *
5907 * Called during initial loading of the driver.
5908 */
5909static void
5910_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
5911{
5912 struct _sas_device *sas_device, *next;
5913 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06005914
5915 /* SAS Device List */
5916 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
5917 list) {
5918 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5919 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5920 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5921
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305922 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
5923 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06005924 _scsih_sas_device_remove(ioc, sas_device);
5925 } else if (!sas_device->starget) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305926 mpt2sas_transport_port_remove(ioc,
5927 sas_device->sas_address,
5928 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06005929 _scsih_sas_device_remove(ioc, sas_device);
5930 }
5931 }
5932}
5933
5934/**
5935 * _scsih_probe_devices - probing for devices
5936 * @ioc: per adapter object
5937 *
5938 * Called during initial loading of the driver.
5939 */
5940static void
5941_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
5942{
5943 u16 volume_mapping_flags =
5944 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
5945 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
5946
5947 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
5948 return; /* return when IOC doesn't support initiator mode */
5949
5950 _scsih_probe_boot_devices(ioc);
5951
5952 if (ioc->ir_firmware) {
5953 if ((volume_mapping_flags &
5954 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
5955 _scsih_probe_sas(ioc);
5956 _scsih_probe_raid(ioc);
5957 } else {
5958 _scsih_probe_raid(ioc);
5959 _scsih_probe_sas(ioc);
5960 }
5961 } else
5962 _scsih_probe_sas(ioc);
5963}
5964
5965/**
Eric Moored5d135b2009-05-18 13:02:08 -06005966 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06005967 * @pdev: PCI device struct
5968 * @id: pci device id
5969 *
5970 * Returns 0 success, anything else error.
5971 */
5972static int
Eric Moored5d135b2009-05-18 13:02:08 -06005973_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06005974{
5975 struct MPT2SAS_ADAPTER *ioc;
5976 struct Scsi_Host *shost;
5977
5978 shost = scsi_host_alloc(&scsih_driver_template,
5979 sizeof(struct MPT2SAS_ADAPTER));
5980 if (!shost)
5981 return -ENODEV;
5982
5983 /* init local params */
5984 ioc = shost_priv(shost);
5985 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
5986 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06005987 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06005988 ioc->shost = shost;
5989 ioc->id = mpt_ids++;
5990 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
5991 ioc->pdev = pdev;
5992 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
5993 ioc->tm_cb_idx = tm_cb_idx;
5994 ioc->ctl_cb_idx = ctl_cb_idx;
5995 ioc->base_cb_idx = base_cb_idx;
5996 ioc->transport_cb_idx = transport_cb_idx;
5997 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305998 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
5999 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006000 ioc->logging_level = logging_level;
6001 /* misc semaphores and spin locks */
6002 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
6003 spin_lock_init(&ioc->scsi_lookup_lock);
6004 spin_lock_init(&ioc->sas_device_lock);
6005 spin_lock_init(&ioc->sas_node_lock);
6006 spin_lock_init(&ioc->fw_event_lock);
6007 spin_lock_init(&ioc->raid_device_lock);
6008
6009 INIT_LIST_HEAD(&ioc->sas_device_list);
6010 INIT_LIST_HEAD(&ioc->sas_device_init_list);
6011 INIT_LIST_HEAD(&ioc->sas_expander_list);
6012 INIT_LIST_HEAD(&ioc->fw_event_list);
6013 INIT_LIST_HEAD(&ioc->raid_device_list);
6014 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306015 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Eric Moore635374e2009-03-09 01:21:12 -06006016
6017 /* init shost parameters */
6018 shost->max_cmd_len = 16;
6019 shost->max_lun = max_lun;
6020 shost->transportt = mpt2sas_transport_template;
6021 shost->unique_id = ioc->id;
6022
6023 if ((scsi_add_host(shost, &pdev->dev))) {
6024 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6025 ioc->name, __FILE__, __LINE__, __func__);
6026 list_del(&ioc->list);
6027 goto out_add_shost_fail;
6028 }
6029
Eric Moore3c621b32009-05-18 12:59:41 -06006030 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
6031 | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306032 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06006033
Eric Moore635374e2009-03-09 01:21:12 -06006034 /* event thread */
6035 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
6036 "fw_event%d", ioc->id);
6037 ioc->firmware_event_thread = create_singlethread_workqueue(
6038 ioc->firmware_event_name);
6039 if (!ioc->firmware_event_thread) {
6040 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6041 ioc->name, __FILE__, __LINE__, __func__);
6042 goto out_thread_fail;
6043 }
6044
6045 ioc->wait_for_port_enable_to_complete = 1;
6046 if ((mpt2sas_base_attach(ioc))) {
6047 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6048 ioc->name, __FILE__, __LINE__, __func__);
6049 goto out_attach_fail;
6050 }
6051
6052 ioc->wait_for_port_enable_to_complete = 0;
6053 _scsih_probe_devices(ioc);
6054 return 0;
6055
6056 out_attach_fail:
6057 destroy_workqueue(ioc->firmware_event_thread);
6058 out_thread_fail:
6059 list_del(&ioc->list);
6060 scsi_remove_host(shost);
6061 out_add_shost_fail:
6062 return -ENODEV;
6063}
6064
6065#ifdef CONFIG_PM
6066/**
Eric Moored5d135b2009-05-18 13:02:08 -06006067 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006068 * @pdev: PCI device struct
6069 * @state: PM state change to (usually PCI_D3)
6070 *
6071 * Returns 0 success, anything else error.
6072 */
6073static int
Eric Moored5d135b2009-05-18 13:02:08 -06006074_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06006075{
6076 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6077 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6078 u32 device_state;
6079
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306080 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006081 flush_scheduled_work();
6082 scsi_block_requests(shost);
6083 device_state = pci_choose_state(pdev, state);
6084 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
6085 "operating state [D%d]\n", ioc->name, pdev,
6086 pci_name(pdev), device_state);
6087
6088 mpt2sas_base_free_resources(ioc);
6089 pci_save_state(pdev);
6090 pci_disable_device(pdev);
6091 pci_set_power_state(pdev, device_state);
6092 return 0;
6093}
6094
6095/**
Eric Moored5d135b2009-05-18 13:02:08 -06006096 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006097 * @pdev: PCI device struct
6098 *
6099 * Returns 0 success, anything else error.
6100 */
6101static int
Eric Moored5d135b2009-05-18 13:02:08 -06006102_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006103{
6104 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6105 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6106 u32 device_state = pdev->current_state;
6107 int r;
6108
6109 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
6110 "operating state [D%d]\n", ioc->name, pdev,
6111 pci_name(pdev), device_state);
6112
6113 pci_set_power_state(pdev, PCI_D0);
6114 pci_enable_wake(pdev, PCI_D0, 0);
6115 pci_restore_state(pdev);
6116 ioc->pdev = pdev;
6117 r = mpt2sas_base_map_resources(ioc);
6118 if (r)
6119 return r;
6120
6121 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
6122 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306123 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006124 return 0;
6125}
6126#endif /* CONFIG_PM */
6127
6128
6129static struct pci_driver scsih_driver = {
6130 .name = MPT2SAS_DRIVER_NAME,
6131 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06006132 .probe = _scsih_probe,
6133 .remove = __devexit_p(_scsih_remove),
Eric Moore635374e2009-03-09 01:21:12 -06006134#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06006135 .suspend = _scsih_suspend,
6136 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06006137#endif
6138};
6139
6140
6141/**
Eric Moored5d135b2009-05-18 13:02:08 -06006142 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06006143 *
6144 * Returns 0 success, anything else error.
6145 */
6146static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06006147_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06006148{
6149 int error;
6150
6151 mpt_ids = 0;
6152 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
6153 MPT2SAS_DRIVER_VERSION);
6154
6155 mpt2sas_transport_template =
6156 sas_attach_transport(&mpt2sas_transport_functions);
6157 if (!mpt2sas_transport_template)
6158 return -ENODEV;
6159
6160 mpt2sas_base_initialize_callback_handler();
6161
6162 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06006163 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06006164
6165 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06006166 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06006167
6168 /* base internal commands callback handler */
6169 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
6170
6171 /* transport internal commands callback handler */
6172 transport_cb_idx = mpt2sas_base_register_callback_handler(
6173 mpt2sas_transport_done);
6174
6175 /* configuration page API internal commands callback handler */
6176 config_cb_idx = mpt2sas_base_register_callback_handler(
6177 mpt2sas_config_done);
6178
6179 /* ctl module callback handler */
6180 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
6181
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306182 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
6183 _scsih_tm_tr_complete);
6184 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
6185 _scsih_sas_control_complete);
6186
Eric Moore635374e2009-03-09 01:21:12 -06006187 mpt2sas_ctl_init();
6188
6189 error = pci_register_driver(&scsih_driver);
6190 if (error)
6191 sas_release_transport(mpt2sas_transport_template);
6192
6193 return error;
6194}
6195
6196/**
Eric Moored5d135b2009-05-18 13:02:08 -06006197 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06006198 *
6199 * Returns 0 success, anything else error.
6200 */
6201static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06006202_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06006203{
6204 printk(KERN_INFO "mpt2sas version %s unloading\n",
6205 MPT2SAS_DRIVER_VERSION);
6206
6207 pci_unregister_driver(&scsih_driver);
6208
6209 sas_release_transport(mpt2sas_transport_template);
6210 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
6211 mpt2sas_base_release_callback_handler(tm_cb_idx);
6212 mpt2sas_base_release_callback_handler(base_cb_idx);
6213 mpt2sas_base_release_callback_handler(transport_cb_idx);
6214 mpt2sas_base_release_callback_handler(config_cb_idx);
6215 mpt2sas_base_release_callback_handler(ctl_cb_idx);
6216
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306217 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
6218 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
6219
Eric Moore635374e2009-03-09 01:21:12 -06006220 mpt2sas_ctl_exit();
6221}
6222
Eric Moored5d135b2009-05-18 13:02:08 -06006223module_init(_scsih_init);
6224module_exit(_scsih_exit);