blob: 8277fa36689874e9e3006903abaeae4cea0665a9 [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
5 * Copyright (C) 2007-2008 LSI Corporation
6 * (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/**
765 * _scsih_scsi_lookup_get - returns scmd entry
766 * @ioc: per adapter object
767 * @smid: system request message index
768 * Context: This function will acquire ioc->scsi_lookup_lock.
769 *
770 * Returns the smid stored scmd pointer.
771 */
772static struct scsi_cmnd *
773_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
774{
775 unsigned long flags;
776 struct scsi_cmnd *scmd;
777
778 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
779 scmd = ioc->scsi_lookup[smid - 1].scmd;
780 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
781 return scmd;
782}
783
784/**
785 * mptscsih_getclear_scsi_lookup - returns scmd entry
786 * @ioc: per adapter object
787 * @smid: system request message index
788 * Context: This function will acquire ioc->scsi_lookup_lock.
789 *
790 * Returns the smid stored scmd pointer, as well as clearing the scmd pointer.
791 */
792static struct scsi_cmnd *
793_scsih_scsi_lookup_getclear(struct MPT2SAS_ADAPTER *ioc, u16 smid)
794{
795 unsigned long flags;
796 struct scsi_cmnd *scmd;
797
798 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
799 scmd = ioc->scsi_lookup[smid - 1].scmd;
800 ioc->scsi_lookup[smid - 1].scmd = NULL;
801 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
802 return scmd;
803}
804
805/**
806 * _scsih_scsi_lookup_set - updates scmd entry in lookup
807 * @ioc: per adapter object
808 * @smid: system request message index
809 * @scmd: pointer to scsi command object
810 * Context: This function will acquire ioc->scsi_lookup_lock.
811 *
812 * This will save scmd pointer in the scsi_lookup array.
813 *
814 * Return nothing.
815 */
816static void
817_scsih_scsi_lookup_set(struct MPT2SAS_ADAPTER *ioc, u16 smid,
818 struct scsi_cmnd *scmd)
819{
820 unsigned long flags;
821
822 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
823 ioc->scsi_lookup[smid - 1].scmd = scmd;
824 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
825}
826
827/**
828 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
829 * @ioc: per adapter object
830 * @smid: system request message index
831 * @scmd: pointer to scsi command object
832 * Context: This function will acquire ioc->scsi_lookup_lock.
833 *
834 * This will search for a scmd pointer in the scsi_lookup array,
835 * returning the revelent smid. A returned value of zero means invalid.
836 */
837static u16
838_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
839 *scmd)
840{
841 u16 smid;
842 unsigned long flags;
843 int i;
844
845 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
846 smid = 0;
847 for (i = 0; i < ioc->request_depth; i++) {
848 if (ioc->scsi_lookup[i].scmd == scmd) {
849 smid = i + 1;
850 goto out;
851 }
852 }
853 out:
854 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
855 return smid;
856}
857
858/**
859 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
860 * @ioc: per adapter object
861 * @id: target id
862 * @channel: channel
863 * Context: This function will acquire ioc->scsi_lookup_lock.
864 *
865 * This will search for a matching channel:id in the scsi_lookup array,
866 * returning 1 if found.
867 */
868static u8
869_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
870 int channel)
871{
872 u8 found;
873 unsigned long flags;
874 int i;
875
876 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
877 found = 0;
878 for (i = 0 ; i < ioc->request_depth; i++) {
879 if (ioc->scsi_lookup[i].scmd &&
880 (ioc->scsi_lookup[i].scmd->device->id == id &&
881 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
882 found = 1;
883 goto out;
884 }
885 }
886 out:
887 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
888 return found;
889}
890
891/**
Eric Moore993e0da2009-05-18 13:00:45 -0600892 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
893 * @ioc: per adapter object
894 * @id: target id
895 * @lun: lun number
896 * @channel: channel
897 * Context: This function will acquire ioc->scsi_lookup_lock.
898 *
899 * This will search for a matching channel:id:lun in the scsi_lookup array,
900 * returning 1 if found.
901 */
902static u8
903_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
904 unsigned int lun, int channel)
905{
906 u8 found;
907 unsigned long flags;
908 int i;
909
910 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
911 found = 0;
912 for (i = 0 ; i < ioc->request_depth; i++) {
913 if (ioc->scsi_lookup[i].scmd &&
914 (ioc->scsi_lookup[i].scmd->device->id == id &&
915 ioc->scsi_lookup[i].scmd->device->channel == channel &&
916 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
917 found = 1;
918 goto out;
919 }
920 }
921 out:
922 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
923 return found;
924}
925
926/**
Eric Moore635374e2009-03-09 01:21:12 -0600927 * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
928 * @ioc: per adapter object
929 * @smid: system request message index
930 *
931 * Returns phys pointer to chain buffer.
932 */
933static dma_addr_t
934_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
935{
936 return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
937 ioc->chains_needed_per_io));
938}
939
940/**
941 * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
942 * @ioc: per adapter object
943 * @smid: system request message index
944 *
945 * Returns virt pointer to chain buffer.
946 */
947static void *
948_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
949{
950 return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
951 ioc->chains_needed_per_io)));
952}
953
954/**
955 * _scsih_build_scatter_gather - main sg creation routine
956 * @ioc: per adapter object
957 * @scmd: scsi command
958 * @smid: system request message index
959 * Context: none.
960 *
961 * The main routine that builds scatter gather table from a given
962 * scsi request sent via the .queuecommand main handler.
963 *
964 * Returns 0 success, anything else error
965 */
966static int
967_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
968 struct scsi_cmnd *scmd, u16 smid)
969{
970 Mpi2SCSIIORequest_t *mpi_request;
971 dma_addr_t chain_dma;
972 struct scatterlist *sg_scmd;
973 void *sg_local, *chain;
974 u32 chain_offset;
975 u32 chain_length;
976 u32 chain_flags;
977 u32 sges_left;
978 u32 sges_in_segment;
979 u32 sgl_flags;
980 u32 sgl_flags_last_element;
981 u32 sgl_flags_end_buffer;
982
983 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
984
985 /* init scatter gather flags */
986 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
987 if (scmd->sc_data_direction == DMA_TO_DEVICE)
988 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
989 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
990 << MPI2_SGE_FLAGS_SHIFT;
991 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
992 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
993 << MPI2_SGE_FLAGS_SHIFT;
994 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
995
996 sg_scmd = scsi_sglist(scmd);
997 sges_left = scsi_dma_map(scmd);
998 if (!sges_left) {
999 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
1000 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
1001 return -ENOMEM;
1002 }
1003
1004 sg_local = &mpi_request->SGL;
1005 sges_in_segment = ioc->max_sges_in_main_message;
1006 if (sges_left <= sges_in_segment)
1007 goto fill_in_last_segment;
1008
1009 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
1010 (sges_in_segment * ioc->sge_size))/4;
1011
1012 /* fill in main message segment when there is a chain following */
1013 while (sges_in_segment) {
1014 if (sges_in_segment == 1)
1015 ioc->base_add_sg_single(sg_local,
1016 sgl_flags_last_element | sg_dma_len(sg_scmd),
1017 sg_dma_address(sg_scmd));
1018 else
1019 ioc->base_add_sg_single(sg_local, sgl_flags |
1020 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1021 sg_scmd = sg_next(sg_scmd);
1022 sg_local += ioc->sge_size;
1023 sges_left--;
1024 sges_in_segment--;
1025 }
1026
1027 /* initializing the chain flags and pointers */
1028 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
1029 chain = _scsih_get_chain_buffer(ioc, smid);
1030 chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
1031 do {
1032 sges_in_segment = (sges_left <=
1033 ioc->max_sges_in_chain_message) ? sges_left :
1034 ioc->max_sges_in_chain_message;
1035 chain_offset = (sges_left == sges_in_segment) ?
1036 0 : (sges_in_segment * ioc->sge_size)/4;
1037 chain_length = sges_in_segment * ioc->sge_size;
1038 if (chain_offset) {
1039 chain_offset = chain_offset <<
1040 MPI2_SGE_CHAIN_OFFSET_SHIFT;
1041 chain_length += ioc->sge_size;
1042 }
1043 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
1044 chain_length, chain_dma);
1045 sg_local = chain;
1046 if (!chain_offset)
1047 goto fill_in_last_segment;
1048
1049 /* fill in chain segments */
1050 while (sges_in_segment) {
1051 if (sges_in_segment == 1)
1052 ioc->base_add_sg_single(sg_local,
1053 sgl_flags_last_element |
1054 sg_dma_len(sg_scmd),
1055 sg_dma_address(sg_scmd));
1056 else
1057 ioc->base_add_sg_single(sg_local, sgl_flags |
1058 sg_dma_len(sg_scmd),
1059 sg_dma_address(sg_scmd));
1060 sg_scmd = sg_next(sg_scmd);
1061 sg_local += ioc->sge_size;
1062 sges_left--;
1063 sges_in_segment--;
1064 }
1065
1066 chain_dma += ioc->request_sz;
1067 chain += ioc->request_sz;
1068 } while (1);
1069
1070
1071 fill_in_last_segment:
1072
1073 /* fill the last segment */
1074 while (sges_left) {
1075 if (sges_left == 1)
1076 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1077 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1078 else
1079 ioc->base_add_sg_single(sg_local, sgl_flags |
1080 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1081 sg_scmd = sg_next(sg_scmd);
1082 sg_local += ioc->sge_size;
1083 sges_left--;
1084 }
1085
1086 return 0;
1087}
1088
1089/**
Eric Moored5d135b2009-05-18 13:02:08 -06001090 * _scsih_change_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001091 * @sdev: scsi device struct
1092 * @qdepth: requested queue depth
1093 *
1094 * Returns queue depth.
1095 */
1096static int
Eric Moored5d135b2009-05-18 13:02:08 -06001097_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Eric Moore635374e2009-03-09 01:21:12 -06001098{
1099 struct Scsi_Host *shost = sdev->host;
1100 int max_depth;
1101 int tag_type;
1102
1103 max_depth = shost->can_queue;
1104 if (!sdev->tagged_supported)
1105 max_depth = 1;
1106 if (qdepth > max_depth)
1107 qdepth = max_depth;
1108 tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
1109 scsi_adjust_queue_depth(sdev, tag_type, qdepth);
1110
1111 if (sdev->inquiry_len > 7)
1112 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1113 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1114 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1115 sdev->ordered_tags, sdev->scsi_level,
1116 (sdev->inquiry[7] & 2) >> 1);
1117
1118 return sdev->queue_depth;
1119}
1120
1121/**
Eric Moored5d135b2009-05-18 13:02:08 -06001122 * _scsih_change_queue_depth - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001123 * @sdev: scsi device struct
1124 * @tag_type: requested tag type
1125 *
1126 * Returns queue tag type.
1127 */
1128static int
Eric Moored5d135b2009-05-18 13:02:08 -06001129_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001130{
1131 if (sdev->tagged_supported) {
1132 scsi_set_tag_type(sdev, tag_type);
1133 if (tag_type)
1134 scsi_activate_tcq(sdev, sdev->queue_depth);
1135 else
1136 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1137 } else
1138 tag_type = 0;
1139
1140 return tag_type;
1141}
1142
1143/**
Eric Moored5d135b2009-05-18 13:02:08 -06001144 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001145 * @starget: scsi target struct
1146 *
1147 * Returns 0 if ok. Any other return is assumed to be an error and
1148 * the device is ignored.
1149 */
1150static int
Eric Moored5d135b2009-05-18 13:02:08 -06001151_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001152{
1153 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1154 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1155 struct MPT2SAS_TARGET *sas_target_priv_data;
1156 struct _sas_device *sas_device;
1157 struct _raid_device *raid_device;
1158 unsigned long flags;
1159 struct sas_rphy *rphy;
1160
1161 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1162 if (!sas_target_priv_data)
1163 return -ENOMEM;
1164
1165 starget->hostdata = sas_target_priv_data;
1166 sas_target_priv_data->starget = starget;
1167 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1168
1169 /* RAID volumes */
1170 if (starget->channel == RAID_CHANNEL) {
1171 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1172 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1173 starget->channel);
1174 if (raid_device) {
1175 sas_target_priv_data->handle = raid_device->handle;
1176 sas_target_priv_data->sas_address = raid_device->wwid;
1177 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
1178 raid_device->starget = starget;
1179 }
1180 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1181 return 0;
1182 }
1183
1184 /* sas/sata devices */
1185 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1186 rphy = dev_to_rphy(starget->dev.parent);
1187 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1188 rphy->identify.sas_address);
1189
1190 if (sas_device) {
1191 sas_target_priv_data->handle = sas_device->handle;
1192 sas_target_priv_data->sas_address = sas_device->sas_address;
1193 sas_device->starget = starget;
1194 sas_device->id = starget->id;
1195 sas_device->channel = starget->channel;
1196 if (sas_device->hidden_raid_component)
1197 sas_target_priv_data->flags |=
1198 MPT_TARGET_FLAGS_RAID_COMPONENT;
1199 }
1200 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1201
1202 return 0;
1203}
1204
1205/**
Eric Moored5d135b2009-05-18 13:02:08 -06001206 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001207 * @starget: scsi target struct
1208 *
1209 * Returns nothing.
1210 */
1211static void
Eric Moored5d135b2009-05-18 13:02:08 -06001212_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001213{
1214 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1215 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1216 struct MPT2SAS_TARGET *sas_target_priv_data;
1217 struct _sas_device *sas_device;
1218 struct _raid_device *raid_device;
1219 unsigned long flags;
1220 struct sas_rphy *rphy;
1221
1222 sas_target_priv_data = starget->hostdata;
1223 if (!sas_target_priv_data)
1224 return;
1225
1226 if (starget->channel == RAID_CHANNEL) {
1227 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1228 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1229 starget->channel);
1230 if (raid_device) {
1231 raid_device->starget = NULL;
1232 raid_device->sdev = NULL;
1233 }
1234 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1235 goto out;
1236 }
1237
1238 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1239 rphy = dev_to_rphy(starget->dev.parent);
1240 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1241 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001242 if (sas_device && (sas_device->starget == starget) &&
1243 (sas_device->id == starget->id) &&
1244 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001245 sas_device->starget = NULL;
1246
1247 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1248
1249 out:
1250 kfree(sas_target_priv_data);
1251 starget->hostdata = NULL;
1252}
1253
1254/**
Eric Moored5d135b2009-05-18 13:02:08 -06001255 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001256 * @sdev: scsi device struct
1257 *
1258 * Returns 0 if ok. Any other return is assumed to be an error and
1259 * the device is ignored.
1260 */
1261static int
Eric Moored5d135b2009-05-18 13:02:08 -06001262_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001263{
1264 struct Scsi_Host *shost;
1265 struct MPT2SAS_ADAPTER *ioc;
1266 struct MPT2SAS_TARGET *sas_target_priv_data;
1267 struct MPT2SAS_DEVICE *sas_device_priv_data;
1268 struct scsi_target *starget;
1269 struct _raid_device *raid_device;
1270 struct _sas_device *sas_device;
1271 unsigned long flags;
1272
1273 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1274 if (!sas_device_priv_data)
1275 return -ENOMEM;
1276
1277 sas_device_priv_data->lun = sdev->lun;
1278 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1279
1280 starget = scsi_target(sdev);
1281 sas_target_priv_data = starget->hostdata;
1282 sas_target_priv_data->num_luns++;
1283 sas_device_priv_data->sas_target = sas_target_priv_data;
1284 sdev->hostdata = sas_device_priv_data;
1285 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1286 sdev->no_uld_attach = 1;
1287
1288 shost = dev_to_shost(&starget->dev);
1289 ioc = shost_priv(shost);
1290 if (starget->channel == RAID_CHANNEL) {
1291 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1292 raid_device = _scsih_raid_device_find_by_id(ioc,
1293 starget->id, starget->channel);
1294 if (raid_device)
1295 raid_device->sdev = sdev; /* raid is single lun */
1296 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1297 } else {
1298 /* set TLR bit for SSP devices */
1299 if (!(ioc->facts.IOCCapabilities &
1300 MPI2_IOCFACTS_CAPABILITY_TLR))
1301 goto out;
1302 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1303 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1304 sas_device_priv_data->sas_target->sas_address);
1305 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1306 if (sas_device && sas_device->device_info &
1307 MPI2_SAS_DEVICE_INFO_SSP_TARGET)
1308 sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON;
1309 }
1310
1311 out:
1312 return 0;
1313}
1314
1315/**
Eric Moored5d135b2009-05-18 13:02:08 -06001316 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001317 * @sdev: scsi device struct
1318 *
1319 * Returns nothing.
1320 */
1321static void
Eric Moored5d135b2009-05-18 13:02:08 -06001322_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001323{
1324 struct MPT2SAS_TARGET *sas_target_priv_data;
1325 struct scsi_target *starget;
1326
1327 if (!sdev->hostdata)
1328 return;
1329
1330 starget = scsi_target(sdev);
1331 sas_target_priv_data = starget->hostdata;
1332 sas_target_priv_data->num_luns--;
1333 kfree(sdev->hostdata);
1334 sdev->hostdata = NULL;
1335}
1336
1337/**
Eric Moored5d135b2009-05-18 13:02:08 -06001338 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001339 * @ioc: per adapter object
1340 * @sas_device: the sas_device object
1341 * @sdev: scsi device struct
1342 */
1343static void
Eric Moored5d135b2009-05-18 13:02:08 -06001344_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06001345 struct _sas_device *sas_device, struct scsi_device *sdev)
1346{
1347 Mpi2ConfigReply_t mpi_reply;
1348 Mpi2SasDevicePage0_t sas_device_pg0;
1349 u32 ioc_status;
1350 u16 flags;
1351 u32 device_info;
1352
1353 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
1354 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
1355 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1356 ioc->name, __FILE__, __LINE__, __func__);
1357 return;
1358 }
1359
1360 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1361 MPI2_IOCSTATUS_MASK;
1362 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1363 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1364 ioc->name, __FILE__, __LINE__, __func__);
1365 return;
1366 }
1367
1368 flags = le16_to_cpu(sas_device_pg0.Flags);
1369 device_info = le16_to_cpu(sas_device_pg0.DeviceInfo);
1370
1371 sdev_printk(KERN_INFO, sdev,
1372 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1373 "sw_preserve(%s)\n",
1374 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1375 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1376 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1377 "n",
1378 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1379 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1380 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1381}
1382
1383/**
1384 * _scsih_get_volume_capabilities - volume capabilities
1385 * @ioc: per adapter object
1386 * @sas_device: the raid_device object
1387 */
1388static void
1389_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1390 struct _raid_device *raid_device)
1391{
1392 Mpi2RaidVolPage0_t *vol_pg0;
1393 Mpi2RaidPhysDiskPage0_t pd_pg0;
1394 Mpi2SasDevicePage0_t sas_device_pg0;
1395 Mpi2ConfigReply_t mpi_reply;
1396 u16 sz;
1397 u8 num_pds;
1398
1399 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1400 &num_pds)) || !num_pds) {
1401 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1402 ioc->name, __FILE__, __LINE__, __func__);
1403 return;
1404 }
1405
1406 raid_device->num_pds = num_pds;
1407 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1408 sizeof(Mpi2RaidVol0PhysDisk_t));
1409 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1410 if (!vol_pg0) {
1411 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1412 ioc->name, __FILE__, __LINE__, __func__);
1413 return;
1414 }
1415
1416 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1417 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1418 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1419 ioc->name, __FILE__, __LINE__, __func__);
1420 kfree(vol_pg0);
1421 return;
1422 }
1423
1424 raid_device->volume_type = vol_pg0->VolumeType;
1425
1426 /* figure out what the underlying devices are by
1427 * obtaining the device_info bits for the 1st device
1428 */
1429 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1430 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1431 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1432 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1433 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1434 le16_to_cpu(pd_pg0.DevHandle)))) {
1435 raid_device->device_info =
1436 le32_to_cpu(sas_device_pg0.DeviceInfo);
1437 }
1438 }
1439
1440 kfree(vol_pg0);
1441}
1442
1443/**
Eric Moored5d135b2009-05-18 13:02:08 -06001444 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001445 * @sdev: scsi device struct
1446 *
1447 * Returns 0 if ok. Any other return is assumed to be an error and
1448 * the device is ignored.
1449 */
1450static int
Eric Moored5d135b2009-05-18 13:02:08 -06001451_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001452{
1453 struct Scsi_Host *shost = sdev->host;
1454 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1455 struct MPT2SAS_DEVICE *sas_device_priv_data;
1456 struct MPT2SAS_TARGET *sas_target_priv_data;
1457 struct _sas_device *sas_device;
1458 struct _raid_device *raid_device;
1459 unsigned long flags;
1460 int qdepth;
1461 u8 ssp_target = 0;
1462 char *ds = "";
1463 char *r_level = "";
1464
1465 qdepth = 1;
1466 sas_device_priv_data = sdev->hostdata;
1467 sas_device_priv_data->configured_lun = 1;
1468 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1469 sas_target_priv_data = sas_device_priv_data->sas_target;
1470
1471 /* raid volume handling */
1472 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1473
1474 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1475 raid_device = _scsih_raid_device_find_by_handle(ioc,
1476 sas_target_priv_data->handle);
1477 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1478 if (!raid_device) {
1479 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1480 ioc->name, __FILE__, __LINE__, __func__);
1481 return 0;
1482 }
1483
1484 _scsih_get_volume_capabilities(ioc, raid_device);
1485
1486 /* RAID Queue Depth Support
1487 * IS volume = underlying qdepth of drive type, either
1488 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
1489 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
1490 */
1491 if (raid_device->device_info &
1492 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1493 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1494 ds = "SSP";
1495 } else {
1496 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1497 if (raid_device->device_info &
1498 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1499 ds = "SATA";
1500 else
1501 ds = "STP";
1502 }
1503
1504 switch (raid_device->volume_type) {
1505 case MPI2_RAID_VOL_TYPE_RAID0:
1506 r_level = "RAID0";
1507 break;
1508 case MPI2_RAID_VOL_TYPE_RAID1E:
1509 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05301510 if (ioc->manu_pg10.OEMIdentifier &&
1511 (ioc->manu_pg10.GenericFlags0 &
1512 MFG10_GF0_R10_DISPLAY) &&
1513 !(raid_device->num_pds % 2))
1514 r_level = "RAID10";
1515 else
1516 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06001517 break;
1518 case MPI2_RAID_VOL_TYPE_RAID1:
1519 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1520 r_level = "RAID1";
1521 break;
1522 case MPI2_RAID_VOL_TYPE_RAID10:
1523 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1524 r_level = "RAID10";
1525 break;
1526 case MPI2_RAID_VOL_TYPE_UNKNOWN:
1527 default:
1528 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1529 r_level = "RAIDX";
1530 break;
1531 }
1532
1533 sdev_printk(KERN_INFO, sdev, "%s: "
1534 "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
1535 r_level, raid_device->handle,
1536 (unsigned long long)raid_device->wwid,
1537 raid_device->num_pds, ds);
Eric Moored5d135b2009-05-18 13:02:08 -06001538 _scsih_change_queue_depth(sdev, qdepth);
Eric Moore635374e2009-03-09 01:21:12 -06001539 return 0;
1540 }
1541
1542 /* non-raid handling */
1543 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1544 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1545 sas_device_priv_data->sas_target->sas_address);
1546 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1547 if (sas_device) {
1548 if (sas_target_priv_data->flags &
1549 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1550 mpt2sas_config_get_volume_handle(ioc,
1551 sas_device->handle, &sas_device->volume_handle);
1552 mpt2sas_config_get_volume_wwid(ioc,
1553 sas_device->volume_handle,
1554 &sas_device->volume_wwid);
1555 }
1556 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1557 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1558 ssp_target = 1;
1559 ds = "SSP";
1560 } else {
1561 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1562 if (sas_device->device_info &
1563 MPI2_SAS_DEVICE_INFO_STP_TARGET)
1564 ds = "STP";
1565 else if (sas_device->device_info &
1566 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1567 ds = "SATA";
1568 }
1569
1570 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
1571 "sas_addr(0x%016llx), device_name(0x%016llx)\n",
1572 ds, sas_device->handle,
1573 (unsigned long long)sas_device->sas_address,
1574 (unsigned long long)sas_device->device_name);
1575 sdev_printk(KERN_INFO, sdev, "%s: "
1576 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
1577 (unsigned long long) sas_device->enclosure_logical_id,
1578 sas_device->slot);
1579
1580 if (!ssp_target)
Eric Moored5d135b2009-05-18 13:02:08 -06001581 _scsih_display_sata_capabilities(ioc, sas_device, sdev);
Eric Moore635374e2009-03-09 01:21:12 -06001582 }
1583
Eric Moored5d135b2009-05-18 13:02:08 -06001584 _scsih_change_queue_depth(sdev, qdepth);
Eric Moore635374e2009-03-09 01:21:12 -06001585
1586 if (ssp_target)
1587 sas_read_port_mode_page(sdev);
1588 return 0;
1589}
1590
1591/**
Eric Moored5d135b2009-05-18 13:02:08 -06001592 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06001593 * @sdev: scsi device struct
1594 * @bdev: pointer to block device context
1595 * @capacity: device size (in 512 byte sectors)
1596 * @params: three element array to place output:
1597 * params[0] number of heads (max 255)
1598 * params[1] number of sectors (max 63)
1599 * params[2] number of cylinders
1600 *
1601 * Return nothing.
1602 */
1603static int
Eric Moored5d135b2009-05-18 13:02:08 -06001604_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06001605 sector_t capacity, int params[])
1606{
1607 int heads;
1608 int sectors;
1609 sector_t cylinders;
1610 ulong dummy;
1611
1612 heads = 64;
1613 sectors = 32;
1614
1615 dummy = heads * sectors;
1616 cylinders = capacity;
1617 sector_div(cylinders, dummy);
1618
1619 /*
1620 * Handle extended translation size for logical drives
1621 * > 1Gb
1622 */
1623 if ((ulong)capacity >= 0x200000) {
1624 heads = 255;
1625 sectors = 63;
1626 dummy = heads * sectors;
1627 cylinders = capacity;
1628 sector_div(cylinders, dummy);
1629 }
1630
1631 /* return result */
1632 params[0] = heads;
1633 params[1] = sectors;
1634 params[2] = cylinders;
1635
1636 return 0;
1637}
1638
1639/**
1640 * _scsih_response_code - translation of device response code
1641 * @ioc: per adapter object
1642 * @response_code: response code returned by the device
1643 *
1644 * Return nothing.
1645 */
1646static void
1647_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
1648{
1649 char *desc;
1650
1651 switch (response_code) {
1652 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1653 desc = "task management request completed";
1654 break;
1655 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1656 desc = "invalid frame";
1657 break;
1658 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1659 desc = "task management request not supported";
1660 break;
1661 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1662 desc = "task management request failed";
1663 break;
1664 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1665 desc = "task management request succeeded";
1666 break;
1667 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1668 desc = "invalid lun";
1669 break;
1670 case 0xA:
1671 desc = "overlapped tag attempted";
1672 break;
1673 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1674 desc = "task queued, however not sent to target";
1675 break;
1676 default:
1677 desc = "unknown";
1678 break;
1679 }
1680 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
1681 ioc->name, response_code, desc);
1682}
1683
1684/**
Eric Moored5d135b2009-05-18 13:02:08 -06001685 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06001686 * @ioc: per adapter object
1687 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301688 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001689 * @reply: reply message frame(lower 32bit addr)
1690 * Context: none.
1691 *
1692 * The callback handler when using scsih_issue_tm.
1693 *
1694 * Return nothing.
1695 */
1696static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301697_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06001698{
1699 MPI2DefaultReply_t *mpi_reply;
1700
1701 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
1702 return;
1703 if (ioc->tm_cmds.smid != smid)
1704 return;
1705 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
1706 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
1707 if (mpi_reply) {
1708 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
1709 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
1710 }
1711 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
1712 complete(&ioc->tm_cmds.done);
1713}
1714
1715/**
1716 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
1717 * @ioc: per adapter object
1718 * @handle: device handle
1719 *
1720 * During taskmangement request, we need to freeze the device queue.
1721 */
1722void
1723mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1724{
1725 struct MPT2SAS_DEVICE *sas_device_priv_data;
1726 struct scsi_device *sdev;
1727 u8 skip = 0;
1728
1729 shost_for_each_device(sdev, ioc->shost) {
1730 if (skip)
1731 continue;
1732 sas_device_priv_data = sdev->hostdata;
1733 if (!sas_device_priv_data)
1734 continue;
1735 if (sas_device_priv_data->sas_target->handle == handle) {
1736 sas_device_priv_data->sas_target->tm_busy = 1;
1737 skip = 1;
1738 ioc->ignore_loginfos = 1;
1739 }
1740 }
1741}
1742
1743/**
1744 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
1745 * @ioc: per adapter object
1746 * @handle: device handle
1747 *
1748 * During taskmangement request, we need to freeze the device queue.
1749 */
1750void
1751mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1752{
1753 struct MPT2SAS_DEVICE *sas_device_priv_data;
1754 struct scsi_device *sdev;
1755 u8 skip = 0;
1756
1757 shost_for_each_device(sdev, ioc->shost) {
1758 if (skip)
1759 continue;
1760 sas_device_priv_data = sdev->hostdata;
1761 if (!sas_device_priv_data)
1762 continue;
1763 if (sas_device_priv_data->sas_target->handle == handle) {
1764 sas_device_priv_data->sas_target->tm_busy = 0;
1765 skip = 1;
1766 ioc->ignore_loginfos = 0;
1767 }
1768 }
1769}
1770
1771/**
1772 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
1773 * @ioc: per adapter struct
1774 * @device_handle: device handle
1775 * @lun: lun number
1776 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
1777 * @smid_task: smid assigned to the task
1778 * @timeout: timeout in seconds
1779 * Context: The calling function needs to acquire the tm_cmds.mutex
1780 *
1781 * A generic API for sending task management requests to firmware.
1782 *
1783 * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling
1784 * this API.
1785 *
1786 * The callback index is set inside `ioc->tm_cb_idx`.
1787 *
1788 * Return nothing.
1789 */
1790void
1791mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
1792 u8 type, u16 smid_task, ulong timeout)
1793{
1794 Mpi2SCSITaskManagementRequest_t *mpi_request;
1795 Mpi2SCSITaskManagementReply_t *mpi_reply;
1796 u16 smid = 0;
1797 u32 ioc_state;
1798 unsigned long timeleft;
Eric Moore635374e2009-03-09 01:21:12 -06001799
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301800 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
1801 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
1802 __func__, ioc->name);
1803 return;
1804 }
1805
1806 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06001807 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1808 __func__, ioc->name);
1809 return;
1810 }
Eric Moore635374e2009-03-09 01:21:12 -06001811
1812 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
1813 if (ioc_state & MPI2_DOORBELL_USED) {
1814 dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
1815 "active!\n", ioc->name));
1816 goto issue_host_reset;
1817 }
1818
1819 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
1820 mpt2sas_base_fault_info(ioc, ioc_state &
1821 MPI2_DOORBELL_DATA_MASK);
1822 goto issue_host_reset;
1823 }
1824
1825 smid = mpt2sas_base_get_smid(ioc, ioc->tm_cb_idx);
1826 if (!smid) {
1827 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1828 ioc->name, __func__);
1829 return;
1830 }
1831
1832 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
1833 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, smid));
1834 ioc->tm_cmds.status = MPT2_CMD_PENDING;
1835 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1836 ioc->tm_cmds.smid = smid;
1837 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
1838 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1839 mpi_request->DevHandle = cpu_to_le16(handle);
1840 mpi_request->TaskType = type;
1841 mpi_request->TaskMID = cpu_to_le16(smid_task);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301842 mpi_request->VP_ID = 0; /* TODO */
1843 mpi_request->VF_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06001844 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
1845 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05301846 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301847 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06001848 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
1849 mpt2sas_scsih_clear_tm_flag(ioc, handle);
1850 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
1851 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
1852 ioc->name, __func__);
1853 _debug_dump_mf(mpi_request,
1854 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
1855 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET))
1856 goto issue_host_reset;
1857 }
1858
1859 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
1860 mpi_reply = ioc->tm_cmds.reply;
1861 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
1862 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
1863 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
1864 le32_to_cpu(mpi_reply->IOCLogInfo),
1865 le32_to_cpu(mpi_reply->TerminationCount)));
1866 if (ioc->logging_level & MPT_DEBUG_TM)
1867 _scsih_response_code(ioc, mpi_reply->ResponseCode);
1868 }
1869 return;
1870 issue_host_reset:
1871 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
1872}
1873
1874/**
Eric Moored5d135b2009-05-18 13:02:08 -06001875 * _scsih_abort - eh threads main abort routine
Eric Moore635374e2009-03-09 01:21:12 -06001876 * @sdev: scsi device struct
1877 *
1878 * Returns SUCCESS if command aborted else FAILED
1879 */
1880static int
Eric Moored5d135b2009-05-18 13:02:08 -06001881_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001882{
1883 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1884 struct MPT2SAS_DEVICE *sas_device_priv_data;
1885 u16 smid;
1886 u16 handle;
1887 int r;
1888 struct scsi_cmnd *scmd_lookup;
1889
1890 printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
1891 ioc->name, scmd);
1892 scsi_print_command(scmd);
1893
1894 sas_device_priv_data = scmd->device->hostdata;
1895 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1896 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
1897 ioc->name, scmd);
1898 scmd->result = DID_NO_CONNECT << 16;
1899 scmd->scsi_done(scmd);
1900 r = SUCCESS;
1901 goto out;
1902 }
1903
1904 /* search for the command */
1905 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
1906 if (!smid) {
1907 scmd->result = DID_RESET << 16;
1908 r = SUCCESS;
1909 goto out;
1910 }
1911
1912 /* for hidden raid components and volumes this is not supported */
1913 if (sas_device_priv_data->sas_target->flags &
1914 MPT_TARGET_FLAGS_RAID_COMPONENT ||
1915 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
1916 scmd->result = DID_RESET << 16;
1917 r = FAILED;
1918 goto out;
1919 }
1920
1921 mutex_lock(&ioc->tm_cmds.mutex);
1922 handle = sas_device_priv_data->sas_target->handle;
1923 mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
1924 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30);
1925
1926 /* sanity check - see whether command actually completed */
1927 scmd_lookup = _scsih_scsi_lookup_get(ioc, smid);
1928 if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number))
1929 r = FAILED;
1930 else
1931 r = SUCCESS;
1932 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
1933 mutex_unlock(&ioc->tm_cmds.mutex);
1934
1935 out:
1936 printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
1937 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
1938 return r;
1939}
1940
Eric Moore635374e2009-03-09 01:21:12 -06001941/**
Eric Moored5d135b2009-05-18 13:02:08 -06001942 * _scsih_dev_reset - eh threads main device reset routine
Eric Moore635374e2009-03-09 01:21:12 -06001943 * @sdev: scsi device struct
1944 *
1945 * Returns SUCCESS if command aborted else FAILED
1946 */
1947static int
Eric Moored5d135b2009-05-18 13:02:08 -06001948_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001949{
1950 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1951 struct MPT2SAS_DEVICE *sas_device_priv_data;
1952 struct _sas_device *sas_device;
1953 unsigned long flags;
1954 u16 handle;
1955 int r;
1956
Eric Moore993e0da2009-05-18 13:00:45 -06001957 printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
Eric Moore635374e2009-03-09 01:21:12 -06001958 ioc->name, scmd);
1959 scsi_print_command(scmd);
1960
1961 sas_device_priv_data = scmd->device->hostdata;
1962 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1963 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
1964 ioc->name, scmd);
1965 scmd->result = DID_NO_CONNECT << 16;
1966 scmd->scsi_done(scmd);
1967 r = SUCCESS;
1968 goto out;
1969 }
1970
1971 /* for hidden raid components obtain the volume_handle */
1972 handle = 0;
1973 if (sas_device_priv_data->sas_target->flags &
1974 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1975 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1976 sas_device = _scsih_sas_device_find_by_handle(ioc,
1977 sas_device_priv_data->sas_target->handle);
1978 if (sas_device)
1979 handle = sas_device->volume_handle;
1980 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1981 } else
1982 handle = sas_device_priv_data->sas_target->handle;
1983
1984 if (!handle) {
1985 scmd->result = DID_RESET << 16;
1986 r = FAILED;
1987 goto out;
1988 }
1989
1990 mutex_lock(&ioc->tm_cmds.mutex);
1991 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore993e0da2009-05-18 13:00:45 -06001992 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun,
1993 30);
1994
1995 /*
1996 * sanity check see whether all commands to this device been
1997 * completed
1998 */
1999 if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id,
2000 scmd->device->lun, scmd->device->channel))
2001 r = FAILED;
2002 else
2003 r = SUCCESS;
2004 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2005 mutex_unlock(&ioc->tm_cmds.mutex);
2006
2007 out:
2008 printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
2009 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2010 return r;
2011}
2012
2013/**
Eric Moored5d135b2009-05-18 13:02:08 -06002014 * _scsih_target_reset - eh threads main target reset routine
Eric Moore993e0da2009-05-18 13:00:45 -06002015 * @sdev: scsi device struct
2016 *
2017 * Returns SUCCESS if command aborted else FAILED
2018 */
2019static int
Eric Moored5d135b2009-05-18 13:02:08 -06002020_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06002021{
2022 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2023 struct MPT2SAS_DEVICE *sas_device_priv_data;
2024 struct _sas_device *sas_device;
2025 unsigned long flags;
2026 u16 handle;
2027 int r;
2028
2029 printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
2030 ioc->name, scmd);
2031 scsi_print_command(scmd);
2032
2033 sas_device_priv_data = scmd->device->hostdata;
2034 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2035 printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
2036 ioc->name, scmd);
2037 scmd->result = DID_NO_CONNECT << 16;
2038 scmd->scsi_done(scmd);
2039 r = SUCCESS;
2040 goto out;
2041 }
2042
2043 /* for hidden raid components obtain the volume_handle */
2044 handle = 0;
2045 if (sas_device_priv_data->sas_target->flags &
2046 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2047 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2048 sas_device = _scsih_sas_device_find_by_handle(ioc,
2049 sas_device_priv_data->sas_target->handle);
2050 if (sas_device)
2051 handle = sas_device->volume_handle;
2052 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2053 } else
2054 handle = sas_device_priv_data->sas_target->handle;
2055
2056 if (!handle) {
2057 scmd->result = DID_RESET << 16;
2058 r = FAILED;
2059 goto out;
2060 }
2061
2062 mutex_lock(&ioc->tm_cmds.mutex);
2063 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore635374e2009-03-09 01:21:12 -06002064 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30);
2065
2066 /*
2067 * sanity check see whether all commands to this target been
2068 * completed
2069 */
2070 if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id,
2071 scmd->device->channel))
2072 r = FAILED;
2073 else
2074 r = SUCCESS;
2075 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2076 mutex_unlock(&ioc->tm_cmds.mutex);
2077
2078 out:
2079 printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
2080 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2081 return r;
2082}
2083
2084/**
Eric Moored5d135b2009-05-18 13:02:08 -06002085 * _scsih_abort - eh threads main host reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002086 * @sdev: scsi device struct
2087 *
2088 * Returns SUCCESS if command aborted else FAILED
2089 */
2090static int
Eric Moored5d135b2009-05-18 13:02:08 -06002091_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002092{
2093 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2094 int r, retval;
2095
2096 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2097 ioc->name, scmd);
2098 scsi_print_command(scmd);
2099
2100 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2101 FORCE_BIG_HAMMER);
2102 r = (retval < 0) ? FAILED : SUCCESS;
2103 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2104 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2105
2106 return r;
2107}
2108
2109/**
2110 * _scsih_fw_event_add - insert and queue up fw_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 * This adds the firmware event object into link list, then queues it up to
2116 * be processed from user context.
2117 *
2118 * Return nothing.
2119 */
2120static void
2121_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2122{
2123 unsigned long flags;
2124
2125 if (ioc->firmware_event_thread == NULL)
2126 return;
2127
2128 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2129 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002130 INIT_WORK(&fw_event->work, _firmware_event_work);
2131 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002132 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2133}
2134
2135/**
2136 * _scsih_fw_event_free - delete fw_event
2137 * @ioc: per adapter object
2138 * @fw_event: object describing the event
2139 * Context: This function will acquire ioc->fw_event_lock.
2140 *
2141 * This removes firmware event object from link list, frees associated memory.
2142 *
2143 * Return nothing.
2144 */
2145static void
2146_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2147 *fw_event)
2148{
2149 unsigned long flags;
2150
2151 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2152 list_del(&fw_event->list);
2153 kfree(fw_event->event_data);
2154 kfree(fw_event);
2155 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2156}
2157
2158/**
2159 * _scsih_fw_event_add - requeue an event
2160 * @ioc: per adapter object
2161 * @fw_event: object describing the event
2162 * Context: This function will acquire ioc->fw_event_lock.
2163 *
2164 * Return nothing.
2165 */
2166static void
2167_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2168 *fw_event, unsigned long delay)
2169{
2170 unsigned long flags;
2171 if (ioc->firmware_event_thread == NULL)
2172 return;
2173
2174 spin_lock_irqsave(&ioc->fw_event_lock, flags);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002175 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002176 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2177}
2178
2179/**
2180 * _scsih_fw_event_off - turn flag off preventing event handling
2181 * @ioc: per adapter object
2182 *
2183 * Used to prevent handling of firmware events during adapter reset
2184 * driver unload.
2185 *
2186 * Return nothing.
2187 */
2188static void
2189_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc)
2190{
2191 unsigned long flags;
2192
2193 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2194 ioc->fw_events_off = 1;
2195 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2196
2197}
2198
2199/**
2200 * _scsih_fw_event_on - turn flag on allowing firmware event handling
2201 * @ioc: per adapter object
2202 *
2203 * Returns nothing.
2204 */
2205static void
2206_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc)
2207{
2208 unsigned long flags;
2209
2210 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2211 ioc->fw_events_off = 0;
2212 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2213}
2214
2215/**
2216 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2217 * @ioc: per adapter object
2218 * @handle: device handle
2219 *
2220 * During device pull we need to appropiately set the sdev state.
2221 */
2222static void
2223_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2224{
2225 struct MPT2SAS_DEVICE *sas_device_priv_data;
2226 struct scsi_device *sdev;
2227
2228 shost_for_each_device(sdev, ioc->shost) {
2229 sas_device_priv_data = sdev->hostdata;
2230 if (!sas_device_priv_data)
2231 continue;
2232 if (!sas_device_priv_data->block)
2233 continue;
2234 if (sas_device_priv_data->sas_target->handle == handle) {
2235 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2236 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2237 "handle(0x%04x)\n", ioc->name, handle));
2238 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302239 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002240 }
2241 }
2242}
2243
2244/**
2245 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2246 * @ioc: per adapter object
2247 * @handle: device handle
2248 *
2249 * During device pull we need to appropiately set the sdev state.
2250 */
2251static void
2252_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2253{
2254 struct MPT2SAS_DEVICE *sas_device_priv_data;
2255 struct scsi_device *sdev;
2256
2257 shost_for_each_device(sdev, ioc->shost) {
2258 sas_device_priv_data = sdev->hostdata;
2259 if (!sas_device_priv_data)
2260 continue;
2261 if (sas_device_priv_data->block)
2262 continue;
2263 if (sas_device_priv_data->sas_target->handle == handle) {
2264 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2265 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2266 "handle(0x%04x)\n", ioc->name, handle));
2267 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302268 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002269 }
2270 }
2271}
2272
2273/**
2274 * _scsih_block_io_to_children_attached_to_ex
2275 * @ioc: per adapter object
2276 * @sas_expander: the sas_device object
2277 *
2278 * This routine set sdev state to SDEV_BLOCK for all devices
2279 * attached to this expander. This function called when expander is
2280 * pulled.
2281 */
2282static void
2283_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2284 struct _sas_node *sas_expander)
2285{
2286 struct _sas_port *mpt2sas_port;
2287 struct _sas_device *sas_device;
2288 struct _sas_node *expander_sibling;
2289 unsigned long flags;
2290
2291 if (!sas_expander)
2292 return;
2293
2294 list_for_each_entry(mpt2sas_port,
2295 &sas_expander->sas_port_list, port_list) {
2296 if (mpt2sas_port->remote_identify.device_type ==
2297 SAS_END_DEVICE) {
2298 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2299 sas_device =
2300 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2301 mpt2sas_port->remote_identify.sas_address);
2302 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2303 if (!sas_device)
2304 continue;
2305 _scsih_block_io_device(ioc, sas_device->handle);
2306 }
2307 }
2308
2309 list_for_each_entry(mpt2sas_port,
2310 &sas_expander->sas_port_list, port_list) {
2311
2312 if (mpt2sas_port->remote_identify.device_type ==
2313 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2314 mpt2sas_port->remote_identify.device_type ==
2315 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2316
2317 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2318 expander_sibling =
2319 mpt2sas_scsih_expander_find_by_sas_address(
2320 ioc, mpt2sas_port->remote_identify.sas_address);
2321 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2322 _scsih_block_io_to_children_attached_to_ex(ioc,
2323 expander_sibling);
2324 }
2325 }
2326}
2327
2328/**
2329 * _scsih_block_io_to_children_attached_directly
2330 * @ioc: per adapter object
2331 * @event_data: topology change event data
2332 *
2333 * This routine set sdev state to SDEV_BLOCK for all devices
2334 * direct attached during device pull.
2335 */
2336static void
2337_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2338 Mpi2EventDataSasTopologyChangeList_t *event_data)
2339{
2340 int i;
2341 u16 handle;
2342 u16 reason_code;
2343 u8 phy_number;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302344 u8 link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06002345
2346 for (i = 0; i < event_data->NumEntries; i++) {
2347 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2348 if (!handle)
2349 continue;
2350 phy_number = event_data->StartPhyNum + i;
2351 reason_code = event_data->PHY[i].PhyStatus &
2352 MPI2_EVENT_SAS_TOPO_RC_MASK;
2353 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2354 _scsih_block_io_device(ioc, handle);
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302355 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) {
2356 link_rate = event_data->PHY[i].LinkRate >> 4;
2357 if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
2358 _scsih_ublock_io_device(ioc, handle);
2359 }
Eric Moore635374e2009-03-09 01:21:12 -06002360 }
2361}
2362
2363/**
2364 * _scsih_check_topo_delete_events - sanity check on topo events
2365 * @ioc: per adapter object
2366 * @event_data: the event data payload
2367 *
2368 * This routine added to better handle cable breaker.
2369 *
2370 * This handles the case where driver recieves multiple expander
2371 * add and delete events in a single shot. When there is a delete event
2372 * the routine will void any pending add events waiting in the event queue.
2373 *
2374 * Return nothing.
2375 */
2376static void
2377_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
2378 Mpi2EventDataSasTopologyChangeList_t *event_data)
2379{
2380 struct fw_event_work *fw_event;
2381 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
2382 u16 expander_handle;
2383 struct _sas_node *sas_expander;
2384 unsigned long flags;
2385
2386 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
2387 if (expander_handle < ioc->sas_hba.num_phys) {
2388 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2389 return;
2390 }
2391
2392 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
2393 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
2394 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2395 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
2396 expander_handle);
2397 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2398 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
2399 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
2400 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2401
2402 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
2403 return;
2404
2405 /* mark ignore flag for pending events */
2406 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2407 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
2408 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
2409 fw_event->ignore)
2410 continue;
2411 local_event_data = fw_event->event_data;
2412 if (local_event_data->ExpStatus ==
2413 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
2414 local_event_data->ExpStatus ==
2415 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
2416 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
2417 expander_handle) {
2418 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
2419 "setting ignoring flag\n", ioc->name));
2420 fw_event->ignore = 1;
2421 }
2422 }
2423 }
2424 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2425}
2426
2427/**
Eric Moore635374e2009-03-09 01:21:12 -06002428 * _scsih_flush_running_cmds - completing outstanding commands.
2429 * @ioc: per adapter object
2430 *
2431 * The flushing out of all pending scmd commands following host reset,
2432 * where all IO is dropped to the floor.
2433 *
2434 * Return nothing.
2435 */
2436static void
2437_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
2438{
2439 struct scsi_cmnd *scmd;
2440 u16 smid;
2441 u16 count = 0;
2442
2443 for (smid = 1; smid <= ioc->request_depth; smid++) {
2444 scmd = _scsih_scsi_lookup_getclear(ioc, smid);
2445 if (!scmd)
2446 continue;
2447 count++;
2448 mpt2sas_base_free_smid(ioc, smid);
2449 scsi_dma_unmap(scmd);
2450 scmd->result = DID_RESET << 16;
2451 scmd->scsi_done(scmd);
2452 }
2453 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
2454 ioc->name, count));
2455}
2456
2457/**
Eric Moore3c621b32009-05-18 12:59:41 -06002458 * _scsih_setup_eedp - setup MPI request for EEDP transfer
2459 * @scmd: pointer to scsi command object
2460 * @mpi_request: pointer to the SCSI_IO reqest message frame
2461 *
2462 * Supporting protection 1 and 3.
2463 *
2464 * Returns nothing
2465 */
2466static void
2467_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
2468{
2469 u16 eedp_flags;
2470 unsigned char prot_op = scsi_get_prot_op(scmd);
2471 unsigned char prot_type = scsi_get_prot_type(scmd);
2472
2473 if (prot_type == SCSI_PROT_DIF_TYPE0 ||
2474 prot_type == SCSI_PROT_DIF_TYPE2 ||
2475 prot_op == SCSI_PROT_NORMAL)
2476 return;
2477
2478 if (prot_op == SCSI_PROT_READ_STRIP)
2479 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
2480 else if (prot_op == SCSI_PROT_WRITE_INSERT)
2481 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
2482 else
2483 return;
2484
2485 mpi_request->EEDPBlockSize = scmd->device->sector_size;
2486
2487 switch (prot_type) {
2488 case SCSI_PROT_DIF_TYPE1:
2489
2490 /*
2491 * enable ref/guard checking
2492 * auto increment ref tag
2493 */
2494 mpi_request->EEDPFlags = eedp_flags |
2495 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
2496 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2497 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2498 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
2499 cpu_to_be32(scsi_get_lba(scmd));
2500
2501 break;
2502
2503 case SCSI_PROT_DIF_TYPE3:
2504
2505 /*
2506 * enable guard checking
2507 */
2508 mpi_request->EEDPFlags = eedp_flags |
2509 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2510
2511 break;
2512 }
2513}
2514
2515/**
2516 * _scsih_eedp_error_handling - return sense code for EEDP errors
2517 * @scmd: pointer to scsi command object
2518 * @ioc_status: ioc status
2519 *
2520 * Returns nothing
2521 */
2522static void
2523_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
2524{
2525 u8 ascq;
2526 u8 sk;
2527 u8 host_byte;
2528
2529 switch (ioc_status) {
2530 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2531 ascq = 0x01;
2532 break;
2533 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2534 ascq = 0x02;
2535 break;
2536 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2537 ascq = 0x03;
2538 break;
2539 default:
2540 ascq = 0x00;
2541 break;
2542 }
2543
2544 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
2545 sk = ILLEGAL_REQUEST;
2546 host_byte = DID_ABORT;
2547 } else {
2548 sk = ABORTED_COMMAND;
2549 host_byte = DID_OK;
2550 }
2551
2552 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
2553 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
2554 SAM_STAT_CHECK_CONDITION;
2555}
2556
2557/**
Eric Moored5d135b2009-05-18 13:02:08 -06002558 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06002559 * @scmd: pointer to scsi command object
2560 * @done: function pointer to be invoked on completion
2561 *
2562 * The callback index is set inside `ioc->scsi_io_cb_idx`.
2563 *
2564 * Returns 0 on success. If there's a failure, return either:
2565 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
2566 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
2567 */
2568static int
Eric Moored5d135b2009-05-18 13:02:08 -06002569_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06002570{
2571 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2572 struct MPT2SAS_DEVICE *sas_device_priv_data;
2573 struct MPT2SAS_TARGET *sas_target_priv_data;
2574 Mpi2SCSIIORequest_t *mpi_request;
2575 u32 mpi_control;
2576 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06002577
2578 scmd->scsi_done = done;
2579 sas_device_priv_data = scmd->device->hostdata;
2580 if (!sas_device_priv_data) {
2581 scmd->result = DID_NO_CONNECT << 16;
2582 scmd->scsi_done(scmd);
2583 return 0;
2584 }
2585
2586 sas_target_priv_data = sas_device_priv_data->sas_target;
2587 if (!sas_target_priv_data || sas_target_priv_data->handle ==
2588 MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
2589 scmd->result = DID_NO_CONNECT << 16;
2590 scmd->scsi_done(scmd);
2591 return 0;
2592 }
2593
2594 /* see if we are busy with task managment stuff */
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302595 if (sas_target_priv_data->tm_busy)
2596 return SCSI_MLQUEUE_DEVICE_BUSY;
2597 else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06002598 return SCSI_MLQUEUE_HOST_BUSY;
Eric Moore635374e2009-03-09 01:21:12 -06002599
2600 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
2601 mpi_control = MPI2_SCSIIO_CONTROL_READ;
2602 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
2603 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
2604 else
2605 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
2606
2607 /* set tags */
2608 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
2609 if (scmd->device->tagged_supported) {
2610 if (scmd->device->ordered_tags)
2611 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
2612 else
2613 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2614 } else
2615/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
2616/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
2617 */
2618 mpi_control |= (0x500);
2619
2620 } else
2621 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2622
2623 if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
2624 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
2625
2626 smid = mpt2sas_base_get_smid(ioc, ioc->scsi_io_cb_idx);
2627 if (!smid) {
2628 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2629 ioc->name, __func__);
2630 goto out;
2631 }
2632 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2633 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06002634 _scsih_setup_eedp(scmd, mpi_request);
Eric Moore635374e2009-03-09 01:21:12 -06002635 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2636 if (sas_device_priv_data->sas_target->flags &
2637 MPT_TARGET_FLAGS_RAID_COMPONENT)
2638 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2639 else
2640 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2641 mpi_request->DevHandle =
2642 cpu_to_le16(sas_device_priv_data->sas_target->handle);
2643 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
2644 mpi_request->Control = cpu_to_le32(mpi_control);
2645 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
2646 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
2647 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
2648 mpi_request->SenseBufferLowAddress =
2649 (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
2650 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
2651 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
2652 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302653 mpi_request->VF_ID = 0; /* TODO */
2654 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06002655 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
2656 mpi_request->LUN);
2657 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
2658
2659 if (!mpi_request->DataLength) {
2660 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
2661 } else {
2662 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
2663 mpt2sas_base_free_smid(ioc, smid);
2664 goto out;
2665 }
2666 }
2667
2668 _scsih_scsi_lookup_set(ioc, smid, scmd);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302669 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Eric Moore635374e2009-03-09 01:21:12 -06002670 sas_device_priv_data->sas_target->handle);
2671 return 0;
2672
2673 out:
2674 return SCSI_MLQUEUE_HOST_BUSY;
2675}
2676
2677/**
2678 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
2679 * @sense_buffer: sense data returned by target
2680 * @data: normalized skey/asc/ascq
2681 *
2682 * Return nothing.
2683 */
2684static void
2685_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
2686{
2687 if ((sense_buffer[0] & 0x7F) >= 0x72) {
2688 /* descriptor format */
2689 data->skey = sense_buffer[1] & 0x0F;
2690 data->asc = sense_buffer[2];
2691 data->ascq = sense_buffer[3];
2692 } else {
2693 /* fixed format */
2694 data->skey = sense_buffer[2] & 0x0F;
2695 data->asc = sense_buffer[12];
2696 data->ascq = sense_buffer[13];
2697 }
2698}
2699
2700#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
2701/**
2702 * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request
2703 * @ioc: per adapter object
2704 * @scmd: pointer to scsi command object
2705 * @mpi_reply: reply mf payload returned from firmware
2706 *
2707 * scsi_status - SCSI Status code returned from target device
2708 * scsi_state - state info associated with SCSI_IO determined by ioc
2709 * ioc_status - ioc supplied status info
2710 *
2711 * Return nothing.
2712 */
2713static void
2714_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
2715 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
2716{
2717 u32 response_info;
2718 u8 *response_bytes;
2719 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
2720 MPI2_IOCSTATUS_MASK;
2721 u8 scsi_state = mpi_reply->SCSIState;
2722 u8 scsi_status = mpi_reply->SCSIStatus;
2723 char *desc_ioc_state = NULL;
2724 char *desc_scsi_status = NULL;
2725 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05302726 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
2727
2728 if (log_info == 0x31170000)
2729 return;
Eric Moore635374e2009-03-09 01:21:12 -06002730
2731 switch (ioc_status) {
2732 case MPI2_IOCSTATUS_SUCCESS:
2733 desc_ioc_state = "success";
2734 break;
2735 case MPI2_IOCSTATUS_INVALID_FUNCTION:
2736 desc_ioc_state = "invalid function";
2737 break;
2738 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2739 desc_ioc_state = "scsi recovered error";
2740 break;
2741 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2742 desc_ioc_state = "scsi invalid dev handle";
2743 break;
2744 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2745 desc_ioc_state = "scsi device not there";
2746 break;
2747 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2748 desc_ioc_state = "scsi data overrun";
2749 break;
2750 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2751 desc_ioc_state = "scsi data underrun";
2752 break;
2753 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2754 desc_ioc_state = "scsi io data error";
2755 break;
2756 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2757 desc_ioc_state = "scsi protocol error";
2758 break;
2759 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2760 desc_ioc_state = "scsi task terminated";
2761 break;
2762 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2763 desc_ioc_state = "scsi residual mismatch";
2764 break;
2765 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2766 desc_ioc_state = "scsi task mgmt failed";
2767 break;
2768 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
2769 desc_ioc_state = "scsi ioc terminated";
2770 break;
2771 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
2772 desc_ioc_state = "scsi ext terminated";
2773 break;
Eric Moore3c621b32009-05-18 12:59:41 -06002774 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2775 desc_ioc_state = "eedp guard error";
2776 break;
2777 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2778 desc_ioc_state = "eedp ref tag error";
2779 break;
2780 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2781 desc_ioc_state = "eedp app tag error";
2782 break;
Eric Moore635374e2009-03-09 01:21:12 -06002783 default:
2784 desc_ioc_state = "unknown";
2785 break;
2786 }
2787
2788 switch (scsi_status) {
2789 case MPI2_SCSI_STATUS_GOOD:
2790 desc_scsi_status = "good";
2791 break;
2792 case MPI2_SCSI_STATUS_CHECK_CONDITION:
2793 desc_scsi_status = "check condition";
2794 break;
2795 case MPI2_SCSI_STATUS_CONDITION_MET:
2796 desc_scsi_status = "condition met";
2797 break;
2798 case MPI2_SCSI_STATUS_BUSY:
2799 desc_scsi_status = "busy";
2800 break;
2801 case MPI2_SCSI_STATUS_INTERMEDIATE:
2802 desc_scsi_status = "intermediate";
2803 break;
2804 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
2805 desc_scsi_status = "intermediate condmet";
2806 break;
2807 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
2808 desc_scsi_status = "reservation conflict";
2809 break;
2810 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
2811 desc_scsi_status = "command terminated";
2812 break;
2813 case MPI2_SCSI_STATUS_TASK_SET_FULL:
2814 desc_scsi_status = "task set full";
2815 break;
2816 case MPI2_SCSI_STATUS_ACA_ACTIVE:
2817 desc_scsi_status = "aca active";
2818 break;
2819 case MPI2_SCSI_STATUS_TASK_ABORTED:
2820 desc_scsi_status = "task aborted";
2821 break;
2822 default:
2823 desc_scsi_status = "unknown";
2824 break;
2825 }
2826
2827 desc_scsi_state[0] = '\0';
2828 if (!scsi_state)
2829 desc_scsi_state = " ";
2830 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
2831 strcat(desc_scsi_state, "response info ");
2832 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
2833 strcat(desc_scsi_state, "state terminated ");
2834 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
2835 strcat(desc_scsi_state, "no status ");
2836 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
2837 strcat(desc_scsi_state, "autosense failed ");
2838 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
2839 strcat(desc_scsi_state, "autosense valid ");
2840
2841 scsi_print_command(scmd);
2842 printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
2843 "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
2844 le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
2845 ioc_status, smid);
2846 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
2847 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
2848 scsi_get_resid(scmd));
2849 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
2850 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
2851 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
2852 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
2853 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
2854 scsi_status, desc_scsi_state, scsi_state);
2855
2856 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2857 struct sense_info data;
2858 _scsih_normalize_sense(scmd->sense_buffer, &data);
2859 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
2860 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey,
2861 data.asc, data.ascq);
2862 }
2863
2864 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
2865 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
2866 response_bytes = (u8 *)&response_info;
2867 _scsih_response_code(ioc, response_bytes[3]);
2868 }
2869}
2870#endif
2871
2872/**
2873 * _scsih_smart_predicted_fault - illuminate Fault LED
2874 * @ioc: per adapter object
2875 * @handle: device handle
2876 *
2877 * Return nothing.
2878 */
2879static void
2880_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2881{
2882 Mpi2SepReply_t mpi_reply;
2883 Mpi2SepRequest_t mpi_request;
2884 struct scsi_target *starget;
2885 struct MPT2SAS_TARGET *sas_target_priv_data;
2886 Mpi2EventNotificationReply_t *event_reply;
2887 Mpi2EventDataSasDeviceStatusChange_t *event_data;
2888 struct _sas_device *sas_device;
2889 ssize_t sz;
2890 unsigned long flags;
2891
2892 /* only handle non-raid devices */
2893 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2894 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
2895 if (!sas_device) {
2896 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2897 return;
2898 }
2899 starget = sas_device->starget;
2900 sas_target_priv_data = starget->hostdata;
2901
2902 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
2903 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
2904 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2905 return;
2906 }
2907 starget_printk(KERN_WARNING, starget, "predicted fault\n");
2908 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2909
2910 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
2911 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
2912 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
2913 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
2914 mpi_request.SlotStatus =
2915 MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
2916 mpi_request.DevHandle = cpu_to_le16(handle);
2917 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
2918 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
2919 &mpi_request)) != 0) {
2920 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
2921 ioc->name, __FILE__, __LINE__, __func__);
2922 return;
2923 }
2924
2925 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
2926 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2927 "enclosure_processor: ioc_status (0x%04x), "
2928 "loginfo(0x%08x)\n", ioc->name,
2929 le16_to_cpu(mpi_reply.IOCStatus),
2930 le32_to_cpu(mpi_reply.IOCLogInfo)));
2931 return;
2932 }
2933 }
2934
2935 /* insert into event log */
2936 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
2937 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
2938 event_reply = kzalloc(sz, GFP_KERNEL);
2939 if (!event_reply) {
2940 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
2941 ioc->name, __FILE__, __LINE__, __func__);
2942 return;
2943 }
2944
2945 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
2946 event_reply->Event =
2947 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
2948 event_reply->MsgLength = sz/4;
2949 event_reply->EventDataLength =
2950 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
2951 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
2952 event_reply->EventData;
2953 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
2954 event_data->ASC = 0x5D;
2955 event_data->DevHandle = cpu_to_le16(handle);
2956 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
2957 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
2958 kfree(event_reply);
2959}
2960
2961/**
Eric Moored5d135b2009-05-18 13:02:08 -06002962 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06002963 * @ioc: per adapter object
2964 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302965 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06002966 * @reply: reply message frame(lower 32bit addr)
2967 *
2968 * Callback handler when using scsih_qcmd.
2969 *
2970 * Return nothing.
2971 */
2972static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302973_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06002974{
2975 Mpi2SCSIIORequest_t *mpi_request;
2976 Mpi2SCSIIOReply_t *mpi_reply;
2977 struct scsi_cmnd *scmd;
2978 u16 ioc_status;
2979 u32 xfer_cnt;
2980 u8 scsi_state;
2981 u8 scsi_status;
2982 u32 log_info;
2983 struct MPT2SAS_DEVICE *sas_device_priv_data;
2984 u32 response_code;
2985
2986 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
2987 scmd = _scsih_scsi_lookup_getclear(ioc, smid);
2988 if (scmd == NULL)
2989 return;
2990
2991 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2992
2993 if (mpi_reply == NULL) {
2994 scmd->result = DID_OK << 16;
2995 goto out;
2996 }
2997
2998 sas_device_priv_data = scmd->device->hostdata;
2999 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
3000 sas_device_priv_data->sas_target->deleted) {
3001 scmd->result = DID_NO_CONNECT << 16;
3002 goto out;
3003 }
3004
3005 /* turning off TLR */
3006 if (!sas_device_priv_data->tlr_snoop_check) {
3007 sas_device_priv_data->tlr_snoop_check++;
3008 if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) {
3009 response_code = (le32_to_cpu(mpi_reply->ResponseInfo)
3010 >> 24);
3011 if (response_code ==
3012 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
3013 sas_device_priv_data->flags &=
3014 ~MPT_DEVICE_TLR_ON;
3015 }
3016 }
3017
3018 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
3019 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
3020 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
3021 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
3022 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3023 else
3024 log_info = 0;
3025 ioc_status &= MPI2_IOCSTATUS_MASK;
3026 scsi_state = mpi_reply->SCSIState;
3027 scsi_status = mpi_reply->SCSIStatus;
3028
3029 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
3030 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
3031 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
3032 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
3033 ioc_status = MPI2_IOCSTATUS_SUCCESS;
3034 }
3035
3036 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3037 struct sense_info data;
3038 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
3039 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06003040 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06003041 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06003042 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06003043 _scsih_normalize_sense(scmd->sense_buffer, &data);
3044 /* failure prediction threshold exceeded */
3045 if (data.asc == 0x5D)
3046 _scsih_smart_predicted_fault(ioc,
3047 le16_to_cpu(mpi_reply->DevHandle));
3048 }
3049
3050 switch (ioc_status) {
3051 case MPI2_IOCSTATUS_BUSY:
3052 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3053 scmd->result = SAM_STAT_BUSY;
3054 break;
3055
3056 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3057 scmd->result = DID_NO_CONNECT << 16;
3058 break;
3059
3060 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3061 if (sas_device_priv_data->block) {
3062 scmd->result = (DID_BUS_BUSY << 16);
3063 break;
3064 }
3065
3066 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3067 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3068 scmd->result = DID_RESET << 16;
3069 break;
3070
3071 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3072 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3073 scmd->result = DID_SOFT_ERROR << 16;
3074 else
3075 scmd->result = (DID_OK << 16) | scsi_status;
3076 break;
3077
3078 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3079 scmd->result = (DID_OK << 16) | scsi_status;
3080
3081 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3082 break;
3083
3084 if (xfer_cnt < scmd->underflow) {
3085 if (scsi_status == SAM_STAT_BUSY)
3086 scmd->result = SAM_STAT_BUSY;
3087 else
3088 scmd->result = DID_SOFT_ERROR << 16;
3089 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3090 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3091 scmd->result = DID_SOFT_ERROR << 16;
3092 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3093 scmd->result = DID_RESET << 16;
3094 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3095 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3096 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3097 scmd->result = (DRIVER_SENSE << 24) |
3098 SAM_STAT_CHECK_CONDITION;
3099 scmd->sense_buffer[0] = 0x70;
3100 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3101 scmd->sense_buffer[12] = 0x20;
3102 scmd->sense_buffer[13] = 0;
3103 }
3104 break;
3105
3106 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3107 scsi_set_resid(scmd, 0);
3108 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3109 case MPI2_IOCSTATUS_SUCCESS:
3110 scmd->result = (DID_OK << 16) | scsi_status;
3111 if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3112 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3113 scmd->result = DID_SOFT_ERROR << 16;
3114 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3115 scmd->result = DID_RESET << 16;
3116 break;
3117
Eric Moore3c621b32009-05-18 12:59:41 -06003118 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3119 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3120 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3121 _scsih_eedp_error_handling(scmd, ioc_status);
3122 break;
Eric Moore635374e2009-03-09 01:21:12 -06003123 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3124 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3125 case MPI2_IOCSTATUS_INVALID_SGL:
3126 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3127 case MPI2_IOCSTATUS_INVALID_FIELD:
3128 case MPI2_IOCSTATUS_INVALID_STATE:
3129 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3130 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3131 default:
3132 scmd->result = DID_SOFT_ERROR << 16;
3133 break;
3134
3135 }
3136
3137#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3138 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3139 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3140#endif
3141
3142 out:
3143 scsi_dma_unmap(scmd);
3144 scmd->scsi_done(scmd);
3145}
3146
3147/**
Eric Moore635374e2009-03-09 01:21:12 -06003148 * _scsih_sas_host_refresh - refreshing sas host object contents
3149 * @ioc: per adapter object
3150 * @update: update link information
3151 * Context: user
3152 *
3153 * During port enable, fw will send topology events for every device. Its
3154 * possible that the handles may change from the previous setting, so this
3155 * code keeping handles updating if changed.
3156 *
3157 * Return nothing.
3158 */
3159static void
3160_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update)
3161{
3162 u16 sz;
3163 u16 ioc_status;
3164 int i;
3165 Mpi2ConfigReply_t mpi_reply;
3166 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3167
3168 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3169 "updating handles for sas_host(0x%016llx)\n",
3170 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3171
3172 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3173 * sizeof(Mpi2SasIOUnit0PhyData_t));
3174 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3175 if (!sas_iounit_pg0) {
3176 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3177 ioc->name, __FILE__, __LINE__, __func__);
3178 return;
3179 }
3180 if (!(mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3181 sas_iounit_pg0, sz))) {
3182 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3183 MPI2_IOCSTATUS_MASK;
3184 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3185 goto out;
3186 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3187 ioc->sas_hba.phy[i].handle =
3188 le16_to_cpu(sas_iounit_pg0->PhyData[i].
3189 ControllerDevHandle);
3190 if (update)
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05303191 mpt2sas_transport_update_links(
3192 ioc,
Eric Moore635374e2009-03-09 01:21:12 -06003193 ioc->sas_hba.phy[i].handle,
3194 le16_to_cpu(sas_iounit_pg0->PhyData[i].
3195 AttachedDevHandle), i,
3196 sas_iounit_pg0->PhyData[i].
3197 NegotiatedLinkRate >> 4);
3198 }
3199 }
3200
3201 out:
3202 kfree(sas_iounit_pg0);
3203}
3204
3205/**
3206 * _scsih_sas_host_add - create sas host object
3207 * @ioc: per adapter object
3208 *
3209 * Creating host side data object, stored in ioc->sas_hba
3210 *
3211 * Return nothing.
3212 */
3213static void
3214_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3215{
3216 int i;
3217 Mpi2ConfigReply_t mpi_reply;
3218 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3219 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3220 Mpi2SasPhyPage0_t phy_pg0;
3221 Mpi2SasDevicePage0_t sas_device_pg0;
3222 Mpi2SasEnclosurePage0_t enclosure_pg0;
3223 u16 ioc_status;
3224 u16 sz;
3225 u16 device_missing_delay;
3226
3227 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3228 if (!ioc->sas_hba.num_phys) {
3229 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3230 ioc->name, __FILE__, __LINE__, __func__);
3231 return;
3232 }
3233
3234 /* sas_iounit page 0 */
3235 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3236 sizeof(Mpi2SasIOUnit0PhyData_t));
3237 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3238 if (!sas_iounit_pg0) {
3239 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3240 ioc->name, __FILE__, __LINE__, __func__);
3241 return;
3242 }
3243 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3244 sas_iounit_pg0, sz))) {
3245 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3246 ioc->name, __FILE__, __LINE__, __func__);
3247 goto out;
3248 }
3249 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3250 MPI2_IOCSTATUS_MASK;
3251 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3252 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3253 ioc->name, __FILE__, __LINE__, __func__);
3254 goto out;
3255 }
3256
3257 /* sas_iounit page 1 */
3258 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3259 sizeof(Mpi2SasIOUnit1PhyData_t));
3260 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3261 if (!sas_iounit_pg1) {
3262 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3263 ioc->name, __FILE__, __LINE__, __func__);
3264 goto out;
3265 }
3266 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3267 sas_iounit_pg1, sz))) {
3268 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3269 ioc->name, __FILE__, __LINE__, __func__);
3270 goto out;
3271 }
3272 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3273 MPI2_IOCSTATUS_MASK;
3274 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3275 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3276 ioc->name, __FILE__, __LINE__, __func__);
3277 goto out;
3278 }
3279
3280 ioc->io_missing_delay =
3281 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3282 device_missing_delay =
3283 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3284 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3285 ioc->device_missing_delay = (device_missing_delay &
3286 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3287 else
3288 ioc->device_missing_delay = device_missing_delay &
3289 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3290
3291 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3292 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3293 sizeof(struct _sas_phy), GFP_KERNEL);
3294 if (!ioc->sas_hba.phy) {
3295 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3296 ioc->name, __FILE__, __LINE__, __func__);
3297 goto out;
3298 }
3299 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3300 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3301 i))) {
3302 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3303 ioc->name, __FILE__, __LINE__, __func__);
3304 goto out;
3305 }
3306 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3307 MPI2_IOCSTATUS_MASK;
3308 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3309 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3310 ioc->name, __FILE__, __LINE__, __func__);
3311 goto out;
3312 }
3313 ioc->sas_hba.phy[i].handle =
3314 le16_to_cpu(sas_iounit_pg0->PhyData[i].ControllerDevHandle);
3315 ioc->sas_hba.phy[i].phy_id = i;
3316 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3317 phy_pg0, ioc->sas_hba.parent_dev);
3318 }
3319 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
3320 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.phy[0].handle))) {
3321 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3322 ioc->name, __FILE__, __LINE__, __func__);
3323 goto out;
3324 }
3325 ioc->sas_hba.handle = le16_to_cpu(sas_device_pg0.DevHandle);
3326 ioc->sas_hba.enclosure_handle =
3327 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3328 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3329 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3330 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3331 (unsigned long long) ioc->sas_hba.sas_address,
3332 ioc->sas_hba.num_phys) ;
3333
3334 if (ioc->sas_hba.enclosure_handle) {
3335 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3336 &enclosure_pg0,
3337 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3338 ioc->sas_hba.enclosure_handle))) {
3339 ioc->sas_hba.enclosure_logical_id =
3340 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3341 }
3342 }
3343
3344 out:
3345 kfree(sas_iounit_pg1);
3346 kfree(sas_iounit_pg0);
3347}
3348
3349/**
3350 * _scsih_expander_add - creating expander object
3351 * @ioc: per adapter object
3352 * @handle: expander handle
3353 *
3354 * Creating expander object, stored in ioc->sas_expander_list.
3355 *
3356 * Return 0 for success, else error.
3357 */
3358static int
3359_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3360{
3361 struct _sas_node *sas_expander;
3362 Mpi2ConfigReply_t mpi_reply;
3363 Mpi2ExpanderPage0_t expander_pg0;
3364 Mpi2ExpanderPage1_t expander_pg1;
3365 Mpi2SasEnclosurePage0_t enclosure_pg0;
3366 u32 ioc_status;
3367 u16 parent_handle;
3368 __le64 sas_address;
3369 int i;
3370 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303371 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003372 int rc = 0;
3373
3374 if (!handle)
3375 return -1;
3376
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303377 if (ioc->shost_recovery)
3378 return -1;
3379
Eric Moore635374e2009-03-09 01:21:12 -06003380 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3381 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3382 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3383 ioc->name, __FILE__, __LINE__, __func__);
3384 return -1;
3385 }
3386
3387 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3388 MPI2_IOCSTATUS_MASK;
3389 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3390 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3391 ioc->name, __FILE__, __LINE__, __func__);
3392 return -1;
3393 }
3394
3395 /* handle out of order topology events */
3396 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
3397 if (parent_handle >= ioc->sas_hba.num_phys) {
3398 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3399 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
3400 parent_handle);
3401 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3402 if (!sas_expander) {
3403 rc = _scsih_expander_add(ioc, parent_handle);
3404 if (rc != 0)
3405 return rc;
3406 }
3407 }
3408
3409 sas_address = le64_to_cpu(expander_pg0.SASAddress);
3410
3411 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3412 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3413 sas_address);
3414 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3415
3416 if (sas_expander)
3417 return 0;
3418
3419 sas_expander = kzalloc(sizeof(struct _sas_node),
3420 GFP_KERNEL);
3421 if (!sas_expander) {
3422 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3423 ioc->name, __FILE__, __LINE__, __func__);
3424 return -1;
3425 }
3426
3427 sas_expander->handle = handle;
3428 sas_expander->num_phys = expander_pg0.NumPhys;
3429 sas_expander->parent_handle = parent_handle;
3430 sas_expander->enclosure_handle =
3431 le16_to_cpu(expander_pg0.EnclosureHandle);
3432 sas_expander->sas_address = sas_address;
3433
3434 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3435 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
3436 handle, sas_expander->parent_handle, (unsigned long long)
3437 sas_expander->sas_address, sas_expander->num_phys);
3438
3439 if (!sas_expander->num_phys)
3440 goto out_fail;
3441 sas_expander->phy = kcalloc(sas_expander->num_phys,
3442 sizeof(struct _sas_phy), GFP_KERNEL);
3443 if (!sas_expander->phy) {
3444 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3445 ioc->name, __FILE__, __LINE__, __func__);
3446 rc = -1;
3447 goto out_fail;
3448 }
3449
3450 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3451 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
3452 sas_expander->parent_handle);
3453 if (!mpt2sas_port) {
3454 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3455 ioc->name, __FILE__, __LINE__, __func__);
3456 rc = -1;
3457 goto out_fail;
3458 }
3459 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3460
3461 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3462 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3463 &expander_pg1, i, handle))) {
3464 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3465 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303466 rc = -1;
3467 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003468 }
3469 sas_expander->phy[i].handle = handle;
3470 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303471
3472 if ((mpt2sas_transport_add_expander_phy(ioc,
3473 &sas_expander->phy[i], expander_pg1,
3474 sas_expander->parent_dev))) {
3475 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3476 ioc->name, __FILE__, __LINE__, __func__);
3477 rc = -1;
3478 goto out_fail;
3479 }
Eric Moore635374e2009-03-09 01:21:12 -06003480 }
3481
3482 if (sas_expander->enclosure_handle) {
3483 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3484 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3485 sas_expander->enclosure_handle))) {
3486 sas_expander->enclosure_logical_id =
3487 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3488 }
3489 }
3490
3491 _scsih_expander_node_add(ioc, sas_expander);
3492 return 0;
3493
3494 out_fail:
3495
Kashyap, Desai20f58952009-08-07 19:34:26 +05303496 if (mpt2sas_port)
3497 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
3498 sas_expander->parent_handle);
Eric Moore635374e2009-03-09 01:21:12 -06003499 kfree(sas_expander);
3500 return rc;
3501}
3502
3503/**
3504 * _scsih_expander_remove - removing expander object
3505 * @ioc: per adapter object
3506 * @handle: expander handle
3507 *
3508 * Return nothing.
3509 */
3510static void
3511_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3512{
3513 struct _sas_node *sas_expander;
3514 unsigned long flags;
3515
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303516 if (ioc->shost_recovery)
3517 return;
3518
Eric Moore635374e2009-03-09 01:21:12 -06003519 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3520 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle);
3521 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3522 _scsih_expander_node_remove(ioc, sas_expander);
3523}
3524
3525/**
3526 * _scsih_add_device - creating sas device object
3527 * @ioc: per adapter object
3528 * @handle: sas device handle
3529 * @phy_num: phy number end device attached to
3530 * @is_pd: is this hidden raid component
3531 *
3532 * Creating end device object, stored in ioc->sas_device_list.
3533 *
3534 * Returns 0 for success, non-zero for failure.
3535 */
3536static int
3537_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
3538{
3539 Mpi2ConfigReply_t mpi_reply;
3540 Mpi2SasDevicePage0_t sas_device_pg0;
3541 Mpi2SasEnclosurePage0_t enclosure_pg0;
3542 struct _sas_device *sas_device;
3543 u32 ioc_status;
3544 __le64 sas_address;
3545 u32 device_info;
3546 unsigned long flags;
3547
3548 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
3549 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
3550 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3551 ioc->name, __FILE__, __LINE__, __func__);
3552 return -1;
3553 }
3554
3555 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3556 MPI2_IOCSTATUS_MASK;
3557 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3558 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3559 ioc->name, __FILE__, __LINE__, __func__);
3560 return -1;
3561 }
3562
3563 /* check if device is present */
3564 if (!(le16_to_cpu(sas_device_pg0.Flags) &
3565 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
3566 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3567 ioc->name, __FILE__, __LINE__, __func__);
3568 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
3569 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
3570 return -1;
3571 }
3572
3573 /* check if there were any issus with discovery */
3574 if (sas_device_pg0.AccessStatus ==
3575 MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
3576 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3577 ioc->name, __FILE__, __LINE__, __func__);
3578 printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
3579 ioc->name, sas_device_pg0.AccessStatus);
3580 return -1;
3581 }
3582
3583 /* check if this is end device */
3584 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
3585 if (!(_scsih_is_end_device(device_info))) {
3586 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3587 ioc->name, __FILE__, __LINE__, __func__);
3588 return -1;
3589 }
3590
3591 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3592
3593 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3594 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
3595 sas_address);
3596 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3597
3598 if (sas_device) {
3599 _scsih_ublock_io_device(ioc, handle);
3600 return 0;
3601 }
3602
3603 sas_device = kzalloc(sizeof(struct _sas_device),
3604 GFP_KERNEL);
3605 if (!sas_device) {
3606 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3607 ioc->name, __FILE__, __LINE__, __func__);
3608 return -1;
3609 }
3610
3611 sas_device->handle = handle;
3612 sas_device->parent_handle =
3613 le16_to_cpu(sas_device_pg0.ParentDevHandle);
3614 sas_device->enclosure_handle =
3615 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3616 sas_device->slot =
3617 le16_to_cpu(sas_device_pg0.Slot);
3618 sas_device->device_info = device_info;
3619 sas_device->sas_address = sas_address;
3620 sas_device->hidden_raid_component = is_pd;
3621
3622 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05303623 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
3624 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3625 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06003626 sas_device->enclosure_logical_id =
3627 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06003628
3629 /* get device name */
3630 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
3631
3632 if (ioc->wait_for_port_enable_to_complete)
3633 _scsih_sas_device_init_add(ioc, sas_device);
3634 else
3635 _scsih_sas_device_add(ioc, sas_device);
3636
3637 return 0;
3638}
3639
3640/**
3641 * _scsih_remove_device - removing sas device object
3642 * @ioc: per adapter object
3643 * @handle: sas device handle
3644 *
3645 * Return nothing.
3646 */
3647static void
3648_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3649{
3650 struct MPT2SAS_TARGET *sas_target_priv_data;
3651 struct _sas_device *sas_device;
3652 unsigned long flags;
3653 Mpi2SasIoUnitControlReply_t mpi_reply;
3654 Mpi2SasIoUnitControlRequest_t mpi_request;
3655 u16 device_handle;
3656
3657 /* lookup sas_device */
3658 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3659 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3660 if (!sas_device) {
3661 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3662 return;
3663 }
3664
3665 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle"
3666 "(0x%04x)\n", ioc->name, __func__, handle));
3667
3668 if (sas_device->starget && sas_device->starget->hostdata) {
3669 sas_target_priv_data = sas_device->starget->hostdata;
3670 sas_target_priv_data->deleted = 1;
3671 }
3672 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3673
3674 if (ioc->remove_host)
3675 goto out;
3676
3677 /* Target Reset to flush out all the outstanding IO */
3678 device_handle = (sas_device->hidden_raid_component) ?
3679 sas_device->volume_handle : handle;
3680 if (device_handle) {
3681 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
3682 "handle(0x%04x)\n", ioc->name, device_handle));
3683 mutex_lock(&ioc->tm_cmds.mutex);
3684 mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
3685 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
3686 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
3687 mutex_unlock(&ioc->tm_cmds.mutex);
3688 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
3689 "done: handle(0x%04x)\n", ioc->name, device_handle));
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303690 if (ioc->shost_recovery)
3691 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003692 }
3693
3694 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
3695 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
3696 "(0x%04x)\n", ioc->name, handle));
3697 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
3698 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
3699 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
3700 mpi_request.DevHandle = handle;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303701 mpi_request.VF_ID = 0; /* TODO */
3702 mpi_request.VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003703 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
3704 &mpi_request)) != 0) {
3705 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3706 ioc->name, __FILE__, __LINE__, __func__);
3707 }
3708
3709 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
3710 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
3711 le16_to_cpu(mpi_reply.IOCStatus),
3712 le32_to_cpu(mpi_reply.IOCLogInfo)));
3713
3714 out:
Kashyap, Desai34a03be2009-08-20 13:23:19 +05303715
3716 _scsih_ublock_io_device(ioc, handle);
3717
Eric Moore635374e2009-03-09 01:21:12 -06003718 mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
3719 sas_device->parent_handle);
3720
3721 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
3722 "(0x%016llx)\n", ioc->name, sas_device->handle,
3723 (unsigned long long) sas_device->sas_address);
3724 _scsih_sas_device_remove(ioc, sas_device);
3725
3726 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
3727 "(0x%04x)\n", ioc->name, __func__, handle));
3728}
3729
3730#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3731/**
3732 * _scsih_sas_topology_change_event_debug - debug for topology event
3733 * @ioc: per adapter object
3734 * @event_data: event data payload
3735 * Context: user.
3736 */
3737static void
3738_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
3739 Mpi2EventDataSasTopologyChangeList_t *event_data)
3740{
3741 int i;
3742 u16 handle;
3743 u16 reason_code;
3744 u8 phy_number;
3745 char *status_str = NULL;
3746 char link_rate[25];
3747
3748 switch (event_data->ExpStatus) {
3749 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
3750 status_str = "add";
3751 break;
3752 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
3753 status_str = "remove";
3754 break;
3755 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
3756 status_str = "responding";
3757 break;
3758 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
3759 status_str = "remove delay";
3760 break;
3761 default:
3762 status_str = "unknown status";
3763 break;
3764 }
3765 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
3766 ioc->name, status_str);
3767 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
3768 "start_phy(%02d), count(%d)\n",
3769 le16_to_cpu(event_data->ExpanderDevHandle),
3770 le16_to_cpu(event_data->EnclosureHandle),
3771 event_data->StartPhyNum, event_data->NumEntries);
3772 for (i = 0; i < event_data->NumEntries; i++) {
3773 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
3774 if (!handle)
3775 continue;
3776 phy_number = event_data->StartPhyNum + i;
3777 reason_code = event_data->PHY[i].PhyStatus &
3778 MPI2_EVENT_SAS_TOPO_RC_MASK;
3779 switch (reason_code) {
3780 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
3781 snprintf(link_rate, 25, ": add, link(0x%02x)",
3782 (event_data->PHY[i].LinkRate >> 4));
3783 status_str = link_rate;
3784 break;
3785 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
3786 status_str = ": remove";
3787 break;
3788 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
3789 status_str = ": remove_delay";
3790 break;
3791 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
3792 snprintf(link_rate, 25, ": link(0x%02x)",
3793 (event_data->PHY[i].LinkRate >> 4));
3794 status_str = link_rate;
3795 break;
3796 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
3797 status_str = ": responding";
3798 break;
3799 default:
3800 status_str = ": unknown";
3801 break;
3802 }
3803 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n",
3804 phy_number, handle, status_str);
3805 }
3806}
3807#endif
3808
3809/**
3810 * _scsih_sas_topology_change_event - handle topology changes
3811 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303812 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06003813 * Context: user.
3814 *
3815 */
3816static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303817_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06003818 struct fw_event_work *fw_event)
3819{
3820 int i;
3821 u16 parent_handle, handle;
3822 u16 reason_code;
3823 u8 phy_number;
3824 struct _sas_node *sas_expander;
3825 unsigned long flags;
3826 u8 link_rate_;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303827 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06003828
3829#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3830 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
3831 _scsih_sas_topology_change_event_debug(ioc, event_data);
3832#endif
3833
3834 if (!ioc->sas_hba.num_phys)
3835 _scsih_sas_host_add(ioc);
3836 else
3837 _scsih_sas_host_refresh(ioc, 0);
3838
3839 if (fw_event->ignore) {
3840 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
3841 "event\n", ioc->name));
3842 return;
3843 }
3844
3845 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
3846
3847 /* handle expander add */
3848 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
3849 if (_scsih_expander_add(ioc, parent_handle) != 0)
3850 return;
3851
3852 /* handle siblings events */
3853 for (i = 0; i < event_data->NumEntries; i++) {
3854 if (fw_event->ignore) {
3855 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
3856 "expander event\n", ioc->name));
3857 return;
3858 }
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303859 if (ioc->shost_recovery)
3860 return;
Eric Moore635374e2009-03-09 01:21:12 -06003861 if (event_data->PHY[i].PhyStatus &
3862 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
3863 continue;
3864 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
3865 if (!handle)
3866 continue;
3867 phy_number = event_data->StartPhyNum + i;
3868 reason_code = event_data->PHY[i].PhyStatus &
3869 MPI2_EVENT_SAS_TOPO_RC_MASK;
3870 link_rate_ = event_data->PHY[i].LinkRate >> 4;
3871 switch (reason_code) {
3872 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
3873 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
3874 if (!parent_handle) {
3875 if (phy_number < ioc->sas_hba.num_phys)
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05303876 mpt2sas_transport_update_links(
3877 ioc,
3878 ioc->sas_hba.phy[phy_number].handle,
3879 handle, phy_number, link_rate_);
Eric Moore635374e2009-03-09 01:21:12 -06003880 } else {
3881 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3882 sas_expander =
3883 mpt2sas_scsih_expander_find_by_handle(ioc,
3884 parent_handle);
3885 spin_unlock_irqrestore(&ioc->sas_node_lock,
3886 flags);
3887 if (sas_expander) {
3888 if (phy_number < sas_expander->num_phys)
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05303889 mpt2sas_transport_update_links(
3890 ioc,
3891 sas_expander->
3892 phy[phy_number].handle,
3893 handle, phy_number,
3894 link_rate_);
Eric Moore635374e2009-03-09 01:21:12 -06003895 }
3896 }
Eric Moore635374e2009-03-09 01:21:12 -06003897 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
3898 if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5)
3899 break;
3900 _scsih_add_device(ioc, handle, phy_number, 0);
3901 }
3902 break;
3903 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
3904 _scsih_remove_device(ioc, handle);
3905 break;
3906 }
3907 }
3908
3909 /* handle expander removal */
3910 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
3911 _scsih_expander_remove(ioc, parent_handle);
3912
3913}
3914
3915#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3916/**
3917 * _scsih_sas_device_status_change_event_debug - debug for device event
3918 * @event_data: event data payload
3919 * Context: user.
3920 *
3921 * Return nothing.
3922 */
3923static void
3924_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
3925 Mpi2EventDataSasDeviceStatusChange_t *event_data)
3926{
3927 char *reason_str = NULL;
3928
3929 switch (event_data->ReasonCode) {
3930 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
3931 reason_str = "smart data";
3932 break;
3933 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
3934 reason_str = "unsupported device discovered";
3935 break;
3936 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
3937 reason_str = "internal device reset";
3938 break;
3939 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
3940 reason_str = "internal task abort";
3941 break;
3942 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
3943 reason_str = "internal task abort set";
3944 break;
3945 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
3946 reason_str = "internal clear task set";
3947 break;
3948 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
3949 reason_str = "internal query task";
3950 break;
3951 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
3952 reason_str = "sata init failure";
3953 break;
3954 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
3955 reason_str = "internal device reset complete";
3956 break;
3957 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
3958 reason_str = "internal task abort complete";
3959 break;
3960 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
3961 reason_str = "internal async notification";
3962 break;
3963 default:
3964 reason_str = "unknown reason";
3965 break;
3966 }
3967 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
3968 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
3969 reason_str, le16_to_cpu(event_data->DevHandle),
3970 (unsigned long long)le64_to_cpu(event_data->SASAddress));
3971 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
3972 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
3973 event_data->ASC, event_data->ASCQ);
3974 printk(KERN_INFO "\n");
3975}
3976#endif
3977
3978/**
3979 * _scsih_sas_device_status_change_event - handle device status change
3980 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303981 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06003982 * Context: user.
3983 *
3984 * Return nothing.
3985 */
3986static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303987_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
3988 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06003989{
3990#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3991 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303992 _scsih_sas_device_status_change_event_debug(ioc,
3993 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06003994#endif
3995}
3996
3997#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3998/**
3999 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
4000 * @ioc: per adapter object
4001 * @event_data: event data payload
4002 * Context: user.
4003 *
4004 * Return nothing.
4005 */
4006static void
4007_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4008 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
4009{
4010 char *reason_str = NULL;
4011
4012 switch (event_data->ReasonCode) {
4013 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
4014 reason_str = "enclosure add";
4015 break;
4016 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
4017 reason_str = "enclosure remove";
4018 break;
4019 default:
4020 reason_str = "unknown reason";
4021 break;
4022 }
4023
4024 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
4025 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
4026 " number slots(%d)\n", ioc->name, reason_str,
4027 le16_to_cpu(event_data->EnclosureHandle),
4028 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
4029 le16_to_cpu(event_data->StartSlot));
4030}
4031#endif
4032
4033/**
4034 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
4035 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304036 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004037 * Context: user.
4038 *
4039 * Return nothing.
4040 */
4041static void
4042_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304043 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004044{
4045#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4046 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4047 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304048 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004049#endif
4050}
4051
4052/**
4053 * _scsih_sas_broadcast_primative_event - handle broadcast events
4054 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304055 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004056 * Context: user.
4057 *
4058 * Return nothing.
4059 */
4060static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304061_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4062 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004063{
4064 struct scsi_cmnd *scmd;
4065 u16 smid, handle;
4066 u32 lun;
4067 struct MPT2SAS_DEVICE *sas_device_priv_data;
4068 u32 termination_count;
4069 u32 query_count;
4070 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304071#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4072 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4073#endif
Eric Moore635374e2009-03-09 01:21:12 -06004074 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4075 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4076 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004077 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4078 __func__));
4079
4080 mutex_lock(&ioc->tm_cmds.mutex);
4081 termination_count = 0;
4082 query_count = 0;
4083 mpi_reply = ioc->tm_cmds.reply;
4084 for (smid = 1; smid <= ioc->request_depth; smid++) {
4085 scmd = _scsih_scsi_lookup_get(ioc, smid);
4086 if (!scmd)
4087 continue;
4088 sas_device_priv_data = scmd->device->hostdata;
4089 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4090 continue;
4091 /* skip hidden raid components */
4092 if (sas_device_priv_data->sas_target->flags &
4093 MPT_TARGET_FLAGS_RAID_COMPONENT)
4094 continue;
4095 /* skip volumes */
4096 if (sas_device_priv_data->sas_target->flags &
4097 MPT_TARGET_FLAGS_VOLUME)
4098 continue;
4099
4100 handle = sas_device_priv_data->sas_target->handle;
4101 lun = sas_device_priv_data->lun;
4102 query_count++;
4103
4104 mpt2sas_scsih_issue_tm(ioc, handle, lun,
4105 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
Eric Moore8901cbb2009-04-21 15:41:32 -06004106 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004107
4108 if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) &&
4109 (mpi_reply->ResponseCode ==
4110 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4111 mpi_reply->ResponseCode ==
4112 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4113 continue;
4114
4115 mpt2sas_scsih_issue_tm(ioc, handle, lun,
Eric Moore8901cbb2009-04-21 15:41:32 -06004116 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30);
4117 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004118 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4119 }
Eric Moore635374e2009-03-09 01:21:12 -06004120 ioc->broadcast_aen_busy = 0;
4121 mutex_unlock(&ioc->tm_cmds.mutex);
4122
4123 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4124 "%s - exit, query_count = %d termination_count = %d\n",
4125 ioc->name, __func__, query_count, termination_count));
4126}
4127
4128/**
4129 * _scsih_sas_discovery_event - handle discovery events
4130 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304131 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004132 * Context: user.
4133 *
4134 * Return nothing.
4135 */
4136static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304137_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4138 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004139{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304140 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4141
Eric Moore635374e2009-03-09 01:21:12 -06004142#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4143 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4144 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4145 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4146 "start" : "stop");
4147 if (event_data->DiscoveryStatus)
4148 printk(MPT2SAS_DEBUG_FMT ", discovery_status(0x%08x)",
4149 ioc->name, le32_to_cpu(event_data->DiscoveryStatus));
4150 printk("\n");
4151 }
4152#endif
4153
4154 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4155 !ioc->sas_hba.num_phys)
4156 _scsih_sas_host_add(ioc);
4157}
4158
4159/**
4160 * _scsih_reprobe_lun - reprobing lun
4161 * @sdev: scsi device struct
4162 * @no_uld_attach: sdev->no_uld_attach flag setting
4163 *
4164 **/
4165static void
4166_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4167{
4168 int rc;
4169
4170 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4171 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4172 sdev->no_uld_attach ? "hidding" : "exposing");
4173 rc = scsi_device_reprobe(sdev);
4174}
4175
4176/**
4177 * _scsih_reprobe_target - reprobing target
4178 * @starget: scsi target struct
4179 * @no_uld_attach: sdev->no_uld_attach flag setting
4180 *
4181 * Note: no_uld_attach flag determines whether the disk device is attached
4182 * to block layer. A value of `1` means to not attach.
4183 **/
4184static void
4185_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4186{
4187 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4188
4189 if (no_uld_attach)
4190 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4191 else
4192 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4193
4194 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4195 _scsih_reprobe_lun);
4196}
4197/**
4198 * _scsih_sas_volume_add - add new volume
4199 * @ioc: per adapter object
4200 * @element: IR config element data
4201 * Context: user.
4202 *
4203 * Return nothing.
4204 */
4205static void
4206_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4207 Mpi2EventIrConfigElement_t *element)
4208{
4209 struct _raid_device *raid_device;
4210 unsigned long flags;
4211 u64 wwid;
4212 u16 handle = le16_to_cpu(element->VolDevHandle);
4213 int rc;
4214
Eric Moore635374e2009-03-09 01:21:12 -06004215 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4216 if (!wwid) {
4217 printk(MPT2SAS_ERR_FMT
4218 "failure at %s:%d/%s()!\n", ioc->name,
4219 __FILE__, __LINE__, __func__);
4220 return;
4221 }
4222
4223 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4224 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4225 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4226
4227 if (raid_device)
4228 return;
4229
4230 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4231 if (!raid_device) {
4232 printk(MPT2SAS_ERR_FMT
4233 "failure at %s:%d/%s()!\n", ioc->name,
4234 __FILE__, __LINE__, __func__);
4235 return;
4236 }
4237
4238 raid_device->id = ioc->sas_id++;
4239 raid_device->channel = RAID_CHANNEL;
4240 raid_device->handle = handle;
4241 raid_device->wwid = wwid;
4242 _scsih_raid_device_add(ioc, raid_device);
4243 if (!ioc->wait_for_port_enable_to_complete) {
4244 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4245 raid_device->id, 0);
4246 if (rc)
4247 _scsih_raid_device_remove(ioc, raid_device);
4248 } else
4249 _scsih_determine_boot_device(ioc, raid_device, 1);
4250}
4251
4252/**
4253 * _scsih_sas_volume_delete - delete volume
4254 * @ioc: per adapter object
4255 * @element: IR config element data
4256 * Context: user.
4257 *
4258 * Return nothing.
4259 */
4260static void
4261_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4262 Mpi2EventIrConfigElement_t *element)
4263{
4264 struct _raid_device *raid_device;
4265 u16 handle = le16_to_cpu(element->VolDevHandle);
4266 unsigned long flags;
4267 struct MPT2SAS_TARGET *sas_target_priv_data;
4268
Eric Moore635374e2009-03-09 01:21:12 -06004269 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4270 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4271 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4272 if (!raid_device)
4273 return;
4274 if (raid_device->starget) {
4275 sas_target_priv_data = raid_device->starget->hostdata;
4276 sas_target_priv_data->deleted = 1;
4277 scsi_remove_target(&raid_device->starget->dev);
4278 }
4279 _scsih_raid_device_remove(ioc, raid_device);
4280}
4281
4282/**
4283 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4284 * @ioc: per adapter object
4285 * @element: IR config element data
4286 * Context: user.
4287 *
4288 * Return nothing.
4289 */
4290static void
4291_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4292 Mpi2EventIrConfigElement_t *element)
4293{
4294 struct _sas_device *sas_device;
4295 unsigned long flags;
4296 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4297
4298 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4299 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4300 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4301 if (!sas_device)
4302 return;
4303
4304 /* exposing raid component */
4305 sas_device->volume_handle = 0;
4306 sas_device->volume_wwid = 0;
4307 sas_device->hidden_raid_component = 0;
4308 _scsih_reprobe_target(sas_device->starget, 0);
4309}
4310
4311/**
4312 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4313 * @ioc: per adapter object
4314 * @element: IR config element data
4315 * Context: user.
4316 *
4317 * Return nothing.
4318 */
4319static void
4320_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4321 Mpi2EventIrConfigElement_t *element)
4322{
4323 struct _sas_device *sas_device;
4324 unsigned long flags;
4325 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4326
4327 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4328 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4329 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4330 if (!sas_device)
4331 return;
4332
4333 /* hiding raid component */
4334 mpt2sas_config_get_volume_handle(ioc, handle,
4335 &sas_device->volume_handle);
4336 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4337 &sas_device->volume_wwid);
4338 sas_device->hidden_raid_component = 1;
4339 _scsih_reprobe_target(sas_device->starget, 1);
4340}
4341
4342/**
4343 * _scsih_sas_pd_delete - delete pd component
4344 * @ioc: per adapter object
4345 * @element: IR config element data
4346 * Context: user.
4347 *
4348 * Return nothing.
4349 */
4350static void
4351_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4352 Mpi2EventIrConfigElement_t *element)
4353{
4354 struct _sas_device *sas_device;
4355 unsigned long flags;
4356 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4357
4358 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4359 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4360 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4361 if (!sas_device)
4362 return;
4363 _scsih_remove_device(ioc, handle);
4364}
4365
4366/**
4367 * _scsih_sas_pd_add - remove pd component
4368 * @ioc: per adapter object
4369 * @element: IR config element data
4370 * Context: user.
4371 *
4372 * Return nothing.
4373 */
4374static void
4375_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
4376 Mpi2EventIrConfigElement_t *element)
4377{
4378 struct _sas_device *sas_device;
4379 unsigned long flags;
4380 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304381 Mpi2ConfigReply_t mpi_reply;
4382 Mpi2SasDevicePage0_t sas_device_pg0;
4383 u32 ioc_status;
Eric Moore635374e2009-03-09 01:21:12 -06004384
4385 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4386 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4387 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304388 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004389 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304390 return;
4391 }
4392
4393 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4394 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4395 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4396 ioc->name, __FILE__, __LINE__, __func__);
4397 return;
4398 }
4399
4400 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4401 MPI2_IOCSTATUS_MASK;
4402 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4403 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4404 ioc->name, __FILE__, __LINE__, __func__);
4405 return;
4406 }
4407
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05304408 mpt2sas_transport_update_links(ioc,
Kashyap, Desai62727a72009-08-07 19:35:18 +05304409 le16_to_cpu(sas_device_pg0.ParentDevHandle),
4410 handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
4411
4412 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06004413}
4414
4415#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4416/**
4417 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
4418 * @ioc: per adapter object
4419 * @event_data: event data payload
4420 * Context: user.
4421 *
4422 * Return nothing.
4423 */
4424static void
4425_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4426 Mpi2EventDataIrConfigChangeList_t *event_data)
4427{
4428 Mpi2EventIrConfigElement_t *element;
4429 u8 element_type;
4430 int i;
4431 char *reason_str = NULL, *element_str = NULL;
4432
4433 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4434
4435 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
4436 ioc->name, (le32_to_cpu(event_data->Flags) &
4437 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
4438 "foreign" : "native", event_data->NumElements);
4439 for (i = 0; i < event_data->NumElements; i++, element++) {
4440 switch (element->ReasonCode) {
4441 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
4442 reason_str = "add";
4443 break;
4444 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
4445 reason_str = "remove";
4446 break;
4447 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
4448 reason_str = "no change";
4449 break;
4450 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4451 reason_str = "hide";
4452 break;
4453 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4454 reason_str = "unhide";
4455 break;
4456 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4457 reason_str = "volume_created";
4458 break;
4459 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4460 reason_str = "volume_deleted";
4461 break;
4462 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4463 reason_str = "pd_created";
4464 break;
4465 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4466 reason_str = "pd_deleted";
4467 break;
4468 default:
4469 reason_str = "unknown reason";
4470 break;
4471 }
4472 element_type = le16_to_cpu(element->ElementFlags) &
4473 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
4474 switch (element_type) {
4475 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
4476 element_str = "volume";
4477 break;
4478 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
4479 element_str = "phys disk";
4480 break;
4481 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
4482 element_str = "hot spare";
4483 break;
4484 default:
4485 element_str = "unknown element";
4486 break;
4487 }
4488 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
4489 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
4490 reason_str, le16_to_cpu(element->VolDevHandle),
4491 le16_to_cpu(element->PhysDiskDevHandle),
4492 element->PhysDiskNum);
4493 }
4494}
4495#endif
4496
4497/**
4498 * _scsih_sas_ir_config_change_event - handle ir configuration change events
4499 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304500 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004501 * Context: user.
4502 *
4503 * Return nothing.
4504 */
4505static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304506_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
4507 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004508{
4509 Mpi2EventIrConfigElement_t *element;
4510 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304511 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304512 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004513
4514#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4515 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4516 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
4517
4518#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05304519 foreign_config = (le32_to_cpu(event_data->Flags) &
4520 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06004521
4522 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4523 for (i = 0; i < event_data->NumElements; i++, element++) {
4524
4525 switch (element->ReasonCode) {
4526 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4527 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304528 if (!foreign_config)
4529 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004530 break;
4531 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4532 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304533 if (!foreign_config)
4534 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004535 break;
4536 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4537 _scsih_sas_pd_hide(ioc, element);
4538 break;
4539 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4540 _scsih_sas_pd_expose(ioc, element);
4541 break;
4542 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4543 _scsih_sas_pd_add(ioc, element);
4544 break;
4545 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4546 _scsih_sas_pd_delete(ioc, element);
4547 break;
4548 }
4549 }
4550}
4551
4552/**
4553 * _scsih_sas_ir_volume_event - IR volume event
4554 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304555 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004556 * Context: user.
4557 *
4558 * Return nothing.
4559 */
4560static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304561_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
4562 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004563{
4564 u64 wwid;
4565 unsigned long flags;
4566 struct _raid_device *raid_device;
4567 u16 handle;
4568 u32 state;
4569 int rc;
4570 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304571 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004572
4573 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
4574 return;
4575
4576 handle = le16_to_cpu(event_data->VolDevHandle);
4577 state = le32_to_cpu(event_data->NewValue);
4578 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4579 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4580 le32_to_cpu(event_data->PreviousValue), state));
4581
4582 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4583 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4584 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4585
4586 switch (state) {
4587 case MPI2_RAID_VOL_STATE_MISSING:
4588 case MPI2_RAID_VOL_STATE_FAILED:
4589 if (!raid_device)
4590 break;
4591 if (raid_device->starget) {
4592 sas_target_priv_data = raid_device->starget->hostdata;
4593 sas_target_priv_data->deleted = 1;
4594 scsi_remove_target(&raid_device->starget->dev);
4595 }
4596 _scsih_raid_device_remove(ioc, raid_device);
4597 break;
4598
4599 case MPI2_RAID_VOL_STATE_ONLINE:
4600 case MPI2_RAID_VOL_STATE_DEGRADED:
4601 case MPI2_RAID_VOL_STATE_OPTIMAL:
4602 if (raid_device)
4603 break;
4604
4605 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4606 if (!wwid) {
4607 printk(MPT2SAS_ERR_FMT
4608 "failure at %s:%d/%s()!\n", ioc->name,
4609 __FILE__, __LINE__, __func__);
4610 break;
4611 }
4612
4613 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4614 if (!raid_device) {
4615 printk(MPT2SAS_ERR_FMT
4616 "failure at %s:%d/%s()!\n", ioc->name,
4617 __FILE__, __LINE__, __func__);
4618 break;
4619 }
4620
4621 raid_device->id = ioc->sas_id++;
4622 raid_device->channel = RAID_CHANNEL;
4623 raid_device->handle = handle;
4624 raid_device->wwid = wwid;
4625 _scsih_raid_device_add(ioc, raid_device);
4626 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4627 raid_device->id, 0);
4628 if (rc)
4629 _scsih_raid_device_remove(ioc, raid_device);
4630 break;
4631
4632 case MPI2_RAID_VOL_STATE_INITIALIZING:
4633 default:
4634 break;
4635 }
4636}
4637
4638/**
4639 * _scsih_sas_ir_physical_disk_event - PD event
4640 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304641 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004642 * Context: user.
4643 *
4644 * Return nothing.
4645 */
4646static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304647_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
4648 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004649{
4650 u16 handle;
4651 u32 state;
4652 struct _sas_device *sas_device;
4653 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304654 Mpi2ConfigReply_t mpi_reply;
4655 Mpi2SasDevicePage0_t sas_device_pg0;
4656 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304657 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004658
4659 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
4660 return;
4661
4662 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
4663 state = le32_to_cpu(event_data->NewValue);
4664
4665 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4666 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4667 le32_to_cpu(event_data->PreviousValue), state));
4668
4669 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4670 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4671 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4672
4673 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06004674 case MPI2_RAID_PD_STATE_ONLINE:
4675 case MPI2_RAID_PD_STATE_DEGRADED:
4676 case MPI2_RAID_PD_STATE_REBUILDING:
4677 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304678 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004679 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304680 return;
4681 }
4682
4683 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
4684 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
4685 handle))) {
4686 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4687 ioc->name, __FILE__, __LINE__, __func__);
4688 return;
4689 }
4690
4691 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4692 MPI2_IOCSTATUS_MASK;
4693 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4694 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4695 ioc->name, __FILE__, __LINE__, __func__);
4696 return;
4697 }
4698
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05304699 mpt2sas_transport_update_links(ioc,
Kashyap, Desai62727a72009-08-07 19:35:18 +05304700 le16_to_cpu(sas_device_pg0.ParentDevHandle),
4701 handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
4702
4703 _scsih_add_device(ioc, handle, 0, 1);
4704
Eric Moore635374e2009-03-09 01:21:12 -06004705 break;
4706
Kashyap, Desai62727a72009-08-07 19:35:18 +05304707 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06004708 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
4709 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
4710 case MPI2_RAID_PD_STATE_HOT_SPARE:
4711 default:
4712 break;
4713 }
4714}
4715
4716#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4717/**
4718 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
4719 * @ioc: per adapter object
4720 * @event_data: event data payload
4721 * Context: user.
4722 *
4723 * Return nothing.
4724 */
4725static void
4726_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
4727 Mpi2EventDataIrOperationStatus_t *event_data)
4728{
4729 char *reason_str = NULL;
4730
4731 switch (event_data->RAIDOperation) {
4732 case MPI2_EVENT_IR_RAIDOP_RESYNC:
4733 reason_str = "resync";
4734 break;
4735 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
4736 reason_str = "online capacity expansion";
4737 break;
4738 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
4739 reason_str = "consistency check";
4740 break;
4741 default:
4742 reason_str = "unknown reason";
4743 break;
4744 }
4745
4746 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
4747 "\thandle(0x%04x), percent complete(%d)\n",
4748 ioc->name, reason_str,
4749 le16_to_cpu(event_data->VolDevHandle),
4750 event_data->PercentComplete);
4751}
4752#endif
4753
4754/**
4755 * _scsih_sas_ir_operation_status_event - handle RAID operation events
4756 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304757 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004758 * Context: user.
4759 *
4760 * Return nothing.
4761 */
4762static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304763_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
4764 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004765{
4766#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4767 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304768 _scsih_sas_ir_operation_status_event_debug(ioc,
4769 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004770#endif
4771}
4772
4773/**
4774 * _scsih_task_set_full - handle task set full
4775 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304776 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004777 * Context: user.
4778 *
4779 * Throttle back qdepth.
4780 */
4781static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304782_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
4783 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004784{
4785 unsigned long flags;
4786 struct _sas_device *sas_device;
4787 static struct _raid_device *raid_device;
4788 struct scsi_device *sdev;
4789 int depth;
4790 u16 current_depth;
4791 u16 handle;
4792 int id, channel;
4793 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304794 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004795
4796 current_depth = le16_to_cpu(event_data->CurrentDepth);
4797 handle = le16_to_cpu(event_data->DevHandle);
4798 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4799 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4800 if (!sas_device) {
4801 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4802 return;
4803 }
4804 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4805 id = sas_device->id;
4806 channel = sas_device->channel;
4807 sas_address = sas_device->sas_address;
4808
4809 /* if hidden raid component, then change to volume characteristics */
4810 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
4811 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4812 raid_device = _scsih_raid_device_find_by_handle(
4813 ioc, sas_device->volume_handle);
4814 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4815 if (raid_device) {
4816 id = raid_device->id;
4817 channel = raid_device->channel;
4818 handle = raid_device->handle;
4819 sas_address = raid_device->wwid;
4820 }
4821 }
4822
4823 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
4824 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
4825 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
4826 handle, (unsigned long long)sas_address, current_depth);
4827
4828 shost_for_each_device(sdev, ioc->shost) {
4829 if (sdev->id == id && sdev->channel == channel) {
4830 if (current_depth > sdev->queue_depth) {
4831 if (ioc->logging_level &
4832 MPT_DEBUG_TASK_SET_FULL)
4833 sdev_printk(KERN_INFO, sdev, "strange "
4834 "observation, the queue depth is"
4835 " (%d) meanwhile fw queue depth "
4836 "is (%d)\n", sdev->queue_depth,
4837 current_depth);
4838 continue;
4839 }
4840 depth = scsi_track_queue_full(sdev,
4841 current_depth - 1);
4842 if (depth > 0)
4843 sdev_printk(KERN_INFO, sdev, "Queue depth "
4844 "reduced to (%d)\n", depth);
4845 else if (depth < 0)
4846 sdev_printk(KERN_INFO, sdev, "Tagged Command "
4847 "Queueing is being disabled\n");
4848 else if (depth == 0)
4849 if (ioc->logging_level &
4850 MPT_DEBUG_TASK_SET_FULL)
4851 sdev_printk(KERN_INFO, sdev,
4852 "Queue depth not changed yet\n");
4853 }
4854 }
4855}
4856
4857/**
4858 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
4859 * @ioc: per adapter object
4860 * @sas_address: sas address
4861 * @slot: enclosure slot id
4862 * @handle: device handle
4863 *
4864 * After host reset, find out whether devices are still responding.
4865 * Used in _scsi_remove_unresponsive_sas_devices.
4866 *
4867 * Return nothing.
4868 */
4869static void
4870_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
4871 u16 slot, u16 handle)
4872{
4873 struct MPT2SAS_TARGET *sas_target_priv_data;
4874 struct scsi_target *starget;
4875 struct _sas_device *sas_device;
4876 unsigned long flags;
4877
4878 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4879 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
4880 if (sas_device->sas_address == sas_address &&
4881 sas_device->slot == slot && sas_device->starget) {
4882 sas_device->responding = 1;
4883 starget_printk(KERN_INFO, sas_device->starget,
4884 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
4885 "logical id(0x%016llx), slot(%d)\n", handle,
4886 (unsigned long long)sas_device->sas_address,
4887 (unsigned long long)
4888 sas_device->enclosure_logical_id,
4889 sas_device->slot);
4890 if (sas_device->handle == handle)
4891 goto out;
4892 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
4893 sas_device->handle);
4894 sas_device->handle = handle;
4895 starget = sas_device->starget;
4896 sas_target_priv_data = starget->hostdata;
4897 sas_target_priv_data->handle = handle;
4898 goto out;
4899 }
4900 }
4901 out:
4902 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4903}
4904
4905/**
4906 * _scsih_search_responding_sas_devices -
4907 * @ioc: per adapter object
4908 *
4909 * After host reset, find out whether devices are still responding.
4910 * If not remove.
4911 *
4912 * Return nothing.
4913 */
4914static void
4915_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
4916{
4917 Mpi2SasDevicePage0_t sas_device_pg0;
4918 Mpi2ConfigReply_t mpi_reply;
4919 u16 ioc_status;
4920 __le64 sas_address;
4921 u16 handle;
4922 u32 device_info;
4923 u16 slot;
4924
4925 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
4926
4927 if (list_empty(&ioc->sas_device_list))
4928 return;
4929
4930 handle = 0xFFFF;
4931 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
4932 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
4933 handle))) {
4934 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4935 MPI2_IOCSTATUS_MASK;
4936 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
4937 break;
4938 handle = le16_to_cpu(sas_device_pg0.DevHandle);
4939 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4940 if (!(_scsih_is_end_device(device_info)))
4941 continue;
4942 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4943 slot = le16_to_cpu(sas_device_pg0.Slot);
4944 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
4945 handle);
4946 }
4947}
4948
4949/**
4950 * _scsih_mark_responding_raid_device - mark a raid_device as responding
4951 * @ioc: per adapter object
4952 * @wwid: world wide identifier for raid volume
4953 * @handle: device handle
4954 *
4955 * After host reset, find out whether devices are still responding.
4956 * Used in _scsi_remove_unresponsive_raid_devices.
4957 *
4958 * Return nothing.
4959 */
4960static void
4961_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
4962 u16 handle)
4963{
4964 struct MPT2SAS_TARGET *sas_target_priv_data;
4965 struct scsi_target *starget;
4966 struct _raid_device *raid_device;
4967 unsigned long flags;
4968
4969 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4970 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
4971 if (raid_device->wwid == wwid && raid_device->starget) {
4972 raid_device->responding = 1;
4973 starget_printk(KERN_INFO, raid_device->starget,
4974 "handle(0x%04x), wwid(0x%016llx)\n", handle,
4975 (unsigned long long)raid_device->wwid);
4976 if (raid_device->handle == handle)
4977 goto out;
4978 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
4979 raid_device->handle);
4980 raid_device->handle = handle;
4981 starget = raid_device->starget;
4982 sas_target_priv_data = starget->hostdata;
4983 sas_target_priv_data->handle = handle;
4984 goto out;
4985 }
4986 }
4987 out:
4988 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4989}
4990
4991/**
4992 * _scsih_search_responding_raid_devices -
4993 * @ioc: per adapter object
4994 *
4995 * After host reset, find out whether devices are still responding.
4996 * If not remove.
4997 *
4998 * Return nothing.
4999 */
5000static void
5001_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
5002{
5003 Mpi2RaidVolPage1_t volume_pg1;
5004 Mpi2ConfigReply_t mpi_reply;
5005 u16 ioc_status;
5006 u16 handle;
5007
5008 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5009
5010 if (list_empty(&ioc->raid_device_list))
5011 return;
5012
5013 handle = 0xFFFF;
5014 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
5015 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
5016 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5017 MPI2_IOCSTATUS_MASK;
5018 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5019 break;
5020 handle = le16_to_cpu(volume_pg1.DevHandle);
5021 _scsih_mark_responding_raid_device(ioc,
5022 le64_to_cpu(volume_pg1.WWID), handle);
5023 }
5024}
5025
5026/**
5027 * _scsih_mark_responding_expander - mark a expander as responding
5028 * @ioc: per adapter object
5029 * @sas_address: sas address
5030 * @handle:
5031 *
5032 * After host reset, find out whether devices are still responding.
5033 * Used in _scsi_remove_unresponsive_expanders.
5034 *
5035 * Return nothing.
5036 */
5037static void
5038_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5039 u16 handle)
5040{
5041 struct _sas_node *sas_expander;
5042 unsigned long flags;
5043
5044 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5045 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
5046 if (sas_expander->sas_address == sas_address) {
5047 sas_expander->responding = 1;
5048 if (sas_expander->handle != handle) {
5049 printk(KERN_INFO "old handle(0x%04x)\n",
5050 sas_expander->handle);
5051 sas_expander->handle = handle;
5052 }
5053 goto out;
5054 }
5055 }
5056 out:
5057 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5058}
5059
5060/**
5061 * _scsih_search_responding_expanders -
5062 * @ioc: per adapter object
5063 *
5064 * After host reset, find out whether devices are still responding.
5065 * If not remove.
5066 *
5067 * Return nothing.
5068 */
5069static void
5070_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5071{
5072 Mpi2ExpanderPage0_t expander_pg0;
5073 Mpi2ConfigReply_t mpi_reply;
5074 u16 ioc_status;
5075 __le64 sas_address;
5076 u16 handle;
5077
5078 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5079
5080 if (list_empty(&ioc->sas_expander_list))
5081 return;
5082
5083 handle = 0xFFFF;
5084 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5085 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5086
5087 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5088 MPI2_IOCSTATUS_MASK;
5089 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5090 break;
5091
5092 handle = le16_to_cpu(expander_pg0.DevHandle);
5093 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5094 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5095 "sas_addr(0x%016llx)\n", handle,
5096 (unsigned long long)sas_address);
5097 _scsih_mark_responding_expander(ioc, sas_address, handle);
5098 }
5099
5100}
5101
5102/**
5103 * _scsih_remove_unresponding_devices - removing unresponding devices
5104 * @ioc: per adapter object
5105 *
5106 * Return nothing.
5107 */
5108static void
5109_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
5110{
5111 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305112 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005113 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005114
Eric Moore635374e2009-03-09 01:21:12 -06005115
5116 list_for_each_entry_safe(sas_device, sas_device_next,
5117 &ioc->sas_device_list, list) {
5118 if (sas_device->responding) {
5119 sas_device->responding = 0;
5120 continue;
5121 }
5122 if (sas_device->starget)
5123 starget_printk(KERN_INFO, sas_device->starget,
5124 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5125 "enclosure logical id(0x%016llx), slot(%d)\n",
5126 sas_device->handle,
5127 (unsigned long long)sas_device->sas_address,
5128 (unsigned long long)
5129 sas_device->enclosure_logical_id,
5130 sas_device->slot);
5131 _scsih_remove_device(ioc, sas_device->handle);
5132 }
5133
5134 list_for_each_entry_safe(raid_device, raid_device_next,
5135 &ioc->raid_device_list, list) {
5136 if (raid_device->responding) {
5137 raid_device->responding = 0;
5138 continue;
5139 }
5140 if (raid_device->starget) {
5141 starget_printk(KERN_INFO, raid_device->starget,
5142 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5143 raid_device->handle,
5144 (unsigned long long)raid_device->wwid);
5145 scsi_remove_target(&raid_device->starget->dev);
5146 }
5147 _scsih_raid_device_remove(ioc, raid_device);
5148 }
5149
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305150 retry_expander_search:
5151 sas_expander = NULL;
5152 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005153 if (sas_expander->responding) {
5154 sas_expander->responding = 0;
5155 continue;
5156 }
Eric Moore635374e2009-03-09 01:21:12 -06005157 _scsih_expander_remove(ioc, sas_expander->handle);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305158 goto retry_expander_search;
5159 }
5160}
5161
5162/**
5163 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5164 * @ioc: per adapter object
5165 * @reset_phase: phase
5166 *
5167 * The handler for doing any required cleanup or initialization.
5168 *
5169 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5170 * MPT2_IOC_DONE_RESET
5171 *
5172 * Return nothing.
5173 */
5174void
5175mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5176{
5177 switch (reset_phase) {
5178 case MPT2_IOC_PRE_RESET:
5179 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5180 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
5181 _scsih_fw_event_off(ioc);
5182 break;
5183 case MPT2_IOC_AFTER_RESET:
5184 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5185 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
5186 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5187 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5188 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5189 complete(&ioc->tm_cmds.done);
5190 }
5191 _scsih_fw_event_on(ioc);
5192 _scsih_flush_running_cmds(ioc);
5193 break;
5194 case MPT2_IOC_DONE_RESET:
5195 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5196 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
5197 _scsih_sas_host_refresh(ioc, 0);
5198 _scsih_search_responding_sas_devices(ioc);
5199 _scsih_search_responding_raid_devices(ioc);
5200 _scsih_search_responding_expanders(ioc);
5201 break;
5202 case MPT2_IOC_RUNNING:
5203 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5204 "MPT2_IOC_RUNNING\n", ioc->name, __func__));
5205 _scsih_remove_unresponding_devices(ioc);
5206 break;
Eric Moore635374e2009-03-09 01:21:12 -06005207 }
5208}
5209
5210/**
5211 * _firmware_event_work - delayed task for processing firmware events
5212 * @ioc: per adapter object
5213 * @work: equal to the fw_event_work object
5214 * Context: user.
5215 *
5216 * Return nothing.
5217 */
5218static void
5219_firmware_event_work(struct work_struct *work)
5220{
5221 struct fw_event_work *fw_event = container_of(work,
Eric Moore6f92a7a2009-04-21 15:43:33 -06005222 struct fw_event_work, work);
Eric Moore635374e2009-03-09 01:21:12 -06005223 unsigned long flags;
5224 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5225
Eric Moore635374e2009-03-09 01:21:12 -06005226 /* the queue is being flushed so ignore this event */
5227 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5228 if (ioc->fw_events_off || ioc->remove_host) {
5229 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5230 _scsih_fw_event_free(ioc, fw_event);
5231 return;
5232 }
5233 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5234
Eric Moore635374e2009-03-09 01:21:12 -06005235 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06005236 _scsih_fw_event_requeue(ioc, fw_event, 1000);
5237 return;
5238 }
Eric Moore635374e2009-03-09 01:21:12 -06005239
5240 switch (fw_event->event) {
5241 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305242 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005243 break;
5244 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305245 _scsih_sas_device_status_change_event(ioc,
5246 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005247 break;
5248 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305249 _scsih_sas_discovery_event(ioc,
5250 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005251 break;
5252 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305253 _scsih_sas_broadcast_primative_event(ioc,
5254 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005255 break;
5256 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5257 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305258 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005259 break;
5260 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305261 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005262 break;
5263 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305264 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005265 break;
5266 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305267 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005268 break;
5269 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305270 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005271 break;
5272 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305273 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005274 break;
5275 }
5276 _scsih_fw_event_free(ioc, fw_event);
5277}
5278
5279/**
5280 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5281 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305282 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06005283 * @reply: reply message frame(lower 32bit addr)
5284 * Context: interrupt.
5285 *
5286 * This function merely adds a new work task into ioc->firmware_event_thread.
5287 * The tasks are worked from _firmware_event_work in user context.
5288 *
5289 * Return nothing.
5290 */
5291void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305292mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
5293 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06005294{
5295 struct fw_event_work *fw_event;
5296 Mpi2EventNotificationReply_t *mpi_reply;
5297 unsigned long flags;
5298 u16 event;
5299
5300 /* events turned off due to host reset or driver unloading */
5301 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5302 if (ioc->fw_events_off || ioc->remove_host) {
5303 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5304 return;
5305 }
5306 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5307
5308 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
5309 event = le16_to_cpu(mpi_reply->Event);
5310
5311 switch (event) {
5312 /* handle these */
5313 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
5314 {
5315 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
5316 (Mpi2EventDataSasBroadcastPrimitive_t *)
5317 mpi_reply->EventData;
5318
5319 if (baen_data->Primitive !=
5320 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
5321 ioc->broadcast_aen_busy)
5322 return;
5323 ioc->broadcast_aen_busy = 1;
5324 break;
5325 }
5326
5327 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
5328 _scsih_check_topo_delete_events(ioc,
5329 (Mpi2EventDataSasTopologyChangeList_t *)
5330 mpi_reply->EventData);
5331 break;
5332
5333 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
5334 case MPI2_EVENT_IR_OPERATION_STATUS:
5335 case MPI2_EVENT_SAS_DISCOVERY:
5336 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5337 case MPI2_EVENT_IR_VOLUME:
5338 case MPI2_EVENT_IR_PHYSICAL_DISK:
5339 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
5340 case MPI2_EVENT_TASK_SET_FULL:
5341 break;
5342
5343 default: /* ignore the rest */
5344 return;
5345 }
5346
5347 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
5348 if (!fw_event) {
5349 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5350 ioc->name, __FILE__, __LINE__, __func__);
5351 return;
5352 }
5353 fw_event->event_data =
5354 kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
5355 if (!fw_event->event_data) {
5356 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5357 ioc->name, __FILE__, __LINE__, __func__);
5358 kfree(fw_event);
5359 return;
5360 }
5361
5362 memcpy(fw_event->event_data, mpi_reply->EventData,
5363 mpi_reply->EventDataLength*4);
5364 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305365 fw_event->VF_ID = mpi_reply->VF_ID;
5366 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06005367 fw_event->event = event;
5368 _scsih_fw_event_add(ioc, fw_event);
5369}
5370
5371/* shost template */
5372static struct scsi_host_template scsih_driver_template = {
5373 .module = THIS_MODULE,
5374 .name = "Fusion MPT SAS Host",
5375 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06005376 .queuecommand = _scsih_qcmd,
5377 .target_alloc = _scsih_target_alloc,
5378 .slave_alloc = _scsih_slave_alloc,
5379 .slave_configure = _scsih_slave_configure,
5380 .target_destroy = _scsih_target_destroy,
5381 .slave_destroy = _scsih_slave_destroy,
5382 .change_queue_depth = _scsih_change_queue_depth,
5383 .change_queue_type = _scsih_change_queue_type,
5384 .eh_abort_handler = _scsih_abort,
5385 .eh_device_reset_handler = _scsih_dev_reset,
5386 .eh_target_reset_handler = _scsih_target_reset,
5387 .eh_host_reset_handler = _scsih_host_reset,
5388 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06005389 .can_queue = 1,
5390 .this_id = -1,
5391 .sg_tablesize = MPT2SAS_SG_DEPTH,
5392 .max_sectors = 8192,
5393 .cmd_per_lun = 7,
5394 .use_clustering = ENABLE_CLUSTERING,
5395 .shost_attrs = mpt2sas_host_attrs,
5396 .sdev_attrs = mpt2sas_dev_attrs,
5397};
5398
5399/**
5400 * _scsih_expander_node_remove - removing expander device from list.
5401 * @ioc: per adapter object
5402 * @sas_expander: the sas_device object
5403 * Context: Calling function should acquire ioc->sas_node_lock.
5404 *
5405 * Removing object and freeing associated memory from the
5406 * ioc->sas_expander_list.
5407 *
5408 * Return nothing.
5409 */
5410static void
5411_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
5412 struct _sas_node *sas_expander)
5413{
5414 struct _sas_port *mpt2sas_port;
5415 struct _sas_device *sas_device;
5416 struct _sas_node *expander_sibling;
5417 unsigned long flags;
5418
5419 if (!sas_expander)
5420 return;
5421
5422 /* remove sibling ports attached to this expander */
5423 retry_device_search:
5424 list_for_each_entry(mpt2sas_port,
5425 &sas_expander->sas_port_list, port_list) {
5426 if (mpt2sas_port->remote_identify.device_type ==
5427 SAS_END_DEVICE) {
5428 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5429 sas_device =
5430 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5431 mpt2sas_port->remote_identify.sas_address);
5432 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5433 if (!sas_device)
5434 continue;
5435 _scsih_remove_device(ioc, sas_device->handle);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305436 if (ioc->shost_recovery)
5437 return;
Eric Moore635374e2009-03-09 01:21:12 -06005438 goto retry_device_search;
5439 }
5440 }
5441
5442 retry_expander_search:
5443 list_for_each_entry(mpt2sas_port,
5444 &sas_expander->sas_port_list, port_list) {
5445
5446 if (mpt2sas_port->remote_identify.device_type ==
5447 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
5448 mpt2sas_port->remote_identify.device_type ==
5449 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
5450
5451 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5452 expander_sibling =
5453 mpt2sas_scsih_expander_find_by_sas_address(
5454 ioc, mpt2sas_port->remote_identify.sas_address);
5455 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5456 if (!expander_sibling)
5457 continue;
5458 _scsih_expander_remove(ioc, expander_sibling->handle);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305459 if (ioc->shost_recovery)
5460 return;
Eric Moore635374e2009-03-09 01:21:12 -06005461 goto retry_expander_search;
5462 }
5463 }
5464
5465 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
5466 sas_expander->parent_handle);
5467
5468 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
5469 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
5470 sas_expander->handle, (unsigned long long)
5471 sas_expander->sas_address);
5472
5473 list_del(&sas_expander->list);
5474 kfree(sas_expander->phy);
5475 kfree(sas_expander);
5476}
5477
5478/**
Eric Moored5d135b2009-05-18 13:02:08 -06005479 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06005480 * @pdev: PCI device struct
5481 *
5482 * Return nothing.
5483 */
5484static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06005485_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06005486{
5487 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5488 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5489 struct _sas_port *mpt2sas_port;
5490 struct _sas_device *sas_device;
5491 struct _sas_node *expander_sibling;
5492 struct workqueue_struct *wq;
5493 unsigned long flags;
5494
5495 ioc->remove_host = 1;
5496 _scsih_fw_event_off(ioc);
5497
5498 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5499 wq = ioc->firmware_event_thread;
5500 ioc->firmware_event_thread = NULL;
5501 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5502 if (wq)
5503 destroy_workqueue(wq);
5504
5505 /* free ports attached to the sas_host */
5506 retry_again:
5507 list_for_each_entry(mpt2sas_port,
5508 &ioc->sas_hba.sas_port_list, port_list) {
5509 if (mpt2sas_port->remote_identify.device_type ==
5510 SAS_END_DEVICE) {
5511 sas_device =
5512 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5513 mpt2sas_port->remote_identify.sas_address);
5514 if (sas_device) {
5515 _scsih_remove_device(ioc, sas_device->handle);
5516 goto retry_again;
5517 }
5518 } else {
5519 expander_sibling =
5520 mpt2sas_scsih_expander_find_by_sas_address(ioc,
5521 mpt2sas_port->remote_identify.sas_address);
5522 if (expander_sibling) {
5523 _scsih_expander_remove(ioc,
5524 expander_sibling->handle);
5525 goto retry_again;
5526 }
5527 }
5528 }
5529
5530 /* free phys attached to the sas_host */
5531 if (ioc->sas_hba.num_phys) {
5532 kfree(ioc->sas_hba.phy);
5533 ioc->sas_hba.phy = NULL;
5534 ioc->sas_hba.num_phys = 0;
5535 }
5536
5537 sas_remove_host(shost);
5538 mpt2sas_base_detach(ioc);
5539 list_del(&ioc->list);
5540 scsi_remove_host(shost);
5541 scsi_host_put(shost);
5542}
5543
5544/**
5545 * _scsih_probe_boot_devices - reports 1st device
5546 * @ioc: per adapter object
5547 *
5548 * If specified in bios page 2, this routine reports the 1st
5549 * device scsi-ml or sas transport for persistent boot device
5550 * purposes. Please refer to function _scsih_determine_boot_device()
5551 */
5552static void
5553_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
5554{
5555 u8 is_raid;
5556 void *device;
5557 struct _sas_device *sas_device;
5558 struct _raid_device *raid_device;
5559 u16 handle, parent_handle;
5560 u64 sas_address;
5561 unsigned long flags;
5562 int rc;
5563
5564 device = NULL;
5565 if (ioc->req_boot_device.device) {
5566 device = ioc->req_boot_device.device;
5567 is_raid = ioc->req_boot_device.is_raid;
5568 } else if (ioc->req_alt_boot_device.device) {
5569 device = ioc->req_alt_boot_device.device;
5570 is_raid = ioc->req_alt_boot_device.is_raid;
5571 } else if (ioc->current_boot_device.device) {
5572 device = ioc->current_boot_device.device;
5573 is_raid = ioc->current_boot_device.is_raid;
5574 }
5575
5576 if (!device)
5577 return;
5578
5579 if (is_raid) {
5580 raid_device = device;
5581 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5582 raid_device->id, 0);
5583 if (rc)
5584 _scsih_raid_device_remove(ioc, raid_device);
5585 } else {
5586 sas_device = device;
5587 handle = sas_device->handle;
5588 parent_handle = sas_device->parent_handle;
5589 sas_address = sas_device->sas_address;
5590 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5591 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5592 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5593 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
5594 sas_device->parent_handle)) {
5595 _scsih_sas_device_remove(ioc, sas_device);
5596 } else if (!sas_device->starget) {
5597 mpt2sas_transport_port_remove(ioc, sas_address,
5598 parent_handle);
5599 _scsih_sas_device_remove(ioc, sas_device);
5600 }
5601 }
5602}
5603
5604/**
5605 * _scsih_probe_raid - reporting raid volumes to scsi-ml
5606 * @ioc: per adapter object
5607 *
5608 * Called during initial loading of the driver.
5609 */
5610static void
5611_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
5612{
5613 struct _raid_device *raid_device, *raid_next;
5614 int rc;
5615
5616 list_for_each_entry_safe(raid_device, raid_next,
5617 &ioc->raid_device_list, list) {
5618 if (raid_device->starget)
5619 continue;
5620 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5621 raid_device->id, 0);
5622 if (rc)
5623 _scsih_raid_device_remove(ioc, raid_device);
5624 }
5625}
5626
5627/**
5628 * _scsih_probe_sas - reporting raid volumes to sas transport
5629 * @ioc: per adapter object
5630 *
5631 * Called during initial loading of the driver.
5632 */
5633static void
5634_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
5635{
5636 struct _sas_device *sas_device, *next;
5637 unsigned long flags;
5638 u16 handle, parent_handle;
5639 u64 sas_address;
5640
5641 /* SAS Device List */
5642 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
5643 list) {
5644 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5645 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5646 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5647
5648 handle = sas_device->handle;
5649 parent_handle = sas_device->parent_handle;
5650 sas_address = sas_device->sas_address;
5651 if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) {
5652 _scsih_sas_device_remove(ioc, sas_device);
5653 } else if (!sas_device->starget) {
5654 mpt2sas_transport_port_remove(ioc, sas_address,
5655 parent_handle);
5656 _scsih_sas_device_remove(ioc, sas_device);
5657 }
5658 }
5659}
5660
5661/**
5662 * _scsih_probe_devices - probing for devices
5663 * @ioc: per adapter object
5664 *
5665 * Called during initial loading of the driver.
5666 */
5667static void
5668_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
5669{
5670 u16 volume_mapping_flags =
5671 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
5672 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
5673
5674 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
5675 return; /* return when IOC doesn't support initiator mode */
5676
5677 _scsih_probe_boot_devices(ioc);
5678
5679 if (ioc->ir_firmware) {
5680 if ((volume_mapping_flags &
5681 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
5682 _scsih_probe_sas(ioc);
5683 _scsih_probe_raid(ioc);
5684 } else {
5685 _scsih_probe_raid(ioc);
5686 _scsih_probe_sas(ioc);
5687 }
5688 } else
5689 _scsih_probe_sas(ioc);
5690}
5691
5692/**
Eric Moored5d135b2009-05-18 13:02:08 -06005693 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06005694 * @pdev: PCI device struct
5695 * @id: pci device id
5696 *
5697 * Returns 0 success, anything else error.
5698 */
5699static int
Eric Moored5d135b2009-05-18 13:02:08 -06005700_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06005701{
5702 struct MPT2SAS_ADAPTER *ioc;
5703 struct Scsi_Host *shost;
5704
5705 shost = scsi_host_alloc(&scsih_driver_template,
5706 sizeof(struct MPT2SAS_ADAPTER));
5707 if (!shost)
5708 return -ENODEV;
5709
5710 /* init local params */
5711 ioc = shost_priv(shost);
5712 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
5713 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06005714 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06005715 ioc->shost = shost;
5716 ioc->id = mpt_ids++;
5717 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
5718 ioc->pdev = pdev;
5719 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
5720 ioc->tm_cb_idx = tm_cb_idx;
5721 ioc->ctl_cb_idx = ctl_cb_idx;
5722 ioc->base_cb_idx = base_cb_idx;
5723 ioc->transport_cb_idx = transport_cb_idx;
5724 ioc->config_cb_idx = config_cb_idx;
5725 ioc->logging_level = logging_level;
5726 /* misc semaphores and spin locks */
5727 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
5728 spin_lock_init(&ioc->scsi_lookup_lock);
5729 spin_lock_init(&ioc->sas_device_lock);
5730 spin_lock_init(&ioc->sas_node_lock);
5731 spin_lock_init(&ioc->fw_event_lock);
5732 spin_lock_init(&ioc->raid_device_lock);
5733
5734 INIT_LIST_HEAD(&ioc->sas_device_list);
5735 INIT_LIST_HEAD(&ioc->sas_device_init_list);
5736 INIT_LIST_HEAD(&ioc->sas_expander_list);
5737 INIT_LIST_HEAD(&ioc->fw_event_list);
5738 INIT_LIST_HEAD(&ioc->raid_device_list);
5739 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
5740
5741 /* init shost parameters */
5742 shost->max_cmd_len = 16;
5743 shost->max_lun = max_lun;
5744 shost->transportt = mpt2sas_transport_template;
5745 shost->unique_id = ioc->id;
5746
5747 if ((scsi_add_host(shost, &pdev->dev))) {
5748 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5749 ioc->name, __FILE__, __LINE__, __func__);
5750 list_del(&ioc->list);
5751 goto out_add_shost_fail;
5752 }
5753
Eric Moore3c621b32009-05-18 12:59:41 -06005754 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
5755 | SHOST_DIF_TYPE3_PROTECTION);
5756
Eric Moore635374e2009-03-09 01:21:12 -06005757 /* event thread */
5758 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
5759 "fw_event%d", ioc->id);
5760 ioc->firmware_event_thread = create_singlethread_workqueue(
5761 ioc->firmware_event_name);
5762 if (!ioc->firmware_event_thread) {
5763 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5764 ioc->name, __FILE__, __LINE__, __func__);
5765 goto out_thread_fail;
5766 }
5767
5768 ioc->wait_for_port_enable_to_complete = 1;
5769 if ((mpt2sas_base_attach(ioc))) {
5770 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5771 ioc->name, __FILE__, __LINE__, __func__);
5772 goto out_attach_fail;
5773 }
5774
5775 ioc->wait_for_port_enable_to_complete = 0;
5776 _scsih_probe_devices(ioc);
5777 return 0;
5778
5779 out_attach_fail:
5780 destroy_workqueue(ioc->firmware_event_thread);
5781 out_thread_fail:
5782 list_del(&ioc->list);
5783 scsi_remove_host(shost);
5784 out_add_shost_fail:
5785 return -ENODEV;
5786}
5787
5788#ifdef CONFIG_PM
5789/**
Eric Moored5d135b2009-05-18 13:02:08 -06005790 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06005791 * @pdev: PCI device struct
5792 * @state: PM state change to (usually PCI_D3)
5793 *
5794 * Returns 0 success, anything else error.
5795 */
5796static int
Eric Moored5d135b2009-05-18 13:02:08 -06005797_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06005798{
5799 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5800 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5801 u32 device_state;
5802
Kashyap, Desaie4750c92009-08-07 19:37:59 +05305803 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005804 flush_scheduled_work();
5805 scsi_block_requests(shost);
5806 device_state = pci_choose_state(pdev, state);
5807 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
5808 "operating state [D%d]\n", ioc->name, pdev,
5809 pci_name(pdev), device_state);
5810
5811 mpt2sas_base_free_resources(ioc);
5812 pci_save_state(pdev);
5813 pci_disable_device(pdev);
5814 pci_set_power_state(pdev, device_state);
5815 return 0;
5816}
5817
5818/**
Eric Moored5d135b2009-05-18 13:02:08 -06005819 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06005820 * @pdev: PCI device struct
5821 *
5822 * Returns 0 success, anything else error.
5823 */
5824static int
Eric Moored5d135b2009-05-18 13:02:08 -06005825_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06005826{
5827 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5828 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5829 u32 device_state = pdev->current_state;
5830 int r;
5831
5832 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
5833 "operating state [D%d]\n", ioc->name, pdev,
5834 pci_name(pdev), device_state);
5835
5836 pci_set_power_state(pdev, PCI_D0);
5837 pci_enable_wake(pdev, PCI_D0, 0);
5838 pci_restore_state(pdev);
5839 ioc->pdev = pdev;
5840 r = mpt2sas_base_map_resources(ioc);
5841 if (r)
5842 return r;
5843
5844 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
5845 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05305846 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005847 return 0;
5848}
5849#endif /* CONFIG_PM */
5850
5851
5852static struct pci_driver scsih_driver = {
5853 .name = MPT2SAS_DRIVER_NAME,
5854 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06005855 .probe = _scsih_probe,
5856 .remove = __devexit_p(_scsih_remove),
Eric Moore635374e2009-03-09 01:21:12 -06005857#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06005858 .suspend = _scsih_suspend,
5859 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06005860#endif
5861};
5862
5863
5864/**
Eric Moored5d135b2009-05-18 13:02:08 -06005865 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06005866 *
5867 * Returns 0 success, anything else error.
5868 */
5869static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06005870_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06005871{
5872 int error;
5873
5874 mpt_ids = 0;
5875 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
5876 MPT2SAS_DRIVER_VERSION);
5877
5878 mpt2sas_transport_template =
5879 sas_attach_transport(&mpt2sas_transport_functions);
5880 if (!mpt2sas_transport_template)
5881 return -ENODEV;
5882
5883 mpt2sas_base_initialize_callback_handler();
5884
5885 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06005886 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06005887
5888 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06005889 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06005890
5891 /* base internal commands callback handler */
5892 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
5893
5894 /* transport internal commands callback handler */
5895 transport_cb_idx = mpt2sas_base_register_callback_handler(
5896 mpt2sas_transport_done);
5897
5898 /* configuration page API internal commands callback handler */
5899 config_cb_idx = mpt2sas_base_register_callback_handler(
5900 mpt2sas_config_done);
5901
5902 /* ctl module callback handler */
5903 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
5904
5905 mpt2sas_ctl_init();
5906
5907 error = pci_register_driver(&scsih_driver);
5908 if (error)
5909 sas_release_transport(mpt2sas_transport_template);
5910
5911 return error;
5912}
5913
5914/**
Eric Moored5d135b2009-05-18 13:02:08 -06005915 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06005916 *
5917 * Returns 0 success, anything else error.
5918 */
5919static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06005920_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06005921{
5922 printk(KERN_INFO "mpt2sas version %s unloading\n",
5923 MPT2SAS_DRIVER_VERSION);
5924
5925 pci_unregister_driver(&scsih_driver);
5926
5927 sas_release_transport(mpt2sas_transport_template);
5928 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
5929 mpt2sas_base_release_callback_handler(tm_cb_idx);
5930 mpt2sas_base_release_callback_handler(base_cb_idx);
5931 mpt2sas_base_release_callback_handler(transport_cb_idx);
5932 mpt2sas_base_release_callback_handler(config_cb_idx);
5933 mpt2sas_base_release_callback_handler(ctl_cb_idx);
5934
5935 mpt2sas_ctl_exit();
5936}
5937
Eric Moored5d135b2009-05-18 13:02:08 -06005938module_init(_scsih_init);
5939module_exit(_scsih_exit);