blob: d4b003a618a1d479a30253338da4dacec5f4fa81 [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
82/* command line options */
Eric Mooreba33fad2009-03-15 21:37:18 -060083static u32 logging_level;
Eric Moore635374e2009-03-09 01:21:12 -060084MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
85 "(default=0)");
86
87/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
88#define MPT2SAS_MAX_LUN (16895)
89static int max_lun = MPT2SAS_MAX_LUN;
90module_param(max_lun, int, 0);
91MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
92
93/**
94 * struct sense_info - common structure for obtaining sense keys
95 * @skey: sense key
96 * @asc: additional sense code
97 * @ascq: additional sense code qualifier
98 */
99struct sense_info {
100 u8 skey;
101 u8 asc;
102 u8 ascq;
103};
104
105
Eric Moore635374e2009-03-09 01:21:12 -0600106/**
107 * struct fw_event_work - firmware event struct
108 * @list: link list framework
109 * @work: work object (ioc->fault_reset_work_q)
110 * @ioc: per adapter object
111 * @VF_ID: virtual function id
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530112 * @VP_ID: virtual port id
Eric Moore635374e2009-03-09 01:21:12 -0600113 * @host_reset_handling: handling events during host reset
114 * @ignore: flag meaning this event has been marked to ignore
115 * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
116 * @event_data: reply event data payload follows
117 *
118 * This object stored on ioc->fw_event_list.
119 */
120struct fw_event_work {
121 struct list_head list;
Eric Moore6f92a7a2009-04-21 15:43:33 -0600122 struct work_struct work;
Eric Moore635374e2009-03-09 01:21:12 -0600123 struct MPT2SAS_ADAPTER *ioc;
124 u8 VF_ID;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530125 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600126 u8 host_reset_handling;
127 u8 ignore;
128 u16 event;
129 void *event_data;
130};
131
132/**
133 * struct _scsi_io_transfer - scsi io transfer
134 * @handle: sas device handle (assigned by firmware)
135 * @is_raid: flag set for hidden raid components
136 * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
137 * @data_length: data transfer length
138 * @data_dma: dma pointer to data
139 * @sense: sense data
140 * @lun: lun number
141 * @cdb_length: cdb length
142 * @cdb: cdb contents
Eric Moore635374e2009-03-09 01:21:12 -0600143 * @timeout: timeout for this command
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530144 * @VF_ID: virtual function id
145 * @VP_ID: virtual port id
146 * @valid_reply: flag set for reply message
Eric Moore635374e2009-03-09 01:21:12 -0600147 * @sense_length: sense length
148 * @ioc_status: ioc status
149 * @scsi_state: scsi state
150 * @scsi_status: scsi staus
151 * @log_info: log information
152 * @transfer_length: data length transfer when there is a reply message
153 *
154 * Used for sending internal scsi commands to devices within this module.
155 * Refer to _scsi_send_scsi_io().
156 */
157struct _scsi_io_transfer {
158 u16 handle;
159 u8 is_raid;
160 enum dma_data_direction dir;
161 u32 data_length;
162 dma_addr_t data_dma;
163 u8 sense[SCSI_SENSE_BUFFERSIZE];
164 u32 lun;
165 u8 cdb_length;
166 u8 cdb[32];
167 u8 timeout;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530168 u8 VF_ID;
169 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600170 u8 valid_reply;
171 /* the following bits are only valid when 'valid_reply = 1' */
172 u32 sense_length;
173 u16 ioc_status;
174 u8 scsi_state;
175 u8 scsi_status;
176 u32 log_info;
177 u32 transfer_length;
178};
179
180/*
181 * The pci device ids are defined in mpi/mpi2_cnfg.h.
182 */
183static struct pci_device_id scsih_pci_table[] = {
184 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
185 PCI_ANY_ID, PCI_ANY_ID },
186 /* Falcon ~ 2008*/
187 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
188 PCI_ANY_ID, PCI_ANY_ID },
189 /* Liberator ~ 2108 */
190 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
191 PCI_ANY_ID, PCI_ANY_ID },
192 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
193 PCI_ANY_ID, PCI_ANY_ID },
194 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
195 PCI_ANY_ID, PCI_ANY_ID },
196 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
197 PCI_ANY_ID, PCI_ANY_ID },
198 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
199 PCI_ANY_ID, PCI_ANY_ID },
200 {0} /* Terminating entry */
201};
202MODULE_DEVICE_TABLE(pci, scsih_pci_table);
203
204/**
Eric Moored5d135b2009-05-18 13:02:08 -0600205 * _scsih_set_debug_level - global setting of ioc->logging_level.
Eric Moore635374e2009-03-09 01:21:12 -0600206 *
207 * Note: The logging levels are defined in mpt2sas_debug.h.
208 */
209static int
Eric Moored5d135b2009-05-18 13:02:08 -0600210_scsih_set_debug_level(const char *val, struct kernel_param *kp)
Eric Moore635374e2009-03-09 01:21:12 -0600211{
212 int ret = param_set_int(val, kp);
213 struct MPT2SAS_ADAPTER *ioc;
214
215 if (ret)
216 return ret;
217
218 printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
Eric Mooreba33fad2009-03-15 21:37:18 -0600219 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
Eric Moore635374e2009-03-09 01:21:12 -0600220 ioc->logging_level = logging_level;
221 return 0;
222}
Eric Moored5d135b2009-05-18 13:02:08 -0600223module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
Eric Moore635374e2009-03-09 01:21:12 -0600224 &logging_level, 0644);
225
226/**
227 * _scsih_srch_boot_sas_address - search based on sas_address
228 * @sas_address: sas address
229 * @boot_device: boot device object from bios page 2
230 *
231 * Returns 1 when there's a match, 0 means no match.
232 */
233static inline int
234_scsih_srch_boot_sas_address(u64 sas_address,
235 Mpi2BootDeviceSasWwid_t *boot_device)
236{
237 return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
238}
239
240/**
241 * _scsih_srch_boot_device_name - search based on device name
242 * @device_name: device name specified in INDENTIFY fram
243 * @boot_device: boot device object from bios page 2
244 *
245 * Returns 1 when there's a match, 0 means no match.
246 */
247static inline int
248_scsih_srch_boot_device_name(u64 device_name,
249 Mpi2BootDeviceDeviceName_t *boot_device)
250{
251 return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
252}
253
254/**
255 * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
256 * @enclosure_logical_id: enclosure logical id
257 * @slot_number: slot number
258 * @boot_device: boot device object from bios page 2
259 *
260 * Returns 1 when there's a match, 0 means no match.
261 */
262static inline int
263_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
264 Mpi2BootDeviceEnclosureSlot_t *boot_device)
265{
266 return (enclosure_logical_id == le64_to_cpu(boot_device->
267 EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
268 SlotNumber)) ? 1 : 0;
269}
270
271/**
272 * _scsih_is_boot_device - search for matching boot device.
273 * @sas_address: sas address
274 * @device_name: device name specified in INDENTIFY fram
275 * @enclosure_logical_id: enclosure logical id
276 * @slot_number: slot number
277 * @form: specifies boot device form
278 * @boot_device: boot device object from bios page 2
279 *
280 * Returns 1 when there's a match, 0 means no match.
281 */
282static int
283_scsih_is_boot_device(u64 sas_address, u64 device_name,
284 u64 enclosure_logical_id, u16 slot, u8 form,
285 Mpi2BiosPage2BootDevice_t *boot_device)
286{
287 int rc = 0;
288
289 switch (form) {
290 case MPI2_BIOSPAGE2_FORM_SAS_WWID:
291 if (!sas_address)
292 break;
293 rc = _scsih_srch_boot_sas_address(
294 sas_address, &boot_device->SasWwid);
295 break;
296 case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
297 if (!enclosure_logical_id)
298 break;
299 rc = _scsih_srch_boot_encl_slot(
300 enclosure_logical_id,
301 slot, &boot_device->EnclosureSlot);
302 break;
303 case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
304 if (!device_name)
305 break;
306 rc = _scsih_srch_boot_device_name(
307 device_name, &boot_device->DeviceName);
308 break;
309 case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
310 break;
311 }
312
313 return rc;
314}
315
316/**
317 * _scsih_determine_boot_device - determine boot device.
318 * @ioc: per adapter object
319 * @device: either sas_device or raid_device object
320 * @is_raid: [flag] 1 = raid object, 0 = sas object
321 *
322 * Determines whether this device should be first reported device to
323 * to scsi-ml or sas transport, this purpose is for persistant boot device.
324 * There are primary, alternate, and current entries in bios page 2. The order
325 * priority is primary, alternate, then current. This routine saves
326 * the corresponding device object and is_raid flag in the ioc object.
327 * The saved data to be used later in _scsih_probe_boot_devices().
328 */
329static void
330_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
331 void *device, u8 is_raid)
332{
333 struct _sas_device *sas_device;
334 struct _raid_device *raid_device;
335 u64 sas_address;
336 u64 device_name;
337 u64 enclosure_logical_id;
338 u16 slot;
339
340 /* only process this function when driver loads */
341 if (!ioc->wait_for_port_enable_to_complete)
342 return;
343
344 if (!is_raid) {
345 sas_device = device;
346 sas_address = sas_device->sas_address;
347 device_name = sas_device->device_name;
348 enclosure_logical_id = sas_device->enclosure_logical_id;
349 slot = sas_device->slot;
350 } else {
351 raid_device = device;
352 sas_address = raid_device->wwid;
353 device_name = 0;
354 enclosure_logical_id = 0;
355 slot = 0;
356 }
357
358 if (!ioc->req_boot_device.device) {
359 if (_scsih_is_boot_device(sas_address, device_name,
360 enclosure_logical_id, slot,
361 (ioc->bios_pg2.ReqBootDeviceForm &
362 MPI2_BIOSPAGE2_FORM_MASK),
363 &ioc->bios_pg2.RequestedBootDevice)) {
364 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
365 "%s: req_boot_device(0x%016llx)\n",
366 ioc->name, __func__,
367 (unsigned long long)sas_address));
368 ioc->req_boot_device.device = device;
369 ioc->req_boot_device.is_raid = is_raid;
370 }
371 }
372
373 if (!ioc->req_alt_boot_device.device) {
374 if (_scsih_is_boot_device(sas_address, device_name,
375 enclosure_logical_id, slot,
376 (ioc->bios_pg2.ReqAltBootDeviceForm &
377 MPI2_BIOSPAGE2_FORM_MASK),
378 &ioc->bios_pg2.RequestedAltBootDevice)) {
379 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
380 "%s: req_alt_boot_device(0x%016llx)\n",
381 ioc->name, __func__,
382 (unsigned long long)sas_address));
383 ioc->req_alt_boot_device.device = device;
384 ioc->req_alt_boot_device.is_raid = is_raid;
385 }
386 }
387
388 if (!ioc->current_boot_device.device) {
389 if (_scsih_is_boot_device(sas_address, device_name,
390 enclosure_logical_id, slot,
391 (ioc->bios_pg2.CurrentBootDeviceForm &
392 MPI2_BIOSPAGE2_FORM_MASK),
393 &ioc->bios_pg2.CurrentBootDevice)) {
394 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
395 "%s: current_boot_device(0x%016llx)\n",
396 ioc->name, __func__,
397 (unsigned long long)sas_address));
398 ioc->current_boot_device.device = device;
399 ioc->current_boot_device.is_raid = is_raid;
400 }
401 }
402}
403
404/**
405 * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
406 * @ioc: per adapter object
407 * @sas_address: sas address
408 * Context: Calling function should acquire ioc->sas_device_lock
409 *
410 * This searches for sas_device based on sas_address, then return sas_device
411 * object.
412 */
413struct _sas_device *
414mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
415 u64 sas_address)
416{
417 struct _sas_device *sas_device, *r;
418
419 r = NULL;
420 /* check the sas_device_init_list */
421 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
422 list) {
423 if (sas_device->sas_address != sas_address)
424 continue;
425 r = sas_device;
426 goto out;
427 }
428
429 /* then check the sas_device_list */
430 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
431 if (sas_device->sas_address != sas_address)
432 continue;
433 r = sas_device;
434 goto out;
435 }
436 out:
437 return r;
438}
439
440/**
441 * _scsih_sas_device_find_by_handle - sas device search
442 * @ioc: per adapter object
443 * @handle: sas device handle (assigned by firmware)
444 * Context: Calling function should acquire ioc->sas_device_lock
445 *
446 * This searches for sas_device based on sas_address, then return sas_device
447 * object.
448 */
449static struct _sas_device *
450_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
451{
452 struct _sas_device *sas_device, *r;
453
454 r = NULL;
455 if (ioc->wait_for_port_enable_to_complete) {
456 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
457 list) {
458 if (sas_device->handle != handle)
459 continue;
460 r = sas_device;
461 goto out;
462 }
463 } else {
464 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
465 if (sas_device->handle != handle)
466 continue;
467 r = sas_device;
468 goto out;
469 }
470 }
471
472 out:
473 return r;
474}
475
476/**
477 * _scsih_sas_device_remove - remove sas_device from list.
478 * @ioc: per adapter object
479 * @sas_device: the sas_device object
480 * Context: This function will acquire ioc->sas_device_lock.
481 *
482 * Removing object and freeing associated memory from the ioc->sas_device_list.
483 */
484static void
485_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
486 struct _sas_device *sas_device)
487{
488 unsigned long flags;
489
490 spin_lock_irqsave(&ioc->sas_device_lock, flags);
491 list_del(&sas_device->list);
492 memset(sas_device, 0, sizeof(struct _sas_device));
493 kfree(sas_device);
494 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
495}
496
497/**
498 * _scsih_sas_device_add - insert sas_device to the list.
499 * @ioc: per adapter object
500 * @sas_device: the sas_device object
501 * Context: This function will acquire ioc->sas_device_lock.
502 *
503 * Adding new object to the ioc->sas_device_list.
504 */
505static void
506_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
507 struct _sas_device *sas_device)
508{
509 unsigned long flags;
510 u16 handle, parent_handle;
511 u64 sas_address;
512
513 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
514 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
515 sas_device->handle, (unsigned long long)sas_device->sas_address));
516
517 spin_lock_irqsave(&ioc->sas_device_lock, flags);
518 list_add_tail(&sas_device->list, &ioc->sas_device_list);
519 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
520
521 handle = sas_device->handle;
522 parent_handle = sas_device->parent_handle;
523 sas_address = sas_device->sas_address;
Eric Moore8901cbb2009-04-21 15:41:32 -0600524 if (!mpt2sas_transport_port_add(ioc, handle, parent_handle))
Eric Moore635374e2009-03-09 01:21:12 -0600525 _scsih_sas_device_remove(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -0600526}
527
528/**
529 * _scsih_sas_device_init_add - insert sas_device to the list.
530 * @ioc: per adapter object
531 * @sas_device: the sas_device object
532 * Context: This function will acquire ioc->sas_device_lock.
533 *
534 * Adding new object at driver load time to the ioc->sas_device_init_list.
535 */
536static void
537_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
538 struct _sas_device *sas_device)
539{
540 unsigned long flags;
541
542 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
543 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
544 sas_device->handle, (unsigned long long)sas_device->sas_address));
545
546 spin_lock_irqsave(&ioc->sas_device_lock, flags);
547 list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
548 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
549 _scsih_determine_boot_device(ioc, sas_device, 0);
550}
551
552/**
553 * mpt2sas_scsih_expander_find_by_handle - expander device search
554 * @ioc: per adapter object
555 * @handle: expander handle (assigned by firmware)
556 * Context: Calling function should acquire ioc->sas_device_lock
557 *
558 * This searches for expander device based on handle, then returns the
559 * sas_node object.
560 */
561struct _sas_node *
562mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
563{
564 struct _sas_node *sas_expander, *r;
565
566 r = NULL;
567 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
568 if (sas_expander->handle != handle)
569 continue;
570 r = sas_expander;
571 goto out;
572 }
573 out:
574 return r;
575}
576
577/**
578 * _scsih_raid_device_find_by_id - raid device search
579 * @ioc: per adapter object
580 * @id: sas device target id
581 * @channel: sas device channel
582 * Context: Calling function should acquire ioc->raid_device_lock
583 *
584 * This searches for raid_device based on target id, then return raid_device
585 * object.
586 */
587static struct _raid_device *
588_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
589{
590 struct _raid_device *raid_device, *r;
591
592 r = NULL;
593 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
594 if (raid_device->id == id && raid_device->channel == channel) {
595 r = raid_device;
596 goto out;
597 }
598 }
599
600 out:
601 return r;
602}
603
604/**
605 * _scsih_raid_device_find_by_handle - raid device search
606 * @ioc: per adapter object
607 * @handle: sas device handle (assigned by firmware)
608 * Context: Calling function should acquire ioc->raid_device_lock
609 *
610 * This searches for raid_device based on handle, then return raid_device
611 * object.
612 */
613static struct _raid_device *
614_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
615{
616 struct _raid_device *raid_device, *r;
617
618 r = NULL;
619 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
620 if (raid_device->handle != handle)
621 continue;
622 r = raid_device;
623 goto out;
624 }
625
626 out:
627 return r;
628}
629
630/**
631 * _scsih_raid_device_find_by_wwid - raid device search
632 * @ioc: per adapter object
633 * @handle: sas device handle (assigned by firmware)
634 * Context: Calling function should acquire ioc->raid_device_lock
635 *
636 * This searches for raid_device based on wwid, then return raid_device
637 * object.
638 */
639static struct _raid_device *
640_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
641{
642 struct _raid_device *raid_device, *r;
643
644 r = NULL;
645 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
646 if (raid_device->wwid != wwid)
647 continue;
648 r = raid_device;
649 goto out;
650 }
651
652 out:
653 return r;
654}
655
656/**
657 * _scsih_raid_device_add - add raid_device object
658 * @ioc: per adapter object
659 * @raid_device: raid_device object
660 *
661 * This is added to the raid_device_list link list.
662 */
663static void
664_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
665 struct _raid_device *raid_device)
666{
667 unsigned long flags;
668
669 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
670 "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
671 raid_device->handle, (unsigned long long)raid_device->wwid));
672
673 spin_lock_irqsave(&ioc->raid_device_lock, flags);
674 list_add_tail(&raid_device->list, &ioc->raid_device_list);
675 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
676}
677
678/**
679 * _scsih_raid_device_remove - delete raid_device object
680 * @ioc: per adapter object
681 * @raid_device: raid_device object
682 *
683 * This is removed from the raid_device_list link list.
684 */
685static void
686_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
687 struct _raid_device *raid_device)
688{
689 unsigned long flags;
690
691 spin_lock_irqsave(&ioc->raid_device_lock, flags);
692 list_del(&raid_device->list);
693 memset(raid_device, 0, sizeof(struct _raid_device));
694 kfree(raid_device);
695 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
696}
697
698/**
699 * mpt2sas_scsih_expander_find_by_sas_address - expander device search
700 * @ioc: per adapter object
701 * @sas_address: sas address
702 * Context: Calling function should acquire ioc->sas_node_lock.
703 *
704 * This searches for expander device based on sas_address, then returns the
705 * sas_node object.
706 */
707struct _sas_node *
708mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
709 u64 sas_address)
710{
711 struct _sas_node *sas_expander, *r;
712
713 r = NULL;
714 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
715 if (sas_expander->sas_address != sas_address)
716 continue;
717 r = sas_expander;
718 goto out;
719 }
720 out:
721 return r;
722}
723
724/**
725 * _scsih_expander_node_add - insert expander device to the list.
726 * @ioc: per adapter object
727 * @sas_expander: the sas_device object
728 * Context: This function will acquire ioc->sas_node_lock.
729 *
730 * Adding new object to the ioc->sas_expander_list.
731 *
732 * Return nothing.
733 */
734static void
735_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
736 struct _sas_node *sas_expander)
737{
738 unsigned long flags;
739
740 spin_lock_irqsave(&ioc->sas_node_lock, flags);
741 list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
742 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
743}
744
745/**
746 * _scsih_is_end_device - determines if device is an end device
747 * @device_info: bitfield providing information about the device.
748 * Context: none
749 *
750 * Returns 1 if end device.
751 */
752static int
753_scsih_is_end_device(u32 device_info)
754{
755 if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
756 ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
757 (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
758 (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
759 return 1;
760 else
761 return 0;
762}
763
764/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530765 * mptscsih_get_scsi_lookup - returns scmd entry
Eric Moore635374e2009-03-09 01:21:12 -0600766 * @ioc: per adapter object
767 * @smid: system request message index
Eric Moore635374e2009-03-09 01:21:12 -0600768 *
769 * Returns the smid stored scmd pointer.
770 */
771static struct scsi_cmnd *
772_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
773{
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530774 return ioc->scsi_lookup[smid - 1].scmd;
Eric Moore635374e2009-03-09 01:21:12 -0600775}
776
777/**
778 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
779 * @ioc: per adapter object
780 * @smid: system request message index
781 * @scmd: pointer to scsi command object
782 * Context: This function will acquire ioc->scsi_lookup_lock.
783 *
784 * This will search for a scmd pointer in the scsi_lookup array,
785 * returning the revelent smid. A returned value of zero means invalid.
786 */
787static u16
788_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
789 *scmd)
790{
791 u16 smid;
792 unsigned long flags;
793 int i;
794
795 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
796 smid = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530797 for (i = 0; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600798 if (ioc->scsi_lookup[i].scmd == scmd) {
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530799 smid = ioc->scsi_lookup[i].smid;
Eric Moore635374e2009-03-09 01:21:12 -0600800 goto out;
801 }
802 }
803 out:
804 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
805 return smid;
806}
807
808/**
809 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
810 * @ioc: per adapter object
811 * @id: target id
812 * @channel: channel
813 * Context: This function will acquire ioc->scsi_lookup_lock.
814 *
815 * This will search for a matching channel:id in the scsi_lookup array,
816 * returning 1 if found.
817 */
818static u8
819_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
820 int channel)
821{
822 u8 found;
823 unsigned long flags;
824 int i;
825
826 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
827 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530828 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600829 if (ioc->scsi_lookup[i].scmd &&
830 (ioc->scsi_lookup[i].scmd->device->id == id &&
831 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
832 found = 1;
833 goto out;
834 }
835 }
836 out:
837 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
838 return found;
839}
840
841/**
Eric Moore993e0da2009-05-18 13:00:45 -0600842 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
843 * @ioc: per adapter object
844 * @id: target id
845 * @lun: lun number
846 * @channel: channel
847 * Context: This function will acquire ioc->scsi_lookup_lock.
848 *
849 * This will search for a matching channel:id:lun in the scsi_lookup array,
850 * returning 1 if found.
851 */
852static u8
853_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
854 unsigned int lun, int channel)
855{
856 u8 found;
857 unsigned long flags;
858 int i;
859
860 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
861 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530862 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore993e0da2009-05-18 13:00:45 -0600863 if (ioc->scsi_lookup[i].scmd &&
864 (ioc->scsi_lookup[i].scmd->device->id == id &&
865 ioc->scsi_lookup[i].scmd->device->channel == channel &&
866 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
867 found = 1;
868 goto out;
869 }
870 }
871 out:
872 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
873 return found;
874}
875
876/**
Eric Moore635374e2009-03-09 01:21:12 -0600877 * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
878 * @ioc: per adapter object
879 * @smid: system request message index
880 *
881 * Returns phys pointer to chain buffer.
882 */
883static dma_addr_t
884_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
885{
886 return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
887 ioc->chains_needed_per_io));
888}
889
890/**
891 * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
892 * @ioc: per adapter object
893 * @smid: system request message index
894 *
895 * Returns virt pointer to chain buffer.
896 */
897static void *
898_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
899{
900 return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
901 ioc->chains_needed_per_io)));
902}
903
904/**
905 * _scsih_build_scatter_gather - main sg creation routine
906 * @ioc: per adapter object
907 * @scmd: scsi command
908 * @smid: system request message index
909 * Context: none.
910 *
911 * The main routine that builds scatter gather table from a given
912 * scsi request sent via the .queuecommand main handler.
913 *
914 * Returns 0 success, anything else error
915 */
916static int
917_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
918 struct scsi_cmnd *scmd, u16 smid)
919{
920 Mpi2SCSIIORequest_t *mpi_request;
921 dma_addr_t chain_dma;
922 struct scatterlist *sg_scmd;
923 void *sg_local, *chain;
924 u32 chain_offset;
925 u32 chain_length;
926 u32 chain_flags;
927 u32 sges_left;
928 u32 sges_in_segment;
929 u32 sgl_flags;
930 u32 sgl_flags_last_element;
931 u32 sgl_flags_end_buffer;
932
933 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
934
935 /* init scatter gather flags */
936 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
937 if (scmd->sc_data_direction == DMA_TO_DEVICE)
938 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
939 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
940 << MPI2_SGE_FLAGS_SHIFT;
941 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
942 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
943 << MPI2_SGE_FLAGS_SHIFT;
944 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
945
946 sg_scmd = scsi_sglist(scmd);
947 sges_left = scsi_dma_map(scmd);
948 if (!sges_left) {
949 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
950 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
951 return -ENOMEM;
952 }
953
954 sg_local = &mpi_request->SGL;
955 sges_in_segment = ioc->max_sges_in_main_message;
956 if (sges_left <= sges_in_segment)
957 goto fill_in_last_segment;
958
959 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
960 (sges_in_segment * ioc->sge_size))/4;
961
962 /* fill in main message segment when there is a chain following */
963 while (sges_in_segment) {
964 if (sges_in_segment == 1)
965 ioc->base_add_sg_single(sg_local,
966 sgl_flags_last_element | sg_dma_len(sg_scmd),
967 sg_dma_address(sg_scmd));
968 else
969 ioc->base_add_sg_single(sg_local, sgl_flags |
970 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
971 sg_scmd = sg_next(sg_scmd);
972 sg_local += ioc->sge_size;
973 sges_left--;
974 sges_in_segment--;
975 }
976
977 /* initializing the chain flags and pointers */
978 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
979 chain = _scsih_get_chain_buffer(ioc, smid);
980 chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
981 do {
982 sges_in_segment = (sges_left <=
983 ioc->max_sges_in_chain_message) ? sges_left :
984 ioc->max_sges_in_chain_message;
985 chain_offset = (sges_left == sges_in_segment) ?
986 0 : (sges_in_segment * ioc->sge_size)/4;
987 chain_length = sges_in_segment * ioc->sge_size;
988 if (chain_offset) {
989 chain_offset = chain_offset <<
990 MPI2_SGE_CHAIN_OFFSET_SHIFT;
991 chain_length += ioc->sge_size;
992 }
993 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
994 chain_length, chain_dma);
995 sg_local = chain;
996 if (!chain_offset)
997 goto fill_in_last_segment;
998
999 /* fill in chain segments */
1000 while (sges_in_segment) {
1001 if (sges_in_segment == 1)
1002 ioc->base_add_sg_single(sg_local,
1003 sgl_flags_last_element |
1004 sg_dma_len(sg_scmd),
1005 sg_dma_address(sg_scmd));
1006 else
1007 ioc->base_add_sg_single(sg_local, sgl_flags |
1008 sg_dma_len(sg_scmd),
1009 sg_dma_address(sg_scmd));
1010 sg_scmd = sg_next(sg_scmd);
1011 sg_local += ioc->sge_size;
1012 sges_left--;
1013 sges_in_segment--;
1014 }
1015
1016 chain_dma += ioc->request_sz;
1017 chain += ioc->request_sz;
1018 } while (1);
1019
1020
1021 fill_in_last_segment:
1022
1023 /* fill the last segment */
1024 while (sges_left) {
1025 if (sges_left == 1)
1026 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1027 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1028 else
1029 ioc->base_add_sg_single(sg_local, sgl_flags |
1030 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1031 sg_scmd = sg_next(sg_scmd);
1032 sg_local += ioc->sge_size;
1033 sges_left--;
1034 }
1035
1036 return 0;
1037}
1038
1039/**
Eric Moored5d135b2009-05-18 13:02:08 -06001040 * _scsih_change_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001041 * @sdev: scsi device struct
1042 * @qdepth: requested queue depth
1043 *
1044 * Returns queue depth.
1045 */
1046static int
Eric Moored5d135b2009-05-18 13:02:08 -06001047_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Eric Moore635374e2009-03-09 01:21:12 -06001048{
1049 struct Scsi_Host *shost = sdev->host;
1050 int max_depth;
1051 int tag_type;
1052
1053 max_depth = shost->can_queue;
1054 if (!sdev->tagged_supported)
1055 max_depth = 1;
1056 if (qdepth > max_depth)
1057 qdepth = max_depth;
1058 tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
1059 scsi_adjust_queue_depth(sdev, tag_type, qdepth);
1060
1061 if (sdev->inquiry_len > 7)
1062 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1063 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1064 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1065 sdev->ordered_tags, sdev->scsi_level,
1066 (sdev->inquiry[7] & 2) >> 1);
1067
1068 return sdev->queue_depth;
1069}
1070
1071/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301072 * _scsih_change_queue_type - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001073 * @sdev: scsi device struct
1074 * @tag_type: requested tag type
1075 *
1076 * Returns queue tag type.
1077 */
1078static int
Eric Moored5d135b2009-05-18 13:02:08 -06001079_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001080{
1081 if (sdev->tagged_supported) {
1082 scsi_set_tag_type(sdev, tag_type);
1083 if (tag_type)
1084 scsi_activate_tcq(sdev, sdev->queue_depth);
1085 else
1086 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1087 } else
1088 tag_type = 0;
1089
1090 return tag_type;
1091}
1092
1093/**
Eric Moored5d135b2009-05-18 13:02:08 -06001094 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001095 * @starget: scsi target struct
1096 *
1097 * Returns 0 if ok. Any other return is assumed to be an error and
1098 * the device is ignored.
1099 */
1100static int
Eric Moored5d135b2009-05-18 13:02:08 -06001101_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001102{
1103 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1104 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1105 struct MPT2SAS_TARGET *sas_target_priv_data;
1106 struct _sas_device *sas_device;
1107 struct _raid_device *raid_device;
1108 unsigned long flags;
1109 struct sas_rphy *rphy;
1110
1111 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1112 if (!sas_target_priv_data)
1113 return -ENOMEM;
1114
1115 starget->hostdata = sas_target_priv_data;
1116 sas_target_priv_data->starget = starget;
1117 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1118
1119 /* RAID volumes */
1120 if (starget->channel == RAID_CHANNEL) {
1121 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1122 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1123 starget->channel);
1124 if (raid_device) {
1125 sas_target_priv_data->handle = raid_device->handle;
1126 sas_target_priv_data->sas_address = raid_device->wwid;
1127 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
1128 raid_device->starget = starget;
1129 }
1130 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1131 return 0;
1132 }
1133
1134 /* sas/sata devices */
1135 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1136 rphy = dev_to_rphy(starget->dev.parent);
1137 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1138 rphy->identify.sas_address);
1139
1140 if (sas_device) {
1141 sas_target_priv_data->handle = sas_device->handle;
1142 sas_target_priv_data->sas_address = sas_device->sas_address;
1143 sas_device->starget = starget;
1144 sas_device->id = starget->id;
1145 sas_device->channel = starget->channel;
1146 if (sas_device->hidden_raid_component)
1147 sas_target_priv_data->flags |=
1148 MPT_TARGET_FLAGS_RAID_COMPONENT;
1149 }
1150 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1151
1152 return 0;
1153}
1154
1155/**
Eric Moored5d135b2009-05-18 13:02:08 -06001156 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001157 * @starget: scsi target struct
1158 *
1159 * Returns nothing.
1160 */
1161static void
Eric Moored5d135b2009-05-18 13:02:08 -06001162_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001163{
1164 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1165 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1166 struct MPT2SAS_TARGET *sas_target_priv_data;
1167 struct _sas_device *sas_device;
1168 struct _raid_device *raid_device;
1169 unsigned long flags;
1170 struct sas_rphy *rphy;
1171
1172 sas_target_priv_data = starget->hostdata;
1173 if (!sas_target_priv_data)
1174 return;
1175
1176 if (starget->channel == RAID_CHANNEL) {
1177 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1178 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1179 starget->channel);
1180 if (raid_device) {
1181 raid_device->starget = NULL;
1182 raid_device->sdev = NULL;
1183 }
1184 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1185 goto out;
1186 }
1187
1188 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1189 rphy = dev_to_rphy(starget->dev.parent);
1190 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1191 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001192 if (sas_device && (sas_device->starget == starget) &&
1193 (sas_device->id == starget->id) &&
1194 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001195 sas_device->starget = NULL;
1196
1197 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1198
1199 out:
1200 kfree(sas_target_priv_data);
1201 starget->hostdata = NULL;
1202}
1203
1204/**
Eric Moored5d135b2009-05-18 13:02:08 -06001205 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001206 * @sdev: scsi device struct
1207 *
1208 * Returns 0 if ok. Any other return is assumed to be an error and
1209 * the device is ignored.
1210 */
1211static int
Eric Moored5d135b2009-05-18 13:02:08 -06001212_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001213{
1214 struct Scsi_Host *shost;
1215 struct MPT2SAS_ADAPTER *ioc;
1216 struct MPT2SAS_TARGET *sas_target_priv_data;
1217 struct MPT2SAS_DEVICE *sas_device_priv_data;
1218 struct scsi_target *starget;
1219 struct _raid_device *raid_device;
1220 struct _sas_device *sas_device;
1221 unsigned long flags;
1222
1223 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1224 if (!sas_device_priv_data)
1225 return -ENOMEM;
1226
1227 sas_device_priv_data->lun = sdev->lun;
1228 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1229
1230 starget = scsi_target(sdev);
1231 sas_target_priv_data = starget->hostdata;
1232 sas_target_priv_data->num_luns++;
1233 sas_device_priv_data->sas_target = sas_target_priv_data;
1234 sdev->hostdata = sas_device_priv_data;
1235 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1236 sdev->no_uld_attach = 1;
1237
1238 shost = dev_to_shost(&starget->dev);
1239 ioc = shost_priv(shost);
1240 if (starget->channel == RAID_CHANNEL) {
1241 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1242 raid_device = _scsih_raid_device_find_by_id(ioc,
1243 starget->id, starget->channel);
1244 if (raid_device)
1245 raid_device->sdev = sdev; /* raid is single lun */
1246 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1247 } else {
1248 /* set TLR bit for SSP devices */
1249 if (!(ioc->facts.IOCCapabilities &
1250 MPI2_IOCFACTS_CAPABILITY_TLR))
1251 goto out;
1252 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1253 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1254 sas_device_priv_data->sas_target->sas_address);
1255 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1256 if (sas_device && sas_device->device_info &
1257 MPI2_SAS_DEVICE_INFO_SSP_TARGET)
1258 sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON;
1259 }
1260
1261 out:
1262 return 0;
1263}
1264
1265/**
Eric Moored5d135b2009-05-18 13:02:08 -06001266 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001267 * @sdev: scsi device struct
1268 *
1269 * Returns nothing.
1270 */
1271static void
Eric Moored5d135b2009-05-18 13:02:08 -06001272_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001273{
1274 struct MPT2SAS_TARGET *sas_target_priv_data;
1275 struct scsi_target *starget;
1276
1277 if (!sdev->hostdata)
1278 return;
1279
1280 starget = scsi_target(sdev);
1281 sas_target_priv_data = starget->hostdata;
1282 sas_target_priv_data->num_luns--;
1283 kfree(sdev->hostdata);
1284 sdev->hostdata = NULL;
1285}
1286
1287/**
Eric Moored5d135b2009-05-18 13:02:08 -06001288 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001289 * @ioc: per adapter object
1290 * @sas_device: the sas_device object
1291 * @sdev: scsi device struct
1292 */
1293static void
Eric Moored5d135b2009-05-18 13:02:08 -06001294_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06001295 struct _sas_device *sas_device, struct scsi_device *sdev)
1296{
1297 Mpi2ConfigReply_t mpi_reply;
1298 Mpi2SasDevicePage0_t sas_device_pg0;
1299 u32 ioc_status;
1300 u16 flags;
1301 u32 device_info;
1302
1303 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
1304 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
1305 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1306 ioc->name, __FILE__, __LINE__, __func__);
1307 return;
1308 }
1309
1310 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1311 MPI2_IOCSTATUS_MASK;
1312 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1313 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1314 ioc->name, __FILE__, __LINE__, __func__);
1315 return;
1316 }
1317
1318 flags = le16_to_cpu(sas_device_pg0.Flags);
1319 device_info = le16_to_cpu(sas_device_pg0.DeviceInfo);
1320
1321 sdev_printk(KERN_INFO, sdev,
1322 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1323 "sw_preserve(%s)\n",
1324 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1325 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1326 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1327 "n",
1328 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1329 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1330 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1331}
1332
1333/**
1334 * _scsih_get_volume_capabilities - volume capabilities
1335 * @ioc: per adapter object
1336 * @sas_device: the raid_device object
1337 */
1338static void
1339_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1340 struct _raid_device *raid_device)
1341{
1342 Mpi2RaidVolPage0_t *vol_pg0;
1343 Mpi2RaidPhysDiskPage0_t pd_pg0;
1344 Mpi2SasDevicePage0_t sas_device_pg0;
1345 Mpi2ConfigReply_t mpi_reply;
1346 u16 sz;
1347 u8 num_pds;
1348
1349 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1350 &num_pds)) || !num_pds) {
1351 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1352 ioc->name, __FILE__, __LINE__, __func__);
1353 return;
1354 }
1355
1356 raid_device->num_pds = num_pds;
1357 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1358 sizeof(Mpi2RaidVol0PhysDisk_t));
1359 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1360 if (!vol_pg0) {
1361 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1362 ioc->name, __FILE__, __LINE__, __func__);
1363 return;
1364 }
1365
1366 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1367 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1368 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1369 ioc->name, __FILE__, __LINE__, __func__);
1370 kfree(vol_pg0);
1371 return;
1372 }
1373
1374 raid_device->volume_type = vol_pg0->VolumeType;
1375
1376 /* figure out what the underlying devices are by
1377 * obtaining the device_info bits for the 1st device
1378 */
1379 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1380 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1381 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1382 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1383 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1384 le16_to_cpu(pd_pg0.DevHandle)))) {
1385 raid_device->device_info =
1386 le32_to_cpu(sas_device_pg0.DeviceInfo);
1387 }
1388 }
1389
1390 kfree(vol_pg0);
1391}
1392
1393/**
Eric Moored5d135b2009-05-18 13:02:08 -06001394 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001395 * @sdev: scsi device struct
1396 *
1397 * Returns 0 if ok. Any other return is assumed to be an error and
1398 * the device is ignored.
1399 */
1400static int
Eric Moored5d135b2009-05-18 13:02:08 -06001401_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001402{
1403 struct Scsi_Host *shost = sdev->host;
1404 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1405 struct MPT2SAS_DEVICE *sas_device_priv_data;
1406 struct MPT2SAS_TARGET *sas_target_priv_data;
1407 struct _sas_device *sas_device;
1408 struct _raid_device *raid_device;
1409 unsigned long flags;
1410 int qdepth;
1411 u8 ssp_target = 0;
1412 char *ds = "";
1413 char *r_level = "";
1414
1415 qdepth = 1;
1416 sas_device_priv_data = sdev->hostdata;
1417 sas_device_priv_data->configured_lun = 1;
1418 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1419 sas_target_priv_data = sas_device_priv_data->sas_target;
1420
1421 /* raid volume handling */
1422 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1423
1424 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1425 raid_device = _scsih_raid_device_find_by_handle(ioc,
1426 sas_target_priv_data->handle);
1427 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1428 if (!raid_device) {
1429 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1430 ioc->name, __FILE__, __LINE__, __func__);
1431 return 0;
1432 }
1433
1434 _scsih_get_volume_capabilities(ioc, raid_device);
1435
1436 /* RAID Queue Depth Support
1437 * IS volume = underlying qdepth of drive type, either
1438 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
1439 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
1440 */
1441 if (raid_device->device_info &
1442 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1443 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1444 ds = "SSP";
1445 } else {
1446 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1447 if (raid_device->device_info &
1448 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1449 ds = "SATA";
1450 else
1451 ds = "STP";
1452 }
1453
1454 switch (raid_device->volume_type) {
1455 case MPI2_RAID_VOL_TYPE_RAID0:
1456 r_level = "RAID0";
1457 break;
1458 case MPI2_RAID_VOL_TYPE_RAID1E:
1459 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05301460 if (ioc->manu_pg10.OEMIdentifier &&
1461 (ioc->manu_pg10.GenericFlags0 &
1462 MFG10_GF0_R10_DISPLAY) &&
1463 !(raid_device->num_pds % 2))
1464 r_level = "RAID10";
1465 else
1466 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06001467 break;
1468 case MPI2_RAID_VOL_TYPE_RAID1:
1469 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1470 r_level = "RAID1";
1471 break;
1472 case MPI2_RAID_VOL_TYPE_RAID10:
1473 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1474 r_level = "RAID10";
1475 break;
1476 case MPI2_RAID_VOL_TYPE_UNKNOWN:
1477 default:
1478 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1479 r_level = "RAIDX";
1480 break;
1481 }
1482
1483 sdev_printk(KERN_INFO, sdev, "%s: "
1484 "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
1485 r_level, raid_device->handle,
1486 (unsigned long long)raid_device->wwid,
1487 raid_device->num_pds, ds);
Eric Moored5d135b2009-05-18 13:02:08 -06001488 _scsih_change_queue_depth(sdev, qdepth);
Eric Moore635374e2009-03-09 01:21:12 -06001489 return 0;
1490 }
1491
1492 /* non-raid handling */
1493 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1494 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1495 sas_device_priv_data->sas_target->sas_address);
1496 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1497 if (sas_device) {
1498 if (sas_target_priv_data->flags &
1499 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1500 mpt2sas_config_get_volume_handle(ioc,
1501 sas_device->handle, &sas_device->volume_handle);
1502 mpt2sas_config_get_volume_wwid(ioc,
1503 sas_device->volume_handle,
1504 &sas_device->volume_wwid);
1505 }
1506 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1507 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1508 ssp_target = 1;
1509 ds = "SSP";
1510 } else {
1511 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1512 if (sas_device->device_info &
1513 MPI2_SAS_DEVICE_INFO_STP_TARGET)
1514 ds = "STP";
1515 else if (sas_device->device_info &
1516 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1517 ds = "SATA";
1518 }
1519
1520 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
1521 "sas_addr(0x%016llx), device_name(0x%016llx)\n",
1522 ds, sas_device->handle,
1523 (unsigned long long)sas_device->sas_address,
1524 (unsigned long long)sas_device->device_name);
1525 sdev_printk(KERN_INFO, sdev, "%s: "
1526 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
1527 (unsigned long long) sas_device->enclosure_logical_id,
1528 sas_device->slot);
1529
1530 if (!ssp_target)
Eric Moored5d135b2009-05-18 13:02:08 -06001531 _scsih_display_sata_capabilities(ioc, sas_device, sdev);
Eric Moore635374e2009-03-09 01:21:12 -06001532 }
1533
Eric Moored5d135b2009-05-18 13:02:08 -06001534 _scsih_change_queue_depth(sdev, qdepth);
Eric Moore635374e2009-03-09 01:21:12 -06001535
1536 if (ssp_target)
1537 sas_read_port_mode_page(sdev);
1538 return 0;
1539}
1540
1541/**
Eric Moored5d135b2009-05-18 13:02:08 -06001542 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06001543 * @sdev: scsi device struct
1544 * @bdev: pointer to block device context
1545 * @capacity: device size (in 512 byte sectors)
1546 * @params: three element array to place output:
1547 * params[0] number of heads (max 255)
1548 * params[1] number of sectors (max 63)
1549 * params[2] number of cylinders
1550 *
1551 * Return nothing.
1552 */
1553static int
Eric Moored5d135b2009-05-18 13:02:08 -06001554_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06001555 sector_t capacity, int params[])
1556{
1557 int heads;
1558 int sectors;
1559 sector_t cylinders;
1560 ulong dummy;
1561
1562 heads = 64;
1563 sectors = 32;
1564
1565 dummy = heads * sectors;
1566 cylinders = capacity;
1567 sector_div(cylinders, dummy);
1568
1569 /*
1570 * Handle extended translation size for logical drives
1571 * > 1Gb
1572 */
1573 if ((ulong)capacity >= 0x200000) {
1574 heads = 255;
1575 sectors = 63;
1576 dummy = heads * sectors;
1577 cylinders = capacity;
1578 sector_div(cylinders, dummy);
1579 }
1580
1581 /* return result */
1582 params[0] = heads;
1583 params[1] = sectors;
1584 params[2] = cylinders;
1585
1586 return 0;
1587}
1588
1589/**
1590 * _scsih_response_code - translation of device response code
1591 * @ioc: per adapter object
1592 * @response_code: response code returned by the device
1593 *
1594 * Return nothing.
1595 */
1596static void
1597_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
1598{
1599 char *desc;
1600
1601 switch (response_code) {
1602 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1603 desc = "task management request completed";
1604 break;
1605 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1606 desc = "invalid frame";
1607 break;
1608 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1609 desc = "task management request not supported";
1610 break;
1611 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1612 desc = "task management request failed";
1613 break;
1614 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1615 desc = "task management request succeeded";
1616 break;
1617 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1618 desc = "invalid lun";
1619 break;
1620 case 0xA:
1621 desc = "overlapped tag attempted";
1622 break;
1623 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1624 desc = "task queued, however not sent to target";
1625 break;
1626 default:
1627 desc = "unknown";
1628 break;
1629 }
1630 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
1631 ioc->name, response_code, desc);
1632}
1633
1634/**
Eric Moored5d135b2009-05-18 13:02:08 -06001635 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06001636 * @ioc: per adapter object
1637 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301638 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001639 * @reply: reply message frame(lower 32bit addr)
1640 * Context: none.
1641 *
1642 * The callback handler when using scsih_issue_tm.
1643 *
1644 * Return nothing.
1645 */
1646static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301647_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06001648{
1649 MPI2DefaultReply_t *mpi_reply;
1650
1651 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
1652 return;
1653 if (ioc->tm_cmds.smid != smid)
1654 return;
1655 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
1656 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
1657 if (mpi_reply) {
1658 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
1659 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
1660 }
1661 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
1662 complete(&ioc->tm_cmds.done);
1663}
1664
1665/**
1666 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
1667 * @ioc: per adapter object
1668 * @handle: device handle
1669 *
1670 * During taskmangement request, we need to freeze the device queue.
1671 */
1672void
1673mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1674{
1675 struct MPT2SAS_DEVICE *sas_device_priv_data;
1676 struct scsi_device *sdev;
1677 u8 skip = 0;
1678
1679 shost_for_each_device(sdev, ioc->shost) {
1680 if (skip)
1681 continue;
1682 sas_device_priv_data = sdev->hostdata;
1683 if (!sas_device_priv_data)
1684 continue;
1685 if (sas_device_priv_data->sas_target->handle == handle) {
1686 sas_device_priv_data->sas_target->tm_busy = 1;
1687 skip = 1;
1688 ioc->ignore_loginfos = 1;
1689 }
1690 }
1691}
1692
1693/**
1694 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
1695 * @ioc: per adapter object
1696 * @handle: device handle
1697 *
1698 * During taskmangement request, we need to freeze the device queue.
1699 */
1700void
1701mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1702{
1703 struct MPT2SAS_DEVICE *sas_device_priv_data;
1704 struct scsi_device *sdev;
1705 u8 skip = 0;
1706
1707 shost_for_each_device(sdev, ioc->shost) {
1708 if (skip)
1709 continue;
1710 sas_device_priv_data = sdev->hostdata;
1711 if (!sas_device_priv_data)
1712 continue;
1713 if (sas_device_priv_data->sas_target->handle == handle) {
1714 sas_device_priv_data->sas_target->tm_busy = 0;
1715 skip = 1;
1716 ioc->ignore_loginfos = 0;
1717 }
1718 }
1719}
1720
1721/**
1722 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
1723 * @ioc: per adapter struct
1724 * @device_handle: device handle
1725 * @lun: lun number
1726 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
1727 * @smid_task: smid assigned to the task
1728 * @timeout: timeout in seconds
1729 * Context: The calling function needs to acquire the tm_cmds.mutex
1730 *
1731 * A generic API for sending task management requests to firmware.
1732 *
1733 * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling
1734 * this API.
1735 *
1736 * The callback index is set inside `ioc->tm_cb_idx`.
1737 *
1738 * Return nothing.
1739 */
1740void
1741mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
1742 u8 type, u16 smid_task, ulong timeout)
1743{
1744 Mpi2SCSITaskManagementRequest_t *mpi_request;
1745 Mpi2SCSITaskManagementReply_t *mpi_reply;
1746 u16 smid = 0;
1747 u32 ioc_state;
1748 unsigned long timeleft;
Eric Moore635374e2009-03-09 01:21:12 -06001749
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301750 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
1751 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
1752 __func__, ioc->name);
1753 return;
1754 }
1755
1756 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06001757 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1758 __func__, ioc->name);
1759 return;
1760 }
Eric Moore635374e2009-03-09 01:21:12 -06001761
1762 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
1763 if (ioc_state & MPI2_DOORBELL_USED) {
1764 dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
1765 "active!\n", ioc->name));
1766 goto issue_host_reset;
1767 }
1768
1769 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
1770 mpt2sas_base_fault_info(ioc, ioc_state &
1771 MPI2_DOORBELL_DATA_MASK);
1772 goto issue_host_reset;
1773 }
1774
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301775 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06001776 if (!smid) {
1777 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1778 ioc->name, __func__);
1779 return;
1780 }
1781
1782 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301783 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
1784 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06001785 ioc->tm_cmds.status = MPT2_CMD_PENDING;
1786 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1787 ioc->tm_cmds.smid = smid;
1788 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
1789 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1790 mpi_request->DevHandle = cpu_to_le16(handle);
1791 mpi_request->TaskType = type;
1792 mpi_request->TaskMID = cpu_to_le16(smid_task);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301793 mpi_request->VP_ID = 0; /* TODO */
1794 mpi_request->VF_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06001795 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
1796 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05301797 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301798 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06001799 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
1800 mpt2sas_scsih_clear_tm_flag(ioc, handle);
1801 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
1802 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
1803 ioc->name, __func__);
1804 _debug_dump_mf(mpi_request,
1805 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
1806 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET))
1807 goto issue_host_reset;
1808 }
1809
1810 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
1811 mpi_reply = ioc->tm_cmds.reply;
1812 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
1813 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
1814 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
1815 le32_to_cpu(mpi_reply->IOCLogInfo),
1816 le32_to_cpu(mpi_reply->TerminationCount)));
1817 if (ioc->logging_level & MPT_DEBUG_TM)
1818 _scsih_response_code(ioc, mpi_reply->ResponseCode);
1819 }
1820 return;
1821 issue_host_reset:
1822 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
1823}
1824
1825/**
Eric Moored5d135b2009-05-18 13:02:08 -06001826 * _scsih_abort - eh threads main abort routine
Eric Moore635374e2009-03-09 01:21:12 -06001827 * @sdev: scsi device struct
1828 *
1829 * Returns SUCCESS if command aborted else FAILED
1830 */
1831static int
Eric Moored5d135b2009-05-18 13:02:08 -06001832_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001833{
1834 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1835 struct MPT2SAS_DEVICE *sas_device_priv_data;
1836 u16 smid;
1837 u16 handle;
1838 int r;
1839 struct scsi_cmnd *scmd_lookup;
1840
1841 printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
1842 ioc->name, scmd);
1843 scsi_print_command(scmd);
1844
1845 sas_device_priv_data = scmd->device->hostdata;
1846 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1847 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
1848 ioc->name, scmd);
1849 scmd->result = DID_NO_CONNECT << 16;
1850 scmd->scsi_done(scmd);
1851 r = SUCCESS;
1852 goto out;
1853 }
1854
1855 /* search for the command */
1856 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
1857 if (!smid) {
1858 scmd->result = DID_RESET << 16;
1859 r = SUCCESS;
1860 goto out;
1861 }
1862
1863 /* for hidden raid components and volumes this is not supported */
1864 if (sas_device_priv_data->sas_target->flags &
1865 MPT_TARGET_FLAGS_RAID_COMPONENT ||
1866 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
1867 scmd->result = DID_RESET << 16;
1868 r = FAILED;
1869 goto out;
1870 }
1871
1872 mutex_lock(&ioc->tm_cmds.mutex);
1873 handle = sas_device_priv_data->sas_target->handle;
1874 mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
1875 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30);
1876
1877 /* sanity check - see whether command actually completed */
1878 scmd_lookup = _scsih_scsi_lookup_get(ioc, smid);
1879 if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number))
1880 r = FAILED;
1881 else
1882 r = SUCCESS;
1883 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
1884 mutex_unlock(&ioc->tm_cmds.mutex);
1885
1886 out:
1887 printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
1888 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
1889 return r;
1890}
1891
Eric Moore635374e2009-03-09 01:21:12 -06001892/**
Eric Moored5d135b2009-05-18 13:02:08 -06001893 * _scsih_dev_reset - eh threads main device reset routine
Eric Moore635374e2009-03-09 01:21:12 -06001894 * @sdev: scsi device struct
1895 *
1896 * Returns SUCCESS if command aborted else FAILED
1897 */
1898static int
Eric Moored5d135b2009-05-18 13:02:08 -06001899_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001900{
1901 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1902 struct MPT2SAS_DEVICE *sas_device_priv_data;
1903 struct _sas_device *sas_device;
1904 unsigned long flags;
1905 u16 handle;
1906 int r;
1907
Eric Moore993e0da2009-05-18 13:00:45 -06001908 printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
Eric Moore635374e2009-03-09 01:21:12 -06001909 ioc->name, scmd);
1910 scsi_print_command(scmd);
1911
1912 sas_device_priv_data = scmd->device->hostdata;
1913 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1914 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
1915 ioc->name, scmd);
1916 scmd->result = DID_NO_CONNECT << 16;
1917 scmd->scsi_done(scmd);
1918 r = SUCCESS;
1919 goto out;
1920 }
1921
1922 /* for hidden raid components obtain the volume_handle */
1923 handle = 0;
1924 if (sas_device_priv_data->sas_target->flags &
1925 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1926 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1927 sas_device = _scsih_sas_device_find_by_handle(ioc,
1928 sas_device_priv_data->sas_target->handle);
1929 if (sas_device)
1930 handle = sas_device->volume_handle;
1931 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1932 } else
1933 handle = sas_device_priv_data->sas_target->handle;
1934
1935 if (!handle) {
1936 scmd->result = DID_RESET << 16;
1937 r = FAILED;
1938 goto out;
1939 }
1940
1941 mutex_lock(&ioc->tm_cmds.mutex);
1942 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore993e0da2009-05-18 13:00:45 -06001943 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun,
1944 30);
1945
1946 /*
1947 * sanity check see whether all commands to this device been
1948 * completed
1949 */
1950 if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id,
1951 scmd->device->lun, scmd->device->channel))
1952 r = FAILED;
1953 else
1954 r = SUCCESS;
1955 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
1956 mutex_unlock(&ioc->tm_cmds.mutex);
1957
1958 out:
1959 printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
1960 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
1961 return r;
1962}
1963
1964/**
Eric Moored5d135b2009-05-18 13:02:08 -06001965 * _scsih_target_reset - eh threads main target reset routine
Eric Moore993e0da2009-05-18 13:00:45 -06001966 * @sdev: scsi device struct
1967 *
1968 * Returns SUCCESS if command aborted else FAILED
1969 */
1970static int
Eric Moored5d135b2009-05-18 13:02:08 -06001971_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06001972{
1973 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1974 struct MPT2SAS_DEVICE *sas_device_priv_data;
1975 struct _sas_device *sas_device;
1976 unsigned long flags;
1977 u16 handle;
1978 int r;
1979
1980 printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
1981 ioc->name, scmd);
1982 scsi_print_command(scmd);
1983
1984 sas_device_priv_data = scmd->device->hostdata;
1985 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1986 printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
1987 ioc->name, scmd);
1988 scmd->result = DID_NO_CONNECT << 16;
1989 scmd->scsi_done(scmd);
1990 r = SUCCESS;
1991 goto out;
1992 }
1993
1994 /* for hidden raid components obtain the volume_handle */
1995 handle = 0;
1996 if (sas_device_priv_data->sas_target->flags &
1997 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1998 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1999 sas_device = _scsih_sas_device_find_by_handle(ioc,
2000 sas_device_priv_data->sas_target->handle);
2001 if (sas_device)
2002 handle = sas_device->volume_handle;
2003 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2004 } else
2005 handle = sas_device_priv_data->sas_target->handle;
2006
2007 if (!handle) {
2008 scmd->result = DID_RESET << 16;
2009 r = FAILED;
2010 goto out;
2011 }
2012
2013 mutex_lock(&ioc->tm_cmds.mutex);
2014 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore635374e2009-03-09 01:21:12 -06002015 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30);
2016
2017 /*
2018 * sanity check see whether all commands to this target been
2019 * completed
2020 */
2021 if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id,
2022 scmd->device->channel))
2023 r = FAILED;
2024 else
2025 r = SUCCESS;
2026 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2027 mutex_unlock(&ioc->tm_cmds.mutex);
2028
2029 out:
2030 printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
2031 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2032 return r;
2033}
2034
2035/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302036 * _scsih_host_reset - eh threads main host reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002037 * @sdev: scsi device struct
2038 *
2039 * Returns SUCCESS if command aborted else FAILED
2040 */
2041static int
Eric Moored5d135b2009-05-18 13:02:08 -06002042_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002043{
2044 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2045 int r, retval;
2046
2047 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2048 ioc->name, scmd);
2049 scsi_print_command(scmd);
2050
2051 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2052 FORCE_BIG_HAMMER);
2053 r = (retval < 0) ? FAILED : SUCCESS;
2054 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2055 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2056
2057 return r;
2058}
2059
2060/**
2061 * _scsih_fw_event_add - insert and queue up fw_event
2062 * @ioc: per adapter object
2063 * @fw_event: object describing the event
2064 * Context: This function will acquire ioc->fw_event_lock.
2065 *
2066 * This adds the firmware event object into link list, then queues it up to
2067 * be processed from user context.
2068 *
2069 * Return nothing.
2070 */
2071static void
2072_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2073{
2074 unsigned long flags;
2075
2076 if (ioc->firmware_event_thread == NULL)
2077 return;
2078
2079 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2080 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002081 INIT_WORK(&fw_event->work, _firmware_event_work);
2082 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002083 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2084}
2085
2086/**
2087 * _scsih_fw_event_free - delete fw_event
2088 * @ioc: per adapter object
2089 * @fw_event: object describing the event
2090 * Context: This function will acquire ioc->fw_event_lock.
2091 *
2092 * This removes firmware event object from link list, frees associated memory.
2093 *
2094 * Return nothing.
2095 */
2096static void
2097_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2098 *fw_event)
2099{
2100 unsigned long flags;
2101
2102 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2103 list_del(&fw_event->list);
2104 kfree(fw_event->event_data);
2105 kfree(fw_event);
2106 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2107}
2108
2109/**
2110 * _scsih_fw_event_add - requeue an event
2111 * @ioc: per adapter object
2112 * @fw_event: object describing the event
2113 * Context: This function will acquire ioc->fw_event_lock.
2114 *
2115 * Return nothing.
2116 */
2117static void
2118_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2119 *fw_event, unsigned long delay)
2120{
2121 unsigned long flags;
2122 if (ioc->firmware_event_thread == NULL)
2123 return;
2124
2125 spin_lock_irqsave(&ioc->fw_event_lock, flags);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002126 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002127 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2128}
2129
2130/**
2131 * _scsih_fw_event_off - turn flag off preventing event handling
2132 * @ioc: per adapter object
2133 *
2134 * Used to prevent handling of firmware events during adapter reset
2135 * driver unload.
2136 *
2137 * Return nothing.
2138 */
2139static void
2140_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc)
2141{
2142 unsigned long flags;
2143
2144 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2145 ioc->fw_events_off = 1;
2146 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2147
2148}
2149
2150/**
2151 * _scsih_fw_event_on - turn flag on allowing firmware event handling
2152 * @ioc: per adapter object
2153 *
2154 * Returns nothing.
2155 */
2156static void
2157_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc)
2158{
2159 unsigned long flags;
2160
2161 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2162 ioc->fw_events_off = 0;
2163 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2164}
2165
2166/**
2167 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2168 * @ioc: per adapter object
2169 * @handle: device handle
2170 *
2171 * During device pull we need to appropiately set the sdev state.
2172 */
2173static void
2174_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2175{
2176 struct MPT2SAS_DEVICE *sas_device_priv_data;
2177 struct scsi_device *sdev;
2178
2179 shost_for_each_device(sdev, ioc->shost) {
2180 sas_device_priv_data = sdev->hostdata;
2181 if (!sas_device_priv_data)
2182 continue;
2183 if (!sas_device_priv_data->block)
2184 continue;
2185 if (sas_device_priv_data->sas_target->handle == handle) {
2186 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2187 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2188 "handle(0x%04x)\n", ioc->name, handle));
2189 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302190 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002191 }
2192 }
2193}
2194
2195/**
2196 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2197 * @ioc: per adapter object
2198 * @handle: device handle
2199 *
2200 * During device pull we need to appropiately set the sdev state.
2201 */
2202static void
2203_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2204{
2205 struct MPT2SAS_DEVICE *sas_device_priv_data;
2206 struct scsi_device *sdev;
2207
2208 shost_for_each_device(sdev, ioc->shost) {
2209 sas_device_priv_data = sdev->hostdata;
2210 if (!sas_device_priv_data)
2211 continue;
2212 if (sas_device_priv_data->block)
2213 continue;
2214 if (sas_device_priv_data->sas_target->handle == handle) {
2215 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2216 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2217 "handle(0x%04x)\n", ioc->name, handle));
2218 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302219 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002220 }
2221 }
2222}
2223
2224/**
2225 * _scsih_block_io_to_children_attached_to_ex
2226 * @ioc: per adapter object
2227 * @sas_expander: the sas_device object
2228 *
2229 * This routine set sdev state to SDEV_BLOCK for all devices
2230 * attached to this expander. This function called when expander is
2231 * pulled.
2232 */
2233static void
2234_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2235 struct _sas_node *sas_expander)
2236{
2237 struct _sas_port *mpt2sas_port;
2238 struct _sas_device *sas_device;
2239 struct _sas_node *expander_sibling;
2240 unsigned long flags;
2241
2242 if (!sas_expander)
2243 return;
2244
2245 list_for_each_entry(mpt2sas_port,
2246 &sas_expander->sas_port_list, port_list) {
2247 if (mpt2sas_port->remote_identify.device_type ==
2248 SAS_END_DEVICE) {
2249 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2250 sas_device =
2251 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2252 mpt2sas_port->remote_identify.sas_address);
2253 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2254 if (!sas_device)
2255 continue;
2256 _scsih_block_io_device(ioc, sas_device->handle);
2257 }
2258 }
2259
2260 list_for_each_entry(mpt2sas_port,
2261 &sas_expander->sas_port_list, port_list) {
2262
2263 if (mpt2sas_port->remote_identify.device_type ==
2264 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2265 mpt2sas_port->remote_identify.device_type ==
2266 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2267
2268 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2269 expander_sibling =
2270 mpt2sas_scsih_expander_find_by_sas_address(
2271 ioc, mpt2sas_port->remote_identify.sas_address);
2272 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2273 _scsih_block_io_to_children_attached_to_ex(ioc,
2274 expander_sibling);
2275 }
2276 }
2277}
2278
2279/**
2280 * _scsih_block_io_to_children_attached_directly
2281 * @ioc: per adapter object
2282 * @event_data: topology change event data
2283 *
2284 * This routine set sdev state to SDEV_BLOCK for all devices
2285 * direct attached during device pull.
2286 */
2287static void
2288_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2289 Mpi2EventDataSasTopologyChangeList_t *event_data)
2290{
2291 int i;
2292 u16 handle;
2293 u16 reason_code;
2294 u8 phy_number;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302295 u8 link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06002296
2297 for (i = 0; i < event_data->NumEntries; i++) {
2298 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2299 if (!handle)
2300 continue;
2301 phy_number = event_data->StartPhyNum + i;
2302 reason_code = event_data->PHY[i].PhyStatus &
2303 MPI2_EVENT_SAS_TOPO_RC_MASK;
2304 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2305 _scsih_block_io_device(ioc, handle);
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302306 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) {
2307 link_rate = event_data->PHY[i].LinkRate >> 4;
2308 if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
2309 _scsih_ublock_io_device(ioc, handle);
2310 }
Eric Moore635374e2009-03-09 01:21:12 -06002311 }
2312}
2313
2314/**
2315 * _scsih_check_topo_delete_events - sanity check on topo events
2316 * @ioc: per adapter object
2317 * @event_data: the event data payload
2318 *
2319 * This routine added to better handle cable breaker.
2320 *
2321 * This handles the case where driver recieves multiple expander
2322 * add and delete events in a single shot. When there is a delete event
2323 * the routine will void any pending add events waiting in the event queue.
2324 *
2325 * Return nothing.
2326 */
2327static void
2328_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
2329 Mpi2EventDataSasTopologyChangeList_t *event_data)
2330{
2331 struct fw_event_work *fw_event;
2332 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
2333 u16 expander_handle;
2334 struct _sas_node *sas_expander;
2335 unsigned long flags;
2336
2337 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
2338 if (expander_handle < ioc->sas_hba.num_phys) {
2339 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2340 return;
2341 }
2342
2343 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
2344 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
2345 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2346 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
2347 expander_handle);
2348 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2349 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
2350 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
2351 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2352
2353 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
2354 return;
2355
2356 /* mark ignore flag for pending events */
2357 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2358 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
2359 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
2360 fw_event->ignore)
2361 continue;
2362 local_event_data = fw_event->event_data;
2363 if (local_event_data->ExpStatus ==
2364 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
2365 local_event_data->ExpStatus ==
2366 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
2367 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
2368 expander_handle) {
2369 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
2370 "setting ignoring flag\n", ioc->name));
2371 fw_event->ignore = 1;
2372 }
2373 }
2374 }
2375 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2376}
2377
2378/**
Eric Moore635374e2009-03-09 01:21:12 -06002379 * _scsih_flush_running_cmds - completing outstanding commands.
2380 * @ioc: per adapter object
2381 *
2382 * The flushing out of all pending scmd commands following host reset,
2383 * where all IO is dropped to the floor.
2384 *
2385 * Return nothing.
2386 */
2387static void
2388_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
2389{
2390 struct scsi_cmnd *scmd;
2391 u16 smid;
2392 u16 count = 0;
2393
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302394 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
2395 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002396 if (!scmd)
2397 continue;
2398 count++;
2399 mpt2sas_base_free_smid(ioc, smid);
2400 scsi_dma_unmap(scmd);
2401 scmd->result = DID_RESET << 16;
2402 scmd->scsi_done(scmd);
2403 }
2404 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
2405 ioc->name, count));
2406}
2407
2408/**
Eric Moore3c621b32009-05-18 12:59:41 -06002409 * _scsih_setup_eedp - setup MPI request for EEDP transfer
2410 * @scmd: pointer to scsi command object
2411 * @mpi_request: pointer to the SCSI_IO reqest message frame
2412 *
2413 * Supporting protection 1 and 3.
2414 *
2415 * Returns nothing
2416 */
2417static void
2418_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
2419{
2420 u16 eedp_flags;
2421 unsigned char prot_op = scsi_get_prot_op(scmd);
2422 unsigned char prot_type = scsi_get_prot_type(scmd);
2423
2424 if (prot_type == SCSI_PROT_DIF_TYPE0 ||
2425 prot_type == SCSI_PROT_DIF_TYPE2 ||
2426 prot_op == SCSI_PROT_NORMAL)
2427 return;
2428
2429 if (prot_op == SCSI_PROT_READ_STRIP)
2430 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
2431 else if (prot_op == SCSI_PROT_WRITE_INSERT)
2432 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
2433 else
2434 return;
2435
2436 mpi_request->EEDPBlockSize = scmd->device->sector_size;
2437
2438 switch (prot_type) {
2439 case SCSI_PROT_DIF_TYPE1:
2440
2441 /*
2442 * enable ref/guard checking
2443 * auto increment ref tag
2444 */
2445 mpi_request->EEDPFlags = eedp_flags |
2446 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
2447 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2448 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2449 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
2450 cpu_to_be32(scsi_get_lba(scmd));
2451
2452 break;
2453
2454 case SCSI_PROT_DIF_TYPE3:
2455
2456 /*
2457 * enable guard checking
2458 */
2459 mpi_request->EEDPFlags = eedp_flags |
2460 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2461
2462 break;
2463 }
2464}
2465
2466/**
2467 * _scsih_eedp_error_handling - return sense code for EEDP errors
2468 * @scmd: pointer to scsi command object
2469 * @ioc_status: ioc status
2470 *
2471 * Returns nothing
2472 */
2473static void
2474_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
2475{
2476 u8 ascq;
2477 u8 sk;
2478 u8 host_byte;
2479
2480 switch (ioc_status) {
2481 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2482 ascq = 0x01;
2483 break;
2484 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2485 ascq = 0x02;
2486 break;
2487 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2488 ascq = 0x03;
2489 break;
2490 default:
2491 ascq = 0x00;
2492 break;
2493 }
2494
2495 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
2496 sk = ILLEGAL_REQUEST;
2497 host_byte = DID_ABORT;
2498 } else {
2499 sk = ABORTED_COMMAND;
2500 host_byte = DID_OK;
2501 }
2502
2503 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
2504 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
2505 SAM_STAT_CHECK_CONDITION;
2506}
2507
2508/**
Eric Moored5d135b2009-05-18 13:02:08 -06002509 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06002510 * @scmd: pointer to scsi command object
2511 * @done: function pointer to be invoked on completion
2512 *
2513 * The callback index is set inside `ioc->scsi_io_cb_idx`.
2514 *
2515 * Returns 0 on success. If there's a failure, return either:
2516 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
2517 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
2518 */
2519static int
Eric Moored5d135b2009-05-18 13:02:08 -06002520_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06002521{
2522 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2523 struct MPT2SAS_DEVICE *sas_device_priv_data;
2524 struct MPT2SAS_TARGET *sas_target_priv_data;
2525 Mpi2SCSIIORequest_t *mpi_request;
2526 u32 mpi_control;
2527 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06002528
2529 scmd->scsi_done = done;
2530 sas_device_priv_data = scmd->device->hostdata;
2531 if (!sas_device_priv_data) {
2532 scmd->result = DID_NO_CONNECT << 16;
2533 scmd->scsi_done(scmd);
2534 return 0;
2535 }
2536
2537 sas_target_priv_data = sas_device_priv_data->sas_target;
2538 if (!sas_target_priv_data || sas_target_priv_data->handle ==
2539 MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
2540 scmd->result = DID_NO_CONNECT << 16;
2541 scmd->scsi_done(scmd);
2542 return 0;
2543 }
2544
2545 /* see if we are busy with task managment stuff */
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302546 if (sas_target_priv_data->tm_busy)
2547 return SCSI_MLQUEUE_DEVICE_BUSY;
2548 else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06002549 return SCSI_MLQUEUE_HOST_BUSY;
Eric Moore635374e2009-03-09 01:21:12 -06002550
2551 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
2552 mpi_control = MPI2_SCSIIO_CONTROL_READ;
2553 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
2554 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
2555 else
2556 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
2557
2558 /* set tags */
2559 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
2560 if (scmd->device->tagged_supported) {
2561 if (scmd->device->ordered_tags)
2562 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
2563 else
2564 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2565 } else
2566/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
2567/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
2568 */
2569 mpi_control |= (0x500);
2570
2571 } else
2572 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2573
2574 if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
2575 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
2576
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302577 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002578 if (!smid) {
2579 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2580 ioc->name, __func__);
2581 goto out;
2582 }
2583 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2584 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06002585 _scsih_setup_eedp(scmd, mpi_request);
Eric Moore635374e2009-03-09 01:21:12 -06002586 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2587 if (sas_device_priv_data->sas_target->flags &
2588 MPT_TARGET_FLAGS_RAID_COMPONENT)
2589 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2590 else
2591 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2592 mpi_request->DevHandle =
2593 cpu_to_le16(sas_device_priv_data->sas_target->handle);
2594 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
2595 mpi_request->Control = cpu_to_le32(mpi_control);
2596 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
2597 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
2598 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
2599 mpi_request->SenseBufferLowAddress =
2600 (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
2601 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
2602 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
2603 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302604 mpi_request->VF_ID = 0; /* TODO */
2605 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06002606 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
2607 mpi_request->LUN);
2608 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
2609
2610 if (!mpi_request->DataLength) {
2611 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
2612 } else {
2613 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
2614 mpt2sas_base_free_smid(ioc, smid);
2615 goto out;
2616 }
2617 }
2618
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302619 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Eric Moore635374e2009-03-09 01:21:12 -06002620 sas_device_priv_data->sas_target->handle);
2621 return 0;
2622
2623 out:
2624 return SCSI_MLQUEUE_HOST_BUSY;
2625}
2626
2627/**
2628 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
2629 * @sense_buffer: sense data returned by target
2630 * @data: normalized skey/asc/ascq
2631 *
2632 * Return nothing.
2633 */
2634static void
2635_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
2636{
2637 if ((sense_buffer[0] & 0x7F) >= 0x72) {
2638 /* descriptor format */
2639 data->skey = sense_buffer[1] & 0x0F;
2640 data->asc = sense_buffer[2];
2641 data->ascq = sense_buffer[3];
2642 } else {
2643 /* fixed format */
2644 data->skey = sense_buffer[2] & 0x0F;
2645 data->asc = sense_buffer[12];
2646 data->ascq = sense_buffer[13];
2647 }
2648}
2649
2650#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
2651/**
2652 * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request
2653 * @ioc: per adapter object
2654 * @scmd: pointer to scsi command object
2655 * @mpi_reply: reply mf payload returned from firmware
2656 *
2657 * scsi_status - SCSI Status code returned from target device
2658 * scsi_state - state info associated with SCSI_IO determined by ioc
2659 * ioc_status - ioc supplied status info
2660 *
2661 * Return nothing.
2662 */
2663static void
2664_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
2665 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
2666{
2667 u32 response_info;
2668 u8 *response_bytes;
2669 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
2670 MPI2_IOCSTATUS_MASK;
2671 u8 scsi_state = mpi_reply->SCSIState;
2672 u8 scsi_status = mpi_reply->SCSIStatus;
2673 char *desc_ioc_state = NULL;
2674 char *desc_scsi_status = NULL;
2675 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05302676 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
2677
2678 if (log_info == 0x31170000)
2679 return;
Eric Moore635374e2009-03-09 01:21:12 -06002680
2681 switch (ioc_status) {
2682 case MPI2_IOCSTATUS_SUCCESS:
2683 desc_ioc_state = "success";
2684 break;
2685 case MPI2_IOCSTATUS_INVALID_FUNCTION:
2686 desc_ioc_state = "invalid function";
2687 break;
2688 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2689 desc_ioc_state = "scsi recovered error";
2690 break;
2691 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2692 desc_ioc_state = "scsi invalid dev handle";
2693 break;
2694 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2695 desc_ioc_state = "scsi device not there";
2696 break;
2697 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2698 desc_ioc_state = "scsi data overrun";
2699 break;
2700 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2701 desc_ioc_state = "scsi data underrun";
2702 break;
2703 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2704 desc_ioc_state = "scsi io data error";
2705 break;
2706 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2707 desc_ioc_state = "scsi protocol error";
2708 break;
2709 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2710 desc_ioc_state = "scsi task terminated";
2711 break;
2712 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2713 desc_ioc_state = "scsi residual mismatch";
2714 break;
2715 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2716 desc_ioc_state = "scsi task mgmt failed";
2717 break;
2718 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
2719 desc_ioc_state = "scsi ioc terminated";
2720 break;
2721 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
2722 desc_ioc_state = "scsi ext terminated";
2723 break;
Eric Moore3c621b32009-05-18 12:59:41 -06002724 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2725 desc_ioc_state = "eedp guard error";
2726 break;
2727 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2728 desc_ioc_state = "eedp ref tag error";
2729 break;
2730 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2731 desc_ioc_state = "eedp app tag error";
2732 break;
Eric Moore635374e2009-03-09 01:21:12 -06002733 default:
2734 desc_ioc_state = "unknown";
2735 break;
2736 }
2737
2738 switch (scsi_status) {
2739 case MPI2_SCSI_STATUS_GOOD:
2740 desc_scsi_status = "good";
2741 break;
2742 case MPI2_SCSI_STATUS_CHECK_CONDITION:
2743 desc_scsi_status = "check condition";
2744 break;
2745 case MPI2_SCSI_STATUS_CONDITION_MET:
2746 desc_scsi_status = "condition met";
2747 break;
2748 case MPI2_SCSI_STATUS_BUSY:
2749 desc_scsi_status = "busy";
2750 break;
2751 case MPI2_SCSI_STATUS_INTERMEDIATE:
2752 desc_scsi_status = "intermediate";
2753 break;
2754 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
2755 desc_scsi_status = "intermediate condmet";
2756 break;
2757 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
2758 desc_scsi_status = "reservation conflict";
2759 break;
2760 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
2761 desc_scsi_status = "command terminated";
2762 break;
2763 case MPI2_SCSI_STATUS_TASK_SET_FULL:
2764 desc_scsi_status = "task set full";
2765 break;
2766 case MPI2_SCSI_STATUS_ACA_ACTIVE:
2767 desc_scsi_status = "aca active";
2768 break;
2769 case MPI2_SCSI_STATUS_TASK_ABORTED:
2770 desc_scsi_status = "task aborted";
2771 break;
2772 default:
2773 desc_scsi_status = "unknown";
2774 break;
2775 }
2776
2777 desc_scsi_state[0] = '\0';
2778 if (!scsi_state)
2779 desc_scsi_state = " ";
2780 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
2781 strcat(desc_scsi_state, "response info ");
2782 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
2783 strcat(desc_scsi_state, "state terminated ");
2784 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
2785 strcat(desc_scsi_state, "no status ");
2786 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
2787 strcat(desc_scsi_state, "autosense failed ");
2788 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
2789 strcat(desc_scsi_state, "autosense valid ");
2790
2791 scsi_print_command(scmd);
2792 printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
2793 "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
2794 le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
2795 ioc_status, smid);
2796 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
2797 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
2798 scsi_get_resid(scmd));
2799 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
2800 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
2801 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
2802 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
2803 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
2804 scsi_status, desc_scsi_state, scsi_state);
2805
2806 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2807 struct sense_info data;
2808 _scsih_normalize_sense(scmd->sense_buffer, &data);
2809 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
2810 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey,
2811 data.asc, data.ascq);
2812 }
2813
2814 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
2815 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
2816 response_bytes = (u8 *)&response_info;
2817 _scsih_response_code(ioc, response_bytes[3]);
2818 }
2819}
2820#endif
2821
2822/**
2823 * _scsih_smart_predicted_fault - illuminate Fault LED
2824 * @ioc: per adapter object
2825 * @handle: device handle
2826 *
2827 * Return nothing.
2828 */
2829static void
2830_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2831{
2832 Mpi2SepReply_t mpi_reply;
2833 Mpi2SepRequest_t mpi_request;
2834 struct scsi_target *starget;
2835 struct MPT2SAS_TARGET *sas_target_priv_data;
2836 Mpi2EventNotificationReply_t *event_reply;
2837 Mpi2EventDataSasDeviceStatusChange_t *event_data;
2838 struct _sas_device *sas_device;
2839 ssize_t sz;
2840 unsigned long flags;
2841
2842 /* only handle non-raid devices */
2843 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2844 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
2845 if (!sas_device) {
2846 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2847 return;
2848 }
2849 starget = sas_device->starget;
2850 sas_target_priv_data = starget->hostdata;
2851
2852 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
2853 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
2854 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2855 return;
2856 }
2857 starget_printk(KERN_WARNING, starget, "predicted fault\n");
2858 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2859
2860 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
2861 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
2862 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
2863 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
2864 mpi_request.SlotStatus =
2865 MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
2866 mpi_request.DevHandle = cpu_to_le16(handle);
2867 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
2868 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
2869 &mpi_request)) != 0) {
2870 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
2871 ioc->name, __FILE__, __LINE__, __func__);
2872 return;
2873 }
2874
2875 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
2876 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2877 "enclosure_processor: ioc_status (0x%04x), "
2878 "loginfo(0x%08x)\n", ioc->name,
2879 le16_to_cpu(mpi_reply.IOCStatus),
2880 le32_to_cpu(mpi_reply.IOCLogInfo)));
2881 return;
2882 }
2883 }
2884
2885 /* insert into event log */
2886 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
2887 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
2888 event_reply = kzalloc(sz, GFP_KERNEL);
2889 if (!event_reply) {
2890 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
2891 ioc->name, __FILE__, __LINE__, __func__);
2892 return;
2893 }
2894
2895 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
2896 event_reply->Event =
2897 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
2898 event_reply->MsgLength = sz/4;
2899 event_reply->EventDataLength =
2900 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
2901 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
2902 event_reply->EventData;
2903 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
2904 event_data->ASC = 0x5D;
2905 event_data->DevHandle = cpu_to_le16(handle);
2906 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
2907 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
2908 kfree(event_reply);
2909}
2910
2911/**
Eric Moored5d135b2009-05-18 13:02:08 -06002912 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06002913 * @ioc: per adapter object
2914 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302915 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06002916 * @reply: reply message frame(lower 32bit addr)
2917 *
2918 * Callback handler when using scsih_qcmd.
2919 *
2920 * Return nothing.
2921 */
2922static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302923_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06002924{
2925 Mpi2SCSIIORequest_t *mpi_request;
2926 Mpi2SCSIIOReply_t *mpi_reply;
2927 struct scsi_cmnd *scmd;
2928 u16 ioc_status;
2929 u32 xfer_cnt;
2930 u8 scsi_state;
2931 u8 scsi_status;
2932 u32 log_info;
2933 struct MPT2SAS_DEVICE *sas_device_priv_data;
2934 u32 response_code;
2935
2936 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302937 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002938 if (scmd == NULL)
2939 return;
2940
2941 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2942
2943 if (mpi_reply == NULL) {
2944 scmd->result = DID_OK << 16;
2945 goto out;
2946 }
2947
2948 sas_device_priv_data = scmd->device->hostdata;
2949 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
2950 sas_device_priv_data->sas_target->deleted) {
2951 scmd->result = DID_NO_CONNECT << 16;
2952 goto out;
2953 }
2954
2955 /* turning off TLR */
2956 if (!sas_device_priv_data->tlr_snoop_check) {
2957 sas_device_priv_data->tlr_snoop_check++;
2958 if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) {
2959 response_code = (le32_to_cpu(mpi_reply->ResponseInfo)
2960 >> 24);
2961 if (response_code ==
2962 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
2963 sas_device_priv_data->flags &=
2964 ~MPT_DEVICE_TLR_ON;
2965 }
2966 }
2967
2968 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
2969 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
2970 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
2971 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
2972 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
2973 else
2974 log_info = 0;
2975 ioc_status &= MPI2_IOCSTATUS_MASK;
2976 scsi_state = mpi_reply->SCSIState;
2977 scsi_status = mpi_reply->SCSIStatus;
2978
2979 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
2980 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
2981 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
2982 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
2983 ioc_status = MPI2_IOCSTATUS_SUCCESS;
2984 }
2985
2986 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2987 struct sense_info data;
2988 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
2989 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06002990 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06002991 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06002992 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06002993 _scsih_normalize_sense(scmd->sense_buffer, &data);
2994 /* failure prediction threshold exceeded */
2995 if (data.asc == 0x5D)
2996 _scsih_smart_predicted_fault(ioc,
2997 le16_to_cpu(mpi_reply->DevHandle));
2998 }
2999
3000 switch (ioc_status) {
3001 case MPI2_IOCSTATUS_BUSY:
3002 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3003 scmd->result = SAM_STAT_BUSY;
3004 break;
3005
3006 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3007 scmd->result = DID_NO_CONNECT << 16;
3008 break;
3009
3010 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3011 if (sas_device_priv_data->block) {
3012 scmd->result = (DID_BUS_BUSY << 16);
3013 break;
3014 }
3015
3016 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3017 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3018 scmd->result = DID_RESET << 16;
3019 break;
3020
3021 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3022 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3023 scmd->result = DID_SOFT_ERROR << 16;
3024 else
3025 scmd->result = (DID_OK << 16) | scsi_status;
3026 break;
3027
3028 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3029 scmd->result = (DID_OK << 16) | scsi_status;
3030
3031 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3032 break;
3033
3034 if (xfer_cnt < scmd->underflow) {
3035 if (scsi_status == SAM_STAT_BUSY)
3036 scmd->result = SAM_STAT_BUSY;
3037 else
3038 scmd->result = DID_SOFT_ERROR << 16;
3039 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3040 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3041 scmd->result = DID_SOFT_ERROR << 16;
3042 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3043 scmd->result = DID_RESET << 16;
3044 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3045 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3046 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3047 scmd->result = (DRIVER_SENSE << 24) |
3048 SAM_STAT_CHECK_CONDITION;
3049 scmd->sense_buffer[0] = 0x70;
3050 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3051 scmd->sense_buffer[12] = 0x20;
3052 scmd->sense_buffer[13] = 0;
3053 }
3054 break;
3055
3056 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3057 scsi_set_resid(scmd, 0);
3058 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3059 case MPI2_IOCSTATUS_SUCCESS:
3060 scmd->result = (DID_OK << 16) | scsi_status;
3061 if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3062 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3063 scmd->result = DID_SOFT_ERROR << 16;
3064 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3065 scmd->result = DID_RESET << 16;
3066 break;
3067
Eric Moore3c621b32009-05-18 12:59:41 -06003068 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3069 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3070 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3071 _scsih_eedp_error_handling(scmd, ioc_status);
3072 break;
Eric Moore635374e2009-03-09 01:21:12 -06003073 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3074 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3075 case MPI2_IOCSTATUS_INVALID_SGL:
3076 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3077 case MPI2_IOCSTATUS_INVALID_FIELD:
3078 case MPI2_IOCSTATUS_INVALID_STATE:
3079 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3080 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3081 default:
3082 scmd->result = DID_SOFT_ERROR << 16;
3083 break;
3084
3085 }
3086
3087#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3088 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3089 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3090#endif
3091
3092 out:
3093 scsi_dma_unmap(scmd);
3094 scmd->scsi_done(scmd);
3095}
3096
3097/**
Eric Moore635374e2009-03-09 01:21:12 -06003098 * _scsih_sas_host_refresh - refreshing sas host object contents
3099 * @ioc: per adapter object
3100 * @update: update link information
3101 * Context: user
3102 *
3103 * During port enable, fw will send topology events for every device. Its
3104 * possible that the handles may change from the previous setting, so this
3105 * code keeping handles updating if changed.
3106 *
3107 * Return nothing.
3108 */
3109static void
3110_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update)
3111{
3112 u16 sz;
3113 u16 ioc_status;
3114 int i;
3115 Mpi2ConfigReply_t mpi_reply;
3116 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3117
3118 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3119 "updating handles for sas_host(0x%016llx)\n",
3120 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3121
3122 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3123 * sizeof(Mpi2SasIOUnit0PhyData_t));
3124 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3125 if (!sas_iounit_pg0) {
3126 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3127 ioc->name, __FILE__, __LINE__, __func__);
3128 return;
3129 }
3130 if (!(mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3131 sas_iounit_pg0, sz))) {
3132 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3133 MPI2_IOCSTATUS_MASK;
3134 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3135 goto out;
3136 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3137 ioc->sas_hba.phy[i].handle =
3138 le16_to_cpu(sas_iounit_pg0->PhyData[i].
3139 ControllerDevHandle);
3140 if (update)
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05303141 mpt2sas_transport_update_links(
3142 ioc,
Eric Moore635374e2009-03-09 01:21:12 -06003143 ioc->sas_hba.phy[i].handle,
3144 le16_to_cpu(sas_iounit_pg0->PhyData[i].
3145 AttachedDevHandle), i,
3146 sas_iounit_pg0->PhyData[i].
3147 NegotiatedLinkRate >> 4);
3148 }
3149 }
3150
3151 out:
3152 kfree(sas_iounit_pg0);
3153}
3154
3155/**
3156 * _scsih_sas_host_add - create sas host object
3157 * @ioc: per adapter object
3158 *
3159 * Creating host side data object, stored in ioc->sas_hba
3160 *
3161 * Return nothing.
3162 */
3163static void
3164_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3165{
3166 int i;
3167 Mpi2ConfigReply_t mpi_reply;
3168 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3169 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3170 Mpi2SasPhyPage0_t phy_pg0;
3171 Mpi2SasDevicePage0_t sas_device_pg0;
3172 Mpi2SasEnclosurePage0_t enclosure_pg0;
3173 u16 ioc_status;
3174 u16 sz;
3175 u16 device_missing_delay;
3176
3177 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3178 if (!ioc->sas_hba.num_phys) {
3179 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3180 ioc->name, __FILE__, __LINE__, __func__);
3181 return;
3182 }
3183
3184 /* sas_iounit page 0 */
3185 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3186 sizeof(Mpi2SasIOUnit0PhyData_t));
3187 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3188 if (!sas_iounit_pg0) {
3189 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3190 ioc->name, __FILE__, __LINE__, __func__);
3191 return;
3192 }
3193 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3194 sas_iounit_pg0, sz))) {
3195 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3196 ioc->name, __FILE__, __LINE__, __func__);
3197 goto out;
3198 }
3199 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3200 MPI2_IOCSTATUS_MASK;
3201 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3202 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3203 ioc->name, __FILE__, __LINE__, __func__);
3204 goto out;
3205 }
3206
3207 /* sas_iounit page 1 */
3208 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3209 sizeof(Mpi2SasIOUnit1PhyData_t));
3210 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3211 if (!sas_iounit_pg1) {
3212 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3213 ioc->name, __FILE__, __LINE__, __func__);
3214 goto out;
3215 }
3216 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3217 sas_iounit_pg1, sz))) {
3218 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3219 ioc->name, __FILE__, __LINE__, __func__);
3220 goto out;
3221 }
3222 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3223 MPI2_IOCSTATUS_MASK;
3224 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3225 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3226 ioc->name, __FILE__, __LINE__, __func__);
3227 goto out;
3228 }
3229
3230 ioc->io_missing_delay =
3231 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3232 device_missing_delay =
3233 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3234 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3235 ioc->device_missing_delay = (device_missing_delay &
3236 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3237 else
3238 ioc->device_missing_delay = device_missing_delay &
3239 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3240
3241 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3242 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3243 sizeof(struct _sas_phy), GFP_KERNEL);
3244 if (!ioc->sas_hba.phy) {
3245 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3246 ioc->name, __FILE__, __LINE__, __func__);
3247 goto out;
3248 }
3249 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3250 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3251 i))) {
3252 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3253 ioc->name, __FILE__, __LINE__, __func__);
3254 goto out;
3255 }
3256 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3257 MPI2_IOCSTATUS_MASK;
3258 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3259 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3260 ioc->name, __FILE__, __LINE__, __func__);
3261 goto out;
3262 }
3263 ioc->sas_hba.phy[i].handle =
3264 le16_to_cpu(sas_iounit_pg0->PhyData[i].ControllerDevHandle);
3265 ioc->sas_hba.phy[i].phy_id = i;
3266 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3267 phy_pg0, ioc->sas_hba.parent_dev);
3268 }
3269 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
3270 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.phy[0].handle))) {
3271 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3272 ioc->name, __FILE__, __LINE__, __func__);
3273 goto out;
3274 }
3275 ioc->sas_hba.handle = le16_to_cpu(sas_device_pg0.DevHandle);
3276 ioc->sas_hba.enclosure_handle =
3277 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3278 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3279 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3280 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3281 (unsigned long long) ioc->sas_hba.sas_address,
3282 ioc->sas_hba.num_phys) ;
3283
3284 if (ioc->sas_hba.enclosure_handle) {
3285 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3286 &enclosure_pg0,
3287 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3288 ioc->sas_hba.enclosure_handle))) {
3289 ioc->sas_hba.enclosure_logical_id =
3290 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3291 }
3292 }
3293
3294 out:
3295 kfree(sas_iounit_pg1);
3296 kfree(sas_iounit_pg0);
3297}
3298
3299/**
3300 * _scsih_expander_add - creating expander object
3301 * @ioc: per adapter object
3302 * @handle: expander handle
3303 *
3304 * Creating expander object, stored in ioc->sas_expander_list.
3305 *
3306 * Return 0 for success, else error.
3307 */
3308static int
3309_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3310{
3311 struct _sas_node *sas_expander;
3312 Mpi2ConfigReply_t mpi_reply;
3313 Mpi2ExpanderPage0_t expander_pg0;
3314 Mpi2ExpanderPage1_t expander_pg1;
3315 Mpi2SasEnclosurePage0_t enclosure_pg0;
3316 u32 ioc_status;
3317 u16 parent_handle;
3318 __le64 sas_address;
3319 int i;
3320 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303321 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003322 int rc = 0;
3323
3324 if (!handle)
3325 return -1;
3326
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303327 if (ioc->shost_recovery)
3328 return -1;
3329
Eric Moore635374e2009-03-09 01:21:12 -06003330 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3331 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3332 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3333 ioc->name, __FILE__, __LINE__, __func__);
3334 return -1;
3335 }
3336
3337 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3338 MPI2_IOCSTATUS_MASK;
3339 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3340 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3341 ioc->name, __FILE__, __LINE__, __func__);
3342 return -1;
3343 }
3344
3345 /* handle out of order topology events */
3346 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
3347 if (parent_handle >= ioc->sas_hba.num_phys) {
3348 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3349 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
3350 parent_handle);
3351 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3352 if (!sas_expander) {
3353 rc = _scsih_expander_add(ioc, parent_handle);
3354 if (rc != 0)
3355 return rc;
3356 }
3357 }
3358
Eric Moore635374e2009-03-09 01:21:12 -06003359 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303360 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06003361 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3362 sas_address);
3363 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3364
3365 if (sas_expander)
3366 return 0;
3367
3368 sas_expander = kzalloc(sizeof(struct _sas_node),
3369 GFP_KERNEL);
3370 if (!sas_expander) {
3371 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3372 ioc->name, __FILE__, __LINE__, __func__);
3373 return -1;
3374 }
3375
3376 sas_expander->handle = handle;
3377 sas_expander->num_phys = expander_pg0.NumPhys;
3378 sas_expander->parent_handle = parent_handle;
3379 sas_expander->enclosure_handle =
3380 le16_to_cpu(expander_pg0.EnclosureHandle);
3381 sas_expander->sas_address = sas_address;
3382
3383 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3384 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
3385 handle, sas_expander->parent_handle, (unsigned long long)
3386 sas_expander->sas_address, sas_expander->num_phys);
3387
3388 if (!sas_expander->num_phys)
3389 goto out_fail;
3390 sas_expander->phy = kcalloc(sas_expander->num_phys,
3391 sizeof(struct _sas_phy), GFP_KERNEL);
3392 if (!sas_expander->phy) {
3393 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3394 ioc->name, __FILE__, __LINE__, __func__);
3395 rc = -1;
3396 goto out_fail;
3397 }
3398
3399 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3400 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
3401 sas_expander->parent_handle);
3402 if (!mpt2sas_port) {
3403 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3404 ioc->name, __FILE__, __LINE__, __func__);
3405 rc = -1;
3406 goto out_fail;
3407 }
3408 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3409
3410 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3411 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3412 &expander_pg1, i, handle))) {
3413 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3414 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303415 rc = -1;
3416 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003417 }
3418 sas_expander->phy[i].handle = handle;
3419 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303420
3421 if ((mpt2sas_transport_add_expander_phy(ioc,
3422 &sas_expander->phy[i], expander_pg1,
3423 sas_expander->parent_dev))) {
3424 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3425 ioc->name, __FILE__, __LINE__, __func__);
3426 rc = -1;
3427 goto out_fail;
3428 }
Eric Moore635374e2009-03-09 01:21:12 -06003429 }
3430
3431 if (sas_expander->enclosure_handle) {
3432 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3433 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3434 sas_expander->enclosure_handle))) {
3435 sas_expander->enclosure_logical_id =
3436 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3437 }
3438 }
3439
3440 _scsih_expander_node_add(ioc, sas_expander);
3441 return 0;
3442
3443 out_fail:
3444
Kashyap, Desai20f58952009-08-07 19:34:26 +05303445 if (mpt2sas_port)
3446 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
3447 sas_expander->parent_handle);
Eric Moore635374e2009-03-09 01:21:12 -06003448 kfree(sas_expander);
3449 return rc;
3450}
3451
3452/**
3453 * _scsih_expander_remove - removing expander object
3454 * @ioc: per adapter object
3455 * @handle: expander handle
3456 *
3457 * Return nothing.
3458 */
3459static void
3460_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3461{
3462 struct _sas_node *sas_expander;
3463 unsigned long flags;
3464
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303465 if (ioc->shost_recovery)
3466 return;
3467
Eric Moore635374e2009-03-09 01:21:12 -06003468 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3469 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle);
3470 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3471 _scsih_expander_node_remove(ioc, sas_expander);
3472}
3473
3474/**
3475 * _scsih_add_device - creating sas device object
3476 * @ioc: per adapter object
3477 * @handle: sas device handle
3478 * @phy_num: phy number end device attached to
3479 * @is_pd: is this hidden raid component
3480 *
3481 * Creating end device object, stored in ioc->sas_device_list.
3482 *
3483 * Returns 0 for success, non-zero for failure.
3484 */
3485static int
3486_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
3487{
3488 Mpi2ConfigReply_t mpi_reply;
3489 Mpi2SasDevicePage0_t sas_device_pg0;
3490 Mpi2SasEnclosurePage0_t enclosure_pg0;
3491 struct _sas_device *sas_device;
3492 u32 ioc_status;
3493 __le64 sas_address;
3494 u32 device_info;
3495 unsigned long flags;
3496
3497 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
3498 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
3499 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3500 ioc->name, __FILE__, __LINE__, __func__);
3501 return -1;
3502 }
3503
3504 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3505 MPI2_IOCSTATUS_MASK;
3506 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3507 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3508 ioc->name, __FILE__, __LINE__, __func__);
3509 return -1;
3510 }
3511
3512 /* check if device is present */
3513 if (!(le16_to_cpu(sas_device_pg0.Flags) &
3514 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
3515 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3516 ioc->name, __FILE__, __LINE__, __func__);
3517 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
3518 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
3519 return -1;
3520 }
3521
3522 /* check if there were any issus with discovery */
3523 if (sas_device_pg0.AccessStatus ==
3524 MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
3525 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3526 ioc->name, __FILE__, __LINE__, __func__);
3527 printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
3528 ioc->name, sas_device_pg0.AccessStatus);
3529 return -1;
3530 }
3531
3532 /* check if this is end device */
3533 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
3534 if (!(_scsih_is_end_device(device_info))) {
3535 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3536 ioc->name, __FILE__, __LINE__, __func__);
3537 return -1;
3538 }
3539
3540 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3541
3542 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3543 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
3544 sas_address);
3545 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3546
3547 if (sas_device) {
3548 _scsih_ublock_io_device(ioc, handle);
3549 return 0;
3550 }
3551
3552 sas_device = kzalloc(sizeof(struct _sas_device),
3553 GFP_KERNEL);
3554 if (!sas_device) {
3555 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3556 ioc->name, __FILE__, __LINE__, __func__);
3557 return -1;
3558 }
3559
3560 sas_device->handle = handle;
3561 sas_device->parent_handle =
3562 le16_to_cpu(sas_device_pg0.ParentDevHandle);
3563 sas_device->enclosure_handle =
3564 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3565 sas_device->slot =
3566 le16_to_cpu(sas_device_pg0.Slot);
3567 sas_device->device_info = device_info;
3568 sas_device->sas_address = sas_address;
3569 sas_device->hidden_raid_component = is_pd;
3570
3571 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05303572 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
3573 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3574 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06003575 sas_device->enclosure_logical_id =
3576 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06003577
3578 /* get device name */
3579 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
3580
3581 if (ioc->wait_for_port_enable_to_complete)
3582 _scsih_sas_device_init_add(ioc, sas_device);
3583 else
3584 _scsih_sas_device_add(ioc, sas_device);
3585
3586 return 0;
3587}
3588
3589/**
3590 * _scsih_remove_device - removing sas device object
3591 * @ioc: per adapter object
3592 * @handle: sas device handle
3593 *
3594 * Return nothing.
3595 */
3596static void
3597_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3598{
3599 struct MPT2SAS_TARGET *sas_target_priv_data;
3600 struct _sas_device *sas_device;
3601 unsigned long flags;
3602 Mpi2SasIoUnitControlReply_t mpi_reply;
3603 Mpi2SasIoUnitControlRequest_t mpi_request;
3604 u16 device_handle;
3605
3606 /* lookup sas_device */
3607 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3608 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3609 if (!sas_device) {
3610 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3611 return;
3612 }
3613
3614 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle"
3615 "(0x%04x)\n", ioc->name, __func__, handle));
3616
3617 if (sas_device->starget && sas_device->starget->hostdata) {
3618 sas_target_priv_data = sas_device->starget->hostdata;
3619 sas_target_priv_data->deleted = 1;
3620 }
3621 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3622
3623 if (ioc->remove_host)
3624 goto out;
3625
3626 /* Target Reset to flush out all the outstanding IO */
3627 device_handle = (sas_device->hidden_raid_component) ?
3628 sas_device->volume_handle : handle;
3629 if (device_handle) {
3630 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
3631 "handle(0x%04x)\n", ioc->name, device_handle));
3632 mutex_lock(&ioc->tm_cmds.mutex);
3633 mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
3634 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
3635 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
3636 mutex_unlock(&ioc->tm_cmds.mutex);
3637 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
3638 "done: handle(0x%04x)\n", ioc->name, device_handle));
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303639 if (ioc->shost_recovery)
3640 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003641 }
3642
3643 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
3644 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
3645 "(0x%04x)\n", ioc->name, handle));
3646 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
3647 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
3648 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
3649 mpi_request.DevHandle = handle;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303650 mpi_request.VF_ID = 0; /* TODO */
3651 mpi_request.VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003652 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
3653 &mpi_request)) != 0) {
3654 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3655 ioc->name, __FILE__, __LINE__, __func__);
3656 }
3657
3658 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
3659 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
3660 le16_to_cpu(mpi_reply.IOCStatus),
3661 le32_to_cpu(mpi_reply.IOCLogInfo)));
3662
3663 out:
Kashyap, Desai34a03be2009-08-20 13:23:19 +05303664
3665 _scsih_ublock_io_device(ioc, handle);
3666
Eric Moore635374e2009-03-09 01:21:12 -06003667 mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
3668 sas_device->parent_handle);
3669
3670 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
3671 "(0x%016llx)\n", ioc->name, sas_device->handle,
3672 (unsigned long long) sas_device->sas_address);
3673 _scsih_sas_device_remove(ioc, sas_device);
3674
3675 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
3676 "(0x%04x)\n", ioc->name, __func__, handle));
3677}
3678
3679#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3680/**
3681 * _scsih_sas_topology_change_event_debug - debug for topology event
3682 * @ioc: per adapter object
3683 * @event_data: event data payload
3684 * Context: user.
3685 */
3686static void
3687_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
3688 Mpi2EventDataSasTopologyChangeList_t *event_data)
3689{
3690 int i;
3691 u16 handle;
3692 u16 reason_code;
3693 u8 phy_number;
3694 char *status_str = NULL;
3695 char link_rate[25];
3696
3697 switch (event_data->ExpStatus) {
3698 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
3699 status_str = "add";
3700 break;
3701 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
3702 status_str = "remove";
3703 break;
3704 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
3705 status_str = "responding";
3706 break;
3707 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
3708 status_str = "remove delay";
3709 break;
3710 default:
3711 status_str = "unknown status";
3712 break;
3713 }
3714 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
3715 ioc->name, status_str);
3716 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
3717 "start_phy(%02d), count(%d)\n",
3718 le16_to_cpu(event_data->ExpanderDevHandle),
3719 le16_to_cpu(event_data->EnclosureHandle),
3720 event_data->StartPhyNum, event_data->NumEntries);
3721 for (i = 0; i < event_data->NumEntries; i++) {
3722 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
3723 if (!handle)
3724 continue;
3725 phy_number = event_data->StartPhyNum + i;
3726 reason_code = event_data->PHY[i].PhyStatus &
3727 MPI2_EVENT_SAS_TOPO_RC_MASK;
3728 switch (reason_code) {
3729 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
3730 snprintf(link_rate, 25, ": add, link(0x%02x)",
3731 (event_data->PHY[i].LinkRate >> 4));
3732 status_str = link_rate;
3733 break;
3734 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
3735 status_str = ": remove";
3736 break;
3737 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
3738 status_str = ": remove_delay";
3739 break;
3740 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
3741 snprintf(link_rate, 25, ": link(0x%02x)",
3742 (event_data->PHY[i].LinkRate >> 4));
3743 status_str = link_rate;
3744 break;
3745 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
3746 status_str = ": responding";
3747 break;
3748 default:
3749 status_str = ": unknown";
3750 break;
3751 }
3752 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n",
3753 phy_number, handle, status_str);
3754 }
3755}
3756#endif
3757
3758/**
3759 * _scsih_sas_topology_change_event - handle topology changes
3760 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303761 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06003762 * Context: user.
3763 *
3764 */
3765static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303766_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06003767 struct fw_event_work *fw_event)
3768{
3769 int i;
3770 u16 parent_handle, handle;
3771 u16 reason_code;
3772 u8 phy_number;
3773 struct _sas_node *sas_expander;
3774 unsigned long flags;
3775 u8 link_rate_;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303776 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06003777
3778#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3779 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
3780 _scsih_sas_topology_change_event_debug(ioc, event_data);
3781#endif
3782
3783 if (!ioc->sas_hba.num_phys)
3784 _scsih_sas_host_add(ioc);
3785 else
3786 _scsih_sas_host_refresh(ioc, 0);
3787
3788 if (fw_event->ignore) {
3789 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
3790 "event\n", ioc->name));
3791 return;
3792 }
3793
3794 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
3795
3796 /* handle expander add */
3797 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
3798 if (_scsih_expander_add(ioc, parent_handle) != 0)
3799 return;
3800
3801 /* handle siblings events */
3802 for (i = 0; i < event_data->NumEntries; i++) {
3803 if (fw_event->ignore) {
3804 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
3805 "expander event\n", ioc->name));
3806 return;
3807 }
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303808 if (ioc->shost_recovery)
3809 return;
Eric Moore635374e2009-03-09 01:21:12 -06003810 if (event_data->PHY[i].PhyStatus &
3811 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
3812 continue;
3813 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
3814 if (!handle)
3815 continue;
3816 phy_number = event_data->StartPhyNum + i;
3817 reason_code = event_data->PHY[i].PhyStatus &
3818 MPI2_EVENT_SAS_TOPO_RC_MASK;
3819 link_rate_ = event_data->PHY[i].LinkRate >> 4;
3820 switch (reason_code) {
3821 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
3822 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
3823 if (!parent_handle) {
3824 if (phy_number < ioc->sas_hba.num_phys)
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05303825 mpt2sas_transport_update_links(
3826 ioc,
3827 ioc->sas_hba.phy[phy_number].handle,
3828 handle, phy_number, link_rate_);
Eric Moore635374e2009-03-09 01:21:12 -06003829 } else {
3830 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3831 sas_expander =
3832 mpt2sas_scsih_expander_find_by_handle(ioc,
3833 parent_handle);
3834 spin_unlock_irqrestore(&ioc->sas_node_lock,
3835 flags);
3836 if (sas_expander) {
3837 if (phy_number < sas_expander->num_phys)
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05303838 mpt2sas_transport_update_links(
3839 ioc,
3840 sas_expander->
3841 phy[phy_number].handle,
3842 handle, phy_number,
3843 link_rate_);
Eric Moore635374e2009-03-09 01:21:12 -06003844 }
3845 }
Eric Moore635374e2009-03-09 01:21:12 -06003846 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
3847 if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5)
3848 break;
3849 _scsih_add_device(ioc, handle, phy_number, 0);
3850 }
3851 break;
3852 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
3853 _scsih_remove_device(ioc, handle);
3854 break;
3855 }
3856 }
3857
3858 /* handle expander removal */
3859 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
3860 _scsih_expander_remove(ioc, parent_handle);
3861
3862}
3863
3864#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3865/**
3866 * _scsih_sas_device_status_change_event_debug - debug for device event
3867 * @event_data: event data payload
3868 * Context: user.
3869 *
3870 * Return nothing.
3871 */
3872static void
3873_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
3874 Mpi2EventDataSasDeviceStatusChange_t *event_data)
3875{
3876 char *reason_str = NULL;
3877
3878 switch (event_data->ReasonCode) {
3879 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
3880 reason_str = "smart data";
3881 break;
3882 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
3883 reason_str = "unsupported device discovered";
3884 break;
3885 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
3886 reason_str = "internal device reset";
3887 break;
3888 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
3889 reason_str = "internal task abort";
3890 break;
3891 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
3892 reason_str = "internal task abort set";
3893 break;
3894 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
3895 reason_str = "internal clear task set";
3896 break;
3897 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
3898 reason_str = "internal query task";
3899 break;
3900 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
3901 reason_str = "sata init failure";
3902 break;
3903 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
3904 reason_str = "internal device reset complete";
3905 break;
3906 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
3907 reason_str = "internal task abort complete";
3908 break;
3909 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
3910 reason_str = "internal async notification";
3911 break;
3912 default:
3913 reason_str = "unknown reason";
3914 break;
3915 }
3916 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
3917 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
3918 reason_str, le16_to_cpu(event_data->DevHandle),
3919 (unsigned long long)le64_to_cpu(event_data->SASAddress));
3920 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
3921 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
3922 event_data->ASC, event_data->ASCQ);
3923 printk(KERN_INFO "\n");
3924}
3925#endif
3926
3927/**
3928 * _scsih_sas_device_status_change_event - handle device status change
3929 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303930 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06003931 * Context: user.
3932 *
3933 * Return nothing.
3934 */
3935static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303936_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
3937 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06003938{
3939#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3940 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303941 _scsih_sas_device_status_change_event_debug(ioc,
3942 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06003943#endif
3944}
3945
3946#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3947/**
3948 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
3949 * @ioc: per adapter object
3950 * @event_data: event data payload
3951 * Context: user.
3952 *
3953 * Return nothing.
3954 */
3955static void
3956_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
3957 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
3958{
3959 char *reason_str = NULL;
3960
3961 switch (event_data->ReasonCode) {
3962 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
3963 reason_str = "enclosure add";
3964 break;
3965 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
3966 reason_str = "enclosure remove";
3967 break;
3968 default:
3969 reason_str = "unknown reason";
3970 break;
3971 }
3972
3973 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
3974 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
3975 " number slots(%d)\n", ioc->name, reason_str,
3976 le16_to_cpu(event_data->EnclosureHandle),
3977 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
3978 le16_to_cpu(event_data->StartSlot));
3979}
3980#endif
3981
3982/**
3983 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
3984 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303985 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06003986 * Context: user.
3987 *
3988 * Return nothing.
3989 */
3990static void
3991_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303992 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06003993{
3994#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3995 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
3996 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303997 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06003998#endif
3999}
4000
4001/**
4002 * _scsih_sas_broadcast_primative_event - handle broadcast events
4003 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304004 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004005 * Context: user.
4006 *
4007 * Return nothing.
4008 */
4009static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304010_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4011 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004012{
4013 struct scsi_cmnd *scmd;
4014 u16 smid, handle;
4015 u32 lun;
4016 struct MPT2SAS_DEVICE *sas_device_priv_data;
4017 u32 termination_count;
4018 u32 query_count;
4019 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304020#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4021 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4022#endif
Eric Moore635374e2009-03-09 01:21:12 -06004023 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4024 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4025 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004026 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4027 __func__));
4028
4029 mutex_lock(&ioc->tm_cmds.mutex);
4030 termination_count = 0;
4031 query_count = 0;
4032 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304033 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06004034 scmd = _scsih_scsi_lookup_get(ioc, smid);
4035 if (!scmd)
4036 continue;
4037 sas_device_priv_data = scmd->device->hostdata;
4038 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4039 continue;
4040 /* skip hidden raid components */
4041 if (sas_device_priv_data->sas_target->flags &
4042 MPT_TARGET_FLAGS_RAID_COMPONENT)
4043 continue;
4044 /* skip volumes */
4045 if (sas_device_priv_data->sas_target->flags &
4046 MPT_TARGET_FLAGS_VOLUME)
4047 continue;
4048
4049 handle = sas_device_priv_data->sas_target->handle;
4050 lun = sas_device_priv_data->lun;
4051 query_count++;
4052
4053 mpt2sas_scsih_issue_tm(ioc, handle, lun,
4054 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
Eric Moore8901cbb2009-04-21 15:41:32 -06004055 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004056
4057 if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) &&
4058 (mpi_reply->ResponseCode ==
4059 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4060 mpi_reply->ResponseCode ==
4061 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4062 continue;
4063
4064 mpt2sas_scsih_issue_tm(ioc, handle, lun,
Eric Moore8901cbb2009-04-21 15:41:32 -06004065 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30);
4066 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004067 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4068 }
Eric Moore635374e2009-03-09 01:21:12 -06004069 ioc->broadcast_aen_busy = 0;
4070 mutex_unlock(&ioc->tm_cmds.mutex);
4071
4072 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4073 "%s - exit, query_count = %d termination_count = %d\n",
4074 ioc->name, __func__, query_count, termination_count));
4075}
4076
4077/**
4078 * _scsih_sas_discovery_event - handle discovery events
4079 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304080 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004081 * Context: user.
4082 *
4083 * Return nothing.
4084 */
4085static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304086_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4087 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004088{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304089 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4090
Eric Moore635374e2009-03-09 01:21:12 -06004091#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4092 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4093 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4094 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4095 "start" : "stop");
4096 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304097 printk("discovery_status(0x%08x)",
4098 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06004099 printk("\n");
4100 }
4101#endif
4102
4103 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4104 !ioc->sas_hba.num_phys)
4105 _scsih_sas_host_add(ioc);
4106}
4107
4108/**
4109 * _scsih_reprobe_lun - reprobing lun
4110 * @sdev: scsi device struct
4111 * @no_uld_attach: sdev->no_uld_attach flag setting
4112 *
4113 **/
4114static void
4115_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4116{
4117 int rc;
4118
4119 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4120 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4121 sdev->no_uld_attach ? "hidding" : "exposing");
4122 rc = scsi_device_reprobe(sdev);
4123}
4124
4125/**
4126 * _scsih_reprobe_target - reprobing target
4127 * @starget: scsi target struct
4128 * @no_uld_attach: sdev->no_uld_attach flag setting
4129 *
4130 * Note: no_uld_attach flag determines whether the disk device is attached
4131 * to block layer. A value of `1` means to not attach.
4132 **/
4133static void
4134_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4135{
4136 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4137
4138 if (no_uld_attach)
4139 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4140 else
4141 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4142
4143 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4144 _scsih_reprobe_lun);
4145}
4146/**
4147 * _scsih_sas_volume_add - add new volume
4148 * @ioc: per adapter object
4149 * @element: IR config element data
4150 * Context: user.
4151 *
4152 * Return nothing.
4153 */
4154static void
4155_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4156 Mpi2EventIrConfigElement_t *element)
4157{
4158 struct _raid_device *raid_device;
4159 unsigned long flags;
4160 u64 wwid;
4161 u16 handle = le16_to_cpu(element->VolDevHandle);
4162 int rc;
4163
Eric Moore635374e2009-03-09 01:21:12 -06004164 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4165 if (!wwid) {
4166 printk(MPT2SAS_ERR_FMT
4167 "failure at %s:%d/%s()!\n", ioc->name,
4168 __FILE__, __LINE__, __func__);
4169 return;
4170 }
4171
4172 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4173 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4174 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4175
4176 if (raid_device)
4177 return;
4178
4179 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4180 if (!raid_device) {
4181 printk(MPT2SAS_ERR_FMT
4182 "failure at %s:%d/%s()!\n", ioc->name,
4183 __FILE__, __LINE__, __func__);
4184 return;
4185 }
4186
4187 raid_device->id = ioc->sas_id++;
4188 raid_device->channel = RAID_CHANNEL;
4189 raid_device->handle = handle;
4190 raid_device->wwid = wwid;
4191 _scsih_raid_device_add(ioc, raid_device);
4192 if (!ioc->wait_for_port_enable_to_complete) {
4193 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4194 raid_device->id, 0);
4195 if (rc)
4196 _scsih_raid_device_remove(ioc, raid_device);
4197 } else
4198 _scsih_determine_boot_device(ioc, raid_device, 1);
4199}
4200
4201/**
4202 * _scsih_sas_volume_delete - delete volume
4203 * @ioc: per adapter object
4204 * @element: IR config element data
4205 * Context: user.
4206 *
4207 * Return nothing.
4208 */
4209static void
4210_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4211 Mpi2EventIrConfigElement_t *element)
4212{
4213 struct _raid_device *raid_device;
4214 u16 handle = le16_to_cpu(element->VolDevHandle);
4215 unsigned long flags;
4216 struct MPT2SAS_TARGET *sas_target_priv_data;
4217
Eric Moore635374e2009-03-09 01:21:12 -06004218 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4219 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4220 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4221 if (!raid_device)
4222 return;
4223 if (raid_device->starget) {
4224 sas_target_priv_data = raid_device->starget->hostdata;
4225 sas_target_priv_data->deleted = 1;
4226 scsi_remove_target(&raid_device->starget->dev);
4227 }
4228 _scsih_raid_device_remove(ioc, raid_device);
4229}
4230
4231/**
4232 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4233 * @ioc: per adapter object
4234 * @element: IR config element data
4235 * Context: user.
4236 *
4237 * Return nothing.
4238 */
4239static void
4240_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4241 Mpi2EventIrConfigElement_t *element)
4242{
4243 struct _sas_device *sas_device;
4244 unsigned long flags;
4245 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4246
4247 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4248 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4249 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4250 if (!sas_device)
4251 return;
4252
4253 /* exposing raid component */
4254 sas_device->volume_handle = 0;
4255 sas_device->volume_wwid = 0;
4256 sas_device->hidden_raid_component = 0;
4257 _scsih_reprobe_target(sas_device->starget, 0);
4258}
4259
4260/**
4261 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4262 * @ioc: per adapter object
4263 * @element: IR config element data
4264 * Context: user.
4265 *
4266 * Return nothing.
4267 */
4268static void
4269_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4270 Mpi2EventIrConfigElement_t *element)
4271{
4272 struct _sas_device *sas_device;
4273 unsigned long flags;
4274 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4275
4276 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4277 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4278 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4279 if (!sas_device)
4280 return;
4281
4282 /* hiding raid component */
4283 mpt2sas_config_get_volume_handle(ioc, handle,
4284 &sas_device->volume_handle);
4285 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4286 &sas_device->volume_wwid);
4287 sas_device->hidden_raid_component = 1;
4288 _scsih_reprobe_target(sas_device->starget, 1);
4289}
4290
4291/**
4292 * _scsih_sas_pd_delete - delete pd component
4293 * @ioc: per adapter object
4294 * @element: IR config element data
4295 * Context: user.
4296 *
4297 * Return nothing.
4298 */
4299static void
4300_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4301 Mpi2EventIrConfigElement_t *element)
4302{
4303 struct _sas_device *sas_device;
4304 unsigned long flags;
4305 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4306
4307 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4308 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4309 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4310 if (!sas_device)
4311 return;
4312 _scsih_remove_device(ioc, handle);
4313}
4314
4315/**
4316 * _scsih_sas_pd_add - remove pd component
4317 * @ioc: per adapter object
4318 * @element: IR config element data
4319 * Context: user.
4320 *
4321 * Return nothing.
4322 */
4323static void
4324_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
4325 Mpi2EventIrConfigElement_t *element)
4326{
4327 struct _sas_device *sas_device;
4328 unsigned long flags;
4329 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304330 Mpi2ConfigReply_t mpi_reply;
4331 Mpi2SasDevicePage0_t sas_device_pg0;
4332 u32 ioc_status;
Eric Moore635374e2009-03-09 01:21:12 -06004333
4334 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4335 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4336 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304337 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004338 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304339 return;
4340 }
4341
4342 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4343 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4344 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4345 ioc->name, __FILE__, __LINE__, __func__);
4346 return;
4347 }
4348
4349 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4350 MPI2_IOCSTATUS_MASK;
4351 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4352 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4353 ioc->name, __FILE__, __LINE__, __func__);
4354 return;
4355 }
4356
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05304357 mpt2sas_transport_update_links(ioc,
Kashyap, Desai62727a72009-08-07 19:35:18 +05304358 le16_to_cpu(sas_device_pg0.ParentDevHandle),
4359 handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
4360
4361 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06004362}
4363
4364#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4365/**
4366 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
4367 * @ioc: per adapter object
4368 * @event_data: event data payload
4369 * Context: user.
4370 *
4371 * Return nothing.
4372 */
4373static void
4374_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4375 Mpi2EventDataIrConfigChangeList_t *event_data)
4376{
4377 Mpi2EventIrConfigElement_t *element;
4378 u8 element_type;
4379 int i;
4380 char *reason_str = NULL, *element_str = NULL;
4381
4382 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4383
4384 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
4385 ioc->name, (le32_to_cpu(event_data->Flags) &
4386 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
4387 "foreign" : "native", event_data->NumElements);
4388 for (i = 0; i < event_data->NumElements; i++, element++) {
4389 switch (element->ReasonCode) {
4390 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
4391 reason_str = "add";
4392 break;
4393 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
4394 reason_str = "remove";
4395 break;
4396 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
4397 reason_str = "no change";
4398 break;
4399 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4400 reason_str = "hide";
4401 break;
4402 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4403 reason_str = "unhide";
4404 break;
4405 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4406 reason_str = "volume_created";
4407 break;
4408 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4409 reason_str = "volume_deleted";
4410 break;
4411 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4412 reason_str = "pd_created";
4413 break;
4414 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4415 reason_str = "pd_deleted";
4416 break;
4417 default:
4418 reason_str = "unknown reason";
4419 break;
4420 }
4421 element_type = le16_to_cpu(element->ElementFlags) &
4422 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
4423 switch (element_type) {
4424 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
4425 element_str = "volume";
4426 break;
4427 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
4428 element_str = "phys disk";
4429 break;
4430 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
4431 element_str = "hot spare";
4432 break;
4433 default:
4434 element_str = "unknown element";
4435 break;
4436 }
4437 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
4438 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
4439 reason_str, le16_to_cpu(element->VolDevHandle),
4440 le16_to_cpu(element->PhysDiskDevHandle),
4441 element->PhysDiskNum);
4442 }
4443}
4444#endif
4445
4446/**
4447 * _scsih_sas_ir_config_change_event - handle ir configuration change events
4448 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304449 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004450 * Context: user.
4451 *
4452 * Return nothing.
4453 */
4454static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304455_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
4456 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004457{
4458 Mpi2EventIrConfigElement_t *element;
4459 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304460 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304461 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004462
4463#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4464 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4465 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
4466
4467#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05304468 foreign_config = (le32_to_cpu(event_data->Flags) &
4469 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06004470
4471 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4472 for (i = 0; i < event_data->NumElements; i++, element++) {
4473
4474 switch (element->ReasonCode) {
4475 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4476 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304477 if (!foreign_config)
4478 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004479 break;
4480 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4481 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304482 if (!foreign_config)
4483 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004484 break;
4485 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4486 _scsih_sas_pd_hide(ioc, element);
4487 break;
4488 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4489 _scsih_sas_pd_expose(ioc, element);
4490 break;
4491 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4492 _scsih_sas_pd_add(ioc, element);
4493 break;
4494 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4495 _scsih_sas_pd_delete(ioc, element);
4496 break;
4497 }
4498 }
4499}
4500
4501/**
4502 * _scsih_sas_ir_volume_event - IR volume event
4503 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304504 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004505 * Context: user.
4506 *
4507 * Return nothing.
4508 */
4509static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304510_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
4511 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004512{
4513 u64 wwid;
4514 unsigned long flags;
4515 struct _raid_device *raid_device;
4516 u16 handle;
4517 u32 state;
4518 int rc;
4519 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304520 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004521
4522 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
4523 return;
4524
4525 handle = le16_to_cpu(event_data->VolDevHandle);
4526 state = le32_to_cpu(event_data->NewValue);
4527 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4528 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4529 le32_to_cpu(event_data->PreviousValue), state));
4530
4531 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4532 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4533 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4534
4535 switch (state) {
4536 case MPI2_RAID_VOL_STATE_MISSING:
4537 case MPI2_RAID_VOL_STATE_FAILED:
4538 if (!raid_device)
4539 break;
4540 if (raid_device->starget) {
4541 sas_target_priv_data = raid_device->starget->hostdata;
4542 sas_target_priv_data->deleted = 1;
4543 scsi_remove_target(&raid_device->starget->dev);
4544 }
4545 _scsih_raid_device_remove(ioc, raid_device);
4546 break;
4547
4548 case MPI2_RAID_VOL_STATE_ONLINE:
4549 case MPI2_RAID_VOL_STATE_DEGRADED:
4550 case MPI2_RAID_VOL_STATE_OPTIMAL:
4551 if (raid_device)
4552 break;
4553
4554 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4555 if (!wwid) {
4556 printk(MPT2SAS_ERR_FMT
4557 "failure at %s:%d/%s()!\n", ioc->name,
4558 __FILE__, __LINE__, __func__);
4559 break;
4560 }
4561
4562 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4563 if (!raid_device) {
4564 printk(MPT2SAS_ERR_FMT
4565 "failure at %s:%d/%s()!\n", ioc->name,
4566 __FILE__, __LINE__, __func__);
4567 break;
4568 }
4569
4570 raid_device->id = ioc->sas_id++;
4571 raid_device->channel = RAID_CHANNEL;
4572 raid_device->handle = handle;
4573 raid_device->wwid = wwid;
4574 _scsih_raid_device_add(ioc, raid_device);
4575 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4576 raid_device->id, 0);
4577 if (rc)
4578 _scsih_raid_device_remove(ioc, raid_device);
4579 break;
4580
4581 case MPI2_RAID_VOL_STATE_INITIALIZING:
4582 default:
4583 break;
4584 }
4585}
4586
4587/**
4588 * _scsih_sas_ir_physical_disk_event - PD event
4589 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304590 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004591 * Context: user.
4592 *
4593 * Return nothing.
4594 */
4595static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304596_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
4597 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004598{
4599 u16 handle;
4600 u32 state;
4601 struct _sas_device *sas_device;
4602 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304603 Mpi2ConfigReply_t mpi_reply;
4604 Mpi2SasDevicePage0_t sas_device_pg0;
4605 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304606 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004607
4608 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
4609 return;
4610
4611 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
4612 state = le32_to_cpu(event_data->NewValue);
4613
4614 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4615 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4616 le32_to_cpu(event_data->PreviousValue), state));
4617
4618 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4619 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4620 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4621
4622 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06004623 case MPI2_RAID_PD_STATE_ONLINE:
4624 case MPI2_RAID_PD_STATE_DEGRADED:
4625 case MPI2_RAID_PD_STATE_REBUILDING:
4626 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304627 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004628 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304629 return;
4630 }
4631
4632 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
4633 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
4634 handle))) {
4635 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4636 ioc->name, __FILE__, __LINE__, __func__);
4637 return;
4638 }
4639
4640 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4641 MPI2_IOCSTATUS_MASK;
4642 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4643 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4644 ioc->name, __FILE__, __LINE__, __func__);
4645 return;
4646 }
4647
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05304648 mpt2sas_transport_update_links(ioc,
Kashyap, Desai62727a72009-08-07 19:35:18 +05304649 le16_to_cpu(sas_device_pg0.ParentDevHandle),
4650 handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
4651
4652 _scsih_add_device(ioc, handle, 0, 1);
4653
Eric Moore635374e2009-03-09 01:21:12 -06004654 break;
4655
Kashyap, Desai62727a72009-08-07 19:35:18 +05304656 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06004657 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
4658 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
4659 case MPI2_RAID_PD_STATE_HOT_SPARE:
4660 default:
4661 break;
4662 }
4663}
4664
4665#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4666/**
4667 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
4668 * @ioc: per adapter object
4669 * @event_data: event data payload
4670 * Context: user.
4671 *
4672 * Return nothing.
4673 */
4674static void
4675_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
4676 Mpi2EventDataIrOperationStatus_t *event_data)
4677{
4678 char *reason_str = NULL;
4679
4680 switch (event_data->RAIDOperation) {
4681 case MPI2_EVENT_IR_RAIDOP_RESYNC:
4682 reason_str = "resync";
4683 break;
4684 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
4685 reason_str = "online capacity expansion";
4686 break;
4687 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
4688 reason_str = "consistency check";
4689 break;
4690 default:
4691 reason_str = "unknown reason";
4692 break;
4693 }
4694
4695 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
4696 "\thandle(0x%04x), percent complete(%d)\n",
4697 ioc->name, reason_str,
4698 le16_to_cpu(event_data->VolDevHandle),
4699 event_data->PercentComplete);
4700}
4701#endif
4702
4703/**
4704 * _scsih_sas_ir_operation_status_event - handle RAID operation events
4705 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304706 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004707 * Context: user.
4708 *
4709 * Return nothing.
4710 */
4711static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304712_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
4713 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004714{
4715#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4716 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304717 _scsih_sas_ir_operation_status_event_debug(ioc,
4718 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004719#endif
4720}
4721
4722/**
4723 * _scsih_task_set_full - handle task set full
4724 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304725 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004726 * Context: user.
4727 *
4728 * Throttle back qdepth.
4729 */
4730static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304731_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
4732 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004733{
4734 unsigned long flags;
4735 struct _sas_device *sas_device;
4736 static struct _raid_device *raid_device;
4737 struct scsi_device *sdev;
4738 int depth;
4739 u16 current_depth;
4740 u16 handle;
4741 int id, channel;
4742 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304743 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004744
4745 current_depth = le16_to_cpu(event_data->CurrentDepth);
4746 handle = le16_to_cpu(event_data->DevHandle);
4747 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4748 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4749 if (!sas_device) {
4750 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4751 return;
4752 }
4753 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4754 id = sas_device->id;
4755 channel = sas_device->channel;
4756 sas_address = sas_device->sas_address;
4757
4758 /* if hidden raid component, then change to volume characteristics */
4759 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
4760 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4761 raid_device = _scsih_raid_device_find_by_handle(
4762 ioc, sas_device->volume_handle);
4763 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4764 if (raid_device) {
4765 id = raid_device->id;
4766 channel = raid_device->channel;
4767 handle = raid_device->handle;
4768 sas_address = raid_device->wwid;
4769 }
4770 }
4771
4772 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
4773 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
4774 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
4775 handle, (unsigned long long)sas_address, current_depth);
4776
4777 shost_for_each_device(sdev, ioc->shost) {
4778 if (sdev->id == id && sdev->channel == channel) {
4779 if (current_depth > sdev->queue_depth) {
4780 if (ioc->logging_level &
4781 MPT_DEBUG_TASK_SET_FULL)
4782 sdev_printk(KERN_INFO, sdev, "strange "
4783 "observation, the queue depth is"
4784 " (%d) meanwhile fw queue depth "
4785 "is (%d)\n", sdev->queue_depth,
4786 current_depth);
4787 continue;
4788 }
4789 depth = scsi_track_queue_full(sdev,
4790 current_depth - 1);
4791 if (depth > 0)
4792 sdev_printk(KERN_INFO, sdev, "Queue depth "
4793 "reduced to (%d)\n", depth);
4794 else if (depth < 0)
4795 sdev_printk(KERN_INFO, sdev, "Tagged Command "
4796 "Queueing is being disabled\n");
4797 else if (depth == 0)
4798 if (ioc->logging_level &
4799 MPT_DEBUG_TASK_SET_FULL)
4800 sdev_printk(KERN_INFO, sdev,
4801 "Queue depth not changed yet\n");
4802 }
4803 }
4804}
4805
4806/**
4807 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
4808 * @ioc: per adapter object
4809 * @sas_address: sas address
4810 * @slot: enclosure slot id
4811 * @handle: device handle
4812 *
4813 * After host reset, find out whether devices are still responding.
4814 * Used in _scsi_remove_unresponsive_sas_devices.
4815 *
4816 * Return nothing.
4817 */
4818static void
4819_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
4820 u16 slot, u16 handle)
4821{
4822 struct MPT2SAS_TARGET *sas_target_priv_data;
4823 struct scsi_target *starget;
4824 struct _sas_device *sas_device;
4825 unsigned long flags;
4826
4827 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4828 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
4829 if (sas_device->sas_address == sas_address &&
4830 sas_device->slot == slot && sas_device->starget) {
4831 sas_device->responding = 1;
4832 starget_printk(KERN_INFO, sas_device->starget,
4833 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
4834 "logical id(0x%016llx), slot(%d)\n", handle,
4835 (unsigned long long)sas_device->sas_address,
4836 (unsigned long long)
4837 sas_device->enclosure_logical_id,
4838 sas_device->slot);
4839 if (sas_device->handle == handle)
4840 goto out;
4841 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
4842 sas_device->handle);
4843 sas_device->handle = handle;
4844 starget = sas_device->starget;
4845 sas_target_priv_data = starget->hostdata;
4846 sas_target_priv_data->handle = handle;
4847 goto out;
4848 }
4849 }
4850 out:
4851 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4852}
4853
4854/**
4855 * _scsih_search_responding_sas_devices -
4856 * @ioc: per adapter object
4857 *
4858 * After host reset, find out whether devices are still responding.
4859 * If not remove.
4860 *
4861 * Return nothing.
4862 */
4863static void
4864_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
4865{
4866 Mpi2SasDevicePage0_t sas_device_pg0;
4867 Mpi2ConfigReply_t mpi_reply;
4868 u16 ioc_status;
4869 __le64 sas_address;
4870 u16 handle;
4871 u32 device_info;
4872 u16 slot;
4873
4874 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
4875
4876 if (list_empty(&ioc->sas_device_list))
4877 return;
4878
4879 handle = 0xFFFF;
4880 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
4881 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
4882 handle))) {
4883 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4884 MPI2_IOCSTATUS_MASK;
4885 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
4886 break;
4887 handle = le16_to_cpu(sas_device_pg0.DevHandle);
4888 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4889 if (!(_scsih_is_end_device(device_info)))
4890 continue;
4891 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4892 slot = le16_to_cpu(sas_device_pg0.Slot);
4893 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
4894 handle);
4895 }
4896}
4897
4898/**
4899 * _scsih_mark_responding_raid_device - mark a raid_device as responding
4900 * @ioc: per adapter object
4901 * @wwid: world wide identifier for raid volume
4902 * @handle: device handle
4903 *
4904 * After host reset, find out whether devices are still responding.
4905 * Used in _scsi_remove_unresponsive_raid_devices.
4906 *
4907 * Return nothing.
4908 */
4909static void
4910_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
4911 u16 handle)
4912{
4913 struct MPT2SAS_TARGET *sas_target_priv_data;
4914 struct scsi_target *starget;
4915 struct _raid_device *raid_device;
4916 unsigned long flags;
4917
4918 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4919 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
4920 if (raid_device->wwid == wwid && raid_device->starget) {
4921 raid_device->responding = 1;
4922 starget_printk(KERN_INFO, raid_device->starget,
4923 "handle(0x%04x), wwid(0x%016llx)\n", handle,
4924 (unsigned long long)raid_device->wwid);
4925 if (raid_device->handle == handle)
4926 goto out;
4927 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
4928 raid_device->handle);
4929 raid_device->handle = handle;
4930 starget = raid_device->starget;
4931 sas_target_priv_data = starget->hostdata;
4932 sas_target_priv_data->handle = handle;
4933 goto out;
4934 }
4935 }
4936 out:
4937 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4938}
4939
4940/**
4941 * _scsih_search_responding_raid_devices -
4942 * @ioc: per adapter object
4943 *
4944 * After host reset, find out whether devices are still responding.
4945 * If not remove.
4946 *
4947 * Return nothing.
4948 */
4949static void
4950_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
4951{
4952 Mpi2RaidVolPage1_t volume_pg1;
4953 Mpi2ConfigReply_t mpi_reply;
4954 u16 ioc_status;
4955 u16 handle;
4956
4957 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
4958
4959 if (list_empty(&ioc->raid_device_list))
4960 return;
4961
4962 handle = 0xFFFF;
4963 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
4964 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
4965 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4966 MPI2_IOCSTATUS_MASK;
4967 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
4968 break;
4969 handle = le16_to_cpu(volume_pg1.DevHandle);
4970 _scsih_mark_responding_raid_device(ioc,
4971 le64_to_cpu(volume_pg1.WWID), handle);
4972 }
4973}
4974
4975/**
4976 * _scsih_mark_responding_expander - mark a expander as responding
4977 * @ioc: per adapter object
4978 * @sas_address: sas address
4979 * @handle:
4980 *
4981 * After host reset, find out whether devices are still responding.
4982 * Used in _scsi_remove_unresponsive_expanders.
4983 *
4984 * Return nothing.
4985 */
4986static void
4987_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
4988 u16 handle)
4989{
4990 struct _sas_node *sas_expander;
4991 unsigned long flags;
4992
4993 spin_lock_irqsave(&ioc->sas_node_lock, flags);
4994 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
4995 if (sas_expander->sas_address == sas_address) {
4996 sas_expander->responding = 1;
4997 if (sas_expander->handle != handle) {
4998 printk(KERN_INFO "old handle(0x%04x)\n",
4999 sas_expander->handle);
5000 sas_expander->handle = handle;
5001 }
5002 goto out;
5003 }
5004 }
5005 out:
5006 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5007}
5008
5009/**
5010 * _scsih_search_responding_expanders -
5011 * @ioc: per adapter object
5012 *
5013 * After host reset, find out whether devices are still responding.
5014 * If not remove.
5015 *
5016 * Return nothing.
5017 */
5018static void
5019_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5020{
5021 Mpi2ExpanderPage0_t expander_pg0;
5022 Mpi2ConfigReply_t mpi_reply;
5023 u16 ioc_status;
5024 __le64 sas_address;
5025 u16 handle;
5026
5027 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5028
5029 if (list_empty(&ioc->sas_expander_list))
5030 return;
5031
5032 handle = 0xFFFF;
5033 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5034 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5035
5036 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5037 MPI2_IOCSTATUS_MASK;
5038 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5039 break;
5040
5041 handle = le16_to_cpu(expander_pg0.DevHandle);
5042 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5043 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5044 "sas_addr(0x%016llx)\n", handle,
5045 (unsigned long long)sas_address);
5046 _scsih_mark_responding_expander(ioc, sas_address, handle);
5047 }
5048
5049}
5050
5051/**
5052 * _scsih_remove_unresponding_devices - removing unresponding devices
5053 * @ioc: per adapter object
5054 *
5055 * Return nothing.
5056 */
5057static void
5058_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
5059{
5060 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305061 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005062 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005063
Eric Moore635374e2009-03-09 01:21:12 -06005064
5065 list_for_each_entry_safe(sas_device, sas_device_next,
5066 &ioc->sas_device_list, list) {
5067 if (sas_device->responding) {
5068 sas_device->responding = 0;
5069 continue;
5070 }
5071 if (sas_device->starget)
5072 starget_printk(KERN_INFO, sas_device->starget,
5073 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5074 "enclosure logical id(0x%016llx), slot(%d)\n",
5075 sas_device->handle,
5076 (unsigned long long)sas_device->sas_address,
5077 (unsigned long long)
5078 sas_device->enclosure_logical_id,
5079 sas_device->slot);
5080 _scsih_remove_device(ioc, sas_device->handle);
5081 }
5082
5083 list_for_each_entry_safe(raid_device, raid_device_next,
5084 &ioc->raid_device_list, list) {
5085 if (raid_device->responding) {
5086 raid_device->responding = 0;
5087 continue;
5088 }
5089 if (raid_device->starget) {
5090 starget_printk(KERN_INFO, raid_device->starget,
5091 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5092 raid_device->handle,
5093 (unsigned long long)raid_device->wwid);
5094 scsi_remove_target(&raid_device->starget->dev);
5095 }
5096 _scsih_raid_device_remove(ioc, raid_device);
5097 }
5098
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305099 retry_expander_search:
5100 sas_expander = NULL;
5101 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005102 if (sas_expander->responding) {
5103 sas_expander->responding = 0;
5104 continue;
5105 }
Eric Moore635374e2009-03-09 01:21:12 -06005106 _scsih_expander_remove(ioc, sas_expander->handle);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305107 goto retry_expander_search;
5108 }
5109}
5110
5111/**
5112 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5113 * @ioc: per adapter object
5114 * @reset_phase: phase
5115 *
5116 * The handler for doing any required cleanup or initialization.
5117 *
5118 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5119 * MPT2_IOC_DONE_RESET
5120 *
5121 * Return nothing.
5122 */
5123void
5124mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5125{
5126 switch (reset_phase) {
5127 case MPT2_IOC_PRE_RESET:
5128 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5129 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
5130 _scsih_fw_event_off(ioc);
5131 break;
5132 case MPT2_IOC_AFTER_RESET:
5133 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5134 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
5135 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5136 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5137 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5138 complete(&ioc->tm_cmds.done);
5139 }
5140 _scsih_fw_event_on(ioc);
5141 _scsih_flush_running_cmds(ioc);
5142 break;
5143 case MPT2_IOC_DONE_RESET:
5144 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5145 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
5146 _scsih_sas_host_refresh(ioc, 0);
5147 _scsih_search_responding_sas_devices(ioc);
5148 _scsih_search_responding_raid_devices(ioc);
5149 _scsih_search_responding_expanders(ioc);
5150 break;
5151 case MPT2_IOC_RUNNING:
5152 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5153 "MPT2_IOC_RUNNING\n", ioc->name, __func__));
5154 _scsih_remove_unresponding_devices(ioc);
5155 break;
Eric Moore635374e2009-03-09 01:21:12 -06005156 }
5157}
5158
5159/**
5160 * _firmware_event_work - delayed task for processing firmware events
5161 * @ioc: per adapter object
5162 * @work: equal to the fw_event_work object
5163 * Context: user.
5164 *
5165 * Return nothing.
5166 */
5167static void
5168_firmware_event_work(struct work_struct *work)
5169{
5170 struct fw_event_work *fw_event = container_of(work,
Eric Moore6f92a7a2009-04-21 15:43:33 -06005171 struct fw_event_work, work);
Eric Moore635374e2009-03-09 01:21:12 -06005172 unsigned long flags;
5173 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5174
Eric Moore635374e2009-03-09 01:21:12 -06005175 /* the queue is being flushed so ignore this event */
5176 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5177 if (ioc->fw_events_off || ioc->remove_host) {
5178 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5179 _scsih_fw_event_free(ioc, fw_event);
5180 return;
5181 }
5182 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5183
Eric Moore635374e2009-03-09 01:21:12 -06005184 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06005185 _scsih_fw_event_requeue(ioc, fw_event, 1000);
5186 return;
5187 }
Eric Moore635374e2009-03-09 01:21:12 -06005188
5189 switch (fw_event->event) {
5190 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305191 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005192 break;
5193 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305194 _scsih_sas_device_status_change_event(ioc,
5195 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005196 break;
5197 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305198 _scsih_sas_discovery_event(ioc,
5199 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005200 break;
5201 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305202 _scsih_sas_broadcast_primative_event(ioc,
5203 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005204 break;
5205 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5206 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305207 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005208 break;
5209 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305210 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005211 break;
5212 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305213 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005214 break;
5215 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305216 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005217 break;
5218 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305219 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005220 break;
5221 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305222 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005223 break;
5224 }
5225 _scsih_fw_event_free(ioc, fw_event);
5226}
5227
5228/**
5229 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5230 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305231 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06005232 * @reply: reply message frame(lower 32bit addr)
5233 * Context: interrupt.
5234 *
5235 * This function merely adds a new work task into ioc->firmware_event_thread.
5236 * The tasks are worked from _firmware_event_work in user context.
5237 *
5238 * Return nothing.
5239 */
5240void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305241mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
5242 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06005243{
5244 struct fw_event_work *fw_event;
5245 Mpi2EventNotificationReply_t *mpi_reply;
5246 unsigned long flags;
5247 u16 event;
5248
5249 /* events turned off due to host reset or driver unloading */
5250 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5251 if (ioc->fw_events_off || ioc->remove_host) {
5252 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5253 return;
5254 }
5255 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5256
5257 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
5258 event = le16_to_cpu(mpi_reply->Event);
5259
5260 switch (event) {
5261 /* handle these */
5262 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
5263 {
5264 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
5265 (Mpi2EventDataSasBroadcastPrimitive_t *)
5266 mpi_reply->EventData;
5267
5268 if (baen_data->Primitive !=
5269 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
5270 ioc->broadcast_aen_busy)
5271 return;
5272 ioc->broadcast_aen_busy = 1;
5273 break;
5274 }
5275
5276 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
5277 _scsih_check_topo_delete_events(ioc,
5278 (Mpi2EventDataSasTopologyChangeList_t *)
5279 mpi_reply->EventData);
5280 break;
5281
5282 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
5283 case MPI2_EVENT_IR_OPERATION_STATUS:
5284 case MPI2_EVENT_SAS_DISCOVERY:
5285 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5286 case MPI2_EVENT_IR_VOLUME:
5287 case MPI2_EVENT_IR_PHYSICAL_DISK:
5288 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
5289 case MPI2_EVENT_TASK_SET_FULL:
5290 break;
5291
5292 default: /* ignore the rest */
5293 return;
5294 }
5295
5296 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
5297 if (!fw_event) {
5298 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5299 ioc->name, __FILE__, __LINE__, __func__);
5300 return;
5301 }
5302 fw_event->event_data =
5303 kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
5304 if (!fw_event->event_data) {
5305 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5306 ioc->name, __FILE__, __LINE__, __func__);
5307 kfree(fw_event);
5308 return;
5309 }
5310
5311 memcpy(fw_event->event_data, mpi_reply->EventData,
5312 mpi_reply->EventDataLength*4);
5313 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305314 fw_event->VF_ID = mpi_reply->VF_ID;
5315 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06005316 fw_event->event = event;
5317 _scsih_fw_event_add(ioc, fw_event);
5318}
5319
5320/* shost template */
5321static struct scsi_host_template scsih_driver_template = {
5322 .module = THIS_MODULE,
5323 .name = "Fusion MPT SAS Host",
5324 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06005325 .queuecommand = _scsih_qcmd,
5326 .target_alloc = _scsih_target_alloc,
5327 .slave_alloc = _scsih_slave_alloc,
5328 .slave_configure = _scsih_slave_configure,
5329 .target_destroy = _scsih_target_destroy,
5330 .slave_destroy = _scsih_slave_destroy,
5331 .change_queue_depth = _scsih_change_queue_depth,
5332 .change_queue_type = _scsih_change_queue_type,
5333 .eh_abort_handler = _scsih_abort,
5334 .eh_device_reset_handler = _scsih_dev_reset,
5335 .eh_target_reset_handler = _scsih_target_reset,
5336 .eh_host_reset_handler = _scsih_host_reset,
5337 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06005338 .can_queue = 1,
5339 .this_id = -1,
5340 .sg_tablesize = MPT2SAS_SG_DEPTH,
5341 .max_sectors = 8192,
5342 .cmd_per_lun = 7,
5343 .use_clustering = ENABLE_CLUSTERING,
5344 .shost_attrs = mpt2sas_host_attrs,
5345 .sdev_attrs = mpt2sas_dev_attrs,
5346};
5347
5348/**
5349 * _scsih_expander_node_remove - removing expander device from list.
5350 * @ioc: per adapter object
5351 * @sas_expander: the sas_device object
5352 * Context: Calling function should acquire ioc->sas_node_lock.
5353 *
5354 * Removing object and freeing associated memory from the
5355 * ioc->sas_expander_list.
5356 *
5357 * Return nothing.
5358 */
5359static void
5360_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
5361 struct _sas_node *sas_expander)
5362{
5363 struct _sas_port *mpt2sas_port;
5364 struct _sas_device *sas_device;
5365 struct _sas_node *expander_sibling;
5366 unsigned long flags;
5367
5368 if (!sas_expander)
5369 return;
5370
5371 /* remove sibling ports attached to this expander */
5372 retry_device_search:
5373 list_for_each_entry(mpt2sas_port,
5374 &sas_expander->sas_port_list, port_list) {
5375 if (mpt2sas_port->remote_identify.device_type ==
5376 SAS_END_DEVICE) {
5377 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5378 sas_device =
5379 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5380 mpt2sas_port->remote_identify.sas_address);
5381 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5382 if (!sas_device)
5383 continue;
5384 _scsih_remove_device(ioc, sas_device->handle);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305385 if (ioc->shost_recovery)
5386 return;
Eric Moore635374e2009-03-09 01:21:12 -06005387 goto retry_device_search;
5388 }
5389 }
5390
5391 retry_expander_search:
5392 list_for_each_entry(mpt2sas_port,
5393 &sas_expander->sas_port_list, port_list) {
5394
5395 if (mpt2sas_port->remote_identify.device_type ==
5396 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
5397 mpt2sas_port->remote_identify.device_type ==
5398 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
5399
5400 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5401 expander_sibling =
5402 mpt2sas_scsih_expander_find_by_sas_address(
5403 ioc, mpt2sas_port->remote_identify.sas_address);
5404 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5405 if (!expander_sibling)
5406 continue;
5407 _scsih_expander_remove(ioc, expander_sibling->handle);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305408 if (ioc->shost_recovery)
5409 return;
Eric Moore635374e2009-03-09 01:21:12 -06005410 goto retry_expander_search;
5411 }
5412 }
5413
5414 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
5415 sas_expander->parent_handle);
5416
5417 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
5418 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
5419 sas_expander->handle, (unsigned long long)
5420 sas_expander->sas_address);
5421
5422 list_del(&sas_expander->list);
5423 kfree(sas_expander->phy);
5424 kfree(sas_expander);
5425}
5426
5427/**
Eric Moored5d135b2009-05-18 13:02:08 -06005428 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06005429 * @pdev: PCI device struct
5430 *
5431 * Return nothing.
5432 */
5433static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06005434_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06005435{
5436 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5437 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5438 struct _sas_port *mpt2sas_port;
5439 struct _sas_device *sas_device;
5440 struct _sas_node *expander_sibling;
5441 struct workqueue_struct *wq;
5442 unsigned long flags;
5443
5444 ioc->remove_host = 1;
5445 _scsih_fw_event_off(ioc);
5446
5447 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5448 wq = ioc->firmware_event_thread;
5449 ioc->firmware_event_thread = NULL;
5450 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5451 if (wq)
5452 destroy_workqueue(wq);
5453
5454 /* free ports attached to the sas_host */
5455 retry_again:
5456 list_for_each_entry(mpt2sas_port,
5457 &ioc->sas_hba.sas_port_list, port_list) {
5458 if (mpt2sas_port->remote_identify.device_type ==
5459 SAS_END_DEVICE) {
5460 sas_device =
5461 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5462 mpt2sas_port->remote_identify.sas_address);
5463 if (sas_device) {
5464 _scsih_remove_device(ioc, sas_device->handle);
5465 goto retry_again;
5466 }
5467 } else {
5468 expander_sibling =
5469 mpt2sas_scsih_expander_find_by_sas_address(ioc,
5470 mpt2sas_port->remote_identify.sas_address);
5471 if (expander_sibling) {
5472 _scsih_expander_remove(ioc,
5473 expander_sibling->handle);
5474 goto retry_again;
5475 }
5476 }
5477 }
5478
5479 /* free phys attached to the sas_host */
5480 if (ioc->sas_hba.num_phys) {
5481 kfree(ioc->sas_hba.phy);
5482 ioc->sas_hba.phy = NULL;
5483 ioc->sas_hba.num_phys = 0;
5484 }
5485
5486 sas_remove_host(shost);
5487 mpt2sas_base_detach(ioc);
5488 list_del(&ioc->list);
5489 scsi_remove_host(shost);
5490 scsi_host_put(shost);
5491}
5492
5493/**
5494 * _scsih_probe_boot_devices - reports 1st device
5495 * @ioc: per adapter object
5496 *
5497 * If specified in bios page 2, this routine reports the 1st
5498 * device scsi-ml or sas transport for persistent boot device
5499 * purposes. Please refer to function _scsih_determine_boot_device()
5500 */
5501static void
5502_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
5503{
5504 u8 is_raid;
5505 void *device;
5506 struct _sas_device *sas_device;
5507 struct _raid_device *raid_device;
5508 u16 handle, parent_handle;
5509 u64 sas_address;
5510 unsigned long flags;
5511 int rc;
5512
5513 device = NULL;
5514 if (ioc->req_boot_device.device) {
5515 device = ioc->req_boot_device.device;
5516 is_raid = ioc->req_boot_device.is_raid;
5517 } else if (ioc->req_alt_boot_device.device) {
5518 device = ioc->req_alt_boot_device.device;
5519 is_raid = ioc->req_alt_boot_device.is_raid;
5520 } else if (ioc->current_boot_device.device) {
5521 device = ioc->current_boot_device.device;
5522 is_raid = ioc->current_boot_device.is_raid;
5523 }
5524
5525 if (!device)
5526 return;
5527
5528 if (is_raid) {
5529 raid_device = device;
5530 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5531 raid_device->id, 0);
5532 if (rc)
5533 _scsih_raid_device_remove(ioc, raid_device);
5534 } else {
5535 sas_device = device;
5536 handle = sas_device->handle;
5537 parent_handle = sas_device->parent_handle;
5538 sas_address = sas_device->sas_address;
5539 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5540 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5541 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5542 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
5543 sas_device->parent_handle)) {
5544 _scsih_sas_device_remove(ioc, sas_device);
5545 } else if (!sas_device->starget) {
5546 mpt2sas_transport_port_remove(ioc, sas_address,
5547 parent_handle);
5548 _scsih_sas_device_remove(ioc, sas_device);
5549 }
5550 }
5551}
5552
5553/**
5554 * _scsih_probe_raid - reporting raid volumes to scsi-ml
5555 * @ioc: per adapter object
5556 *
5557 * Called during initial loading of the driver.
5558 */
5559static void
5560_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
5561{
5562 struct _raid_device *raid_device, *raid_next;
5563 int rc;
5564
5565 list_for_each_entry_safe(raid_device, raid_next,
5566 &ioc->raid_device_list, list) {
5567 if (raid_device->starget)
5568 continue;
5569 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5570 raid_device->id, 0);
5571 if (rc)
5572 _scsih_raid_device_remove(ioc, raid_device);
5573 }
5574}
5575
5576/**
5577 * _scsih_probe_sas - reporting raid volumes to sas transport
5578 * @ioc: per adapter object
5579 *
5580 * Called during initial loading of the driver.
5581 */
5582static void
5583_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
5584{
5585 struct _sas_device *sas_device, *next;
5586 unsigned long flags;
5587 u16 handle, parent_handle;
5588 u64 sas_address;
5589
5590 /* SAS Device List */
5591 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
5592 list) {
5593 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5594 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5595 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5596
5597 handle = sas_device->handle;
5598 parent_handle = sas_device->parent_handle;
5599 sas_address = sas_device->sas_address;
5600 if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) {
5601 _scsih_sas_device_remove(ioc, sas_device);
5602 } else if (!sas_device->starget) {
5603 mpt2sas_transport_port_remove(ioc, sas_address,
5604 parent_handle);
5605 _scsih_sas_device_remove(ioc, sas_device);
5606 }
5607 }
5608}
5609
5610/**
5611 * _scsih_probe_devices - probing for devices
5612 * @ioc: per adapter object
5613 *
5614 * Called during initial loading of the driver.
5615 */
5616static void
5617_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
5618{
5619 u16 volume_mapping_flags =
5620 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
5621 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
5622
5623 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
5624 return; /* return when IOC doesn't support initiator mode */
5625
5626 _scsih_probe_boot_devices(ioc);
5627
5628 if (ioc->ir_firmware) {
5629 if ((volume_mapping_flags &
5630 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
5631 _scsih_probe_sas(ioc);
5632 _scsih_probe_raid(ioc);
5633 } else {
5634 _scsih_probe_raid(ioc);
5635 _scsih_probe_sas(ioc);
5636 }
5637 } else
5638 _scsih_probe_sas(ioc);
5639}
5640
5641/**
Eric Moored5d135b2009-05-18 13:02:08 -06005642 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06005643 * @pdev: PCI device struct
5644 * @id: pci device id
5645 *
5646 * Returns 0 success, anything else error.
5647 */
5648static int
Eric Moored5d135b2009-05-18 13:02:08 -06005649_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06005650{
5651 struct MPT2SAS_ADAPTER *ioc;
5652 struct Scsi_Host *shost;
5653
5654 shost = scsi_host_alloc(&scsih_driver_template,
5655 sizeof(struct MPT2SAS_ADAPTER));
5656 if (!shost)
5657 return -ENODEV;
5658
5659 /* init local params */
5660 ioc = shost_priv(shost);
5661 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
5662 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06005663 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06005664 ioc->shost = shost;
5665 ioc->id = mpt_ids++;
5666 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
5667 ioc->pdev = pdev;
5668 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
5669 ioc->tm_cb_idx = tm_cb_idx;
5670 ioc->ctl_cb_idx = ctl_cb_idx;
5671 ioc->base_cb_idx = base_cb_idx;
5672 ioc->transport_cb_idx = transport_cb_idx;
5673 ioc->config_cb_idx = config_cb_idx;
5674 ioc->logging_level = logging_level;
5675 /* misc semaphores and spin locks */
5676 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
5677 spin_lock_init(&ioc->scsi_lookup_lock);
5678 spin_lock_init(&ioc->sas_device_lock);
5679 spin_lock_init(&ioc->sas_node_lock);
5680 spin_lock_init(&ioc->fw_event_lock);
5681 spin_lock_init(&ioc->raid_device_lock);
5682
5683 INIT_LIST_HEAD(&ioc->sas_device_list);
5684 INIT_LIST_HEAD(&ioc->sas_device_init_list);
5685 INIT_LIST_HEAD(&ioc->sas_expander_list);
5686 INIT_LIST_HEAD(&ioc->fw_event_list);
5687 INIT_LIST_HEAD(&ioc->raid_device_list);
5688 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
5689
5690 /* init shost parameters */
5691 shost->max_cmd_len = 16;
5692 shost->max_lun = max_lun;
5693 shost->transportt = mpt2sas_transport_template;
5694 shost->unique_id = ioc->id;
5695
5696 if ((scsi_add_host(shost, &pdev->dev))) {
5697 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5698 ioc->name, __FILE__, __LINE__, __func__);
5699 list_del(&ioc->list);
5700 goto out_add_shost_fail;
5701 }
5702
Eric Moore3c621b32009-05-18 12:59:41 -06005703 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
5704 | SHOST_DIF_TYPE3_PROTECTION);
5705
Eric Moore635374e2009-03-09 01:21:12 -06005706 /* event thread */
5707 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
5708 "fw_event%d", ioc->id);
5709 ioc->firmware_event_thread = create_singlethread_workqueue(
5710 ioc->firmware_event_name);
5711 if (!ioc->firmware_event_thread) {
5712 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5713 ioc->name, __FILE__, __LINE__, __func__);
5714 goto out_thread_fail;
5715 }
5716
5717 ioc->wait_for_port_enable_to_complete = 1;
5718 if ((mpt2sas_base_attach(ioc))) {
5719 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5720 ioc->name, __FILE__, __LINE__, __func__);
5721 goto out_attach_fail;
5722 }
5723
5724 ioc->wait_for_port_enable_to_complete = 0;
5725 _scsih_probe_devices(ioc);
5726 return 0;
5727
5728 out_attach_fail:
5729 destroy_workqueue(ioc->firmware_event_thread);
5730 out_thread_fail:
5731 list_del(&ioc->list);
5732 scsi_remove_host(shost);
5733 out_add_shost_fail:
5734 return -ENODEV;
5735}
5736
5737#ifdef CONFIG_PM
5738/**
Eric Moored5d135b2009-05-18 13:02:08 -06005739 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06005740 * @pdev: PCI device struct
5741 * @state: PM state change to (usually PCI_D3)
5742 *
5743 * Returns 0 success, anything else error.
5744 */
5745static int
Eric Moored5d135b2009-05-18 13:02:08 -06005746_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06005747{
5748 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5749 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5750 u32 device_state;
5751
Kashyap, Desaie4750c92009-08-07 19:37:59 +05305752 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005753 flush_scheduled_work();
5754 scsi_block_requests(shost);
5755 device_state = pci_choose_state(pdev, state);
5756 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
5757 "operating state [D%d]\n", ioc->name, pdev,
5758 pci_name(pdev), device_state);
5759
5760 mpt2sas_base_free_resources(ioc);
5761 pci_save_state(pdev);
5762 pci_disable_device(pdev);
5763 pci_set_power_state(pdev, device_state);
5764 return 0;
5765}
5766
5767/**
Eric Moored5d135b2009-05-18 13:02:08 -06005768 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06005769 * @pdev: PCI device struct
5770 *
5771 * Returns 0 success, anything else error.
5772 */
5773static int
Eric Moored5d135b2009-05-18 13:02:08 -06005774_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06005775{
5776 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5777 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5778 u32 device_state = pdev->current_state;
5779 int r;
5780
5781 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
5782 "operating state [D%d]\n", ioc->name, pdev,
5783 pci_name(pdev), device_state);
5784
5785 pci_set_power_state(pdev, PCI_D0);
5786 pci_enable_wake(pdev, PCI_D0, 0);
5787 pci_restore_state(pdev);
5788 ioc->pdev = pdev;
5789 r = mpt2sas_base_map_resources(ioc);
5790 if (r)
5791 return r;
5792
5793 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
5794 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05305795 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005796 return 0;
5797}
5798#endif /* CONFIG_PM */
5799
5800
5801static struct pci_driver scsih_driver = {
5802 .name = MPT2SAS_DRIVER_NAME,
5803 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06005804 .probe = _scsih_probe,
5805 .remove = __devexit_p(_scsih_remove),
Eric Moore635374e2009-03-09 01:21:12 -06005806#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06005807 .suspend = _scsih_suspend,
5808 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06005809#endif
5810};
5811
5812
5813/**
Eric Moored5d135b2009-05-18 13:02:08 -06005814 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06005815 *
5816 * Returns 0 success, anything else error.
5817 */
5818static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06005819_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06005820{
5821 int error;
5822
5823 mpt_ids = 0;
5824 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
5825 MPT2SAS_DRIVER_VERSION);
5826
5827 mpt2sas_transport_template =
5828 sas_attach_transport(&mpt2sas_transport_functions);
5829 if (!mpt2sas_transport_template)
5830 return -ENODEV;
5831
5832 mpt2sas_base_initialize_callback_handler();
5833
5834 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06005835 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06005836
5837 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06005838 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06005839
5840 /* base internal commands callback handler */
5841 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
5842
5843 /* transport internal commands callback handler */
5844 transport_cb_idx = mpt2sas_base_register_callback_handler(
5845 mpt2sas_transport_done);
5846
5847 /* configuration page API internal commands callback handler */
5848 config_cb_idx = mpt2sas_base_register_callback_handler(
5849 mpt2sas_config_done);
5850
5851 /* ctl module callback handler */
5852 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
5853
5854 mpt2sas_ctl_init();
5855
5856 error = pci_register_driver(&scsih_driver);
5857 if (error)
5858 sas_release_transport(mpt2sas_transport_template);
5859
5860 return error;
5861}
5862
5863/**
Eric Moored5d135b2009-05-18 13:02:08 -06005864 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06005865 *
5866 * Returns 0 success, anything else error.
5867 */
5868static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06005869_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06005870{
5871 printk(KERN_INFO "mpt2sas version %s unloading\n",
5872 MPT2SAS_DRIVER_VERSION);
5873
5874 pci_unregister_driver(&scsih_driver);
5875
5876 sas_release_transport(mpt2sas_transport_template);
5877 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
5878 mpt2sas_base_release_callback_handler(tm_cb_idx);
5879 mpt2sas_base_release_callback_handler(base_cb_idx);
5880 mpt2sas_base_release_callback_handler(transport_cb_idx);
5881 mpt2sas_base_release_callback_handler(config_cb_idx);
5882 mpt2sas_base_release_callback_handler(ctl_cb_idx);
5883
5884 mpt2sas_ctl_exit();
5885}
5886
Eric Moored5d135b2009-05-18 13:02:08 -06005887module_init(_scsih_init);
5888module_exit(_scsih_exit);