blob: 9ec50729d535a5e3ff3533dafaf2eacf9061f032 [file] [log] [blame]
Eric Moore635374e2009-03-09 01:21:12 -06001/*
2 * Scsi Host Layer for MPT (Message Passing Technology) based controllers
3 *
4 * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
Kashyap, Desai19d3ebe2009-09-14 11:01:36 +05305 * Copyright (C) 2007-2009 LSI Corporation
Eric Moore635374e2009-03-09 01:21:12 -06006 * (mailto:DL-MPTFusionLinux@lsi.com)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * NO WARRANTY
19 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
20 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
21 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
22 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
23 * solely responsible for determining the appropriateness of using and
24 * distributing the Program and assumes all risks associated with its
25 * exercise of rights under this Agreement, including but not limited to
26 * the risks and costs of program errors, damage to or loss of data,
27 * programs or equipment, and unavailability or interruption of operations.
28
29 * DISCLAIMER OF LIABILITY
30 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
31 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
36 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
37
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
41 * USA.
42 */
43
44#include <linux/version.h>
45#include <linux/module.h>
46#include <linux/kernel.h>
47#include <linux/init.h>
48#include <linux/errno.h>
49#include <linux/blkdev.h>
50#include <linux/sched.h>
51#include <linux/workqueue.h>
52#include <linux/delay.h>
53#include <linux/pci.h>
54#include <linux/interrupt.h>
55
56#include "mpt2sas_base.h"
57
58MODULE_AUTHOR(MPT2SAS_AUTHOR);
59MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
60MODULE_LICENSE("GPL");
61MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
62
63#define RAID_CHANNEL 1
64
65/* forward proto's */
66static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
67 struct _sas_node *sas_expander);
68static void _firmware_event_work(struct work_struct *work);
69
70/* global parameters */
Eric Mooreba33fad2009-03-15 21:37:18 -060071LIST_HEAD(mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -060072
73/* local parameters */
Eric Moore635374e2009-03-09 01:21:12 -060074static u8 scsi_io_cb_idx = -1;
75static u8 tm_cb_idx = -1;
76static u8 ctl_cb_idx = -1;
77static u8 base_cb_idx = -1;
78static u8 transport_cb_idx = -1;
79static u8 config_cb_idx = -1;
80static int mpt_ids;
81
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053082static u8 tm_tr_cb_idx = -1 ;
83static u8 tm_sas_control_cb_idx = -1;
84
Eric Moore635374e2009-03-09 01:21:12 -060085/* command line options */
Eric Mooreba33fad2009-03-15 21:37:18 -060086static u32 logging_level;
Eric Moore635374e2009-03-09 01:21:12 -060087MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
88 "(default=0)");
89
90/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
91#define MPT2SAS_MAX_LUN (16895)
92static int max_lun = MPT2SAS_MAX_LUN;
93module_param(max_lun, int, 0);
94MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
95
96/**
97 * struct sense_info - common structure for obtaining sense keys
98 * @skey: sense key
99 * @asc: additional sense code
100 * @ascq: additional sense code qualifier
101 */
102struct sense_info {
103 u8 skey;
104 u8 asc;
105 u8 ascq;
106};
107
108
Eric Moore635374e2009-03-09 01:21:12 -0600109/**
110 * struct fw_event_work - firmware event struct
111 * @list: link list framework
112 * @work: work object (ioc->fault_reset_work_q)
113 * @ioc: per adapter object
114 * @VF_ID: virtual function id
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530115 * @VP_ID: virtual port id
Eric Moore635374e2009-03-09 01:21:12 -0600116 * @host_reset_handling: handling events during host reset
117 * @ignore: flag meaning this event has been marked to ignore
118 * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
119 * @event_data: reply event data payload follows
120 *
121 * This object stored on ioc->fw_event_list.
122 */
123struct fw_event_work {
124 struct list_head list;
Eric Moore6f92a7a2009-04-21 15:43:33 -0600125 struct work_struct work;
Eric Moore635374e2009-03-09 01:21:12 -0600126 struct MPT2SAS_ADAPTER *ioc;
127 u8 VF_ID;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530128 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600129 u8 host_reset_handling;
130 u8 ignore;
131 u16 event;
132 void *event_data;
133};
134
135/**
136 * struct _scsi_io_transfer - scsi io transfer
137 * @handle: sas device handle (assigned by firmware)
138 * @is_raid: flag set for hidden raid components
139 * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
140 * @data_length: data transfer length
141 * @data_dma: dma pointer to data
142 * @sense: sense data
143 * @lun: lun number
144 * @cdb_length: cdb length
145 * @cdb: cdb contents
Eric Moore635374e2009-03-09 01:21:12 -0600146 * @timeout: timeout for this command
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530147 * @VF_ID: virtual function id
148 * @VP_ID: virtual port id
149 * @valid_reply: flag set for reply message
Eric Moore635374e2009-03-09 01:21:12 -0600150 * @sense_length: sense length
151 * @ioc_status: ioc status
152 * @scsi_state: scsi state
153 * @scsi_status: scsi staus
154 * @log_info: log information
155 * @transfer_length: data length transfer when there is a reply message
156 *
157 * Used for sending internal scsi commands to devices within this module.
158 * Refer to _scsi_send_scsi_io().
159 */
160struct _scsi_io_transfer {
161 u16 handle;
162 u8 is_raid;
163 enum dma_data_direction dir;
164 u32 data_length;
165 dma_addr_t data_dma;
166 u8 sense[SCSI_SENSE_BUFFERSIZE];
167 u32 lun;
168 u8 cdb_length;
169 u8 cdb[32];
170 u8 timeout;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530171 u8 VF_ID;
172 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600173 u8 valid_reply;
174 /* the following bits are only valid when 'valid_reply = 1' */
175 u32 sense_length;
176 u16 ioc_status;
177 u8 scsi_state;
178 u8 scsi_status;
179 u32 log_info;
180 u32 transfer_length;
181};
182
183/*
184 * The pci device ids are defined in mpi/mpi2_cnfg.h.
185 */
186static struct pci_device_id scsih_pci_table[] = {
187 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
188 PCI_ANY_ID, PCI_ANY_ID },
189 /* Falcon ~ 2008*/
190 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
191 PCI_ANY_ID, PCI_ANY_ID },
192 /* Liberator ~ 2108 */
193 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
194 PCI_ANY_ID, PCI_ANY_ID },
195 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
196 PCI_ANY_ID, PCI_ANY_ID },
197 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
198 PCI_ANY_ID, PCI_ANY_ID },
199 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
200 PCI_ANY_ID, PCI_ANY_ID },
201 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
202 PCI_ANY_ID, PCI_ANY_ID },
203 {0} /* Terminating entry */
204};
205MODULE_DEVICE_TABLE(pci, scsih_pci_table);
206
207/**
Eric Moored5d135b2009-05-18 13:02:08 -0600208 * _scsih_set_debug_level - global setting of ioc->logging_level.
Eric Moore635374e2009-03-09 01:21:12 -0600209 *
210 * Note: The logging levels are defined in mpt2sas_debug.h.
211 */
212static int
Eric Moored5d135b2009-05-18 13:02:08 -0600213_scsih_set_debug_level(const char *val, struct kernel_param *kp)
Eric Moore635374e2009-03-09 01:21:12 -0600214{
215 int ret = param_set_int(val, kp);
216 struct MPT2SAS_ADAPTER *ioc;
217
218 if (ret)
219 return ret;
220
221 printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
Eric Mooreba33fad2009-03-15 21:37:18 -0600222 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
Eric Moore635374e2009-03-09 01:21:12 -0600223 ioc->logging_level = logging_level;
224 return 0;
225}
Eric Moored5d135b2009-05-18 13:02:08 -0600226module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
Eric Moore635374e2009-03-09 01:21:12 -0600227 &logging_level, 0644);
228
229/**
230 * _scsih_srch_boot_sas_address - search based on sas_address
231 * @sas_address: sas address
232 * @boot_device: boot device object from bios page 2
233 *
234 * Returns 1 when there's a match, 0 means no match.
235 */
236static inline int
237_scsih_srch_boot_sas_address(u64 sas_address,
238 Mpi2BootDeviceSasWwid_t *boot_device)
239{
240 return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
241}
242
243/**
244 * _scsih_srch_boot_device_name - search based on device name
245 * @device_name: device name specified in INDENTIFY fram
246 * @boot_device: boot device object from bios page 2
247 *
248 * Returns 1 when there's a match, 0 means no match.
249 */
250static inline int
251_scsih_srch_boot_device_name(u64 device_name,
252 Mpi2BootDeviceDeviceName_t *boot_device)
253{
254 return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
255}
256
257/**
258 * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
259 * @enclosure_logical_id: enclosure logical id
260 * @slot_number: slot number
261 * @boot_device: boot device object from bios page 2
262 *
263 * Returns 1 when there's a match, 0 means no match.
264 */
265static inline int
266_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
267 Mpi2BootDeviceEnclosureSlot_t *boot_device)
268{
269 return (enclosure_logical_id == le64_to_cpu(boot_device->
270 EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
271 SlotNumber)) ? 1 : 0;
272}
273
274/**
275 * _scsih_is_boot_device - search for matching boot device.
276 * @sas_address: sas address
277 * @device_name: device name specified in INDENTIFY fram
278 * @enclosure_logical_id: enclosure logical id
279 * @slot_number: slot number
280 * @form: specifies boot device form
281 * @boot_device: boot device object from bios page 2
282 *
283 * Returns 1 when there's a match, 0 means no match.
284 */
285static int
286_scsih_is_boot_device(u64 sas_address, u64 device_name,
287 u64 enclosure_logical_id, u16 slot, u8 form,
288 Mpi2BiosPage2BootDevice_t *boot_device)
289{
290 int rc = 0;
291
292 switch (form) {
293 case MPI2_BIOSPAGE2_FORM_SAS_WWID:
294 if (!sas_address)
295 break;
296 rc = _scsih_srch_boot_sas_address(
297 sas_address, &boot_device->SasWwid);
298 break;
299 case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
300 if (!enclosure_logical_id)
301 break;
302 rc = _scsih_srch_boot_encl_slot(
303 enclosure_logical_id,
304 slot, &boot_device->EnclosureSlot);
305 break;
306 case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
307 if (!device_name)
308 break;
309 rc = _scsih_srch_boot_device_name(
310 device_name, &boot_device->DeviceName);
311 break;
312 case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
313 break;
314 }
315
316 return rc;
317}
318
319/**
320 * _scsih_determine_boot_device - determine boot device.
321 * @ioc: per adapter object
322 * @device: either sas_device or raid_device object
323 * @is_raid: [flag] 1 = raid object, 0 = sas object
324 *
325 * Determines whether this device should be first reported device to
326 * to scsi-ml or sas transport, this purpose is for persistant boot device.
327 * There are primary, alternate, and current entries in bios page 2. The order
328 * priority is primary, alternate, then current. This routine saves
329 * the corresponding device object and is_raid flag in the ioc object.
330 * The saved data to be used later in _scsih_probe_boot_devices().
331 */
332static void
333_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
334 void *device, u8 is_raid)
335{
336 struct _sas_device *sas_device;
337 struct _raid_device *raid_device;
338 u64 sas_address;
339 u64 device_name;
340 u64 enclosure_logical_id;
341 u16 slot;
342
343 /* only process this function when driver loads */
344 if (!ioc->wait_for_port_enable_to_complete)
345 return;
346
347 if (!is_raid) {
348 sas_device = device;
349 sas_address = sas_device->sas_address;
350 device_name = sas_device->device_name;
351 enclosure_logical_id = sas_device->enclosure_logical_id;
352 slot = sas_device->slot;
353 } else {
354 raid_device = device;
355 sas_address = raid_device->wwid;
356 device_name = 0;
357 enclosure_logical_id = 0;
358 slot = 0;
359 }
360
361 if (!ioc->req_boot_device.device) {
362 if (_scsih_is_boot_device(sas_address, device_name,
363 enclosure_logical_id, slot,
364 (ioc->bios_pg2.ReqBootDeviceForm &
365 MPI2_BIOSPAGE2_FORM_MASK),
366 &ioc->bios_pg2.RequestedBootDevice)) {
367 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
368 "%s: req_boot_device(0x%016llx)\n",
369 ioc->name, __func__,
370 (unsigned long long)sas_address));
371 ioc->req_boot_device.device = device;
372 ioc->req_boot_device.is_raid = is_raid;
373 }
374 }
375
376 if (!ioc->req_alt_boot_device.device) {
377 if (_scsih_is_boot_device(sas_address, device_name,
378 enclosure_logical_id, slot,
379 (ioc->bios_pg2.ReqAltBootDeviceForm &
380 MPI2_BIOSPAGE2_FORM_MASK),
381 &ioc->bios_pg2.RequestedAltBootDevice)) {
382 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
383 "%s: req_alt_boot_device(0x%016llx)\n",
384 ioc->name, __func__,
385 (unsigned long long)sas_address));
386 ioc->req_alt_boot_device.device = device;
387 ioc->req_alt_boot_device.is_raid = is_raid;
388 }
389 }
390
391 if (!ioc->current_boot_device.device) {
392 if (_scsih_is_boot_device(sas_address, device_name,
393 enclosure_logical_id, slot,
394 (ioc->bios_pg2.CurrentBootDeviceForm &
395 MPI2_BIOSPAGE2_FORM_MASK),
396 &ioc->bios_pg2.CurrentBootDevice)) {
397 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
398 "%s: current_boot_device(0x%016llx)\n",
399 ioc->name, __func__,
400 (unsigned long long)sas_address));
401 ioc->current_boot_device.device = device;
402 ioc->current_boot_device.is_raid = is_raid;
403 }
404 }
405}
406
407/**
408 * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
409 * @ioc: per adapter object
410 * @sas_address: sas address
411 * Context: Calling function should acquire ioc->sas_device_lock
412 *
413 * This searches for sas_device based on sas_address, then return sas_device
414 * object.
415 */
416struct _sas_device *
417mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
418 u64 sas_address)
419{
420 struct _sas_device *sas_device, *r;
421
422 r = NULL;
423 /* check the sas_device_init_list */
424 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
425 list) {
426 if (sas_device->sas_address != sas_address)
427 continue;
428 r = sas_device;
429 goto out;
430 }
431
432 /* then check the sas_device_list */
433 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
434 if (sas_device->sas_address != sas_address)
435 continue;
436 r = sas_device;
437 goto out;
438 }
439 out:
440 return r;
441}
442
443/**
444 * _scsih_sas_device_find_by_handle - sas device search
445 * @ioc: per adapter object
446 * @handle: sas device handle (assigned by firmware)
447 * Context: Calling function should acquire ioc->sas_device_lock
448 *
449 * This searches for sas_device based on sas_address, then return sas_device
450 * object.
451 */
452static struct _sas_device *
453_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
454{
455 struct _sas_device *sas_device, *r;
456
457 r = NULL;
458 if (ioc->wait_for_port_enable_to_complete) {
459 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
460 list) {
461 if (sas_device->handle != handle)
462 continue;
463 r = sas_device;
464 goto out;
465 }
466 } else {
467 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
468 if (sas_device->handle != handle)
469 continue;
470 r = sas_device;
471 goto out;
472 }
473 }
474
475 out:
476 return r;
477}
478
479/**
480 * _scsih_sas_device_remove - remove sas_device from list.
481 * @ioc: per adapter object
482 * @sas_device: the sas_device object
483 * Context: This function will acquire ioc->sas_device_lock.
484 *
485 * Removing object and freeing associated memory from the ioc->sas_device_list.
486 */
487static void
488_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
489 struct _sas_device *sas_device)
490{
491 unsigned long flags;
492
493 spin_lock_irqsave(&ioc->sas_device_lock, flags);
494 list_del(&sas_device->list);
495 memset(sas_device, 0, sizeof(struct _sas_device));
496 kfree(sas_device);
497 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
498}
499
500/**
501 * _scsih_sas_device_add - insert sas_device to the list.
502 * @ioc: per adapter object
503 * @sas_device: the sas_device object
504 * Context: This function will acquire ioc->sas_device_lock.
505 *
506 * Adding new object to the ioc->sas_device_list.
507 */
508static void
509_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
510 struct _sas_device *sas_device)
511{
512 unsigned long flags;
513 u16 handle, parent_handle;
514 u64 sas_address;
515
516 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
517 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
518 sas_device->handle, (unsigned long long)sas_device->sas_address));
519
520 spin_lock_irqsave(&ioc->sas_device_lock, flags);
521 list_add_tail(&sas_device->list, &ioc->sas_device_list);
522 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
523
524 handle = sas_device->handle;
525 parent_handle = sas_device->parent_handle;
526 sas_address = sas_device->sas_address;
Eric Moore8901cbb2009-04-21 15:41:32 -0600527 if (!mpt2sas_transport_port_add(ioc, handle, parent_handle))
Eric Moore635374e2009-03-09 01:21:12 -0600528 _scsih_sas_device_remove(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -0600529}
530
531/**
532 * _scsih_sas_device_init_add - insert sas_device to the list.
533 * @ioc: per adapter object
534 * @sas_device: the sas_device object
535 * Context: This function will acquire ioc->sas_device_lock.
536 *
537 * Adding new object at driver load time to the ioc->sas_device_init_list.
538 */
539static void
540_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
541 struct _sas_device *sas_device)
542{
543 unsigned long flags;
544
545 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
546 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
547 sas_device->handle, (unsigned long long)sas_device->sas_address));
548
549 spin_lock_irqsave(&ioc->sas_device_lock, flags);
550 list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
551 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
552 _scsih_determine_boot_device(ioc, sas_device, 0);
553}
554
555/**
556 * mpt2sas_scsih_expander_find_by_handle - expander device search
557 * @ioc: per adapter object
558 * @handle: expander handle (assigned by firmware)
559 * Context: Calling function should acquire ioc->sas_device_lock
560 *
561 * This searches for expander device based on handle, then returns the
562 * sas_node object.
563 */
564struct _sas_node *
565mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
566{
567 struct _sas_node *sas_expander, *r;
568
569 r = NULL;
570 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
571 if (sas_expander->handle != handle)
572 continue;
573 r = sas_expander;
574 goto out;
575 }
576 out:
577 return r;
578}
579
580/**
581 * _scsih_raid_device_find_by_id - raid device search
582 * @ioc: per adapter object
583 * @id: sas device target id
584 * @channel: sas device channel
585 * Context: Calling function should acquire ioc->raid_device_lock
586 *
587 * This searches for raid_device based on target id, then return raid_device
588 * object.
589 */
590static struct _raid_device *
591_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
592{
593 struct _raid_device *raid_device, *r;
594
595 r = NULL;
596 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
597 if (raid_device->id == id && raid_device->channel == channel) {
598 r = raid_device;
599 goto out;
600 }
601 }
602
603 out:
604 return r;
605}
606
607/**
608 * _scsih_raid_device_find_by_handle - raid device search
609 * @ioc: per adapter object
610 * @handle: sas device handle (assigned by firmware)
611 * Context: Calling function should acquire ioc->raid_device_lock
612 *
613 * This searches for raid_device based on handle, then return raid_device
614 * object.
615 */
616static struct _raid_device *
617_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
618{
619 struct _raid_device *raid_device, *r;
620
621 r = NULL;
622 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
623 if (raid_device->handle != handle)
624 continue;
625 r = raid_device;
626 goto out;
627 }
628
629 out:
630 return r;
631}
632
633/**
634 * _scsih_raid_device_find_by_wwid - raid device search
635 * @ioc: per adapter object
636 * @handle: sas device handle (assigned by firmware)
637 * Context: Calling function should acquire ioc->raid_device_lock
638 *
639 * This searches for raid_device based on wwid, then return raid_device
640 * object.
641 */
642static struct _raid_device *
643_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
644{
645 struct _raid_device *raid_device, *r;
646
647 r = NULL;
648 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
649 if (raid_device->wwid != wwid)
650 continue;
651 r = raid_device;
652 goto out;
653 }
654
655 out:
656 return r;
657}
658
659/**
660 * _scsih_raid_device_add - add raid_device object
661 * @ioc: per adapter object
662 * @raid_device: raid_device object
663 *
664 * This is added to the raid_device_list link list.
665 */
666static void
667_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
668 struct _raid_device *raid_device)
669{
670 unsigned long flags;
671
672 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
673 "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
674 raid_device->handle, (unsigned long long)raid_device->wwid));
675
676 spin_lock_irqsave(&ioc->raid_device_lock, flags);
677 list_add_tail(&raid_device->list, &ioc->raid_device_list);
678 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
679}
680
681/**
682 * _scsih_raid_device_remove - delete raid_device object
683 * @ioc: per adapter object
684 * @raid_device: raid_device object
685 *
686 * This is removed from the raid_device_list link list.
687 */
688static void
689_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
690 struct _raid_device *raid_device)
691{
692 unsigned long flags;
693
694 spin_lock_irqsave(&ioc->raid_device_lock, flags);
695 list_del(&raid_device->list);
696 memset(raid_device, 0, sizeof(struct _raid_device));
697 kfree(raid_device);
698 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
699}
700
701/**
702 * mpt2sas_scsih_expander_find_by_sas_address - expander device search
703 * @ioc: per adapter object
704 * @sas_address: sas address
705 * Context: Calling function should acquire ioc->sas_node_lock.
706 *
707 * This searches for expander device based on sas_address, then returns the
708 * sas_node object.
709 */
710struct _sas_node *
711mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
712 u64 sas_address)
713{
714 struct _sas_node *sas_expander, *r;
715
716 r = NULL;
717 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
718 if (sas_expander->sas_address != sas_address)
719 continue;
720 r = sas_expander;
721 goto out;
722 }
723 out:
724 return r;
725}
726
727/**
728 * _scsih_expander_node_add - insert expander device to the list.
729 * @ioc: per adapter object
730 * @sas_expander: the sas_device object
731 * Context: This function will acquire ioc->sas_node_lock.
732 *
733 * Adding new object to the ioc->sas_expander_list.
734 *
735 * Return nothing.
736 */
737static void
738_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
739 struct _sas_node *sas_expander)
740{
741 unsigned long flags;
742
743 spin_lock_irqsave(&ioc->sas_node_lock, flags);
744 list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
745 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
746}
747
748/**
749 * _scsih_is_end_device - determines if device is an end device
750 * @device_info: bitfield providing information about the device.
751 * Context: none
752 *
753 * Returns 1 if end device.
754 */
755static int
756_scsih_is_end_device(u32 device_info)
757{
758 if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
759 ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
760 (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
761 (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
762 return 1;
763 else
764 return 0;
765}
766
767/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530768 * mptscsih_get_scsi_lookup - returns scmd entry
Eric Moore635374e2009-03-09 01:21:12 -0600769 * @ioc: per adapter object
770 * @smid: system request message index
Eric Moore635374e2009-03-09 01:21:12 -0600771 *
772 * Returns the smid stored scmd pointer.
773 */
774static struct scsi_cmnd *
775_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
776{
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530777 return ioc->scsi_lookup[smid - 1].scmd;
Eric Moore635374e2009-03-09 01:21:12 -0600778}
779
780/**
781 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
782 * @ioc: per adapter object
783 * @smid: system request message index
784 * @scmd: pointer to scsi command object
785 * Context: This function will acquire ioc->scsi_lookup_lock.
786 *
787 * This will search for a scmd pointer in the scsi_lookup array,
788 * returning the revelent smid. A returned value of zero means invalid.
789 */
790static u16
791_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
792 *scmd)
793{
794 u16 smid;
795 unsigned long flags;
796 int i;
797
798 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
799 smid = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530800 for (i = 0; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600801 if (ioc->scsi_lookup[i].scmd == scmd) {
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530802 smid = ioc->scsi_lookup[i].smid;
Eric Moore635374e2009-03-09 01:21:12 -0600803 goto out;
804 }
805 }
806 out:
807 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
808 return smid;
809}
810
811/**
812 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
813 * @ioc: per adapter object
814 * @id: target id
815 * @channel: channel
816 * Context: This function will acquire ioc->scsi_lookup_lock.
817 *
818 * This will search for a matching channel:id in the scsi_lookup array,
819 * returning 1 if found.
820 */
821static u8
822_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
823 int channel)
824{
825 u8 found;
826 unsigned long flags;
827 int i;
828
829 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
830 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530831 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600832 if (ioc->scsi_lookup[i].scmd &&
833 (ioc->scsi_lookup[i].scmd->device->id == id &&
834 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
835 found = 1;
836 goto out;
837 }
838 }
839 out:
840 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
841 return found;
842}
843
844/**
Eric Moore993e0da2009-05-18 13:00:45 -0600845 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
846 * @ioc: per adapter object
847 * @id: target id
848 * @lun: lun number
849 * @channel: channel
850 * Context: This function will acquire ioc->scsi_lookup_lock.
851 *
852 * This will search for a matching channel:id:lun in the scsi_lookup array,
853 * returning 1 if found.
854 */
855static u8
856_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
857 unsigned int lun, int channel)
858{
859 u8 found;
860 unsigned long flags;
861 int i;
862
863 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
864 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530865 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore993e0da2009-05-18 13:00:45 -0600866 if (ioc->scsi_lookup[i].scmd &&
867 (ioc->scsi_lookup[i].scmd->device->id == id &&
868 ioc->scsi_lookup[i].scmd->device->channel == channel &&
869 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
870 found = 1;
871 goto out;
872 }
873 }
874 out:
875 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
876 return found;
877}
878
879/**
Eric Moore635374e2009-03-09 01:21:12 -0600880 * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
881 * @ioc: per adapter object
882 * @smid: system request message index
883 *
884 * Returns phys pointer to chain buffer.
885 */
886static dma_addr_t
887_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
888{
889 return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
890 ioc->chains_needed_per_io));
891}
892
893/**
894 * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
895 * @ioc: per adapter object
896 * @smid: system request message index
897 *
898 * Returns virt pointer to chain buffer.
899 */
900static void *
901_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
902{
903 return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
904 ioc->chains_needed_per_io)));
905}
906
907/**
908 * _scsih_build_scatter_gather - main sg creation routine
909 * @ioc: per adapter object
910 * @scmd: scsi command
911 * @smid: system request message index
912 * Context: none.
913 *
914 * The main routine that builds scatter gather table from a given
915 * scsi request sent via the .queuecommand main handler.
916 *
917 * Returns 0 success, anything else error
918 */
919static int
920_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
921 struct scsi_cmnd *scmd, u16 smid)
922{
923 Mpi2SCSIIORequest_t *mpi_request;
924 dma_addr_t chain_dma;
925 struct scatterlist *sg_scmd;
926 void *sg_local, *chain;
927 u32 chain_offset;
928 u32 chain_length;
929 u32 chain_flags;
930 u32 sges_left;
931 u32 sges_in_segment;
932 u32 sgl_flags;
933 u32 sgl_flags_last_element;
934 u32 sgl_flags_end_buffer;
935
936 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
937
938 /* init scatter gather flags */
939 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
940 if (scmd->sc_data_direction == DMA_TO_DEVICE)
941 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
942 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
943 << MPI2_SGE_FLAGS_SHIFT;
944 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
945 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
946 << MPI2_SGE_FLAGS_SHIFT;
947 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
948
949 sg_scmd = scsi_sglist(scmd);
950 sges_left = scsi_dma_map(scmd);
951 if (!sges_left) {
952 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
953 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
954 return -ENOMEM;
955 }
956
957 sg_local = &mpi_request->SGL;
958 sges_in_segment = ioc->max_sges_in_main_message;
959 if (sges_left <= sges_in_segment)
960 goto fill_in_last_segment;
961
962 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
963 (sges_in_segment * ioc->sge_size))/4;
964
965 /* fill in main message segment when there is a chain following */
966 while (sges_in_segment) {
967 if (sges_in_segment == 1)
968 ioc->base_add_sg_single(sg_local,
969 sgl_flags_last_element | sg_dma_len(sg_scmd),
970 sg_dma_address(sg_scmd));
971 else
972 ioc->base_add_sg_single(sg_local, sgl_flags |
973 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
974 sg_scmd = sg_next(sg_scmd);
975 sg_local += ioc->sge_size;
976 sges_left--;
977 sges_in_segment--;
978 }
979
980 /* initializing the chain flags and pointers */
981 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
982 chain = _scsih_get_chain_buffer(ioc, smid);
983 chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
984 do {
985 sges_in_segment = (sges_left <=
986 ioc->max_sges_in_chain_message) ? sges_left :
987 ioc->max_sges_in_chain_message;
988 chain_offset = (sges_left == sges_in_segment) ?
989 0 : (sges_in_segment * ioc->sge_size)/4;
990 chain_length = sges_in_segment * ioc->sge_size;
991 if (chain_offset) {
992 chain_offset = chain_offset <<
993 MPI2_SGE_CHAIN_OFFSET_SHIFT;
994 chain_length += ioc->sge_size;
995 }
996 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
997 chain_length, chain_dma);
998 sg_local = chain;
999 if (!chain_offset)
1000 goto fill_in_last_segment;
1001
1002 /* fill in chain segments */
1003 while (sges_in_segment) {
1004 if (sges_in_segment == 1)
1005 ioc->base_add_sg_single(sg_local,
1006 sgl_flags_last_element |
1007 sg_dma_len(sg_scmd),
1008 sg_dma_address(sg_scmd));
1009 else
1010 ioc->base_add_sg_single(sg_local, sgl_flags |
1011 sg_dma_len(sg_scmd),
1012 sg_dma_address(sg_scmd));
1013 sg_scmd = sg_next(sg_scmd);
1014 sg_local += ioc->sge_size;
1015 sges_left--;
1016 sges_in_segment--;
1017 }
1018
1019 chain_dma += ioc->request_sz;
1020 chain += ioc->request_sz;
1021 } while (1);
1022
1023
1024 fill_in_last_segment:
1025
1026 /* fill the last segment */
1027 while (sges_left) {
1028 if (sges_left == 1)
1029 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1030 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1031 else
1032 ioc->base_add_sg_single(sg_local, sgl_flags |
1033 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1034 sg_scmd = sg_next(sg_scmd);
1035 sg_local += ioc->sge_size;
1036 sges_left--;
1037 }
1038
1039 return 0;
1040}
1041
1042/**
Eric Moored5d135b2009-05-18 13:02:08 -06001043 * _scsih_change_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001044 * @sdev: scsi device struct
1045 * @qdepth: requested queue depth
1046 *
1047 * Returns queue depth.
1048 */
1049static int
Eric Moored5d135b2009-05-18 13:02:08 -06001050_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
Eric Moore635374e2009-03-09 01:21:12 -06001051{
1052 struct Scsi_Host *shost = sdev->host;
1053 int max_depth;
1054 int tag_type;
1055
1056 max_depth = shost->can_queue;
1057 if (!sdev->tagged_supported)
1058 max_depth = 1;
1059 if (qdepth > max_depth)
1060 qdepth = max_depth;
1061 tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
1062 scsi_adjust_queue_depth(sdev, tag_type, qdepth);
1063
1064 if (sdev->inquiry_len > 7)
1065 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1066 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1067 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1068 sdev->ordered_tags, sdev->scsi_level,
1069 (sdev->inquiry[7] & 2) >> 1);
1070
1071 return sdev->queue_depth;
1072}
1073
1074/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301075 * _scsih_change_queue_type - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001076 * @sdev: scsi device struct
1077 * @tag_type: requested tag type
1078 *
1079 * Returns queue tag type.
1080 */
1081static int
Eric Moored5d135b2009-05-18 13:02:08 -06001082_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001083{
1084 if (sdev->tagged_supported) {
1085 scsi_set_tag_type(sdev, tag_type);
1086 if (tag_type)
1087 scsi_activate_tcq(sdev, sdev->queue_depth);
1088 else
1089 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1090 } else
1091 tag_type = 0;
1092
1093 return tag_type;
1094}
1095
1096/**
Eric Moored5d135b2009-05-18 13:02:08 -06001097 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001098 * @starget: scsi target struct
1099 *
1100 * Returns 0 if ok. Any other return is assumed to be an error and
1101 * the device is ignored.
1102 */
1103static int
Eric Moored5d135b2009-05-18 13:02:08 -06001104_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001105{
1106 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1107 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1108 struct MPT2SAS_TARGET *sas_target_priv_data;
1109 struct _sas_device *sas_device;
1110 struct _raid_device *raid_device;
1111 unsigned long flags;
1112 struct sas_rphy *rphy;
1113
1114 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1115 if (!sas_target_priv_data)
1116 return -ENOMEM;
1117
1118 starget->hostdata = sas_target_priv_data;
1119 sas_target_priv_data->starget = starget;
1120 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1121
1122 /* RAID volumes */
1123 if (starget->channel == RAID_CHANNEL) {
1124 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1125 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1126 starget->channel);
1127 if (raid_device) {
1128 sas_target_priv_data->handle = raid_device->handle;
1129 sas_target_priv_data->sas_address = raid_device->wwid;
1130 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
1131 raid_device->starget = starget;
1132 }
1133 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1134 return 0;
1135 }
1136
1137 /* sas/sata devices */
1138 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1139 rphy = dev_to_rphy(starget->dev.parent);
1140 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1141 rphy->identify.sas_address);
1142
1143 if (sas_device) {
1144 sas_target_priv_data->handle = sas_device->handle;
1145 sas_target_priv_data->sas_address = sas_device->sas_address;
1146 sas_device->starget = starget;
1147 sas_device->id = starget->id;
1148 sas_device->channel = starget->channel;
1149 if (sas_device->hidden_raid_component)
1150 sas_target_priv_data->flags |=
1151 MPT_TARGET_FLAGS_RAID_COMPONENT;
1152 }
1153 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1154
1155 return 0;
1156}
1157
1158/**
Eric Moored5d135b2009-05-18 13:02:08 -06001159 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001160 * @starget: scsi target struct
1161 *
1162 * Returns nothing.
1163 */
1164static void
Eric Moored5d135b2009-05-18 13:02:08 -06001165_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001166{
1167 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1168 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1169 struct MPT2SAS_TARGET *sas_target_priv_data;
1170 struct _sas_device *sas_device;
1171 struct _raid_device *raid_device;
1172 unsigned long flags;
1173 struct sas_rphy *rphy;
1174
1175 sas_target_priv_data = starget->hostdata;
1176 if (!sas_target_priv_data)
1177 return;
1178
1179 if (starget->channel == RAID_CHANNEL) {
1180 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1181 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1182 starget->channel);
1183 if (raid_device) {
1184 raid_device->starget = NULL;
1185 raid_device->sdev = NULL;
1186 }
1187 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1188 goto out;
1189 }
1190
1191 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1192 rphy = dev_to_rphy(starget->dev.parent);
1193 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1194 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001195 if (sas_device && (sas_device->starget == starget) &&
1196 (sas_device->id == starget->id) &&
1197 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001198 sas_device->starget = NULL;
1199
1200 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1201
1202 out:
1203 kfree(sas_target_priv_data);
1204 starget->hostdata = NULL;
1205}
1206
1207/**
Eric Moored5d135b2009-05-18 13:02:08 -06001208 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001209 * @sdev: scsi device struct
1210 *
1211 * Returns 0 if ok. Any other return is assumed to be an error and
1212 * the device is ignored.
1213 */
1214static int
Eric Moored5d135b2009-05-18 13:02:08 -06001215_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001216{
1217 struct Scsi_Host *shost;
1218 struct MPT2SAS_ADAPTER *ioc;
1219 struct MPT2SAS_TARGET *sas_target_priv_data;
1220 struct MPT2SAS_DEVICE *sas_device_priv_data;
1221 struct scsi_target *starget;
1222 struct _raid_device *raid_device;
1223 struct _sas_device *sas_device;
1224 unsigned long flags;
1225
1226 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1227 if (!sas_device_priv_data)
1228 return -ENOMEM;
1229
1230 sas_device_priv_data->lun = sdev->lun;
1231 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1232
1233 starget = scsi_target(sdev);
1234 sas_target_priv_data = starget->hostdata;
1235 sas_target_priv_data->num_luns++;
1236 sas_device_priv_data->sas_target = sas_target_priv_data;
1237 sdev->hostdata = sas_device_priv_data;
1238 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1239 sdev->no_uld_attach = 1;
1240
1241 shost = dev_to_shost(&starget->dev);
1242 ioc = shost_priv(shost);
1243 if (starget->channel == RAID_CHANNEL) {
1244 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1245 raid_device = _scsih_raid_device_find_by_id(ioc,
1246 starget->id, starget->channel);
1247 if (raid_device)
1248 raid_device->sdev = sdev; /* raid is single lun */
1249 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1250 } else {
1251 /* set TLR bit for SSP devices */
1252 if (!(ioc->facts.IOCCapabilities &
1253 MPI2_IOCFACTS_CAPABILITY_TLR))
1254 goto out;
1255 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1256 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1257 sas_device_priv_data->sas_target->sas_address);
1258 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1259 if (sas_device && sas_device->device_info &
1260 MPI2_SAS_DEVICE_INFO_SSP_TARGET)
1261 sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON;
1262 }
1263
1264 out:
1265 return 0;
1266}
1267
1268/**
Eric Moored5d135b2009-05-18 13:02:08 -06001269 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001270 * @sdev: scsi device struct
1271 *
1272 * Returns nothing.
1273 */
1274static void
Eric Moored5d135b2009-05-18 13:02:08 -06001275_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001276{
1277 struct MPT2SAS_TARGET *sas_target_priv_data;
1278 struct scsi_target *starget;
1279
1280 if (!sdev->hostdata)
1281 return;
1282
1283 starget = scsi_target(sdev);
1284 sas_target_priv_data = starget->hostdata;
1285 sas_target_priv_data->num_luns--;
1286 kfree(sdev->hostdata);
1287 sdev->hostdata = NULL;
1288}
1289
1290/**
Eric Moored5d135b2009-05-18 13:02:08 -06001291 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001292 * @ioc: per adapter object
1293 * @sas_device: the sas_device object
1294 * @sdev: scsi device struct
1295 */
1296static void
Eric Moored5d135b2009-05-18 13:02:08 -06001297_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06001298 struct _sas_device *sas_device, struct scsi_device *sdev)
1299{
1300 Mpi2ConfigReply_t mpi_reply;
1301 Mpi2SasDevicePage0_t sas_device_pg0;
1302 u32 ioc_status;
1303 u16 flags;
1304 u32 device_info;
1305
1306 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
1307 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
1308 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1309 ioc->name, __FILE__, __LINE__, __func__);
1310 return;
1311 }
1312
1313 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1314 MPI2_IOCSTATUS_MASK;
1315 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1316 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1317 ioc->name, __FILE__, __LINE__, __func__);
1318 return;
1319 }
1320
1321 flags = le16_to_cpu(sas_device_pg0.Flags);
1322 device_info = le16_to_cpu(sas_device_pg0.DeviceInfo);
1323
1324 sdev_printk(KERN_INFO, sdev,
1325 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1326 "sw_preserve(%s)\n",
1327 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1328 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1329 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1330 "n",
1331 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1332 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1333 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1334}
1335
1336/**
1337 * _scsih_get_volume_capabilities - volume capabilities
1338 * @ioc: per adapter object
1339 * @sas_device: the raid_device object
1340 */
1341static void
1342_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1343 struct _raid_device *raid_device)
1344{
1345 Mpi2RaidVolPage0_t *vol_pg0;
1346 Mpi2RaidPhysDiskPage0_t pd_pg0;
1347 Mpi2SasDevicePage0_t sas_device_pg0;
1348 Mpi2ConfigReply_t mpi_reply;
1349 u16 sz;
1350 u8 num_pds;
1351
1352 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1353 &num_pds)) || !num_pds) {
1354 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1355 ioc->name, __FILE__, __LINE__, __func__);
1356 return;
1357 }
1358
1359 raid_device->num_pds = num_pds;
1360 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1361 sizeof(Mpi2RaidVol0PhysDisk_t));
1362 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1363 if (!vol_pg0) {
1364 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1365 ioc->name, __FILE__, __LINE__, __func__);
1366 return;
1367 }
1368
1369 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1370 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1371 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1372 ioc->name, __FILE__, __LINE__, __func__);
1373 kfree(vol_pg0);
1374 return;
1375 }
1376
1377 raid_device->volume_type = vol_pg0->VolumeType;
1378
1379 /* figure out what the underlying devices are by
1380 * obtaining the device_info bits for the 1st device
1381 */
1382 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1383 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1384 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1385 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1386 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1387 le16_to_cpu(pd_pg0.DevHandle)))) {
1388 raid_device->device_info =
1389 le32_to_cpu(sas_device_pg0.DeviceInfo);
1390 }
1391 }
1392
1393 kfree(vol_pg0);
1394}
1395
1396/**
Eric Moored5d135b2009-05-18 13:02:08 -06001397 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001398 * @sdev: scsi device struct
1399 *
1400 * Returns 0 if ok. Any other return is assumed to be an error and
1401 * the device is ignored.
1402 */
1403static int
Eric Moored5d135b2009-05-18 13:02:08 -06001404_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001405{
1406 struct Scsi_Host *shost = sdev->host;
1407 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1408 struct MPT2SAS_DEVICE *sas_device_priv_data;
1409 struct MPT2SAS_TARGET *sas_target_priv_data;
1410 struct _sas_device *sas_device;
1411 struct _raid_device *raid_device;
1412 unsigned long flags;
1413 int qdepth;
1414 u8 ssp_target = 0;
1415 char *ds = "";
1416 char *r_level = "";
1417
1418 qdepth = 1;
1419 sas_device_priv_data = sdev->hostdata;
1420 sas_device_priv_data->configured_lun = 1;
1421 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1422 sas_target_priv_data = sas_device_priv_data->sas_target;
1423
1424 /* raid volume handling */
1425 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1426
1427 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1428 raid_device = _scsih_raid_device_find_by_handle(ioc,
1429 sas_target_priv_data->handle);
1430 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1431 if (!raid_device) {
1432 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1433 ioc->name, __FILE__, __LINE__, __func__);
1434 return 0;
1435 }
1436
1437 _scsih_get_volume_capabilities(ioc, raid_device);
1438
1439 /* RAID Queue Depth Support
1440 * IS volume = underlying qdepth of drive type, either
1441 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
1442 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
1443 */
1444 if (raid_device->device_info &
1445 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1446 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1447 ds = "SSP";
1448 } else {
1449 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1450 if (raid_device->device_info &
1451 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1452 ds = "SATA";
1453 else
1454 ds = "STP";
1455 }
1456
1457 switch (raid_device->volume_type) {
1458 case MPI2_RAID_VOL_TYPE_RAID0:
1459 r_level = "RAID0";
1460 break;
1461 case MPI2_RAID_VOL_TYPE_RAID1E:
1462 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05301463 if (ioc->manu_pg10.OEMIdentifier &&
1464 (ioc->manu_pg10.GenericFlags0 &
1465 MFG10_GF0_R10_DISPLAY) &&
1466 !(raid_device->num_pds % 2))
1467 r_level = "RAID10";
1468 else
1469 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06001470 break;
1471 case MPI2_RAID_VOL_TYPE_RAID1:
1472 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1473 r_level = "RAID1";
1474 break;
1475 case MPI2_RAID_VOL_TYPE_RAID10:
1476 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1477 r_level = "RAID10";
1478 break;
1479 case MPI2_RAID_VOL_TYPE_UNKNOWN:
1480 default:
1481 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1482 r_level = "RAIDX";
1483 break;
1484 }
1485
1486 sdev_printk(KERN_INFO, sdev, "%s: "
1487 "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
1488 r_level, raid_device->handle,
1489 (unsigned long long)raid_device->wwid,
1490 raid_device->num_pds, ds);
Eric Moored5d135b2009-05-18 13:02:08 -06001491 _scsih_change_queue_depth(sdev, qdepth);
Eric Moore635374e2009-03-09 01:21:12 -06001492 return 0;
1493 }
1494
1495 /* non-raid handling */
1496 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1497 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1498 sas_device_priv_data->sas_target->sas_address);
1499 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1500 if (sas_device) {
1501 if (sas_target_priv_data->flags &
1502 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1503 mpt2sas_config_get_volume_handle(ioc,
1504 sas_device->handle, &sas_device->volume_handle);
1505 mpt2sas_config_get_volume_wwid(ioc,
1506 sas_device->volume_handle,
1507 &sas_device->volume_wwid);
1508 }
1509 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1510 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1511 ssp_target = 1;
1512 ds = "SSP";
1513 } else {
1514 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1515 if (sas_device->device_info &
1516 MPI2_SAS_DEVICE_INFO_STP_TARGET)
1517 ds = "STP";
1518 else if (sas_device->device_info &
1519 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1520 ds = "SATA";
1521 }
1522
1523 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
1524 "sas_addr(0x%016llx), device_name(0x%016llx)\n",
1525 ds, sas_device->handle,
1526 (unsigned long long)sas_device->sas_address,
1527 (unsigned long long)sas_device->device_name);
1528 sdev_printk(KERN_INFO, sdev, "%s: "
1529 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
1530 (unsigned long long) sas_device->enclosure_logical_id,
1531 sas_device->slot);
1532
1533 if (!ssp_target)
Eric Moored5d135b2009-05-18 13:02:08 -06001534 _scsih_display_sata_capabilities(ioc, sas_device, sdev);
Eric Moore635374e2009-03-09 01:21:12 -06001535 }
1536
Eric Moored5d135b2009-05-18 13:02:08 -06001537 _scsih_change_queue_depth(sdev, qdepth);
Eric Moore635374e2009-03-09 01:21:12 -06001538
1539 if (ssp_target)
1540 sas_read_port_mode_page(sdev);
1541 return 0;
1542}
1543
1544/**
Eric Moored5d135b2009-05-18 13:02:08 -06001545 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06001546 * @sdev: scsi device struct
1547 * @bdev: pointer to block device context
1548 * @capacity: device size (in 512 byte sectors)
1549 * @params: three element array to place output:
1550 * params[0] number of heads (max 255)
1551 * params[1] number of sectors (max 63)
1552 * params[2] number of cylinders
1553 *
1554 * Return nothing.
1555 */
1556static int
Eric Moored5d135b2009-05-18 13:02:08 -06001557_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06001558 sector_t capacity, int params[])
1559{
1560 int heads;
1561 int sectors;
1562 sector_t cylinders;
1563 ulong dummy;
1564
1565 heads = 64;
1566 sectors = 32;
1567
1568 dummy = heads * sectors;
1569 cylinders = capacity;
1570 sector_div(cylinders, dummy);
1571
1572 /*
1573 * Handle extended translation size for logical drives
1574 * > 1Gb
1575 */
1576 if ((ulong)capacity >= 0x200000) {
1577 heads = 255;
1578 sectors = 63;
1579 dummy = heads * sectors;
1580 cylinders = capacity;
1581 sector_div(cylinders, dummy);
1582 }
1583
1584 /* return result */
1585 params[0] = heads;
1586 params[1] = sectors;
1587 params[2] = cylinders;
1588
1589 return 0;
1590}
1591
1592/**
1593 * _scsih_response_code - translation of device response code
1594 * @ioc: per adapter object
1595 * @response_code: response code returned by the device
1596 *
1597 * Return nothing.
1598 */
1599static void
1600_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
1601{
1602 char *desc;
1603
1604 switch (response_code) {
1605 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1606 desc = "task management request completed";
1607 break;
1608 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1609 desc = "invalid frame";
1610 break;
1611 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1612 desc = "task management request not supported";
1613 break;
1614 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1615 desc = "task management request failed";
1616 break;
1617 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1618 desc = "task management request succeeded";
1619 break;
1620 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1621 desc = "invalid lun";
1622 break;
1623 case 0xA:
1624 desc = "overlapped tag attempted";
1625 break;
1626 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1627 desc = "task queued, however not sent to target";
1628 break;
1629 default:
1630 desc = "unknown";
1631 break;
1632 }
1633 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
1634 ioc->name, response_code, desc);
1635}
1636
1637/**
Eric Moored5d135b2009-05-18 13:02:08 -06001638 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06001639 * @ioc: per adapter object
1640 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301641 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001642 * @reply: reply message frame(lower 32bit addr)
1643 * Context: none.
1644 *
1645 * The callback handler when using scsih_issue_tm.
1646 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301647 * Return 1 meaning mf should be freed from _base_interrupt
1648 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06001649 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301650static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301651_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06001652{
1653 MPI2DefaultReply_t *mpi_reply;
1654
1655 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301656 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001657 if (ioc->tm_cmds.smid != smid)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301658 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001659 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
1660 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
1661 if (mpi_reply) {
1662 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
1663 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
1664 }
1665 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
1666 complete(&ioc->tm_cmds.done);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301667 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001668}
1669
1670/**
1671 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
1672 * @ioc: per adapter object
1673 * @handle: device handle
1674 *
1675 * During taskmangement request, we need to freeze the device queue.
1676 */
1677void
1678mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1679{
1680 struct MPT2SAS_DEVICE *sas_device_priv_data;
1681 struct scsi_device *sdev;
1682 u8 skip = 0;
1683
1684 shost_for_each_device(sdev, ioc->shost) {
1685 if (skip)
1686 continue;
1687 sas_device_priv_data = sdev->hostdata;
1688 if (!sas_device_priv_data)
1689 continue;
1690 if (sas_device_priv_data->sas_target->handle == handle) {
1691 sas_device_priv_data->sas_target->tm_busy = 1;
1692 skip = 1;
1693 ioc->ignore_loginfos = 1;
1694 }
1695 }
1696}
1697
1698/**
1699 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
1700 * @ioc: per adapter object
1701 * @handle: device handle
1702 *
1703 * During taskmangement request, we need to freeze the device queue.
1704 */
1705void
1706mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1707{
1708 struct MPT2SAS_DEVICE *sas_device_priv_data;
1709 struct scsi_device *sdev;
1710 u8 skip = 0;
1711
1712 shost_for_each_device(sdev, ioc->shost) {
1713 if (skip)
1714 continue;
1715 sas_device_priv_data = sdev->hostdata;
1716 if (!sas_device_priv_data)
1717 continue;
1718 if (sas_device_priv_data->sas_target->handle == handle) {
1719 sas_device_priv_data->sas_target->tm_busy = 0;
1720 skip = 1;
1721 ioc->ignore_loginfos = 0;
1722 }
1723 }
1724}
1725
1726/**
1727 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
1728 * @ioc: per adapter struct
1729 * @device_handle: device handle
1730 * @lun: lun number
1731 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
1732 * @smid_task: smid assigned to the task
1733 * @timeout: timeout in seconds
1734 * Context: The calling function needs to acquire the tm_cmds.mutex
1735 *
1736 * A generic API for sending task management requests to firmware.
1737 *
1738 * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling
1739 * this API.
1740 *
1741 * The callback index is set inside `ioc->tm_cb_idx`.
1742 *
1743 * Return nothing.
1744 */
1745void
1746mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
1747 u8 type, u16 smid_task, ulong timeout)
1748{
1749 Mpi2SCSITaskManagementRequest_t *mpi_request;
1750 Mpi2SCSITaskManagementReply_t *mpi_reply;
1751 u16 smid = 0;
1752 u32 ioc_state;
1753 unsigned long timeleft;
Eric Moore635374e2009-03-09 01:21:12 -06001754
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301755 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
1756 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
1757 __func__, ioc->name);
1758 return;
1759 }
1760
1761 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06001762 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1763 __func__, ioc->name);
1764 return;
1765 }
Eric Moore635374e2009-03-09 01:21:12 -06001766
1767 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
1768 if (ioc_state & MPI2_DOORBELL_USED) {
1769 dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
1770 "active!\n", ioc->name));
1771 goto issue_host_reset;
1772 }
1773
1774 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
1775 mpt2sas_base_fault_info(ioc, ioc_state &
1776 MPI2_DOORBELL_DATA_MASK);
1777 goto issue_host_reset;
1778 }
1779
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301780 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06001781 if (!smid) {
1782 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1783 ioc->name, __func__);
1784 return;
1785 }
1786
1787 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301788 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
1789 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06001790 ioc->tm_cmds.status = MPT2_CMD_PENDING;
1791 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1792 ioc->tm_cmds.smid = smid;
1793 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
1794 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1795 mpi_request->DevHandle = cpu_to_le16(handle);
1796 mpi_request->TaskType = type;
1797 mpi_request->TaskMID = cpu_to_le16(smid_task);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301798 mpi_request->VP_ID = 0; /* TODO */
1799 mpi_request->VF_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06001800 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
1801 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05301802 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301803 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06001804 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
1805 mpt2sas_scsih_clear_tm_flag(ioc, handle);
1806 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
1807 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
1808 ioc->name, __func__);
1809 _debug_dump_mf(mpi_request,
1810 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
1811 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET))
1812 goto issue_host_reset;
1813 }
1814
1815 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
1816 mpi_reply = ioc->tm_cmds.reply;
1817 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
1818 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
1819 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
1820 le32_to_cpu(mpi_reply->IOCLogInfo),
1821 le32_to_cpu(mpi_reply->TerminationCount)));
1822 if (ioc->logging_level & MPT_DEBUG_TM)
1823 _scsih_response_code(ioc, mpi_reply->ResponseCode);
1824 }
1825 return;
1826 issue_host_reset:
1827 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
1828}
1829
1830/**
Eric Moored5d135b2009-05-18 13:02:08 -06001831 * _scsih_abort - eh threads main abort routine
Eric Moore635374e2009-03-09 01:21:12 -06001832 * @sdev: scsi device struct
1833 *
1834 * Returns SUCCESS if command aborted else FAILED
1835 */
1836static int
Eric Moored5d135b2009-05-18 13:02:08 -06001837_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001838{
1839 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1840 struct MPT2SAS_DEVICE *sas_device_priv_data;
1841 u16 smid;
1842 u16 handle;
1843 int r;
1844 struct scsi_cmnd *scmd_lookup;
1845
1846 printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
1847 ioc->name, scmd);
1848 scsi_print_command(scmd);
1849
1850 sas_device_priv_data = scmd->device->hostdata;
1851 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1852 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
1853 ioc->name, scmd);
1854 scmd->result = DID_NO_CONNECT << 16;
1855 scmd->scsi_done(scmd);
1856 r = SUCCESS;
1857 goto out;
1858 }
1859
1860 /* search for the command */
1861 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
1862 if (!smid) {
1863 scmd->result = DID_RESET << 16;
1864 r = SUCCESS;
1865 goto out;
1866 }
1867
1868 /* for hidden raid components and volumes this is not supported */
1869 if (sas_device_priv_data->sas_target->flags &
1870 MPT_TARGET_FLAGS_RAID_COMPONENT ||
1871 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
1872 scmd->result = DID_RESET << 16;
1873 r = FAILED;
1874 goto out;
1875 }
1876
1877 mutex_lock(&ioc->tm_cmds.mutex);
1878 handle = sas_device_priv_data->sas_target->handle;
1879 mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
1880 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30);
1881
1882 /* sanity check - see whether command actually completed */
1883 scmd_lookup = _scsih_scsi_lookup_get(ioc, smid);
1884 if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number))
1885 r = FAILED;
1886 else
1887 r = SUCCESS;
1888 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
1889 mutex_unlock(&ioc->tm_cmds.mutex);
1890
1891 out:
1892 printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
1893 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
1894 return r;
1895}
1896
Eric Moore635374e2009-03-09 01:21:12 -06001897/**
Eric Moored5d135b2009-05-18 13:02:08 -06001898 * _scsih_dev_reset - eh threads main device reset routine
Eric Moore635374e2009-03-09 01:21:12 -06001899 * @sdev: scsi device struct
1900 *
1901 * Returns SUCCESS if command aborted else FAILED
1902 */
1903static int
Eric Moored5d135b2009-05-18 13:02:08 -06001904_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001905{
1906 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1907 struct MPT2SAS_DEVICE *sas_device_priv_data;
1908 struct _sas_device *sas_device;
1909 unsigned long flags;
1910 u16 handle;
1911 int r;
1912
Eric Moore993e0da2009-05-18 13:00:45 -06001913 printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
Eric Moore635374e2009-03-09 01:21:12 -06001914 ioc->name, scmd);
1915 scsi_print_command(scmd);
1916
1917 sas_device_priv_data = scmd->device->hostdata;
1918 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1919 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
1920 ioc->name, scmd);
1921 scmd->result = DID_NO_CONNECT << 16;
1922 scmd->scsi_done(scmd);
1923 r = SUCCESS;
1924 goto out;
1925 }
1926
1927 /* for hidden raid components obtain the volume_handle */
1928 handle = 0;
1929 if (sas_device_priv_data->sas_target->flags &
1930 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1931 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1932 sas_device = _scsih_sas_device_find_by_handle(ioc,
1933 sas_device_priv_data->sas_target->handle);
1934 if (sas_device)
1935 handle = sas_device->volume_handle;
1936 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1937 } else
1938 handle = sas_device_priv_data->sas_target->handle;
1939
1940 if (!handle) {
1941 scmd->result = DID_RESET << 16;
1942 r = FAILED;
1943 goto out;
1944 }
1945
1946 mutex_lock(&ioc->tm_cmds.mutex);
1947 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore993e0da2009-05-18 13:00:45 -06001948 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun,
1949 30);
1950
1951 /*
1952 * sanity check see whether all commands to this device been
1953 * completed
1954 */
1955 if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id,
1956 scmd->device->lun, scmd->device->channel))
1957 r = FAILED;
1958 else
1959 r = SUCCESS;
1960 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
1961 mutex_unlock(&ioc->tm_cmds.mutex);
1962
1963 out:
1964 printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
1965 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
1966 return r;
1967}
1968
1969/**
Eric Moored5d135b2009-05-18 13:02:08 -06001970 * _scsih_target_reset - eh threads main target reset routine
Eric Moore993e0da2009-05-18 13:00:45 -06001971 * @sdev: scsi device struct
1972 *
1973 * Returns SUCCESS if command aborted else FAILED
1974 */
1975static int
Eric Moored5d135b2009-05-18 13:02:08 -06001976_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06001977{
1978 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
1979 struct MPT2SAS_DEVICE *sas_device_priv_data;
1980 struct _sas_device *sas_device;
1981 unsigned long flags;
1982 u16 handle;
1983 int r;
1984
1985 printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
1986 ioc->name, scmd);
1987 scsi_print_command(scmd);
1988
1989 sas_device_priv_data = scmd->device->hostdata;
1990 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
1991 printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
1992 ioc->name, scmd);
1993 scmd->result = DID_NO_CONNECT << 16;
1994 scmd->scsi_done(scmd);
1995 r = SUCCESS;
1996 goto out;
1997 }
1998
1999 /* for hidden raid components obtain the volume_handle */
2000 handle = 0;
2001 if (sas_device_priv_data->sas_target->flags &
2002 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2003 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2004 sas_device = _scsih_sas_device_find_by_handle(ioc,
2005 sas_device_priv_data->sas_target->handle);
2006 if (sas_device)
2007 handle = sas_device->volume_handle;
2008 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2009 } else
2010 handle = sas_device_priv_data->sas_target->handle;
2011
2012 if (!handle) {
2013 scmd->result = DID_RESET << 16;
2014 r = FAILED;
2015 goto out;
2016 }
2017
2018 mutex_lock(&ioc->tm_cmds.mutex);
2019 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore635374e2009-03-09 01:21:12 -06002020 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30);
2021
2022 /*
2023 * sanity check see whether all commands to this target been
2024 * completed
2025 */
2026 if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id,
2027 scmd->device->channel))
2028 r = FAILED;
2029 else
2030 r = SUCCESS;
2031 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2032 mutex_unlock(&ioc->tm_cmds.mutex);
2033
2034 out:
2035 printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
2036 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2037 return r;
2038}
2039
2040/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302041 * _scsih_host_reset - eh threads main host reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002042 * @sdev: scsi device struct
2043 *
2044 * Returns SUCCESS if command aborted else FAILED
2045 */
2046static int
Eric Moored5d135b2009-05-18 13:02:08 -06002047_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002048{
2049 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2050 int r, retval;
2051
2052 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2053 ioc->name, scmd);
2054 scsi_print_command(scmd);
2055
2056 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2057 FORCE_BIG_HAMMER);
2058 r = (retval < 0) ? FAILED : SUCCESS;
2059 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2060 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2061
2062 return r;
2063}
2064
2065/**
2066 * _scsih_fw_event_add - insert and queue up fw_event
2067 * @ioc: per adapter object
2068 * @fw_event: object describing the event
2069 * Context: This function will acquire ioc->fw_event_lock.
2070 *
2071 * This adds the firmware event object into link list, then queues it up to
2072 * be processed from user context.
2073 *
2074 * Return nothing.
2075 */
2076static void
2077_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2078{
2079 unsigned long flags;
2080
2081 if (ioc->firmware_event_thread == NULL)
2082 return;
2083
2084 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2085 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002086 INIT_WORK(&fw_event->work, _firmware_event_work);
2087 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002088 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2089}
2090
2091/**
2092 * _scsih_fw_event_free - delete fw_event
2093 * @ioc: per adapter object
2094 * @fw_event: object describing the event
2095 * Context: This function will acquire ioc->fw_event_lock.
2096 *
2097 * This removes firmware event object from link list, frees associated memory.
2098 *
2099 * Return nothing.
2100 */
2101static void
2102_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2103 *fw_event)
2104{
2105 unsigned long flags;
2106
2107 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2108 list_del(&fw_event->list);
2109 kfree(fw_event->event_data);
2110 kfree(fw_event);
2111 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2112}
2113
2114/**
2115 * _scsih_fw_event_add - requeue an event
2116 * @ioc: per adapter object
2117 * @fw_event: object describing the event
2118 * Context: This function will acquire ioc->fw_event_lock.
2119 *
2120 * Return nothing.
2121 */
2122static void
2123_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2124 *fw_event, unsigned long delay)
2125{
2126 unsigned long flags;
2127 if (ioc->firmware_event_thread == NULL)
2128 return;
2129
2130 spin_lock_irqsave(&ioc->fw_event_lock, flags);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002131 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_off - turn flag off preventing event handling
2137 * @ioc: per adapter object
2138 *
2139 * Used to prevent handling of firmware events during adapter reset
2140 * driver unload.
2141 *
2142 * Return nothing.
2143 */
2144static void
2145_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc)
2146{
2147 unsigned long flags;
2148
2149 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2150 ioc->fw_events_off = 1;
2151 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2152
2153}
2154
2155/**
2156 * _scsih_fw_event_on - turn flag on allowing firmware event handling
2157 * @ioc: per adapter object
2158 *
2159 * Returns nothing.
2160 */
2161static void
2162_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc)
2163{
2164 unsigned long flags;
2165
2166 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2167 ioc->fw_events_off = 0;
2168 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2169}
2170
2171/**
2172 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2173 * @ioc: per adapter object
2174 * @handle: device handle
2175 *
2176 * During device pull we need to appropiately set the sdev state.
2177 */
2178static void
2179_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2180{
2181 struct MPT2SAS_DEVICE *sas_device_priv_data;
2182 struct scsi_device *sdev;
2183
2184 shost_for_each_device(sdev, ioc->shost) {
2185 sas_device_priv_data = sdev->hostdata;
2186 if (!sas_device_priv_data)
2187 continue;
2188 if (!sas_device_priv_data->block)
2189 continue;
2190 if (sas_device_priv_data->sas_target->handle == handle) {
2191 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2192 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2193 "handle(0x%04x)\n", ioc->name, handle));
2194 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302195 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002196 }
2197 }
2198}
2199
2200/**
2201 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2202 * @ioc: per adapter object
2203 * @handle: device handle
2204 *
2205 * During device pull we need to appropiately set the sdev state.
2206 */
2207static void
2208_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2209{
2210 struct MPT2SAS_DEVICE *sas_device_priv_data;
2211 struct scsi_device *sdev;
2212
2213 shost_for_each_device(sdev, ioc->shost) {
2214 sas_device_priv_data = sdev->hostdata;
2215 if (!sas_device_priv_data)
2216 continue;
2217 if (sas_device_priv_data->block)
2218 continue;
2219 if (sas_device_priv_data->sas_target->handle == handle) {
2220 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2221 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2222 "handle(0x%04x)\n", ioc->name, handle));
2223 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302224 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002225 }
2226 }
2227}
2228
2229/**
2230 * _scsih_block_io_to_children_attached_to_ex
2231 * @ioc: per adapter object
2232 * @sas_expander: the sas_device object
2233 *
2234 * This routine set sdev state to SDEV_BLOCK for all devices
2235 * attached to this expander. This function called when expander is
2236 * pulled.
2237 */
2238static void
2239_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2240 struct _sas_node *sas_expander)
2241{
2242 struct _sas_port *mpt2sas_port;
2243 struct _sas_device *sas_device;
2244 struct _sas_node *expander_sibling;
2245 unsigned long flags;
2246
2247 if (!sas_expander)
2248 return;
2249
2250 list_for_each_entry(mpt2sas_port,
2251 &sas_expander->sas_port_list, port_list) {
2252 if (mpt2sas_port->remote_identify.device_type ==
2253 SAS_END_DEVICE) {
2254 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2255 sas_device =
2256 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2257 mpt2sas_port->remote_identify.sas_address);
2258 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2259 if (!sas_device)
2260 continue;
2261 _scsih_block_io_device(ioc, sas_device->handle);
2262 }
2263 }
2264
2265 list_for_each_entry(mpt2sas_port,
2266 &sas_expander->sas_port_list, port_list) {
2267
2268 if (mpt2sas_port->remote_identify.device_type ==
2269 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2270 mpt2sas_port->remote_identify.device_type ==
2271 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2272
2273 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2274 expander_sibling =
2275 mpt2sas_scsih_expander_find_by_sas_address(
2276 ioc, mpt2sas_port->remote_identify.sas_address);
2277 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2278 _scsih_block_io_to_children_attached_to_ex(ioc,
2279 expander_sibling);
2280 }
2281 }
2282}
2283
2284/**
2285 * _scsih_block_io_to_children_attached_directly
2286 * @ioc: per adapter object
2287 * @event_data: topology change event data
2288 *
2289 * This routine set sdev state to SDEV_BLOCK for all devices
2290 * direct attached during device pull.
2291 */
2292static void
2293_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2294 Mpi2EventDataSasTopologyChangeList_t *event_data)
2295{
2296 int i;
2297 u16 handle;
2298 u16 reason_code;
2299 u8 phy_number;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302300 u8 link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06002301
2302 for (i = 0; i < event_data->NumEntries; i++) {
2303 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2304 if (!handle)
2305 continue;
2306 phy_number = event_data->StartPhyNum + i;
2307 reason_code = event_data->PHY[i].PhyStatus &
2308 MPI2_EVENT_SAS_TOPO_RC_MASK;
2309 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2310 _scsih_block_io_device(ioc, handle);
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302311 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) {
2312 link_rate = event_data->PHY[i].LinkRate >> 4;
2313 if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
2314 _scsih_ublock_io_device(ioc, handle);
2315 }
Eric Moore635374e2009-03-09 01:21:12 -06002316 }
2317}
2318
2319/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302320 * _scsih_tm_tr_send - send task management request
2321 * @ioc: per adapter object
2322 * @handle: device handle
2323 * Context: interrupt time.
2324 *
2325 * This code is to initiate the device removal handshake protocal
2326 * with controller firmware. This function will issue target reset
2327 * using high priority request queue. It will send a sas iounit
2328 * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
2329 *
2330 * This is designed to send muliple task management request at the same
2331 * time to the fifo. If the fifo is full, we will append the request,
2332 * and process it in a future completion.
2333 */
2334static void
2335_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2336{
2337 Mpi2SCSITaskManagementRequest_t *mpi_request;
2338 struct MPT2SAS_TARGET *sas_target_priv_data;
2339 u16 smid;
2340 struct _sas_device *sas_device;
2341 unsigned long flags;
2342 struct _tr_list *delayed_tr;
2343
2344 if (ioc->shost_recovery) {
2345 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2346 __func__, ioc->name);
2347 return;
2348 }
2349
2350 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2351 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
2352 if (!sas_device) {
2353 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2354 printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
2355 ioc->name, __func__);
2356 return;
2357 }
2358 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2359
2360 /* skip is hidden raid component */
2361 if (sas_device->hidden_raid_component)
2362 return;
2363
2364 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
2365 if (!smid) {
2366 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
2367 if (!delayed_tr)
2368 return;
2369 INIT_LIST_HEAD(&delayed_tr->list);
2370 delayed_tr->handle = handle;
2371 delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
2372 list_add_tail(&delayed_tr->list,
2373 &ioc->delayed_tr_list);
2374 if (sas_device->starget)
2375 dewtprintk(ioc, starget_printk(KERN_INFO,
2376 sas_device->starget, "DELAYED:tr:handle(0x%04x), "
2377 "(open)\n", sas_device->handle));
2378 return;
2379 }
2380
2381 if (sas_device->starget && sas_device->starget->hostdata) {
2382 sas_target_priv_data = sas_device->starget->hostdata;
2383 sas_target_priv_data->tm_busy = 1;
2384 dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
2385 "tr:handle(0x%04x), (open)\n", sas_device->handle));
2386 }
2387
2388 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2389 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2390 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2391 mpi_request->DevHandle = cpu_to_le16(handle);
2392 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
2393 sas_device->state |= MPTSAS_STATE_TR_SEND;
2394 sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
2395 mpt2sas_base_put_smid_hi_priority(ioc, smid);
2396}
2397
2398
2399
2400/**
2401 * _scsih_sas_control_complete - completion routine
2402 * @ioc: per adapter object
2403 * @smid: system request message index
2404 * @msix_index: MSIX table index supplied by the OS
2405 * @reply: reply message frame(lower 32bit addr)
2406 * Context: interrupt time.
2407 *
2408 * This is the sas iounit controll completion routine.
2409 * This code is part of the code to initiate the device removal
2410 * handshake protocal with controller firmware.
2411 *
2412 * Return 1 meaning mf should be freed from _base_interrupt
2413 * 0 means the mf is freed from this function.
2414 */
2415static u8
2416_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
2417 u8 msix_index, u32 reply)
2418{
2419 unsigned long flags;
2420 u16 handle;
2421 struct _sas_device *sas_device;
2422 Mpi2SasIoUnitControlReply_t *mpi_reply =
2423 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2424
2425 handle = le16_to_cpu(mpi_reply->DevHandle);
2426
2427 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2428 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
2429 if (!sas_device) {
2430 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2431 printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
2432 ioc->name, __func__);
2433 return 1;
2434 }
2435 sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
2436 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2437
2438 if (sas_device->starget)
2439 dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
2440 "sc_complete:handle(0x%04x), "
2441 "ioc_status(0x%04x), loginfo(0x%08x)\n",
2442 handle, le16_to_cpu(mpi_reply->IOCStatus),
2443 le32_to_cpu(mpi_reply->IOCLogInfo)));
2444 return 1;
2445}
2446
2447/**
2448 * _scsih_tm_tr_complete -
2449 * @ioc: per adapter object
2450 * @smid: system request message index
2451 * @msix_index: MSIX table index supplied by the OS
2452 * @reply: reply message frame(lower 32bit addr)
2453 * Context: interrupt time.
2454 *
2455 * This is the target reset completion routine.
2456 * This code is part of the code to initiate the device removal
2457 * handshake protocal with controller firmware.
2458 * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE)
2459 *
2460 * Return 1 meaning mf should be freed from _base_interrupt
2461 * 0 means the mf is freed from this function.
2462 */
2463static u8
2464_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
2465 u32 reply)
2466{
2467 unsigned long flags;
2468 u16 handle;
2469 struct _sas_device *sas_device;
2470 Mpi2SCSITaskManagementReply_t *mpi_reply =
2471 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2472 Mpi2SasIoUnitControlRequest_t *mpi_request;
2473 u16 smid_sas_ctrl;
2474 struct MPT2SAS_TARGET *sas_target_priv_data;
2475 struct _tr_list *delayed_tr;
2476 u8 rc;
2477
2478 handle = le16_to_cpu(mpi_reply->DevHandle);
2479 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2480 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
2481 if (!sas_device) {
2482 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2483 printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n",
2484 ioc->name, __func__);
2485 return 1;
2486 }
2487 sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
2488 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2489
2490 if (sas_device->starget)
2491 dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget,
2492 "tr_complete:handle(0x%04x), (%s) ioc_status(0x%04x), "
2493 "loginfo(0x%08x), completed(%d)\n",
2494 sas_device->handle, (sas_device->state &
2495 MPT2SAS_REQ_SAS_CNTRL) ? "open" : "active",
2496 le16_to_cpu(mpi_reply->IOCStatus),
2497 le32_to_cpu(mpi_reply->IOCLogInfo),
2498 le32_to_cpu(mpi_reply->TerminationCount)));
2499
2500 if (sas_device->starget && sas_device->starget->hostdata) {
2501 sas_target_priv_data = sas_device->starget->hostdata;
2502 sas_target_priv_data->tm_busy = 0;
2503 }
2504
2505 if (!list_empty(&ioc->delayed_tr_list)) {
2506 delayed_tr = list_entry(ioc->delayed_tr_list.next,
2507 struct _tr_list, list);
2508 mpt2sas_base_free_smid(ioc, smid);
2509 if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL)
2510 _scsih_tm_tr_send(ioc, delayed_tr->handle);
2511 list_del(&delayed_tr->list);
2512 kfree(delayed_tr);
2513 rc = 0; /* tells base_interrupt not to free mf */
2514 } else
2515 rc = 1;
2516
2517
2518 if (!(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
2519 return rc;
2520
2521 if (ioc->shost_recovery) {
2522 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2523 __func__, ioc->name);
2524 return rc;
2525 }
2526
2527 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
2528 if (!smid_sas_ctrl) {
2529 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2530 ioc->name, __func__);
2531 return rc;
2532 }
2533
2534 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
2535 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
2536 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
2537 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
2538 mpi_request->DevHandle = mpi_reply->DevHandle;
2539 sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
2540 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
2541 return rc;
2542}
2543
2544/**
Eric Moore635374e2009-03-09 01:21:12 -06002545 * _scsih_check_topo_delete_events - sanity check on topo events
2546 * @ioc: per adapter object
2547 * @event_data: the event data payload
2548 *
2549 * This routine added to better handle cable breaker.
2550 *
2551 * This handles the case where driver recieves multiple expander
2552 * add and delete events in a single shot. When there is a delete event
2553 * the routine will void any pending add events waiting in the event queue.
2554 *
2555 * Return nothing.
2556 */
2557static void
2558_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
2559 Mpi2EventDataSasTopologyChangeList_t *event_data)
2560{
2561 struct fw_event_work *fw_event;
2562 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
2563 u16 expander_handle;
2564 struct _sas_node *sas_expander;
2565 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302566 int i, reason_code;
2567 u16 handle;
2568
2569 for (i = 0 ; i < event_data->NumEntries; i++) {
2570 if (event_data->PHY[i].PhyStatus &
2571 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
2572 continue;
2573 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2574 if (!handle)
2575 continue;
2576 reason_code = event_data->PHY[i].PhyStatus &
2577 MPI2_EVENT_SAS_TOPO_RC_MASK;
2578 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
2579 _scsih_tm_tr_send(ioc, handle);
2580 }
Eric Moore635374e2009-03-09 01:21:12 -06002581
2582 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
2583 if (expander_handle < ioc->sas_hba.num_phys) {
2584 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2585 return;
2586 }
2587
2588 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
2589 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
2590 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2591 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
2592 expander_handle);
2593 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2594 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
2595 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
2596 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2597
2598 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
2599 return;
2600
2601 /* mark ignore flag for pending events */
2602 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2603 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
2604 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
2605 fw_event->ignore)
2606 continue;
2607 local_event_data = fw_event->event_data;
2608 if (local_event_data->ExpStatus ==
2609 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
2610 local_event_data->ExpStatus ==
2611 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
2612 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
2613 expander_handle) {
2614 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
2615 "setting ignoring flag\n", ioc->name));
2616 fw_event->ignore = 1;
2617 }
2618 }
2619 }
2620 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2621}
2622
2623/**
Eric Moore635374e2009-03-09 01:21:12 -06002624 * _scsih_flush_running_cmds - completing outstanding commands.
2625 * @ioc: per adapter object
2626 *
2627 * The flushing out of all pending scmd commands following host reset,
2628 * where all IO is dropped to the floor.
2629 *
2630 * Return nothing.
2631 */
2632static void
2633_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
2634{
2635 struct scsi_cmnd *scmd;
2636 u16 smid;
2637 u16 count = 0;
2638
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302639 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
2640 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002641 if (!scmd)
2642 continue;
2643 count++;
2644 mpt2sas_base_free_smid(ioc, smid);
2645 scsi_dma_unmap(scmd);
2646 scmd->result = DID_RESET << 16;
2647 scmd->scsi_done(scmd);
2648 }
2649 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
2650 ioc->name, count));
2651}
2652
2653/**
Eric Moore3c621b32009-05-18 12:59:41 -06002654 * _scsih_setup_eedp - setup MPI request for EEDP transfer
2655 * @scmd: pointer to scsi command object
2656 * @mpi_request: pointer to the SCSI_IO reqest message frame
2657 *
2658 * Supporting protection 1 and 3.
2659 *
2660 * Returns nothing
2661 */
2662static void
2663_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
2664{
2665 u16 eedp_flags;
2666 unsigned char prot_op = scsi_get_prot_op(scmd);
2667 unsigned char prot_type = scsi_get_prot_type(scmd);
2668
2669 if (prot_type == SCSI_PROT_DIF_TYPE0 ||
2670 prot_type == SCSI_PROT_DIF_TYPE2 ||
2671 prot_op == SCSI_PROT_NORMAL)
2672 return;
2673
2674 if (prot_op == SCSI_PROT_READ_STRIP)
2675 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
2676 else if (prot_op == SCSI_PROT_WRITE_INSERT)
2677 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
2678 else
2679 return;
2680
2681 mpi_request->EEDPBlockSize = scmd->device->sector_size;
2682
2683 switch (prot_type) {
2684 case SCSI_PROT_DIF_TYPE1:
2685
2686 /*
2687 * enable ref/guard checking
2688 * auto increment ref tag
2689 */
2690 mpi_request->EEDPFlags = eedp_flags |
2691 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
2692 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2693 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2694 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
2695 cpu_to_be32(scsi_get_lba(scmd));
2696
2697 break;
2698
2699 case SCSI_PROT_DIF_TYPE3:
2700
2701 /*
2702 * enable guard checking
2703 */
2704 mpi_request->EEDPFlags = eedp_flags |
2705 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2706
2707 break;
2708 }
2709}
2710
2711/**
2712 * _scsih_eedp_error_handling - return sense code for EEDP errors
2713 * @scmd: pointer to scsi command object
2714 * @ioc_status: ioc status
2715 *
2716 * Returns nothing
2717 */
2718static void
2719_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
2720{
2721 u8 ascq;
2722 u8 sk;
2723 u8 host_byte;
2724
2725 switch (ioc_status) {
2726 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2727 ascq = 0x01;
2728 break;
2729 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2730 ascq = 0x02;
2731 break;
2732 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2733 ascq = 0x03;
2734 break;
2735 default:
2736 ascq = 0x00;
2737 break;
2738 }
2739
2740 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
2741 sk = ILLEGAL_REQUEST;
2742 host_byte = DID_ABORT;
2743 } else {
2744 sk = ABORTED_COMMAND;
2745 host_byte = DID_OK;
2746 }
2747
2748 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
2749 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
2750 SAM_STAT_CHECK_CONDITION;
2751}
2752
2753/**
Eric Moored5d135b2009-05-18 13:02:08 -06002754 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06002755 * @scmd: pointer to scsi command object
2756 * @done: function pointer to be invoked on completion
2757 *
2758 * The callback index is set inside `ioc->scsi_io_cb_idx`.
2759 *
2760 * Returns 0 on success. If there's a failure, return either:
2761 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
2762 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
2763 */
2764static int
Eric Moored5d135b2009-05-18 13:02:08 -06002765_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06002766{
2767 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2768 struct MPT2SAS_DEVICE *sas_device_priv_data;
2769 struct MPT2SAS_TARGET *sas_target_priv_data;
2770 Mpi2SCSIIORequest_t *mpi_request;
2771 u32 mpi_control;
2772 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06002773
2774 scmd->scsi_done = done;
2775 sas_device_priv_data = scmd->device->hostdata;
2776 if (!sas_device_priv_data) {
2777 scmd->result = DID_NO_CONNECT << 16;
2778 scmd->scsi_done(scmd);
2779 return 0;
2780 }
2781
2782 sas_target_priv_data = sas_device_priv_data->sas_target;
2783 if (!sas_target_priv_data || sas_target_priv_data->handle ==
2784 MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
2785 scmd->result = DID_NO_CONNECT << 16;
2786 scmd->scsi_done(scmd);
2787 return 0;
2788 }
2789
2790 /* see if we are busy with task managment stuff */
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302791 if (sas_target_priv_data->tm_busy)
2792 return SCSI_MLQUEUE_DEVICE_BUSY;
2793 else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06002794 return SCSI_MLQUEUE_HOST_BUSY;
Eric Moore635374e2009-03-09 01:21:12 -06002795
2796 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
2797 mpi_control = MPI2_SCSIIO_CONTROL_READ;
2798 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
2799 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
2800 else
2801 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
2802
2803 /* set tags */
2804 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
2805 if (scmd->device->tagged_supported) {
2806 if (scmd->device->ordered_tags)
2807 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
2808 else
2809 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2810 } else
2811/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
2812/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
2813 */
2814 mpi_control |= (0x500);
2815
2816 } else
2817 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2818
2819 if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
2820 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
2821
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302822 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002823 if (!smid) {
2824 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2825 ioc->name, __func__);
2826 goto out;
2827 }
2828 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2829 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06002830 _scsih_setup_eedp(scmd, mpi_request);
Eric Moore635374e2009-03-09 01:21:12 -06002831 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2832 if (sas_device_priv_data->sas_target->flags &
2833 MPT_TARGET_FLAGS_RAID_COMPONENT)
2834 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
2835 else
2836 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
2837 mpi_request->DevHandle =
2838 cpu_to_le16(sas_device_priv_data->sas_target->handle);
2839 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
2840 mpi_request->Control = cpu_to_le32(mpi_control);
2841 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
2842 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
2843 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
2844 mpi_request->SenseBufferLowAddress =
2845 (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
2846 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
2847 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
2848 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302849 mpi_request->VF_ID = 0; /* TODO */
2850 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06002851 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
2852 mpi_request->LUN);
2853 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
2854
2855 if (!mpi_request->DataLength) {
2856 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
2857 } else {
2858 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
2859 mpt2sas_base_free_smid(ioc, smid);
2860 goto out;
2861 }
2862 }
2863
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302864 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Eric Moore635374e2009-03-09 01:21:12 -06002865 sas_device_priv_data->sas_target->handle);
2866 return 0;
2867
2868 out:
2869 return SCSI_MLQUEUE_HOST_BUSY;
2870}
2871
2872/**
2873 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
2874 * @sense_buffer: sense data returned by target
2875 * @data: normalized skey/asc/ascq
2876 *
2877 * Return nothing.
2878 */
2879static void
2880_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
2881{
2882 if ((sense_buffer[0] & 0x7F) >= 0x72) {
2883 /* descriptor format */
2884 data->skey = sense_buffer[1] & 0x0F;
2885 data->asc = sense_buffer[2];
2886 data->ascq = sense_buffer[3];
2887 } else {
2888 /* fixed format */
2889 data->skey = sense_buffer[2] & 0x0F;
2890 data->asc = sense_buffer[12];
2891 data->ascq = sense_buffer[13];
2892 }
2893}
2894
2895#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
2896/**
2897 * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request
2898 * @ioc: per adapter object
2899 * @scmd: pointer to scsi command object
2900 * @mpi_reply: reply mf payload returned from firmware
2901 *
2902 * scsi_status - SCSI Status code returned from target device
2903 * scsi_state - state info associated with SCSI_IO determined by ioc
2904 * ioc_status - ioc supplied status info
2905 *
2906 * Return nothing.
2907 */
2908static void
2909_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
2910 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
2911{
2912 u32 response_info;
2913 u8 *response_bytes;
2914 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
2915 MPI2_IOCSTATUS_MASK;
2916 u8 scsi_state = mpi_reply->SCSIState;
2917 u8 scsi_status = mpi_reply->SCSIStatus;
2918 char *desc_ioc_state = NULL;
2919 char *desc_scsi_status = NULL;
2920 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05302921 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
2922
2923 if (log_info == 0x31170000)
2924 return;
Eric Moore635374e2009-03-09 01:21:12 -06002925
2926 switch (ioc_status) {
2927 case MPI2_IOCSTATUS_SUCCESS:
2928 desc_ioc_state = "success";
2929 break;
2930 case MPI2_IOCSTATUS_INVALID_FUNCTION:
2931 desc_ioc_state = "invalid function";
2932 break;
2933 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2934 desc_ioc_state = "scsi recovered error";
2935 break;
2936 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2937 desc_ioc_state = "scsi invalid dev handle";
2938 break;
2939 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2940 desc_ioc_state = "scsi device not there";
2941 break;
2942 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2943 desc_ioc_state = "scsi data overrun";
2944 break;
2945 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2946 desc_ioc_state = "scsi data underrun";
2947 break;
2948 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2949 desc_ioc_state = "scsi io data error";
2950 break;
2951 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2952 desc_ioc_state = "scsi protocol error";
2953 break;
2954 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2955 desc_ioc_state = "scsi task terminated";
2956 break;
2957 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2958 desc_ioc_state = "scsi residual mismatch";
2959 break;
2960 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2961 desc_ioc_state = "scsi task mgmt failed";
2962 break;
2963 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
2964 desc_ioc_state = "scsi ioc terminated";
2965 break;
2966 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
2967 desc_ioc_state = "scsi ext terminated";
2968 break;
Eric Moore3c621b32009-05-18 12:59:41 -06002969 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2970 desc_ioc_state = "eedp guard error";
2971 break;
2972 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2973 desc_ioc_state = "eedp ref tag error";
2974 break;
2975 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2976 desc_ioc_state = "eedp app tag error";
2977 break;
Eric Moore635374e2009-03-09 01:21:12 -06002978 default:
2979 desc_ioc_state = "unknown";
2980 break;
2981 }
2982
2983 switch (scsi_status) {
2984 case MPI2_SCSI_STATUS_GOOD:
2985 desc_scsi_status = "good";
2986 break;
2987 case MPI2_SCSI_STATUS_CHECK_CONDITION:
2988 desc_scsi_status = "check condition";
2989 break;
2990 case MPI2_SCSI_STATUS_CONDITION_MET:
2991 desc_scsi_status = "condition met";
2992 break;
2993 case MPI2_SCSI_STATUS_BUSY:
2994 desc_scsi_status = "busy";
2995 break;
2996 case MPI2_SCSI_STATUS_INTERMEDIATE:
2997 desc_scsi_status = "intermediate";
2998 break;
2999 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
3000 desc_scsi_status = "intermediate condmet";
3001 break;
3002 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
3003 desc_scsi_status = "reservation conflict";
3004 break;
3005 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
3006 desc_scsi_status = "command terminated";
3007 break;
3008 case MPI2_SCSI_STATUS_TASK_SET_FULL:
3009 desc_scsi_status = "task set full";
3010 break;
3011 case MPI2_SCSI_STATUS_ACA_ACTIVE:
3012 desc_scsi_status = "aca active";
3013 break;
3014 case MPI2_SCSI_STATUS_TASK_ABORTED:
3015 desc_scsi_status = "task aborted";
3016 break;
3017 default:
3018 desc_scsi_status = "unknown";
3019 break;
3020 }
3021
3022 desc_scsi_state[0] = '\0';
3023 if (!scsi_state)
3024 desc_scsi_state = " ";
3025 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3026 strcat(desc_scsi_state, "response info ");
3027 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3028 strcat(desc_scsi_state, "state terminated ");
3029 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
3030 strcat(desc_scsi_state, "no status ");
3031 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
3032 strcat(desc_scsi_state, "autosense failed ");
3033 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
3034 strcat(desc_scsi_state, "autosense valid ");
3035
3036 scsi_print_command(scmd);
3037 printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
3038 "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
3039 le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
3040 ioc_status, smid);
3041 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
3042 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
3043 scsi_get_resid(scmd));
3044 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
3045 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
3046 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
3047 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
3048 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
3049 scsi_status, desc_scsi_state, scsi_state);
3050
3051 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3052 struct sense_info data;
3053 _scsih_normalize_sense(scmd->sense_buffer, &data);
3054 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
3055 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey,
3056 data.asc, data.ascq);
3057 }
3058
3059 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
3060 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
3061 response_bytes = (u8 *)&response_info;
3062 _scsih_response_code(ioc, response_bytes[3]);
3063 }
3064}
3065#endif
3066
3067/**
3068 * _scsih_smart_predicted_fault - illuminate Fault LED
3069 * @ioc: per adapter object
3070 * @handle: device handle
3071 *
3072 * Return nothing.
3073 */
3074static void
3075_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3076{
3077 Mpi2SepReply_t mpi_reply;
3078 Mpi2SepRequest_t mpi_request;
3079 struct scsi_target *starget;
3080 struct MPT2SAS_TARGET *sas_target_priv_data;
3081 Mpi2EventNotificationReply_t *event_reply;
3082 Mpi2EventDataSasDeviceStatusChange_t *event_data;
3083 struct _sas_device *sas_device;
3084 ssize_t sz;
3085 unsigned long flags;
3086
3087 /* only handle non-raid devices */
3088 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3089 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3090 if (!sas_device) {
3091 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3092 return;
3093 }
3094 starget = sas_device->starget;
3095 sas_target_priv_data = starget->hostdata;
3096
3097 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
3098 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
3099 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3100 return;
3101 }
3102 starget_printk(KERN_WARNING, starget, "predicted fault\n");
3103 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3104
3105 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
3106 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
3107 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
3108 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
3109 mpi_request.SlotStatus =
3110 MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
3111 mpi_request.DevHandle = cpu_to_le16(handle);
3112 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
3113 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
3114 &mpi_request)) != 0) {
3115 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3116 ioc->name, __FILE__, __LINE__, __func__);
3117 return;
3118 }
3119
3120 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
3121 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3122 "enclosure_processor: ioc_status (0x%04x), "
3123 "loginfo(0x%08x)\n", ioc->name,
3124 le16_to_cpu(mpi_reply.IOCStatus),
3125 le32_to_cpu(mpi_reply.IOCLogInfo)));
3126 return;
3127 }
3128 }
3129
3130 /* insert into event log */
3131 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
3132 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
3133 event_reply = kzalloc(sz, GFP_KERNEL);
3134 if (!event_reply) {
3135 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3136 ioc->name, __FILE__, __LINE__, __func__);
3137 return;
3138 }
3139
3140 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
3141 event_reply->Event =
3142 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
3143 event_reply->MsgLength = sz/4;
3144 event_reply->EventDataLength =
3145 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
3146 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
3147 event_reply->EventData;
3148 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
3149 event_data->ASC = 0x5D;
3150 event_data->DevHandle = cpu_to_le16(handle);
3151 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
3152 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
3153 kfree(event_reply);
3154}
3155
3156/**
Eric Moored5d135b2009-05-18 13:02:08 -06003157 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06003158 * @ioc: per adapter object
3159 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303160 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06003161 * @reply: reply message frame(lower 32bit addr)
3162 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303163 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06003164 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303165 * Return 1 meaning mf should be freed from _base_interrupt
3166 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06003167 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303168static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303169_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06003170{
3171 Mpi2SCSIIORequest_t *mpi_request;
3172 Mpi2SCSIIOReply_t *mpi_reply;
3173 struct scsi_cmnd *scmd;
3174 u16 ioc_status;
3175 u32 xfer_cnt;
3176 u8 scsi_state;
3177 u8 scsi_status;
3178 u32 log_info;
3179 struct MPT2SAS_DEVICE *sas_device_priv_data;
3180 u32 response_code;
3181
3182 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303183 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003184 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303185 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003186
3187 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3188
3189 if (mpi_reply == NULL) {
3190 scmd->result = DID_OK << 16;
3191 goto out;
3192 }
3193
3194 sas_device_priv_data = scmd->device->hostdata;
3195 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
3196 sas_device_priv_data->sas_target->deleted) {
3197 scmd->result = DID_NO_CONNECT << 16;
3198 goto out;
3199 }
3200
3201 /* turning off TLR */
3202 if (!sas_device_priv_data->tlr_snoop_check) {
3203 sas_device_priv_data->tlr_snoop_check++;
3204 if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) {
3205 response_code = (le32_to_cpu(mpi_reply->ResponseInfo)
3206 >> 24);
3207 if (response_code ==
3208 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
3209 sas_device_priv_data->flags &=
3210 ~MPT_DEVICE_TLR_ON;
3211 }
3212 }
3213
3214 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
3215 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
3216 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
3217 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
3218 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3219 else
3220 log_info = 0;
3221 ioc_status &= MPI2_IOCSTATUS_MASK;
3222 scsi_state = mpi_reply->SCSIState;
3223 scsi_status = mpi_reply->SCSIStatus;
3224
3225 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
3226 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
3227 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
3228 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
3229 ioc_status = MPI2_IOCSTATUS_SUCCESS;
3230 }
3231
3232 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3233 struct sense_info data;
3234 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
3235 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06003236 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06003237 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06003238 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06003239 _scsih_normalize_sense(scmd->sense_buffer, &data);
3240 /* failure prediction threshold exceeded */
3241 if (data.asc == 0x5D)
3242 _scsih_smart_predicted_fault(ioc,
3243 le16_to_cpu(mpi_reply->DevHandle));
3244 }
3245
3246 switch (ioc_status) {
3247 case MPI2_IOCSTATUS_BUSY:
3248 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3249 scmd->result = SAM_STAT_BUSY;
3250 break;
3251
3252 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3253 scmd->result = DID_NO_CONNECT << 16;
3254 break;
3255
3256 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3257 if (sas_device_priv_data->block) {
3258 scmd->result = (DID_BUS_BUSY << 16);
3259 break;
3260 }
3261
3262 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3263 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3264 scmd->result = DID_RESET << 16;
3265 break;
3266
3267 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3268 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3269 scmd->result = DID_SOFT_ERROR << 16;
3270 else
3271 scmd->result = (DID_OK << 16) | scsi_status;
3272 break;
3273
3274 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3275 scmd->result = (DID_OK << 16) | scsi_status;
3276
3277 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3278 break;
3279
3280 if (xfer_cnt < scmd->underflow) {
3281 if (scsi_status == SAM_STAT_BUSY)
3282 scmd->result = SAM_STAT_BUSY;
3283 else
3284 scmd->result = DID_SOFT_ERROR << 16;
3285 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3286 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3287 scmd->result = DID_SOFT_ERROR << 16;
3288 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3289 scmd->result = DID_RESET << 16;
3290 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3291 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3292 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3293 scmd->result = (DRIVER_SENSE << 24) |
3294 SAM_STAT_CHECK_CONDITION;
3295 scmd->sense_buffer[0] = 0x70;
3296 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3297 scmd->sense_buffer[12] = 0x20;
3298 scmd->sense_buffer[13] = 0;
3299 }
3300 break;
3301
3302 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3303 scsi_set_resid(scmd, 0);
3304 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3305 case MPI2_IOCSTATUS_SUCCESS:
3306 scmd->result = (DID_OK << 16) | scsi_status;
3307 if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3308 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3309 scmd->result = DID_SOFT_ERROR << 16;
3310 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3311 scmd->result = DID_RESET << 16;
3312 break;
3313
Eric Moore3c621b32009-05-18 12:59:41 -06003314 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3315 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3316 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3317 _scsih_eedp_error_handling(scmd, ioc_status);
3318 break;
Eric Moore635374e2009-03-09 01:21:12 -06003319 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3320 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3321 case MPI2_IOCSTATUS_INVALID_SGL:
3322 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3323 case MPI2_IOCSTATUS_INVALID_FIELD:
3324 case MPI2_IOCSTATUS_INVALID_STATE:
3325 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3326 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3327 default:
3328 scmd->result = DID_SOFT_ERROR << 16;
3329 break;
3330
3331 }
3332
3333#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3334 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3335 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3336#endif
3337
3338 out:
3339 scsi_dma_unmap(scmd);
3340 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303341 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003342}
3343
3344/**
Eric Moore635374e2009-03-09 01:21:12 -06003345 * _scsih_sas_host_refresh - refreshing sas host object contents
3346 * @ioc: per adapter object
3347 * @update: update link information
3348 * Context: user
3349 *
3350 * During port enable, fw will send topology events for every device. Its
3351 * possible that the handles may change from the previous setting, so this
3352 * code keeping handles updating if changed.
3353 *
3354 * Return nothing.
3355 */
3356static void
3357_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update)
3358{
3359 u16 sz;
3360 u16 ioc_status;
3361 int i;
3362 Mpi2ConfigReply_t mpi_reply;
3363 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3364
3365 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3366 "updating handles for sas_host(0x%016llx)\n",
3367 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3368
3369 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3370 * sizeof(Mpi2SasIOUnit0PhyData_t));
3371 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3372 if (!sas_iounit_pg0) {
3373 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3374 ioc->name, __FILE__, __LINE__, __func__);
3375 return;
3376 }
3377 if (!(mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3378 sas_iounit_pg0, sz))) {
3379 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3380 MPI2_IOCSTATUS_MASK;
3381 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3382 goto out;
3383 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3384 ioc->sas_hba.phy[i].handle =
3385 le16_to_cpu(sas_iounit_pg0->PhyData[i].
3386 ControllerDevHandle);
3387 if (update)
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05303388 mpt2sas_transport_update_links(
3389 ioc,
Eric Moore635374e2009-03-09 01:21:12 -06003390 ioc->sas_hba.phy[i].handle,
3391 le16_to_cpu(sas_iounit_pg0->PhyData[i].
3392 AttachedDevHandle), i,
3393 sas_iounit_pg0->PhyData[i].
3394 NegotiatedLinkRate >> 4);
3395 }
3396 }
3397
3398 out:
3399 kfree(sas_iounit_pg0);
3400}
3401
3402/**
3403 * _scsih_sas_host_add - create sas host object
3404 * @ioc: per adapter object
3405 *
3406 * Creating host side data object, stored in ioc->sas_hba
3407 *
3408 * Return nothing.
3409 */
3410static void
3411_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3412{
3413 int i;
3414 Mpi2ConfigReply_t mpi_reply;
3415 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3416 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3417 Mpi2SasPhyPage0_t phy_pg0;
3418 Mpi2SasDevicePage0_t sas_device_pg0;
3419 Mpi2SasEnclosurePage0_t enclosure_pg0;
3420 u16 ioc_status;
3421 u16 sz;
3422 u16 device_missing_delay;
3423
3424 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3425 if (!ioc->sas_hba.num_phys) {
3426 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3427 ioc->name, __FILE__, __LINE__, __func__);
3428 return;
3429 }
3430
3431 /* sas_iounit page 0 */
3432 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3433 sizeof(Mpi2SasIOUnit0PhyData_t));
3434 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3435 if (!sas_iounit_pg0) {
3436 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3437 ioc->name, __FILE__, __LINE__, __func__);
3438 return;
3439 }
3440 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3441 sas_iounit_pg0, sz))) {
3442 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3443 ioc->name, __FILE__, __LINE__, __func__);
3444 goto out;
3445 }
3446 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3447 MPI2_IOCSTATUS_MASK;
3448 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3449 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3450 ioc->name, __FILE__, __LINE__, __func__);
3451 goto out;
3452 }
3453
3454 /* sas_iounit page 1 */
3455 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3456 sizeof(Mpi2SasIOUnit1PhyData_t));
3457 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3458 if (!sas_iounit_pg1) {
3459 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3460 ioc->name, __FILE__, __LINE__, __func__);
3461 goto out;
3462 }
3463 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3464 sas_iounit_pg1, sz))) {
3465 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3466 ioc->name, __FILE__, __LINE__, __func__);
3467 goto out;
3468 }
3469 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3470 MPI2_IOCSTATUS_MASK;
3471 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3472 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3473 ioc->name, __FILE__, __LINE__, __func__);
3474 goto out;
3475 }
3476
3477 ioc->io_missing_delay =
3478 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3479 device_missing_delay =
3480 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3481 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3482 ioc->device_missing_delay = (device_missing_delay &
3483 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3484 else
3485 ioc->device_missing_delay = device_missing_delay &
3486 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3487
3488 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3489 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3490 sizeof(struct _sas_phy), GFP_KERNEL);
3491 if (!ioc->sas_hba.phy) {
3492 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3493 ioc->name, __FILE__, __LINE__, __func__);
3494 goto out;
3495 }
3496 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3497 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3498 i))) {
3499 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3500 ioc->name, __FILE__, __LINE__, __func__);
3501 goto out;
3502 }
3503 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3504 MPI2_IOCSTATUS_MASK;
3505 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3506 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3507 ioc->name, __FILE__, __LINE__, __func__);
3508 goto out;
3509 }
3510 ioc->sas_hba.phy[i].handle =
3511 le16_to_cpu(sas_iounit_pg0->PhyData[i].ControllerDevHandle);
3512 ioc->sas_hba.phy[i].phy_id = i;
3513 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3514 phy_pg0, ioc->sas_hba.parent_dev);
3515 }
3516 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
3517 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.phy[0].handle))) {
3518 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3519 ioc->name, __FILE__, __LINE__, __func__);
3520 goto out;
3521 }
3522 ioc->sas_hba.handle = le16_to_cpu(sas_device_pg0.DevHandle);
3523 ioc->sas_hba.enclosure_handle =
3524 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3525 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3526 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3527 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3528 (unsigned long long) ioc->sas_hba.sas_address,
3529 ioc->sas_hba.num_phys) ;
3530
3531 if (ioc->sas_hba.enclosure_handle) {
3532 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3533 &enclosure_pg0,
3534 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3535 ioc->sas_hba.enclosure_handle))) {
3536 ioc->sas_hba.enclosure_logical_id =
3537 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3538 }
3539 }
3540
3541 out:
3542 kfree(sas_iounit_pg1);
3543 kfree(sas_iounit_pg0);
3544}
3545
3546/**
3547 * _scsih_expander_add - creating expander object
3548 * @ioc: per adapter object
3549 * @handle: expander handle
3550 *
3551 * Creating expander object, stored in ioc->sas_expander_list.
3552 *
3553 * Return 0 for success, else error.
3554 */
3555static int
3556_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3557{
3558 struct _sas_node *sas_expander;
3559 Mpi2ConfigReply_t mpi_reply;
3560 Mpi2ExpanderPage0_t expander_pg0;
3561 Mpi2ExpanderPage1_t expander_pg1;
3562 Mpi2SasEnclosurePage0_t enclosure_pg0;
3563 u32 ioc_status;
3564 u16 parent_handle;
3565 __le64 sas_address;
3566 int i;
3567 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303568 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003569 int rc = 0;
3570
3571 if (!handle)
3572 return -1;
3573
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303574 if (ioc->shost_recovery)
3575 return -1;
3576
Eric Moore635374e2009-03-09 01:21:12 -06003577 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3578 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3579 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3580 ioc->name, __FILE__, __LINE__, __func__);
3581 return -1;
3582 }
3583
3584 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3585 MPI2_IOCSTATUS_MASK;
3586 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3587 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3588 ioc->name, __FILE__, __LINE__, __func__);
3589 return -1;
3590 }
3591
3592 /* handle out of order topology events */
3593 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
3594 if (parent_handle >= ioc->sas_hba.num_phys) {
3595 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3596 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
3597 parent_handle);
3598 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3599 if (!sas_expander) {
3600 rc = _scsih_expander_add(ioc, parent_handle);
3601 if (rc != 0)
3602 return rc;
3603 }
3604 }
3605
Eric Moore635374e2009-03-09 01:21:12 -06003606 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303607 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06003608 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3609 sas_address);
3610 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3611
3612 if (sas_expander)
3613 return 0;
3614
3615 sas_expander = kzalloc(sizeof(struct _sas_node),
3616 GFP_KERNEL);
3617 if (!sas_expander) {
3618 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3619 ioc->name, __FILE__, __LINE__, __func__);
3620 return -1;
3621 }
3622
3623 sas_expander->handle = handle;
3624 sas_expander->num_phys = expander_pg0.NumPhys;
3625 sas_expander->parent_handle = parent_handle;
3626 sas_expander->enclosure_handle =
3627 le16_to_cpu(expander_pg0.EnclosureHandle);
3628 sas_expander->sas_address = sas_address;
3629
3630 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3631 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
3632 handle, sas_expander->parent_handle, (unsigned long long)
3633 sas_expander->sas_address, sas_expander->num_phys);
3634
3635 if (!sas_expander->num_phys)
3636 goto out_fail;
3637 sas_expander->phy = kcalloc(sas_expander->num_phys,
3638 sizeof(struct _sas_phy), GFP_KERNEL);
3639 if (!sas_expander->phy) {
3640 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3641 ioc->name, __FILE__, __LINE__, __func__);
3642 rc = -1;
3643 goto out_fail;
3644 }
3645
3646 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3647 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
3648 sas_expander->parent_handle);
3649 if (!mpt2sas_port) {
3650 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3651 ioc->name, __FILE__, __LINE__, __func__);
3652 rc = -1;
3653 goto out_fail;
3654 }
3655 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3656
3657 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3658 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3659 &expander_pg1, i, handle))) {
3660 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3661 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303662 rc = -1;
3663 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003664 }
3665 sas_expander->phy[i].handle = handle;
3666 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303667
3668 if ((mpt2sas_transport_add_expander_phy(ioc,
3669 &sas_expander->phy[i], expander_pg1,
3670 sas_expander->parent_dev))) {
3671 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3672 ioc->name, __FILE__, __LINE__, __func__);
3673 rc = -1;
3674 goto out_fail;
3675 }
Eric Moore635374e2009-03-09 01:21:12 -06003676 }
3677
3678 if (sas_expander->enclosure_handle) {
3679 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3680 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3681 sas_expander->enclosure_handle))) {
3682 sas_expander->enclosure_logical_id =
3683 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3684 }
3685 }
3686
3687 _scsih_expander_node_add(ioc, sas_expander);
3688 return 0;
3689
3690 out_fail:
3691
Kashyap, Desai20f58952009-08-07 19:34:26 +05303692 if (mpt2sas_port)
3693 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
3694 sas_expander->parent_handle);
Eric Moore635374e2009-03-09 01:21:12 -06003695 kfree(sas_expander);
3696 return rc;
3697}
3698
3699/**
3700 * _scsih_expander_remove - removing expander object
3701 * @ioc: per adapter object
3702 * @handle: expander handle
3703 *
3704 * Return nothing.
3705 */
3706static void
3707_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3708{
3709 struct _sas_node *sas_expander;
3710 unsigned long flags;
3711
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303712 if (ioc->shost_recovery)
3713 return;
3714
Eric Moore635374e2009-03-09 01:21:12 -06003715 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3716 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle);
3717 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3718 _scsih_expander_node_remove(ioc, sas_expander);
3719}
3720
3721/**
3722 * _scsih_add_device - creating sas device object
3723 * @ioc: per adapter object
3724 * @handle: sas device handle
3725 * @phy_num: phy number end device attached to
3726 * @is_pd: is this hidden raid component
3727 *
3728 * Creating end device object, stored in ioc->sas_device_list.
3729 *
3730 * Returns 0 for success, non-zero for failure.
3731 */
3732static int
3733_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
3734{
3735 Mpi2ConfigReply_t mpi_reply;
3736 Mpi2SasDevicePage0_t sas_device_pg0;
3737 Mpi2SasEnclosurePage0_t enclosure_pg0;
3738 struct _sas_device *sas_device;
3739 u32 ioc_status;
3740 __le64 sas_address;
3741 u32 device_info;
3742 unsigned long flags;
3743
3744 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
3745 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
3746 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3747 ioc->name, __FILE__, __LINE__, __func__);
3748 return -1;
3749 }
3750
3751 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3752 MPI2_IOCSTATUS_MASK;
3753 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3754 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3755 ioc->name, __FILE__, __LINE__, __func__);
3756 return -1;
3757 }
3758
3759 /* check if device is present */
3760 if (!(le16_to_cpu(sas_device_pg0.Flags) &
3761 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
3762 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3763 ioc->name, __FILE__, __LINE__, __func__);
3764 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
3765 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
3766 return -1;
3767 }
3768
3769 /* check if there were any issus with discovery */
3770 if (sas_device_pg0.AccessStatus ==
3771 MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
3772 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3773 ioc->name, __FILE__, __LINE__, __func__);
3774 printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
3775 ioc->name, sas_device_pg0.AccessStatus);
3776 return -1;
3777 }
3778
3779 /* check if this is end device */
3780 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
3781 if (!(_scsih_is_end_device(device_info))) {
3782 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3783 ioc->name, __FILE__, __LINE__, __func__);
3784 return -1;
3785 }
3786
3787 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3788
3789 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3790 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
3791 sas_address);
3792 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3793
3794 if (sas_device) {
3795 _scsih_ublock_io_device(ioc, handle);
3796 return 0;
3797 }
3798
3799 sas_device = kzalloc(sizeof(struct _sas_device),
3800 GFP_KERNEL);
3801 if (!sas_device) {
3802 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3803 ioc->name, __FILE__, __LINE__, __func__);
3804 return -1;
3805 }
3806
3807 sas_device->handle = handle;
3808 sas_device->parent_handle =
3809 le16_to_cpu(sas_device_pg0.ParentDevHandle);
3810 sas_device->enclosure_handle =
3811 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3812 sas_device->slot =
3813 le16_to_cpu(sas_device_pg0.Slot);
3814 sas_device->device_info = device_info;
3815 sas_device->sas_address = sas_address;
3816 sas_device->hidden_raid_component = is_pd;
3817
3818 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05303819 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
3820 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3821 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06003822 sas_device->enclosure_logical_id =
3823 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06003824
3825 /* get device name */
3826 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
3827
3828 if (ioc->wait_for_port_enable_to_complete)
3829 _scsih_sas_device_init_add(ioc, sas_device);
3830 else
3831 _scsih_sas_device_add(ioc, sas_device);
3832
3833 return 0;
3834}
3835
3836/**
3837 * _scsih_remove_device - removing sas device object
3838 * @ioc: per adapter object
3839 * @handle: sas device handle
3840 *
3841 * Return nothing.
3842 */
3843static void
3844_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3845{
3846 struct MPT2SAS_TARGET *sas_target_priv_data;
3847 struct _sas_device *sas_device;
3848 unsigned long flags;
3849 Mpi2SasIoUnitControlReply_t mpi_reply;
3850 Mpi2SasIoUnitControlRequest_t mpi_request;
3851 u16 device_handle;
3852
3853 /* lookup sas_device */
3854 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3855 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3856 if (!sas_device) {
3857 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3858 return;
3859 }
3860
3861 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle"
3862 "(0x%04x)\n", ioc->name, __func__, handle));
3863
3864 if (sas_device->starget && sas_device->starget->hostdata) {
3865 sas_target_priv_data = sas_device->starget->hostdata;
3866 sas_target_priv_data->deleted = 1;
3867 }
3868 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3869
3870 if (ioc->remove_host)
3871 goto out;
3872
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303873 if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
3874 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
3875 "target_reset handle(0x%04x)\n", ioc->name, handle));
3876 goto skip_tr;
3877 }
3878
Eric Moore635374e2009-03-09 01:21:12 -06003879 /* Target Reset to flush out all the outstanding IO */
3880 device_handle = (sas_device->hidden_raid_component) ?
3881 sas_device->volume_handle : handle;
3882 if (device_handle) {
3883 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
3884 "handle(0x%04x)\n", ioc->name, device_handle));
3885 mutex_lock(&ioc->tm_cmds.mutex);
3886 mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
3887 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
3888 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
3889 mutex_unlock(&ioc->tm_cmds.mutex);
3890 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
3891 "done: handle(0x%04x)\n", ioc->name, device_handle));
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303892 if (ioc->shost_recovery)
3893 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003894 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303895 skip_tr:
3896
3897 if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) {
3898 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
3899 "sas_cntrl handle(0x%04x)\n", ioc->name, handle));
3900 goto out;
3901 }
Eric Moore635374e2009-03-09 01:21:12 -06003902
3903 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
3904 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
3905 "(0x%04x)\n", ioc->name, handle));
3906 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
3907 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
3908 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
3909 mpi_request.DevHandle = handle;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303910 mpi_request.VF_ID = 0; /* TODO */
3911 mpi_request.VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003912 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
3913 &mpi_request)) != 0) {
3914 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3915 ioc->name, __FILE__, __LINE__, __func__);
3916 }
3917
3918 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
3919 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
3920 le16_to_cpu(mpi_reply.IOCStatus),
3921 le32_to_cpu(mpi_reply.IOCLogInfo)));
3922
3923 out:
Kashyap, Desai34a03be2009-08-20 13:23:19 +05303924
3925 _scsih_ublock_io_device(ioc, handle);
3926
Eric Moore635374e2009-03-09 01:21:12 -06003927 mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
3928 sas_device->parent_handle);
3929
3930 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
3931 "(0x%016llx)\n", ioc->name, sas_device->handle,
3932 (unsigned long long) sas_device->sas_address);
3933 _scsih_sas_device_remove(ioc, sas_device);
3934
3935 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
3936 "(0x%04x)\n", ioc->name, __func__, handle));
3937}
3938
3939#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3940/**
3941 * _scsih_sas_topology_change_event_debug - debug for topology event
3942 * @ioc: per adapter object
3943 * @event_data: event data payload
3944 * Context: user.
3945 */
3946static void
3947_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
3948 Mpi2EventDataSasTopologyChangeList_t *event_data)
3949{
3950 int i;
3951 u16 handle;
3952 u16 reason_code;
3953 u8 phy_number;
3954 char *status_str = NULL;
3955 char link_rate[25];
3956
3957 switch (event_data->ExpStatus) {
3958 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
3959 status_str = "add";
3960 break;
3961 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
3962 status_str = "remove";
3963 break;
3964 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
3965 status_str = "responding";
3966 break;
3967 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
3968 status_str = "remove delay";
3969 break;
3970 default:
3971 status_str = "unknown status";
3972 break;
3973 }
3974 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
3975 ioc->name, status_str);
3976 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
3977 "start_phy(%02d), count(%d)\n",
3978 le16_to_cpu(event_data->ExpanderDevHandle),
3979 le16_to_cpu(event_data->EnclosureHandle),
3980 event_data->StartPhyNum, event_data->NumEntries);
3981 for (i = 0; i < event_data->NumEntries; i++) {
3982 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
3983 if (!handle)
3984 continue;
3985 phy_number = event_data->StartPhyNum + i;
3986 reason_code = event_data->PHY[i].PhyStatus &
3987 MPI2_EVENT_SAS_TOPO_RC_MASK;
3988 switch (reason_code) {
3989 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
3990 snprintf(link_rate, 25, ": add, link(0x%02x)",
3991 (event_data->PHY[i].LinkRate >> 4));
3992 status_str = link_rate;
3993 break;
3994 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
3995 status_str = ": remove";
3996 break;
3997 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
3998 status_str = ": remove_delay";
3999 break;
4000 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
4001 snprintf(link_rate, 25, ": link(0x%02x)",
4002 (event_data->PHY[i].LinkRate >> 4));
4003 status_str = link_rate;
4004 break;
4005 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
4006 status_str = ": responding";
4007 break;
4008 default:
4009 status_str = ": unknown";
4010 break;
4011 }
4012 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n",
4013 phy_number, handle, status_str);
4014 }
4015}
4016#endif
4017
4018/**
4019 * _scsih_sas_topology_change_event - handle topology changes
4020 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304021 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004022 * Context: user.
4023 *
4024 */
4025static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304026_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06004027 struct fw_event_work *fw_event)
4028{
4029 int i;
4030 u16 parent_handle, handle;
4031 u16 reason_code;
4032 u8 phy_number;
4033 struct _sas_node *sas_expander;
4034 unsigned long flags;
4035 u8 link_rate_;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304036 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004037
4038#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4039 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4040 _scsih_sas_topology_change_event_debug(ioc, event_data);
4041#endif
4042
4043 if (!ioc->sas_hba.num_phys)
4044 _scsih_sas_host_add(ioc);
4045 else
4046 _scsih_sas_host_refresh(ioc, 0);
4047
4048 if (fw_event->ignore) {
4049 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
4050 "event\n", ioc->name));
4051 return;
4052 }
4053
4054 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
4055
4056 /* handle expander add */
4057 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
4058 if (_scsih_expander_add(ioc, parent_handle) != 0)
4059 return;
4060
4061 /* handle siblings events */
4062 for (i = 0; i < event_data->NumEntries; i++) {
4063 if (fw_event->ignore) {
4064 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
4065 "expander event\n", ioc->name));
4066 return;
4067 }
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304068 if (ioc->shost_recovery)
4069 return;
Eric Moore635374e2009-03-09 01:21:12 -06004070 if (event_data->PHY[i].PhyStatus &
4071 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
4072 continue;
4073 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4074 if (!handle)
4075 continue;
4076 phy_number = event_data->StartPhyNum + i;
4077 reason_code = event_data->PHY[i].PhyStatus &
4078 MPI2_EVENT_SAS_TOPO_RC_MASK;
4079 link_rate_ = event_data->PHY[i].LinkRate >> 4;
4080 switch (reason_code) {
4081 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
4082 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
4083 if (!parent_handle) {
4084 if (phy_number < ioc->sas_hba.num_phys)
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05304085 mpt2sas_transport_update_links(
4086 ioc,
4087 ioc->sas_hba.phy[phy_number].handle,
4088 handle, phy_number, link_rate_);
Eric Moore635374e2009-03-09 01:21:12 -06004089 } else {
4090 spin_lock_irqsave(&ioc->sas_node_lock, flags);
4091 sas_expander =
4092 mpt2sas_scsih_expander_find_by_handle(ioc,
4093 parent_handle);
4094 spin_unlock_irqrestore(&ioc->sas_node_lock,
4095 flags);
4096 if (sas_expander) {
4097 if (phy_number < sas_expander->num_phys)
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05304098 mpt2sas_transport_update_links(
4099 ioc,
4100 sas_expander->
4101 phy[phy_number].handle,
4102 handle, phy_number,
4103 link_rate_);
Eric Moore635374e2009-03-09 01:21:12 -06004104 }
4105 }
Eric Moore635374e2009-03-09 01:21:12 -06004106 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
4107 if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5)
4108 break;
4109 _scsih_add_device(ioc, handle, phy_number, 0);
4110 }
4111 break;
4112 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
4113 _scsih_remove_device(ioc, handle);
4114 break;
4115 }
4116 }
4117
4118 /* handle expander removal */
4119 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
4120 _scsih_expander_remove(ioc, parent_handle);
4121
4122}
4123
4124#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4125/**
4126 * _scsih_sas_device_status_change_event_debug - debug for device event
4127 * @event_data: event data payload
4128 * Context: user.
4129 *
4130 * Return nothing.
4131 */
4132static void
4133_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4134 Mpi2EventDataSasDeviceStatusChange_t *event_data)
4135{
4136 char *reason_str = NULL;
4137
4138 switch (event_data->ReasonCode) {
4139 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
4140 reason_str = "smart data";
4141 break;
4142 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
4143 reason_str = "unsupported device discovered";
4144 break;
4145 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
4146 reason_str = "internal device reset";
4147 break;
4148 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
4149 reason_str = "internal task abort";
4150 break;
4151 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
4152 reason_str = "internal task abort set";
4153 break;
4154 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
4155 reason_str = "internal clear task set";
4156 break;
4157 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
4158 reason_str = "internal query task";
4159 break;
4160 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
4161 reason_str = "sata init failure";
4162 break;
4163 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
4164 reason_str = "internal device reset complete";
4165 break;
4166 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
4167 reason_str = "internal task abort complete";
4168 break;
4169 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
4170 reason_str = "internal async notification";
4171 break;
4172 default:
4173 reason_str = "unknown reason";
4174 break;
4175 }
4176 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
4177 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
4178 reason_str, le16_to_cpu(event_data->DevHandle),
4179 (unsigned long long)le64_to_cpu(event_data->SASAddress));
4180 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
4181 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
4182 event_data->ASC, event_data->ASCQ);
4183 printk(KERN_INFO "\n");
4184}
4185#endif
4186
4187/**
4188 * _scsih_sas_device_status_change_event - handle device status change
4189 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304190 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004191 * Context: user.
4192 *
4193 * Return nothing.
4194 */
4195static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304196_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
4197 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004198{
4199#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4200 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304201 _scsih_sas_device_status_change_event_debug(ioc,
4202 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004203#endif
4204}
4205
4206#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4207/**
4208 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
4209 * @ioc: per adapter object
4210 * @event_data: event data payload
4211 * Context: user.
4212 *
4213 * Return nothing.
4214 */
4215static void
4216_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4217 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
4218{
4219 char *reason_str = NULL;
4220
4221 switch (event_data->ReasonCode) {
4222 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
4223 reason_str = "enclosure add";
4224 break;
4225 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
4226 reason_str = "enclosure remove";
4227 break;
4228 default:
4229 reason_str = "unknown reason";
4230 break;
4231 }
4232
4233 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
4234 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
4235 " number slots(%d)\n", ioc->name, reason_str,
4236 le16_to_cpu(event_data->EnclosureHandle),
4237 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
4238 le16_to_cpu(event_data->StartSlot));
4239}
4240#endif
4241
4242/**
4243 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
4244 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304245 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004246 * Context: user.
4247 *
4248 * Return nothing.
4249 */
4250static void
4251_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304252 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004253{
4254#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4255 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4256 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304257 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004258#endif
4259}
4260
4261/**
4262 * _scsih_sas_broadcast_primative_event - handle broadcast events
4263 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304264 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004265 * Context: user.
4266 *
4267 * Return nothing.
4268 */
4269static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304270_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4271 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004272{
4273 struct scsi_cmnd *scmd;
4274 u16 smid, handle;
4275 u32 lun;
4276 struct MPT2SAS_DEVICE *sas_device_priv_data;
4277 u32 termination_count;
4278 u32 query_count;
4279 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304280#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4281 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4282#endif
Eric Moore635374e2009-03-09 01:21:12 -06004283 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4284 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4285 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004286 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4287 __func__));
4288
4289 mutex_lock(&ioc->tm_cmds.mutex);
4290 termination_count = 0;
4291 query_count = 0;
4292 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304293 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06004294 scmd = _scsih_scsi_lookup_get(ioc, smid);
4295 if (!scmd)
4296 continue;
4297 sas_device_priv_data = scmd->device->hostdata;
4298 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4299 continue;
4300 /* skip hidden raid components */
4301 if (sas_device_priv_data->sas_target->flags &
4302 MPT_TARGET_FLAGS_RAID_COMPONENT)
4303 continue;
4304 /* skip volumes */
4305 if (sas_device_priv_data->sas_target->flags &
4306 MPT_TARGET_FLAGS_VOLUME)
4307 continue;
4308
4309 handle = sas_device_priv_data->sas_target->handle;
4310 lun = sas_device_priv_data->lun;
4311 query_count++;
4312
4313 mpt2sas_scsih_issue_tm(ioc, handle, lun,
4314 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
Eric Moore8901cbb2009-04-21 15:41:32 -06004315 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004316
4317 if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) &&
4318 (mpi_reply->ResponseCode ==
4319 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4320 mpi_reply->ResponseCode ==
4321 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4322 continue;
4323
4324 mpt2sas_scsih_issue_tm(ioc, handle, lun,
Eric Moore8901cbb2009-04-21 15:41:32 -06004325 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30);
4326 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004327 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4328 }
Eric Moore635374e2009-03-09 01:21:12 -06004329 ioc->broadcast_aen_busy = 0;
4330 mutex_unlock(&ioc->tm_cmds.mutex);
4331
4332 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4333 "%s - exit, query_count = %d termination_count = %d\n",
4334 ioc->name, __func__, query_count, termination_count));
4335}
4336
4337/**
4338 * _scsih_sas_discovery_event - handle discovery events
4339 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304340 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004341 * Context: user.
4342 *
4343 * Return nothing.
4344 */
4345static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304346_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4347 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004348{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304349 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4350
Eric Moore635374e2009-03-09 01:21:12 -06004351#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4352 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4353 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4354 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4355 "start" : "stop");
4356 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304357 printk("discovery_status(0x%08x)",
4358 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06004359 printk("\n");
4360 }
4361#endif
4362
4363 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4364 !ioc->sas_hba.num_phys)
4365 _scsih_sas_host_add(ioc);
4366}
4367
4368/**
4369 * _scsih_reprobe_lun - reprobing lun
4370 * @sdev: scsi device struct
4371 * @no_uld_attach: sdev->no_uld_attach flag setting
4372 *
4373 **/
4374static void
4375_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4376{
4377 int rc;
4378
4379 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4380 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4381 sdev->no_uld_attach ? "hidding" : "exposing");
4382 rc = scsi_device_reprobe(sdev);
4383}
4384
4385/**
4386 * _scsih_reprobe_target - reprobing target
4387 * @starget: scsi target struct
4388 * @no_uld_attach: sdev->no_uld_attach flag setting
4389 *
4390 * Note: no_uld_attach flag determines whether the disk device is attached
4391 * to block layer. A value of `1` means to not attach.
4392 **/
4393static void
4394_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4395{
4396 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4397
4398 if (no_uld_attach)
4399 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4400 else
4401 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4402
4403 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4404 _scsih_reprobe_lun);
4405}
4406/**
4407 * _scsih_sas_volume_add - add new volume
4408 * @ioc: per adapter object
4409 * @element: IR config element data
4410 * Context: user.
4411 *
4412 * Return nothing.
4413 */
4414static void
4415_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4416 Mpi2EventIrConfigElement_t *element)
4417{
4418 struct _raid_device *raid_device;
4419 unsigned long flags;
4420 u64 wwid;
4421 u16 handle = le16_to_cpu(element->VolDevHandle);
4422 int rc;
4423
Eric Moore635374e2009-03-09 01:21:12 -06004424 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4425 if (!wwid) {
4426 printk(MPT2SAS_ERR_FMT
4427 "failure at %s:%d/%s()!\n", ioc->name,
4428 __FILE__, __LINE__, __func__);
4429 return;
4430 }
4431
4432 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4433 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4434 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4435
4436 if (raid_device)
4437 return;
4438
4439 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4440 if (!raid_device) {
4441 printk(MPT2SAS_ERR_FMT
4442 "failure at %s:%d/%s()!\n", ioc->name,
4443 __FILE__, __LINE__, __func__);
4444 return;
4445 }
4446
4447 raid_device->id = ioc->sas_id++;
4448 raid_device->channel = RAID_CHANNEL;
4449 raid_device->handle = handle;
4450 raid_device->wwid = wwid;
4451 _scsih_raid_device_add(ioc, raid_device);
4452 if (!ioc->wait_for_port_enable_to_complete) {
4453 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4454 raid_device->id, 0);
4455 if (rc)
4456 _scsih_raid_device_remove(ioc, raid_device);
4457 } else
4458 _scsih_determine_boot_device(ioc, raid_device, 1);
4459}
4460
4461/**
4462 * _scsih_sas_volume_delete - delete volume
4463 * @ioc: per adapter object
4464 * @element: IR config element data
4465 * Context: user.
4466 *
4467 * Return nothing.
4468 */
4469static void
4470_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4471 Mpi2EventIrConfigElement_t *element)
4472{
4473 struct _raid_device *raid_device;
4474 u16 handle = le16_to_cpu(element->VolDevHandle);
4475 unsigned long flags;
4476 struct MPT2SAS_TARGET *sas_target_priv_data;
4477
Eric Moore635374e2009-03-09 01:21:12 -06004478 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4479 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4480 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4481 if (!raid_device)
4482 return;
4483 if (raid_device->starget) {
4484 sas_target_priv_data = raid_device->starget->hostdata;
4485 sas_target_priv_data->deleted = 1;
4486 scsi_remove_target(&raid_device->starget->dev);
4487 }
4488 _scsih_raid_device_remove(ioc, raid_device);
4489}
4490
4491/**
4492 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4493 * @ioc: per adapter object
4494 * @element: IR config element data
4495 * Context: user.
4496 *
4497 * Return nothing.
4498 */
4499static void
4500_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4501 Mpi2EventIrConfigElement_t *element)
4502{
4503 struct _sas_device *sas_device;
4504 unsigned long flags;
4505 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4506
4507 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4508 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4509 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4510 if (!sas_device)
4511 return;
4512
4513 /* exposing raid component */
4514 sas_device->volume_handle = 0;
4515 sas_device->volume_wwid = 0;
4516 sas_device->hidden_raid_component = 0;
4517 _scsih_reprobe_target(sas_device->starget, 0);
4518}
4519
4520/**
4521 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4522 * @ioc: per adapter object
4523 * @element: IR config element data
4524 * Context: user.
4525 *
4526 * Return nothing.
4527 */
4528static void
4529_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4530 Mpi2EventIrConfigElement_t *element)
4531{
4532 struct _sas_device *sas_device;
4533 unsigned long flags;
4534 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4535
4536 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4537 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4538 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4539 if (!sas_device)
4540 return;
4541
4542 /* hiding raid component */
4543 mpt2sas_config_get_volume_handle(ioc, handle,
4544 &sas_device->volume_handle);
4545 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4546 &sas_device->volume_wwid);
4547 sas_device->hidden_raid_component = 1;
4548 _scsih_reprobe_target(sas_device->starget, 1);
4549}
4550
4551/**
4552 * _scsih_sas_pd_delete - delete pd component
4553 * @ioc: per adapter object
4554 * @element: IR config element data
4555 * Context: user.
4556 *
4557 * Return nothing.
4558 */
4559static void
4560_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4561 Mpi2EventIrConfigElement_t *element)
4562{
4563 struct _sas_device *sas_device;
4564 unsigned long flags;
4565 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4566
4567 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4568 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4569 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4570 if (!sas_device)
4571 return;
4572 _scsih_remove_device(ioc, handle);
4573}
4574
4575/**
4576 * _scsih_sas_pd_add - remove pd component
4577 * @ioc: per adapter object
4578 * @element: IR config element data
4579 * Context: user.
4580 *
4581 * Return nothing.
4582 */
4583static void
4584_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
4585 Mpi2EventIrConfigElement_t *element)
4586{
4587 struct _sas_device *sas_device;
4588 unsigned long flags;
4589 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304590 Mpi2ConfigReply_t mpi_reply;
4591 Mpi2SasDevicePage0_t sas_device_pg0;
4592 u32 ioc_status;
Eric Moore635374e2009-03-09 01:21:12 -06004593
4594 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4595 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4596 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304597 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004598 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304599 return;
4600 }
4601
4602 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4603 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4604 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4605 ioc->name, __FILE__, __LINE__, __func__);
4606 return;
4607 }
4608
4609 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4610 MPI2_IOCSTATUS_MASK;
4611 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4612 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4613 ioc->name, __FILE__, __LINE__, __func__);
4614 return;
4615 }
4616
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05304617 mpt2sas_transport_update_links(ioc,
Kashyap, Desai62727a72009-08-07 19:35:18 +05304618 le16_to_cpu(sas_device_pg0.ParentDevHandle),
4619 handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
4620
4621 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06004622}
4623
4624#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4625/**
4626 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
4627 * @ioc: per adapter object
4628 * @event_data: event data payload
4629 * Context: user.
4630 *
4631 * Return nothing.
4632 */
4633static void
4634_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4635 Mpi2EventDataIrConfigChangeList_t *event_data)
4636{
4637 Mpi2EventIrConfigElement_t *element;
4638 u8 element_type;
4639 int i;
4640 char *reason_str = NULL, *element_str = NULL;
4641
4642 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4643
4644 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
4645 ioc->name, (le32_to_cpu(event_data->Flags) &
4646 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
4647 "foreign" : "native", event_data->NumElements);
4648 for (i = 0; i < event_data->NumElements; i++, element++) {
4649 switch (element->ReasonCode) {
4650 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
4651 reason_str = "add";
4652 break;
4653 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
4654 reason_str = "remove";
4655 break;
4656 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
4657 reason_str = "no change";
4658 break;
4659 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4660 reason_str = "hide";
4661 break;
4662 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4663 reason_str = "unhide";
4664 break;
4665 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4666 reason_str = "volume_created";
4667 break;
4668 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4669 reason_str = "volume_deleted";
4670 break;
4671 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4672 reason_str = "pd_created";
4673 break;
4674 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4675 reason_str = "pd_deleted";
4676 break;
4677 default:
4678 reason_str = "unknown reason";
4679 break;
4680 }
4681 element_type = le16_to_cpu(element->ElementFlags) &
4682 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
4683 switch (element_type) {
4684 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
4685 element_str = "volume";
4686 break;
4687 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
4688 element_str = "phys disk";
4689 break;
4690 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
4691 element_str = "hot spare";
4692 break;
4693 default:
4694 element_str = "unknown element";
4695 break;
4696 }
4697 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
4698 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
4699 reason_str, le16_to_cpu(element->VolDevHandle),
4700 le16_to_cpu(element->PhysDiskDevHandle),
4701 element->PhysDiskNum);
4702 }
4703}
4704#endif
4705
4706/**
4707 * _scsih_sas_ir_config_change_event - handle ir configuration change events
4708 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304709 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004710 * Context: user.
4711 *
4712 * Return nothing.
4713 */
4714static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304715_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
4716 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004717{
4718 Mpi2EventIrConfigElement_t *element;
4719 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304720 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304721 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004722
4723#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4724 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4725 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
4726
4727#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05304728 foreign_config = (le32_to_cpu(event_data->Flags) &
4729 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06004730
4731 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4732 for (i = 0; i < event_data->NumElements; i++, element++) {
4733
4734 switch (element->ReasonCode) {
4735 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
4736 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304737 if (!foreign_config)
4738 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004739 break;
4740 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
4741 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304742 if (!foreign_config)
4743 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06004744 break;
4745 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
4746 _scsih_sas_pd_hide(ioc, element);
4747 break;
4748 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
4749 _scsih_sas_pd_expose(ioc, element);
4750 break;
4751 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
4752 _scsih_sas_pd_add(ioc, element);
4753 break;
4754 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
4755 _scsih_sas_pd_delete(ioc, element);
4756 break;
4757 }
4758 }
4759}
4760
4761/**
4762 * _scsih_sas_ir_volume_event - IR volume event
4763 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304764 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004765 * Context: user.
4766 *
4767 * Return nothing.
4768 */
4769static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304770_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
4771 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004772{
4773 u64 wwid;
4774 unsigned long flags;
4775 struct _raid_device *raid_device;
4776 u16 handle;
4777 u32 state;
4778 int rc;
4779 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304780 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004781
4782 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
4783 return;
4784
4785 handle = le16_to_cpu(event_data->VolDevHandle);
4786 state = le32_to_cpu(event_data->NewValue);
4787 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4788 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4789 le32_to_cpu(event_data->PreviousValue), state));
4790
4791 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4792 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4793 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4794
4795 switch (state) {
4796 case MPI2_RAID_VOL_STATE_MISSING:
4797 case MPI2_RAID_VOL_STATE_FAILED:
4798 if (!raid_device)
4799 break;
4800 if (raid_device->starget) {
4801 sas_target_priv_data = raid_device->starget->hostdata;
4802 sas_target_priv_data->deleted = 1;
4803 scsi_remove_target(&raid_device->starget->dev);
4804 }
4805 _scsih_raid_device_remove(ioc, raid_device);
4806 break;
4807
4808 case MPI2_RAID_VOL_STATE_ONLINE:
4809 case MPI2_RAID_VOL_STATE_DEGRADED:
4810 case MPI2_RAID_VOL_STATE_OPTIMAL:
4811 if (raid_device)
4812 break;
4813
4814 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4815 if (!wwid) {
4816 printk(MPT2SAS_ERR_FMT
4817 "failure at %s:%d/%s()!\n", ioc->name,
4818 __FILE__, __LINE__, __func__);
4819 break;
4820 }
4821
4822 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4823 if (!raid_device) {
4824 printk(MPT2SAS_ERR_FMT
4825 "failure at %s:%d/%s()!\n", ioc->name,
4826 __FILE__, __LINE__, __func__);
4827 break;
4828 }
4829
4830 raid_device->id = ioc->sas_id++;
4831 raid_device->channel = RAID_CHANNEL;
4832 raid_device->handle = handle;
4833 raid_device->wwid = wwid;
4834 _scsih_raid_device_add(ioc, raid_device);
4835 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4836 raid_device->id, 0);
4837 if (rc)
4838 _scsih_raid_device_remove(ioc, raid_device);
4839 break;
4840
4841 case MPI2_RAID_VOL_STATE_INITIALIZING:
4842 default:
4843 break;
4844 }
4845}
4846
4847/**
4848 * _scsih_sas_ir_physical_disk_event - PD event
4849 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304850 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004851 * Context: user.
4852 *
4853 * Return nothing.
4854 */
4855static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304856_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
4857 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004858{
4859 u16 handle;
4860 u32 state;
4861 struct _sas_device *sas_device;
4862 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304863 Mpi2ConfigReply_t mpi_reply;
4864 Mpi2SasDevicePage0_t sas_device_pg0;
4865 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304866 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004867
4868 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
4869 return;
4870
4871 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
4872 state = le32_to_cpu(event_data->NewValue);
4873
4874 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
4875 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
4876 le32_to_cpu(event_data->PreviousValue), state));
4877
4878 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4879 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4880 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4881
4882 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06004883 case MPI2_RAID_PD_STATE_ONLINE:
4884 case MPI2_RAID_PD_STATE_DEGRADED:
4885 case MPI2_RAID_PD_STATE_REBUILDING:
4886 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05304887 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004888 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304889 return;
4890 }
4891
4892 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
4893 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
4894 handle))) {
4895 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4896 ioc->name, __FILE__, __LINE__, __func__);
4897 return;
4898 }
4899
4900 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4901 MPI2_IOCSTATUS_MASK;
4902 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4903 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4904 ioc->name, __FILE__, __LINE__, __func__);
4905 return;
4906 }
4907
Kashyap, Desaicc0f5202009-08-20 13:22:39 +05304908 mpt2sas_transport_update_links(ioc,
Kashyap, Desai62727a72009-08-07 19:35:18 +05304909 le16_to_cpu(sas_device_pg0.ParentDevHandle),
4910 handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
4911
4912 _scsih_add_device(ioc, handle, 0, 1);
4913
Eric Moore635374e2009-03-09 01:21:12 -06004914 break;
4915
Kashyap, Desai62727a72009-08-07 19:35:18 +05304916 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06004917 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
4918 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
4919 case MPI2_RAID_PD_STATE_HOT_SPARE:
4920 default:
4921 break;
4922 }
4923}
4924
4925#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4926/**
4927 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
4928 * @ioc: per adapter object
4929 * @event_data: event data payload
4930 * Context: user.
4931 *
4932 * Return nothing.
4933 */
4934static void
4935_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
4936 Mpi2EventDataIrOperationStatus_t *event_data)
4937{
4938 char *reason_str = NULL;
4939
4940 switch (event_data->RAIDOperation) {
4941 case MPI2_EVENT_IR_RAIDOP_RESYNC:
4942 reason_str = "resync";
4943 break;
4944 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
4945 reason_str = "online capacity expansion";
4946 break;
4947 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
4948 reason_str = "consistency check";
4949 break;
4950 default:
4951 reason_str = "unknown reason";
4952 break;
4953 }
4954
4955 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
4956 "\thandle(0x%04x), percent complete(%d)\n",
4957 ioc->name, reason_str,
4958 le16_to_cpu(event_data->VolDevHandle),
4959 event_data->PercentComplete);
4960}
4961#endif
4962
4963/**
4964 * _scsih_sas_ir_operation_status_event - handle RAID operation events
4965 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304966 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004967 * Context: user.
4968 *
4969 * Return nothing.
4970 */
4971static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304972_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
4973 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004974{
4975#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4976 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304977 _scsih_sas_ir_operation_status_event_debug(ioc,
4978 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004979#endif
4980}
4981
4982/**
4983 * _scsih_task_set_full - handle task set full
4984 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304985 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004986 * Context: user.
4987 *
4988 * Throttle back qdepth.
4989 */
4990static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304991_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
4992 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004993{
4994 unsigned long flags;
4995 struct _sas_device *sas_device;
4996 static struct _raid_device *raid_device;
4997 struct scsi_device *sdev;
4998 int depth;
4999 u16 current_depth;
5000 u16 handle;
5001 int id, channel;
5002 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305003 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005004
5005 current_depth = le16_to_cpu(event_data->CurrentDepth);
5006 handle = le16_to_cpu(event_data->DevHandle);
5007 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5008 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5009 if (!sas_device) {
5010 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5011 return;
5012 }
5013 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5014 id = sas_device->id;
5015 channel = sas_device->channel;
5016 sas_address = sas_device->sas_address;
5017
5018 /* if hidden raid component, then change to volume characteristics */
5019 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
5020 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5021 raid_device = _scsih_raid_device_find_by_handle(
5022 ioc, sas_device->volume_handle);
5023 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5024 if (raid_device) {
5025 id = raid_device->id;
5026 channel = raid_device->channel;
5027 handle = raid_device->handle;
5028 sas_address = raid_device->wwid;
5029 }
5030 }
5031
5032 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
5033 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
5034 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
5035 handle, (unsigned long long)sas_address, current_depth);
5036
5037 shost_for_each_device(sdev, ioc->shost) {
5038 if (sdev->id == id && sdev->channel == channel) {
5039 if (current_depth > sdev->queue_depth) {
5040 if (ioc->logging_level &
5041 MPT_DEBUG_TASK_SET_FULL)
5042 sdev_printk(KERN_INFO, sdev, "strange "
5043 "observation, the queue depth is"
5044 " (%d) meanwhile fw queue depth "
5045 "is (%d)\n", sdev->queue_depth,
5046 current_depth);
5047 continue;
5048 }
5049 depth = scsi_track_queue_full(sdev,
5050 current_depth - 1);
5051 if (depth > 0)
5052 sdev_printk(KERN_INFO, sdev, "Queue depth "
5053 "reduced to (%d)\n", depth);
5054 else if (depth < 0)
5055 sdev_printk(KERN_INFO, sdev, "Tagged Command "
5056 "Queueing is being disabled\n");
5057 else if (depth == 0)
5058 if (ioc->logging_level &
5059 MPT_DEBUG_TASK_SET_FULL)
5060 sdev_printk(KERN_INFO, sdev,
5061 "Queue depth not changed yet\n");
5062 }
5063 }
5064}
5065
5066/**
5067 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
5068 * @ioc: per adapter object
5069 * @sas_address: sas address
5070 * @slot: enclosure slot id
5071 * @handle: device handle
5072 *
5073 * After host reset, find out whether devices are still responding.
5074 * Used in _scsi_remove_unresponsive_sas_devices.
5075 *
5076 * Return nothing.
5077 */
5078static void
5079_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5080 u16 slot, u16 handle)
5081{
5082 struct MPT2SAS_TARGET *sas_target_priv_data;
5083 struct scsi_target *starget;
5084 struct _sas_device *sas_device;
5085 unsigned long flags;
5086
5087 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5088 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
5089 if (sas_device->sas_address == sas_address &&
5090 sas_device->slot == slot && sas_device->starget) {
5091 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305092 sas_device->state = 0;
5093 starget = sas_device->starget;
5094 sas_target_priv_data = starget->hostdata;
5095 sas_target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06005096 starget_printk(KERN_INFO, sas_device->starget,
5097 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
5098 "logical id(0x%016llx), slot(%d)\n", handle,
5099 (unsigned long long)sas_device->sas_address,
5100 (unsigned long long)
5101 sas_device->enclosure_logical_id,
5102 sas_device->slot);
5103 if (sas_device->handle == handle)
5104 goto out;
5105 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5106 sas_device->handle);
5107 sas_device->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005108 sas_target_priv_data->handle = handle;
5109 goto out;
5110 }
5111 }
5112 out:
5113 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5114}
5115
5116/**
5117 * _scsih_search_responding_sas_devices -
5118 * @ioc: per adapter object
5119 *
5120 * After host reset, find out whether devices are still responding.
5121 * If not remove.
5122 *
5123 * Return nothing.
5124 */
5125static void
5126_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
5127{
5128 Mpi2SasDevicePage0_t sas_device_pg0;
5129 Mpi2ConfigReply_t mpi_reply;
5130 u16 ioc_status;
5131 __le64 sas_address;
5132 u16 handle;
5133 u32 device_info;
5134 u16 slot;
5135
5136 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5137
5138 if (list_empty(&ioc->sas_device_list))
5139 return;
5140
5141 handle = 0xFFFF;
5142 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5143 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
5144 handle))) {
5145 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5146 MPI2_IOCSTATUS_MASK;
5147 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5148 break;
5149 handle = le16_to_cpu(sas_device_pg0.DevHandle);
5150 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5151 if (!(_scsih_is_end_device(device_info)))
5152 continue;
5153 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5154 slot = le16_to_cpu(sas_device_pg0.Slot);
5155 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
5156 handle);
5157 }
5158}
5159
5160/**
5161 * _scsih_mark_responding_raid_device - mark a raid_device as responding
5162 * @ioc: per adapter object
5163 * @wwid: world wide identifier for raid volume
5164 * @handle: device handle
5165 *
5166 * After host reset, find out whether devices are still responding.
5167 * Used in _scsi_remove_unresponsive_raid_devices.
5168 *
5169 * Return nothing.
5170 */
5171static void
5172_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
5173 u16 handle)
5174{
5175 struct MPT2SAS_TARGET *sas_target_priv_data;
5176 struct scsi_target *starget;
5177 struct _raid_device *raid_device;
5178 unsigned long flags;
5179
5180 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5181 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
5182 if (raid_device->wwid == wwid && raid_device->starget) {
5183 raid_device->responding = 1;
5184 starget_printk(KERN_INFO, raid_device->starget,
5185 "handle(0x%04x), wwid(0x%016llx)\n", handle,
5186 (unsigned long long)raid_device->wwid);
5187 if (raid_device->handle == handle)
5188 goto out;
5189 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5190 raid_device->handle);
5191 raid_device->handle = handle;
5192 starget = raid_device->starget;
5193 sas_target_priv_data = starget->hostdata;
5194 sas_target_priv_data->handle = handle;
5195 goto out;
5196 }
5197 }
5198 out:
5199 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5200}
5201
5202/**
5203 * _scsih_search_responding_raid_devices -
5204 * @ioc: per adapter object
5205 *
5206 * After host reset, find out whether devices are still responding.
5207 * If not remove.
5208 *
5209 * Return nothing.
5210 */
5211static void
5212_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
5213{
5214 Mpi2RaidVolPage1_t volume_pg1;
5215 Mpi2ConfigReply_t mpi_reply;
5216 u16 ioc_status;
5217 u16 handle;
5218
5219 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5220
5221 if (list_empty(&ioc->raid_device_list))
5222 return;
5223
5224 handle = 0xFFFF;
5225 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
5226 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
5227 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5228 MPI2_IOCSTATUS_MASK;
5229 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5230 break;
5231 handle = le16_to_cpu(volume_pg1.DevHandle);
5232 _scsih_mark_responding_raid_device(ioc,
5233 le64_to_cpu(volume_pg1.WWID), handle);
5234 }
5235}
5236
5237/**
5238 * _scsih_mark_responding_expander - mark a expander as responding
5239 * @ioc: per adapter object
5240 * @sas_address: sas address
5241 * @handle:
5242 *
5243 * After host reset, find out whether devices are still responding.
5244 * Used in _scsi_remove_unresponsive_expanders.
5245 *
5246 * Return nothing.
5247 */
5248static void
5249_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5250 u16 handle)
5251{
5252 struct _sas_node *sas_expander;
5253 unsigned long flags;
5254
5255 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5256 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
5257 if (sas_expander->sas_address == sas_address) {
5258 sas_expander->responding = 1;
5259 if (sas_expander->handle != handle) {
5260 printk(KERN_INFO "old handle(0x%04x)\n",
5261 sas_expander->handle);
5262 sas_expander->handle = handle;
5263 }
5264 goto out;
5265 }
5266 }
5267 out:
5268 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5269}
5270
5271/**
5272 * _scsih_search_responding_expanders -
5273 * @ioc: per adapter object
5274 *
5275 * After host reset, find out whether devices are still responding.
5276 * If not remove.
5277 *
5278 * Return nothing.
5279 */
5280static void
5281_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5282{
5283 Mpi2ExpanderPage0_t expander_pg0;
5284 Mpi2ConfigReply_t mpi_reply;
5285 u16 ioc_status;
5286 __le64 sas_address;
5287 u16 handle;
5288
5289 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5290
5291 if (list_empty(&ioc->sas_expander_list))
5292 return;
5293
5294 handle = 0xFFFF;
5295 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5296 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5297
5298 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5299 MPI2_IOCSTATUS_MASK;
5300 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5301 break;
5302
5303 handle = le16_to_cpu(expander_pg0.DevHandle);
5304 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5305 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5306 "sas_addr(0x%016llx)\n", handle,
5307 (unsigned long long)sas_address);
5308 _scsih_mark_responding_expander(ioc, sas_address, handle);
5309 }
5310
5311}
5312
5313/**
5314 * _scsih_remove_unresponding_devices - removing unresponding devices
5315 * @ioc: per adapter object
5316 *
5317 * Return nothing.
5318 */
5319static void
5320_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
5321{
5322 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305323 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005324 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005325
Eric Moore635374e2009-03-09 01:21:12 -06005326
5327 list_for_each_entry_safe(sas_device, sas_device_next,
5328 &ioc->sas_device_list, list) {
5329 if (sas_device->responding) {
5330 sas_device->responding = 0;
5331 continue;
5332 }
5333 if (sas_device->starget)
5334 starget_printk(KERN_INFO, sas_device->starget,
5335 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5336 "enclosure logical id(0x%016llx), slot(%d)\n",
5337 sas_device->handle,
5338 (unsigned long long)sas_device->sas_address,
5339 (unsigned long long)
5340 sas_device->enclosure_logical_id,
5341 sas_device->slot);
5342 _scsih_remove_device(ioc, sas_device->handle);
5343 }
5344
5345 list_for_each_entry_safe(raid_device, raid_device_next,
5346 &ioc->raid_device_list, list) {
5347 if (raid_device->responding) {
5348 raid_device->responding = 0;
5349 continue;
5350 }
5351 if (raid_device->starget) {
5352 starget_printk(KERN_INFO, raid_device->starget,
5353 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5354 raid_device->handle,
5355 (unsigned long long)raid_device->wwid);
5356 scsi_remove_target(&raid_device->starget->dev);
5357 }
5358 _scsih_raid_device_remove(ioc, raid_device);
5359 }
5360
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305361 retry_expander_search:
5362 sas_expander = NULL;
5363 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005364 if (sas_expander->responding) {
5365 sas_expander->responding = 0;
5366 continue;
5367 }
Eric Moore635374e2009-03-09 01:21:12 -06005368 _scsih_expander_remove(ioc, sas_expander->handle);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305369 goto retry_expander_search;
5370 }
5371}
5372
5373/**
5374 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5375 * @ioc: per adapter object
5376 * @reset_phase: phase
5377 *
5378 * The handler for doing any required cleanup or initialization.
5379 *
5380 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5381 * MPT2_IOC_DONE_RESET
5382 *
5383 * Return nothing.
5384 */
5385void
5386mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5387{
5388 switch (reset_phase) {
5389 case MPT2_IOC_PRE_RESET:
5390 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5391 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
5392 _scsih_fw_event_off(ioc);
5393 break;
5394 case MPT2_IOC_AFTER_RESET:
5395 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5396 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
5397 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5398 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5399 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5400 complete(&ioc->tm_cmds.done);
5401 }
5402 _scsih_fw_event_on(ioc);
5403 _scsih_flush_running_cmds(ioc);
5404 break;
5405 case MPT2_IOC_DONE_RESET:
5406 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5407 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
5408 _scsih_sas_host_refresh(ioc, 0);
5409 _scsih_search_responding_sas_devices(ioc);
5410 _scsih_search_responding_raid_devices(ioc);
5411 _scsih_search_responding_expanders(ioc);
5412 break;
5413 case MPT2_IOC_RUNNING:
5414 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5415 "MPT2_IOC_RUNNING\n", ioc->name, __func__));
5416 _scsih_remove_unresponding_devices(ioc);
5417 break;
Eric Moore635374e2009-03-09 01:21:12 -06005418 }
5419}
5420
5421/**
5422 * _firmware_event_work - delayed task for processing firmware events
5423 * @ioc: per adapter object
5424 * @work: equal to the fw_event_work object
5425 * Context: user.
5426 *
5427 * Return nothing.
5428 */
5429static void
5430_firmware_event_work(struct work_struct *work)
5431{
5432 struct fw_event_work *fw_event = container_of(work,
Eric Moore6f92a7a2009-04-21 15:43:33 -06005433 struct fw_event_work, work);
Eric Moore635374e2009-03-09 01:21:12 -06005434 unsigned long flags;
5435 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5436
Eric Moore635374e2009-03-09 01:21:12 -06005437 /* the queue is being flushed so ignore this event */
5438 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5439 if (ioc->fw_events_off || ioc->remove_host) {
5440 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5441 _scsih_fw_event_free(ioc, fw_event);
5442 return;
5443 }
5444 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5445
Eric Moore635374e2009-03-09 01:21:12 -06005446 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06005447 _scsih_fw_event_requeue(ioc, fw_event, 1000);
5448 return;
5449 }
Eric Moore635374e2009-03-09 01:21:12 -06005450
5451 switch (fw_event->event) {
5452 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305453 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005454 break;
5455 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305456 _scsih_sas_device_status_change_event(ioc,
5457 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005458 break;
5459 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305460 _scsih_sas_discovery_event(ioc,
5461 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005462 break;
5463 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305464 _scsih_sas_broadcast_primative_event(ioc,
5465 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005466 break;
5467 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5468 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305469 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005470 break;
5471 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305472 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005473 break;
5474 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305475 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005476 break;
5477 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305478 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005479 break;
5480 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305481 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005482 break;
5483 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305484 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005485 break;
5486 }
5487 _scsih_fw_event_free(ioc, fw_event);
5488}
5489
5490/**
5491 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5492 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305493 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06005494 * @reply: reply message frame(lower 32bit addr)
5495 * Context: interrupt.
5496 *
5497 * This function merely adds a new work task into ioc->firmware_event_thread.
5498 * The tasks are worked from _firmware_event_work in user context.
5499 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305500 * Return 1 meaning mf should be freed from _base_interrupt
5501 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06005502 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305503u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305504mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
5505 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06005506{
5507 struct fw_event_work *fw_event;
5508 Mpi2EventNotificationReply_t *mpi_reply;
5509 unsigned long flags;
5510 u16 event;
5511
5512 /* events turned off due to host reset or driver unloading */
5513 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5514 if (ioc->fw_events_off || ioc->remove_host) {
5515 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305516 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005517 }
5518 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5519
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305520 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06005521 event = le16_to_cpu(mpi_reply->Event);
5522
5523 switch (event) {
5524 /* handle these */
5525 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
5526 {
5527 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
5528 (Mpi2EventDataSasBroadcastPrimitive_t *)
5529 mpi_reply->EventData;
5530
5531 if (baen_data->Primitive !=
5532 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
5533 ioc->broadcast_aen_busy)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305534 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005535 ioc->broadcast_aen_busy = 1;
5536 break;
5537 }
5538
5539 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
5540 _scsih_check_topo_delete_events(ioc,
5541 (Mpi2EventDataSasTopologyChangeList_t *)
5542 mpi_reply->EventData);
5543 break;
5544
5545 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
5546 case MPI2_EVENT_IR_OPERATION_STATUS:
5547 case MPI2_EVENT_SAS_DISCOVERY:
5548 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5549 case MPI2_EVENT_IR_VOLUME:
5550 case MPI2_EVENT_IR_PHYSICAL_DISK:
5551 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
5552 case MPI2_EVENT_TASK_SET_FULL:
5553 break;
5554
5555 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305556 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005557 }
5558
5559 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
5560 if (!fw_event) {
5561 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5562 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305563 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005564 }
5565 fw_event->event_data =
5566 kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
5567 if (!fw_event->event_data) {
5568 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5569 ioc->name, __FILE__, __LINE__, __func__);
5570 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305571 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005572 }
5573
5574 memcpy(fw_event->event_data, mpi_reply->EventData,
5575 mpi_reply->EventDataLength*4);
5576 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305577 fw_event->VF_ID = mpi_reply->VF_ID;
5578 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06005579 fw_event->event = event;
5580 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305581 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005582}
5583
5584/* shost template */
5585static struct scsi_host_template scsih_driver_template = {
5586 .module = THIS_MODULE,
5587 .name = "Fusion MPT SAS Host",
5588 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06005589 .queuecommand = _scsih_qcmd,
5590 .target_alloc = _scsih_target_alloc,
5591 .slave_alloc = _scsih_slave_alloc,
5592 .slave_configure = _scsih_slave_configure,
5593 .target_destroy = _scsih_target_destroy,
5594 .slave_destroy = _scsih_slave_destroy,
5595 .change_queue_depth = _scsih_change_queue_depth,
5596 .change_queue_type = _scsih_change_queue_type,
5597 .eh_abort_handler = _scsih_abort,
5598 .eh_device_reset_handler = _scsih_dev_reset,
5599 .eh_target_reset_handler = _scsih_target_reset,
5600 .eh_host_reset_handler = _scsih_host_reset,
5601 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06005602 .can_queue = 1,
5603 .this_id = -1,
5604 .sg_tablesize = MPT2SAS_SG_DEPTH,
5605 .max_sectors = 8192,
5606 .cmd_per_lun = 7,
5607 .use_clustering = ENABLE_CLUSTERING,
5608 .shost_attrs = mpt2sas_host_attrs,
5609 .sdev_attrs = mpt2sas_dev_attrs,
5610};
5611
5612/**
5613 * _scsih_expander_node_remove - removing expander device from list.
5614 * @ioc: per adapter object
5615 * @sas_expander: the sas_device object
5616 * Context: Calling function should acquire ioc->sas_node_lock.
5617 *
5618 * Removing object and freeing associated memory from the
5619 * ioc->sas_expander_list.
5620 *
5621 * Return nothing.
5622 */
5623static void
5624_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
5625 struct _sas_node *sas_expander)
5626{
5627 struct _sas_port *mpt2sas_port;
5628 struct _sas_device *sas_device;
5629 struct _sas_node *expander_sibling;
5630 unsigned long flags;
5631
5632 if (!sas_expander)
5633 return;
5634
5635 /* remove sibling ports attached to this expander */
5636 retry_device_search:
5637 list_for_each_entry(mpt2sas_port,
5638 &sas_expander->sas_port_list, port_list) {
5639 if (mpt2sas_port->remote_identify.device_type ==
5640 SAS_END_DEVICE) {
5641 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5642 sas_device =
5643 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5644 mpt2sas_port->remote_identify.sas_address);
5645 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5646 if (!sas_device)
5647 continue;
5648 _scsih_remove_device(ioc, sas_device->handle);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305649 if (ioc->shost_recovery)
5650 return;
Eric Moore635374e2009-03-09 01:21:12 -06005651 goto retry_device_search;
5652 }
5653 }
5654
5655 retry_expander_search:
5656 list_for_each_entry(mpt2sas_port,
5657 &sas_expander->sas_port_list, port_list) {
5658
5659 if (mpt2sas_port->remote_identify.device_type ==
5660 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
5661 mpt2sas_port->remote_identify.device_type ==
5662 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
5663
5664 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5665 expander_sibling =
5666 mpt2sas_scsih_expander_find_by_sas_address(
5667 ioc, mpt2sas_port->remote_identify.sas_address);
5668 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5669 if (!expander_sibling)
5670 continue;
5671 _scsih_expander_remove(ioc, expander_sibling->handle);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305672 if (ioc->shost_recovery)
5673 return;
Eric Moore635374e2009-03-09 01:21:12 -06005674 goto retry_expander_search;
5675 }
5676 }
5677
5678 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
5679 sas_expander->parent_handle);
5680
5681 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
5682 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
5683 sas_expander->handle, (unsigned long long)
5684 sas_expander->sas_address);
5685
5686 list_del(&sas_expander->list);
5687 kfree(sas_expander->phy);
5688 kfree(sas_expander);
5689}
5690
5691/**
Eric Moored5d135b2009-05-18 13:02:08 -06005692 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06005693 * @pdev: PCI device struct
5694 *
5695 * Return nothing.
5696 */
5697static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06005698_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06005699{
5700 struct Scsi_Host *shost = pci_get_drvdata(pdev);
5701 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
5702 struct _sas_port *mpt2sas_port;
5703 struct _sas_device *sas_device;
5704 struct _sas_node *expander_sibling;
5705 struct workqueue_struct *wq;
5706 unsigned long flags;
5707
5708 ioc->remove_host = 1;
5709 _scsih_fw_event_off(ioc);
5710
5711 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5712 wq = ioc->firmware_event_thread;
5713 ioc->firmware_event_thread = NULL;
5714 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5715 if (wq)
5716 destroy_workqueue(wq);
5717
5718 /* free ports attached to the sas_host */
5719 retry_again:
5720 list_for_each_entry(mpt2sas_port,
5721 &ioc->sas_hba.sas_port_list, port_list) {
5722 if (mpt2sas_port->remote_identify.device_type ==
5723 SAS_END_DEVICE) {
5724 sas_device =
5725 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5726 mpt2sas_port->remote_identify.sas_address);
5727 if (sas_device) {
5728 _scsih_remove_device(ioc, sas_device->handle);
5729 goto retry_again;
5730 }
5731 } else {
5732 expander_sibling =
5733 mpt2sas_scsih_expander_find_by_sas_address(ioc,
5734 mpt2sas_port->remote_identify.sas_address);
5735 if (expander_sibling) {
5736 _scsih_expander_remove(ioc,
5737 expander_sibling->handle);
5738 goto retry_again;
5739 }
5740 }
5741 }
5742
5743 /* free phys attached to the sas_host */
5744 if (ioc->sas_hba.num_phys) {
5745 kfree(ioc->sas_hba.phy);
5746 ioc->sas_hba.phy = NULL;
5747 ioc->sas_hba.num_phys = 0;
5748 }
5749
5750 sas_remove_host(shost);
5751 mpt2sas_base_detach(ioc);
5752 list_del(&ioc->list);
5753 scsi_remove_host(shost);
5754 scsi_host_put(shost);
5755}
5756
5757/**
5758 * _scsih_probe_boot_devices - reports 1st device
5759 * @ioc: per adapter object
5760 *
5761 * If specified in bios page 2, this routine reports the 1st
5762 * device scsi-ml or sas transport for persistent boot device
5763 * purposes. Please refer to function _scsih_determine_boot_device()
5764 */
5765static void
5766_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
5767{
5768 u8 is_raid;
5769 void *device;
5770 struct _sas_device *sas_device;
5771 struct _raid_device *raid_device;
5772 u16 handle, parent_handle;
5773 u64 sas_address;
5774 unsigned long flags;
5775 int rc;
5776
5777 device = NULL;
5778 if (ioc->req_boot_device.device) {
5779 device = ioc->req_boot_device.device;
5780 is_raid = ioc->req_boot_device.is_raid;
5781 } else if (ioc->req_alt_boot_device.device) {
5782 device = ioc->req_alt_boot_device.device;
5783 is_raid = ioc->req_alt_boot_device.is_raid;
5784 } else if (ioc->current_boot_device.device) {
5785 device = ioc->current_boot_device.device;
5786 is_raid = ioc->current_boot_device.is_raid;
5787 }
5788
5789 if (!device)
5790 return;
5791
5792 if (is_raid) {
5793 raid_device = device;
5794 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5795 raid_device->id, 0);
5796 if (rc)
5797 _scsih_raid_device_remove(ioc, raid_device);
5798 } else {
5799 sas_device = device;
5800 handle = sas_device->handle;
5801 parent_handle = sas_device->parent_handle;
5802 sas_address = sas_device->sas_address;
5803 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5804 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5805 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5806 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
5807 sas_device->parent_handle)) {
5808 _scsih_sas_device_remove(ioc, sas_device);
5809 } else if (!sas_device->starget) {
5810 mpt2sas_transport_port_remove(ioc, sas_address,
5811 parent_handle);
5812 _scsih_sas_device_remove(ioc, sas_device);
5813 }
5814 }
5815}
5816
5817/**
5818 * _scsih_probe_raid - reporting raid volumes to scsi-ml
5819 * @ioc: per adapter object
5820 *
5821 * Called during initial loading of the driver.
5822 */
5823static void
5824_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
5825{
5826 struct _raid_device *raid_device, *raid_next;
5827 int rc;
5828
5829 list_for_each_entry_safe(raid_device, raid_next,
5830 &ioc->raid_device_list, list) {
5831 if (raid_device->starget)
5832 continue;
5833 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5834 raid_device->id, 0);
5835 if (rc)
5836 _scsih_raid_device_remove(ioc, raid_device);
5837 }
5838}
5839
5840/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305841 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06005842 * @ioc: per adapter object
5843 *
5844 * Called during initial loading of the driver.
5845 */
5846static void
5847_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
5848{
5849 struct _sas_device *sas_device, *next;
5850 unsigned long flags;
5851 u16 handle, parent_handle;
5852 u64 sas_address;
5853
5854 /* SAS Device List */
5855 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
5856 list) {
5857 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5858 list_move_tail(&sas_device->list, &ioc->sas_device_list);
5859 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5860
5861 handle = sas_device->handle;
5862 parent_handle = sas_device->parent_handle;
5863 sas_address = sas_device->sas_address;
5864 if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) {
5865 _scsih_sas_device_remove(ioc, sas_device);
5866 } else if (!sas_device->starget) {
5867 mpt2sas_transport_port_remove(ioc, sas_address,
5868 parent_handle);
5869 _scsih_sas_device_remove(ioc, sas_device);
5870 }
5871 }
5872}
5873
5874/**
5875 * _scsih_probe_devices - probing for devices
5876 * @ioc: per adapter object
5877 *
5878 * Called during initial loading of the driver.
5879 */
5880static void
5881_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
5882{
5883 u16 volume_mapping_flags =
5884 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
5885 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
5886
5887 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
5888 return; /* return when IOC doesn't support initiator mode */
5889
5890 _scsih_probe_boot_devices(ioc);
5891
5892 if (ioc->ir_firmware) {
5893 if ((volume_mapping_flags &
5894 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
5895 _scsih_probe_sas(ioc);
5896 _scsih_probe_raid(ioc);
5897 } else {
5898 _scsih_probe_raid(ioc);
5899 _scsih_probe_sas(ioc);
5900 }
5901 } else
5902 _scsih_probe_sas(ioc);
5903}
5904
5905/**
Eric Moored5d135b2009-05-18 13:02:08 -06005906 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06005907 * @pdev: PCI device struct
5908 * @id: pci device id
5909 *
5910 * Returns 0 success, anything else error.
5911 */
5912static int
Eric Moored5d135b2009-05-18 13:02:08 -06005913_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06005914{
5915 struct MPT2SAS_ADAPTER *ioc;
5916 struct Scsi_Host *shost;
5917
5918 shost = scsi_host_alloc(&scsih_driver_template,
5919 sizeof(struct MPT2SAS_ADAPTER));
5920 if (!shost)
5921 return -ENODEV;
5922
5923 /* init local params */
5924 ioc = shost_priv(shost);
5925 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
5926 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06005927 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06005928 ioc->shost = shost;
5929 ioc->id = mpt_ids++;
5930 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
5931 ioc->pdev = pdev;
5932 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
5933 ioc->tm_cb_idx = tm_cb_idx;
5934 ioc->ctl_cb_idx = ctl_cb_idx;
5935 ioc->base_cb_idx = base_cb_idx;
5936 ioc->transport_cb_idx = transport_cb_idx;
5937 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305938 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
5939 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06005940 ioc->logging_level = logging_level;
5941 /* misc semaphores and spin locks */
5942 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
5943 spin_lock_init(&ioc->scsi_lookup_lock);
5944 spin_lock_init(&ioc->sas_device_lock);
5945 spin_lock_init(&ioc->sas_node_lock);
5946 spin_lock_init(&ioc->fw_event_lock);
5947 spin_lock_init(&ioc->raid_device_lock);
5948
5949 INIT_LIST_HEAD(&ioc->sas_device_list);
5950 INIT_LIST_HEAD(&ioc->sas_device_init_list);
5951 INIT_LIST_HEAD(&ioc->sas_expander_list);
5952 INIT_LIST_HEAD(&ioc->fw_event_list);
5953 INIT_LIST_HEAD(&ioc->raid_device_list);
5954 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305955 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Eric Moore635374e2009-03-09 01:21:12 -06005956
5957 /* init shost parameters */
5958 shost->max_cmd_len = 16;
5959 shost->max_lun = max_lun;
5960 shost->transportt = mpt2sas_transport_template;
5961 shost->unique_id = ioc->id;
5962
5963 if ((scsi_add_host(shost, &pdev->dev))) {
5964 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5965 ioc->name, __FILE__, __LINE__, __func__);
5966 list_del(&ioc->list);
5967 goto out_add_shost_fail;
5968 }
5969
Eric Moore3c621b32009-05-18 12:59:41 -06005970 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
5971 | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305972 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06005973
Eric Moore635374e2009-03-09 01:21:12 -06005974 /* event thread */
5975 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
5976 "fw_event%d", ioc->id);
5977 ioc->firmware_event_thread = create_singlethread_workqueue(
5978 ioc->firmware_event_name);
5979 if (!ioc->firmware_event_thread) {
5980 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5981 ioc->name, __FILE__, __LINE__, __func__);
5982 goto out_thread_fail;
5983 }
5984
5985 ioc->wait_for_port_enable_to_complete = 1;
5986 if ((mpt2sas_base_attach(ioc))) {
5987 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5988 ioc->name, __FILE__, __LINE__, __func__);
5989 goto out_attach_fail;
5990 }
5991
5992 ioc->wait_for_port_enable_to_complete = 0;
5993 _scsih_probe_devices(ioc);
5994 return 0;
5995
5996 out_attach_fail:
5997 destroy_workqueue(ioc->firmware_event_thread);
5998 out_thread_fail:
5999 list_del(&ioc->list);
6000 scsi_remove_host(shost);
6001 out_add_shost_fail:
6002 return -ENODEV;
6003}
6004
6005#ifdef CONFIG_PM
6006/**
Eric Moored5d135b2009-05-18 13:02:08 -06006007 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006008 * @pdev: PCI device struct
6009 * @state: PM state change to (usually PCI_D3)
6010 *
6011 * Returns 0 success, anything else error.
6012 */
6013static int
Eric Moored5d135b2009-05-18 13:02:08 -06006014_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06006015{
6016 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6017 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6018 u32 device_state;
6019
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306020 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006021 flush_scheduled_work();
6022 scsi_block_requests(shost);
6023 device_state = pci_choose_state(pdev, state);
6024 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
6025 "operating state [D%d]\n", ioc->name, pdev,
6026 pci_name(pdev), device_state);
6027
6028 mpt2sas_base_free_resources(ioc);
6029 pci_save_state(pdev);
6030 pci_disable_device(pdev);
6031 pci_set_power_state(pdev, device_state);
6032 return 0;
6033}
6034
6035/**
Eric Moored5d135b2009-05-18 13:02:08 -06006036 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006037 * @pdev: PCI device struct
6038 *
6039 * Returns 0 success, anything else error.
6040 */
6041static int
Eric Moored5d135b2009-05-18 13:02:08 -06006042_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006043{
6044 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6045 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6046 u32 device_state = pdev->current_state;
6047 int r;
6048
6049 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
6050 "operating state [D%d]\n", ioc->name, pdev,
6051 pci_name(pdev), device_state);
6052
6053 pci_set_power_state(pdev, PCI_D0);
6054 pci_enable_wake(pdev, PCI_D0, 0);
6055 pci_restore_state(pdev);
6056 ioc->pdev = pdev;
6057 r = mpt2sas_base_map_resources(ioc);
6058 if (r)
6059 return r;
6060
6061 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
6062 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306063 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006064 return 0;
6065}
6066#endif /* CONFIG_PM */
6067
6068
6069static struct pci_driver scsih_driver = {
6070 .name = MPT2SAS_DRIVER_NAME,
6071 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06006072 .probe = _scsih_probe,
6073 .remove = __devexit_p(_scsih_remove),
Eric Moore635374e2009-03-09 01:21:12 -06006074#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06006075 .suspend = _scsih_suspend,
6076 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06006077#endif
6078};
6079
6080
6081/**
Eric Moored5d135b2009-05-18 13:02:08 -06006082 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06006083 *
6084 * Returns 0 success, anything else error.
6085 */
6086static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06006087_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06006088{
6089 int error;
6090
6091 mpt_ids = 0;
6092 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
6093 MPT2SAS_DRIVER_VERSION);
6094
6095 mpt2sas_transport_template =
6096 sas_attach_transport(&mpt2sas_transport_functions);
6097 if (!mpt2sas_transport_template)
6098 return -ENODEV;
6099
6100 mpt2sas_base_initialize_callback_handler();
6101
6102 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06006103 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06006104
6105 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06006106 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06006107
6108 /* base internal commands callback handler */
6109 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
6110
6111 /* transport internal commands callback handler */
6112 transport_cb_idx = mpt2sas_base_register_callback_handler(
6113 mpt2sas_transport_done);
6114
6115 /* configuration page API internal commands callback handler */
6116 config_cb_idx = mpt2sas_base_register_callback_handler(
6117 mpt2sas_config_done);
6118
6119 /* ctl module callback handler */
6120 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
6121
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306122 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
6123 _scsih_tm_tr_complete);
6124 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
6125 _scsih_sas_control_complete);
6126
Eric Moore635374e2009-03-09 01:21:12 -06006127 mpt2sas_ctl_init();
6128
6129 error = pci_register_driver(&scsih_driver);
6130 if (error)
6131 sas_release_transport(mpt2sas_transport_template);
6132
6133 return error;
6134}
6135
6136/**
Eric Moored5d135b2009-05-18 13:02:08 -06006137 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06006138 *
6139 * Returns 0 success, anything else error.
6140 */
6141static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06006142_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06006143{
6144 printk(KERN_INFO "mpt2sas version %s unloading\n",
6145 MPT2SAS_DRIVER_VERSION);
6146
6147 pci_unregister_driver(&scsih_driver);
6148
6149 sas_release_transport(mpt2sas_transport_template);
6150 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
6151 mpt2sas_base_release_callback_handler(tm_cb_idx);
6152 mpt2sas_base_release_callback_handler(base_cb_idx);
6153 mpt2sas_base_release_callback_handler(transport_cb_idx);
6154 mpt2sas_base_release_callback_handler(config_cb_idx);
6155 mpt2sas_base_release_callback_handler(ctl_cb_idx);
6156
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306157 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
6158 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
6159
Eric Moore635374e2009-03-09 01:21:12 -06006160 mpt2sas_ctl_exit();
6161}
6162
Eric Moored5d135b2009-05-18 13:02:08 -06006163module_init(_scsih_init);
6164module_exit(_scsih_exit);