blob: 344a22ad2f33d000a11fa83c2bf75f818db4eb2e [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>
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +053055#include <linux/raid_class.h>
Eric Moore635374e2009-03-09 01:21:12 -060056
57#include "mpt2sas_base.h"
58
59MODULE_AUTHOR(MPT2SAS_AUTHOR);
60MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
61MODULE_LICENSE("GPL");
62MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
63
64#define RAID_CHANNEL 1
65
66/* forward proto's */
67static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
68 struct _sas_node *sas_expander);
69static void _firmware_event_work(struct work_struct *work);
70
71/* global parameters */
Eric Mooreba33fad2009-03-15 21:37:18 -060072LIST_HEAD(mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -060073
74/* local parameters */
Eric Moore635374e2009-03-09 01:21:12 -060075static u8 scsi_io_cb_idx = -1;
76static u8 tm_cb_idx = -1;
77static u8 ctl_cb_idx = -1;
78static u8 base_cb_idx = -1;
79static u8 transport_cb_idx = -1;
Kashyap, Desai744090d2009-10-05 15:56:56 +053080static u8 scsih_cb_idx = -1;
Eric Moore635374e2009-03-09 01:21:12 -060081static u8 config_cb_idx = -1;
82static int mpt_ids;
83
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053084static u8 tm_tr_cb_idx = -1 ;
85static u8 tm_sas_control_cb_idx = -1;
86
Eric Moore635374e2009-03-09 01:21:12 -060087/* command line options */
Eric Mooreba33fad2009-03-15 21:37:18 -060088static u32 logging_level;
Eric Moore635374e2009-03-09 01:21:12 -060089MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
90 "(default=0)");
91
92/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
93#define MPT2SAS_MAX_LUN (16895)
94static int max_lun = MPT2SAS_MAX_LUN;
95module_param(max_lun, int, 0);
96MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
97
98/**
99 * struct sense_info - common structure for obtaining sense keys
100 * @skey: sense key
101 * @asc: additional sense code
102 * @ascq: additional sense code qualifier
103 */
104struct sense_info {
105 u8 skey;
106 u8 asc;
107 u8 ascq;
108};
109
110
Eric Moore635374e2009-03-09 01:21:12 -0600111/**
112 * struct fw_event_work - firmware event struct
113 * @list: link list framework
114 * @work: work object (ioc->fault_reset_work_q)
115 * @ioc: per adapter object
116 * @VF_ID: virtual function id
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530117 * @VP_ID: virtual port id
Eric Moore635374e2009-03-09 01:21:12 -0600118 * @host_reset_handling: handling events during host reset
119 * @ignore: flag meaning this event has been marked to ignore
120 * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
121 * @event_data: reply event data payload follows
122 *
123 * This object stored on ioc->fw_event_list.
124 */
125struct fw_event_work {
126 struct list_head list;
Eric Moore6f92a7a2009-04-21 15:43:33 -0600127 struct work_struct work;
Eric Moore635374e2009-03-09 01:21:12 -0600128 struct MPT2SAS_ADAPTER *ioc;
129 u8 VF_ID;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530130 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600131 u8 host_reset_handling;
132 u8 ignore;
133 u16 event;
134 void *event_data;
135};
136
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +0530137/* raid transport support */
138static struct raid_template *mpt2sas_raid_template;
139
Eric Moore635374e2009-03-09 01:21:12 -0600140/**
141 * struct _scsi_io_transfer - scsi io transfer
142 * @handle: sas device handle (assigned by firmware)
143 * @is_raid: flag set for hidden raid components
144 * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
145 * @data_length: data transfer length
146 * @data_dma: dma pointer to data
147 * @sense: sense data
148 * @lun: lun number
149 * @cdb_length: cdb length
150 * @cdb: cdb contents
Eric Moore635374e2009-03-09 01:21:12 -0600151 * @timeout: timeout for this command
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530152 * @VF_ID: virtual function id
153 * @VP_ID: virtual port id
154 * @valid_reply: flag set for reply message
Eric Moore635374e2009-03-09 01:21:12 -0600155 * @sense_length: sense length
156 * @ioc_status: ioc status
157 * @scsi_state: scsi state
158 * @scsi_status: scsi staus
159 * @log_info: log information
160 * @transfer_length: data length transfer when there is a reply message
161 *
162 * Used for sending internal scsi commands to devices within this module.
163 * Refer to _scsi_send_scsi_io().
164 */
165struct _scsi_io_transfer {
166 u16 handle;
167 u8 is_raid;
168 enum dma_data_direction dir;
169 u32 data_length;
170 dma_addr_t data_dma;
171 u8 sense[SCSI_SENSE_BUFFERSIZE];
172 u32 lun;
173 u8 cdb_length;
174 u8 cdb[32];
175 u8 timeout;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530176 u8 VF_ID;
177 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600178 u8 valid_reply;
179 /* the following bits are only valid when 'valid_reply = 1' */
180 u32 sense_length;
181 u16 ioc_status;
182 u8 scsi_state;
183 u8 scsi_status;
184 u32 log_info;
185 u32 transfer_length;
186};
187
188/*
189 * The pci device ids are defined in mpi/mpi2_cnfg.h.
190 */
191static struct pci_device_id scsih_pci_table[] = {
192 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
193 PCI_ANY_ID, PCI_ANY_ID },
194 /* Falcon ~ 2008*/
195 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
196 PCI_ANY_ID, PCI_ANY_ID },
197 /* Liberator ~ 2108 */
198 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
199 PCI_ANY_ID, PCI_ANY_ID },
200 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
201 PCI_ANY_ID, PCI_ANY_ID },
202 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
203 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530204 /* Meteor ~ 2116 */
Eric Moore635374e2009-03-09 01:21:12 -0600205 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
206 PCI_ANY_ID, PCI_ANY_ID },
207 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
208 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530209 /* Thunderbolt ~ 2208 */
210 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
211 PCI_ANY_ID, PCI_ANY_ID },
212 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
213 PCI_ANY_ID, PCI_ANY_ID },
214 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
215 PCI_ANY_ID, PCI_ANY_ID },
216 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
217 PCI_ANY_ID, PCI_ANY_ID },
218 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
219 PCI_ANY_ID, PCI_ANY_ID },
220 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
221 PCI_ANY_ID, PCI_ANY_ID },
222 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7,
223 PCI_ANY_ID, PCI_ANY_ID },
224 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8,
225 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore635374e2009-03-09 01:21:12 -0600226 {0} /* Terminating entry */
227};
228MODULE_DEVICE_TABLE(pci, scsih_pci_table);
229
230/**
Eric Moored5d135b2009-05-18 13:02:08 -0600231 * _scsih_set_debug_level - global setting of ioc->logging_level.
Eric Moore635374e2009-03-09 01:21:12 -0600232 *
233 * Note: The logging levels are defined in mpt2sas_debug.h.
234 */
235static int
Eric Moored5d135b2009-05-18 13:02:08 -0600236_scsih_set_debug_level(const char *val, struct kernel_param *kp)
Eric Moore635374e2009-03-09 01:21:12 -0600237{
238 int ret = param_set_int(val, kp);
239 struct MPT2SAS_ADAPTER *ioc;
240
241 if (ret)
242 return ret;
243
244 printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
Eric Mooreba33fad2009-03-15 21:37:18 -0600245 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
Eric Moore635374e2009-03-09 01:21:12 -0600246 ioc->logging_level = logging_level;
247 return 0;
248}
Eric Moored5d135b2009-05-18 13:02:08 -0600249module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
Eric Moore635374e2009-03-09 01:21:12 -0600250 &logging_level, 0644);
251
252/**
253 * _scsih_srch_boot_sas_address - search based on sas_address
254 * @sas_address: sas address
255 * @boot_device: boot device object from bios page 2
256 *
257 * Returns 1 when there's a match, 0 means no match.
258 */
259static inline int
260_scsih_srch_boot_sas_address(u64 sas_address,
261 Mpi2BootDeviceSasWwid_t *boot_device)
262{
263 return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
264}
265
266/**
267 * _scsih_srch_boot_device_name - search based on device name
268 * @device_name: device name specified in INDENTIFY fram
269 * @boot_device: boot device object from bios page 2
270 *
271 * Returns 1 when there's a match, 0 means no match.
272 */
273static inline int
274_scsih_srch_boot_device_name(u64 device_name,
275 Mpi2BootDeviceDeviceName_t *boot_device)
276{
277 return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
278}
279
280/**
281 * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
282 * @enclosure_logical_id: enclosure logical id
283 * @slot_number: slot number
284 * @boot_device: boot device object from bios page 2
285 *
286 * Returns 1 when there's a match, 0 means no match.
287 */
288static inline int
289_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
290 Mpi2BootDeviceEnclosureSlot_t *boot_device)
291{
292 return (enclosure_logical_id == le64_to_cpu(boot_device->
293 EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
294 SlotNumber)) ? 1 : 0;
295}
296
297/**
298 * _scsih_is_boot_device - search for matching boot device.
299 * @sas_address: sas address
300 * @device_name: device name specified in INDENTIFY fram
301 * @enclosure_logical_id: enclosure logical id
302 * @slot_number: slot number
303 * @form: specifies boot device form
304 * @boot_device: boot device object from bios page 2
305 *
306 * Returns 1 when there's a match, 0 means no match.
307 */
308static int
309_scsih_is_boot_device(u64 sas_address, u64 device_name,
310 u64 enclosure_logical_id, u16 slot, u8 form,
311 Mpi2BiosPage2BootDevice_t *boot_device)
312{
313 int rc = 0;
314
315 switch (form) {
316 case MPI2_BIOSPAGE2_FORM_SAS_WWID:
317 if (!sas_address)
318 break;
319 rc = _scsih_srch_boot_sas_address(
320 sas_address, &boot_device->SasWwid);
321 break;
322 case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
323 if (!enclosure_logical_id)
324 break;
325 rc = _scsih_srch_boot_encl_slot(
326 enclosure_logical_id,
327 slot, &boot_device->EnclosureSlot);
328 break;
329 case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
330 if (!device_name)
331 break;
332 rc = _scsih_srch_boot_device_name(
333 device_name, &boot_device->DeviceName);
334 break;
335 case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
336 break;
337 }
338
339 return rc;
340}
341
342/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530343 * _scsih_get_sas_address - set the sas_address for given device handle
344 * @handle: device handle
345 * @sas_address: sas address
346 *
347 * Returns 0 success, non-zero when failure
348 */
349static int
350_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
351 u64 *sas_address)
352{
353 Mpi2SasDevicePage0_t sas_device_pg0;
354 Mpi2ConfigReply_t mpi_reply;
355 u32 ioc_status;
356
357 if (handle <= ioc->sas_hba.num_phys) {
358 *sas_address = ioc->sas_hba.sas_address;
359 return 0;
360 } else
361 *sas_address = 0;
362
363 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
364 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
365 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
366 ioc->name, __FILE__, __LINE__, __func__);
367 return -ENXIO;
368 }
369
370 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
371 MPI2_IOCSTATUS_MASK;
372 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
373 printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
374 "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
375 __FILE__, __LINE__, __func__);
376 return -EIO;
377 }
378
379 *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
380 return 0;
381}
382
383/**
Eric Moore635374e2009-03-09 01:21:12 -0600384 * _scsih_determine_boot_device - determine boot device.
385 * @ioc: per adapter object
386 * @device: either sas_device or raid_device object
387 * @is_raid: [flag] 1 = raid object, 0 = sas object
388 *
389 * Determines whether this device should be first reported device to
390 * to scsi-ml or sas transport, this purpose is for persistant boot device.
391 * There are primary, alternate, and current entries in bios page 2. The order
392 * priority is primary, alternate, then current. This routine saves
393 * the corresponding device object and is_raid flag in the ioc object.
394 * The saved data to be used later in _scsih_probe_boot_devices().
395 */
396static void
397_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
398 void *device, u8 is_raid)
399{
400 struct _sas_device *sas_device;
401 struct _raid_device *raid_device;
402 u64 sas_address;
403 u64 device_name;
404 u64 enclosure_logical_id;
405 u16 slot;
406
407 /* only process this function when driver loads */
408 if (!ioc->wait_for_port_enable_to_complete)
409 return;
410
411 if (!is_raid) {
412 sas_device = device;
413 sas_address = sas_device->sas_address;
414 device_name = sas_device->device_name;
415 enclosure_logical_id = sas_device->enclosure_logical_id;
416 slot = sas_device->slot;
417 } else {
418 raid_device = device;
419 sas_address = raid_device->wwid;
420 device_name = 0;
421 enclosure_logical_id = 0;
422 slot = 0;
423 }
424
425 if (!ioc->req_boot_device.device) {
426 if (_scsih_is_boot_device(sas_address, device_name,
427 enclosure_logical_id, slot,
428 (ioc->bios_pg2.ReqBootDeviceForm &
429 MPI2_BIOSPAGE2_FORM_MASK),
430 &ioc->bios_pg2.RequestedBootDevice)) {
431 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
432 "%s: req_boot_device(0x%016llx)\n",
433 ioc->name, __func__,
434 (unsigned long long)sas_address));
435 ioc->req_boot_device.device = device;
436 ioc->req_boot_device.is_raid = is_raid;
437 }
438 }
439
440 if (!ioc->req_alt_boot_device.device) {
441 if (_scsih_is_boot_device(sas_address, device_name,
442 enclosure_logical_id, slot,
443 (ioc->bios_pg2.ReqAltBootDeviceForm &
444 MPI2_BIOSPAGE2_FORM_MASK),
445 &ioc->bios_pg2.RequestedAltBootDevice)) {
446 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
447 "%s: req_alt_boot_device(0x%016llx)\n",
448 ioc->name, __func__,
449 (unsigned long long)sas_address));
450 ioc->req_alt_boot_device.device = device;
451 ioc->req_alt_boot_device.is_raid = is_raid;
452 }
453 }
454
455 if (!ioc->current_boot_device.device) {
456 if (_scsih_is_boot_device(sas_address, device_name,
457 enclosure_logical_id, slot,
458 (ioc->bios_pg2.CurrentBootDeviceForm &
459 MPI2_BIOSPAGE2_FORM_MASK),
460 &ioc->bios_pg2.CurrentBootDevice)) {
461 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
462 "%s: current_boot_device(0x%016llx)\n",
463 ioc->name, __func__,
464 (unsigned long long)sas_address));
465 ioc->current_boot_device.device = device;
466 ioc->current_boot_device.is_raid = is_raid;
467 }
468 }
469}
470
471/**
472 * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
473 * @ioc: per adapter object
474 * @sas_address: sas address
475 * Context: Calling function should acquire ioc->sas_device_lock
476 *
477 * This searches for sas_device based on sas_address, then return sas_device
478 * object.
479 */
480struct _sas_device *
481mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
482 u64 sas_address)
483{
484 struct _sas_device *sas_device, *r;
485
486 r = NULL;
487 /* check the sas_device_init_list */
488 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
489 list) {
490 if (sas_device->sas_address != sas_address)
491 continue;
492 r = sas_device;
493 goto out;
494 }
495
496 /* then check the sas_device_list */
497 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
498 if (sas_device->sas_address != sas_address)
499 continue;
500 r = sas_device;
501 goto out;
502 }
503 out:
504 return r;
505}
506
507/**
508 * _scsih_sas_device_find_by_handle - sas device search
509 * @ioc: per adapter object
510 * @handle: sas device handle (assigned by firmware)
511 * Context: Calling function should acquire ioc->sas_device_lock
512 *
513 * This searches for sas_device based on sas_address, then return sas_device
514 * object.
515 */
516static struct _sas_device *
517_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
518{
519 struct _sas_device *sas_device, *r;
520
521 r = NULL;
522 if (ioc->wait_for_port_enable_to_complete) {
523 list_for_each_entry(sas_device, &ioc->sas_device_init_list,
524 list) {
525 if (sas_device->handle != handle)
526 continue;
527 r = sas_device;
528 goto out;
529 }
530 } else {
531 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
532 if (sas_device->handle != handle)
533 continue;
534 r = sas_device;
535 goto out;
536 }
537 }
538
539 out:
540 return r;
541}
542
543/**
544 * _scsih_sas_device_remove - remove sas_device from list.
545 * @ioc: per adapter object
546 * @sas_device: the sas_device object
547 * Context: This function will acquire ioc->sas_device_lock.
548 *
549 * Removing object and freeing associated memory from the ioc->sas_device_list.
550 */
551static void
552_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
553 struct _sas_device *sas_device)
554{
555 unsigned long flags;
556
557 spin_lock_irqsave(&ioc->sas_device_lock, flags);
558 list_del(&sas_device->list);
559 memset(sas_device, 0, sizeof(struct _sas_device));
560 kfree(sas_device);
561 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
562}
563
564/**
565 * _scsih_sas_device_add - insert sas_device to the list.
566 * @ioc: per adapter object
567 * @sas_device: the sas_device object
568 * Context: This function will acquire ioc->sas_device_lock.
569 *
570 * Adding new object to the ioc->sas_device_list.
571 */
572static void
573_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
574 struct _sas_device *sas_device)
575{
576 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -0600577
578 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
579 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
580 sas_device->handle, (unsigned long long)sas_device->sas_address));
581
582 spin_lock_irqsave(&ioc->sas_device_lock, flags);
583 list_add_tail(&sas_device->list, &ioc->sas_device_list);
584 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
585
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530586 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
587 sas_device->sas_address_parent))
Eric Moore635374e2009-03-09 01:21:12 -0600588 _scsih_sas_device_remove(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -0600589}
590
591/**
592 * _scsih_sas_device_init_add - insert sas_device to the list.
593 * @ioc: per adapter object
594 * @sas_device: the sas_device object
595 * Context: This function will acquire ioc->sas_device_lock.
596 *
597 * Adding new object at driver load time to the ioc->sas_device_init_list.
598 */
599static void
600_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
601 struct _sas_device *sas_device)
602{
603 unsigned long flags;
604
605 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
606 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
607 sas_device->handle, (unsigned long long)sas_device->sas_address));
608
609 spin_lock_irqsave(&ioc->sas_device_lock, flags);
610 list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
611 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
612 _scsih_determine_boot_device(ioc, sas_device, 0);
613}
614
615/**
Eric Moore635374e2009-03-09 01:21:12 -0600616 * _scsih_raid_device_find_by_id - raid device search
617 * @ioc: per adapter object
618 * @id: sas device target id
619 * @channel: sas device channel
620 * Context: Calling function should acquire ioc->raid_device_lock
621 *
622 * This searches for raid_device based on target id, then return raid_device
623 * object.
624 */
625static struct _raid_device *
626_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
627{
628 struct _raid_device *raid_device, *r;
629
630 r = NULL;
631 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
632 if (raid_device->id == id && raid_device->channel == channel) {
633 r = raid_device;
634 goto out;
635 }
636 }
637
638 out:
639 return r;
640}
641
642/**
643 * _scsih_raid_device_find_by_handle - raid device search
644 * @ioc: per adapter object
645 * @handle: sas device handle (assigned by firmware)
646 * Context: Calling function should acquire ioc->raid_device_lock
647 *
648 * This searches for raid_device based on handle, then return raid_device
649 * object.
650 */
651static struct _raid_device *
652_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
653{
654 struct _raid_device *raid_device, *r;
655
656 r = NULL;
657 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
658 if (raid_device->handle != handle)
659 continue;
660 r = raid_device;
661 goto out;
662 }
663
664 out:
665 return r;
666}
667
668/**
669 * _scsih_raid_device_find_by_wwid - raid device search
670 * @ioc: per adapter object
671 * @handle: sas device handle (assigned by firmware)
672 * Context: Calling function should acquire ioc->raid_device_lock
673 *
674 * This searches for raid_device based on wwid, then return raid_device
675 * object.
676 */
677static struct _raid_device *
678_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
679{
680 struct _raid_device *raid_device, *r;
681
682 r = NULL;
683 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
684 if (raid_device->wwid != wwid)
685 continue;
686 r = raid_device;
687 goto out;
688 }
689
690 out:
691 return r;
692}
693
694/**
695 * _scsih_raid_device_add - add raid_device object
696 * @ioc: per adapter object
697 * @raid_device: raid_device object
698 *
699 * This is added to the raid_device_list link list.
700 */
701static void
702_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
703 struct _raid_device *raid_device)
704{
705 unsigned long flags;
706
707 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
708 "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
709 raid_device->handle, (unsigned long long)raid_device->wwid));
710
711 spin_lock_irqsave(&ioc->raid_device_lock, flags);
712 list_add_tail(&raid_device->list, &ioc->raid_device_list);
713 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
714}
715
716/**
717 * _scsih_raid_device_remove - delete raid_device object
718 * @ioc: per adapter object
719 * @raid_device: raid_device object
720 *
721 * This is removed from the raid_device_list link list.
722 */
723static void
724_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
725 struct _raid_device *raid_device)
726{
727 unsigned long flags;
728
729 spin_lock_irqsave(&ioc->raid_device_lock, flags);
730 list_del(&raid_device->list);
731 memset(raid_device, 0, sizeof(struct _raid_device));
732 kfree(raid_device);
733 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
734}
735
736/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530737 * mpt2sas_scsih_expander_find_by_handle - expander device search
738 * @ioc: per adapter object
739 * @handle: expander handle (assigned by firmware)
740 * Context: Calling function should acquire ioc->sas_device_lock
741 *
742 * This searches for expander device based on handle, then returns the
743 * sas_node object.
744 */
745struct _sas_node *
746mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
747{
748 struct _sas_node *sas_expander, *r;
749
750 r = NULL;
751 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
752 if (sas_expander->handle != handle)
753 continue;
754 r = sas_expander;
755 goto out;
756 }
757 out:
758 return r;
759}
760
761/**
Eric Moore635374e2009-03-09 01:21:12 -0600762 * mpt2sas_scsih_expander_find_by_sas_address - expander device search
763 * @ioc: per adapter object
764 * @sas_address: sas address
765 * Context: Calling function should acquire ioc->sas_node_lock.
766 *
767 * This searches for expander device based on sas_address, then returns the
768 * sas_node object.
769 */
770struct _sas_node *
771mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
772 u64 sas_address)
773{
774 struct _sas_node *sas_expander, *r;
775
776 r = NULL;
777 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
778 if (sas_expander->sas_address != sas_address)
779 continue;
780 r = sas_expander;
781 goto out;
782 }
783 out:
784 return r;
785}
786
787/**
788 * _scsih_expander_node_add - insert expander device to the list.
789 * @ioc: per adapter object
790 * @sas_expander: the sas_device object
791 * Context: This function will acquire ioc->sas_node_lock.
792 *
793 * Adding new object to the ioc->sas_expander_list.
794 *
795 * Return nothing.
796 */
797static void
798_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
799 struct _sas_node *sas_expander)
800{
801 unsigned long flags;
802
803 spin_lock_irqsave(&ioc->sas_node_lock, flags);
804 list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
805 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
806}
807
808/**
809 * _scsih_is_end_device - determines if device is an end device
810 * @device_info: bitfield providing information about the device.
811 * Context: none
812 *
813 * Returns 1 if end device.
814 */
815static int
816_scsih_is_end_device(u32 device_info)
817{
818 if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
819 ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
820 (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
821 (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
822 return 1;
823 else
824 return 0;
825}
826
827/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530828 * mptscsih_get_scsi_lookup - returns scmd entry
Eric Moore635374e2009-03-09 01:21:12 -0600829 * @ioc: per adapter object
830 * @smid: system request message index
Eric Moore635374e2009-03-09 01:21:12 -0600831 *
832 * Returns the smid stored scmd pointer.
833 */
834static struct scsi_cmnd *
835_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
836{
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530837 return ioc->scsi_lookup[smid - 1].scmd;
Eric Moore635374e2009-03-09 01:21:12 -0600838}
839
840/**
841 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
842 * @ioc: per adapter object
843 * @smid: system request message index
844 * @scmd: pointer to scsi command object
845 * Context: This function will acquire ioc->scsi_lookup_lock.
846 *
847 * This will search for a scmd pointer in the scsi_lookup array,
848 * returning the revelent smid. A returned value of zero means invalid.
849 */
850static u16
851_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
852 *scmd)
853{
854 u16 smid;
855 unsigned long flags;
856 int i;
857
858 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
859 smid = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530860 for (i = 0; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600861 if (ioc->scsi_lookup[i].scmd == scmd) {
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530862 smid = ioc->scsi_lookup[i].smid;
Eric Moore635374e2009-03-09 01:21:12 -0600863 goto out;
864 }
865 }
866 out:
867 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
868 return smid;
869}
870
871/**
872 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
873 * @ioc: per adapter object
874 * @id: target id
875 * @channel: channel
876 * Context: This function will acquire ioc->scsi_lookup_lock.
877 *
878 * This will search for a matching channel:id in the scsi_lookup array,
879 * returning 1 if found.
880 */
881static u8
882_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
883 int channel)
884{
885 u8 found;
886 unsigned long flags;
887 int i;
888
889 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
890 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530891 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600892 if (ioc->scsi_lookup[i].scmd &&
893 (ioc->scsi_lookup[i].scmd->device->id == id &&
894 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
895 found = 1;
896 goto out;
897 }
898 }
899 out:
900 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
901 return found;
902}
903
904/**
Eric Moore993e0da2009-05-18 13:00:45 -0600905 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
906 * @ioc: per adapter object
907 * @id: target id
908 * @lun: lun number
909 * @channel: channel
910 * Context: This function will acquire ioc->scsi_lookup_lock.
911 *
912 * This will search for a matching channel:id:lun in the scsi_lookup array,
913 * returning 1 if found.
914 */
915static u8
916_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
917 unsigned int lun, int channel)
918{
919 u8 found;
920 unsigned long flags;
921 int i;
922
923 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
924 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530925 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore993e0da2009-05-18 13:00:45 -0600926 if (ioc->scsi_lookup[i].scmd &&
927 (ioc->scsi_lookup[i].scmd->device->id == id &&
928 ioc->scsi_lookup[i].scmd->device->channel == channel &&
929 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
930 found = 1;
931 goto out;
932 }
933 }
934 out:
935 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
936 return found;
937}
938
939/**
Eric Moore635374e2009-03-09 01:21:12 -0600940 * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
941 * @ioc: per adapter object
942 * @smid: system request message index
943 *
944 * Returns phys pointer to chain buffer.
945 */
946static dma_addr_t
947_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
948{
949 return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
950 ioc->chains_needed_per_io));
951}
952
953/**
954 * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
955 * @ioc: per adapter object
956 * @smid: system request message index
957 *
958 * Returns virt pointer to chain buffer.
959 */
960static void *
961_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
962{
963 return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
964 ioc->chains_needed_per_io)));
965}
966
967/**
968 * _scsih_build_scatter_gather - main sg creation routine
969 * @ioc: per adapter object
970 * @scmd: scsi command
971 * @smid: system request message index
972 * Context: none.
973 *
974 * The main routine that builds scatter gather table from a given
975 * scsi request sent via the .queuecommand main handler.
976 *
977 * Returns 0 success, anything else error
978 */
979static int
980_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
981 struct scsi_cmnd *scmd, u16 smid)
982{
983 Mpi2SCSIIORequest_t *mpi_request;
984 dma_addr_t chain_dma;
985 struct scatterlist *sg_scmd;
986 void *sg_local, *chain;
987 u32 chain_offset;
988 u32 chain_length;
989 u32 chain_flags;
990 u32 sges_left;
991 u32 sges_in_segment;
992 u32 sgl_flags;
993 u32 sgl_flags_last_element;
994 u32 sgl_flags_end_buffer;
995
996 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
997
998 /* init scatter gather flags */
999 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
1000 if (scmd->sc_data_direction == DMA_TO_DEVICE)
1001 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
1002 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
1003 << MPI2_SGE_FLAGS_SHIFT;
1004 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
1005 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
1006 << MPI2_SGE_FLAGS_SHIFT;
1007 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1008
1009 sg_scmd = scsi_sglist(scmd);
1010 sges_left = scsi_dma_map(scmd);
1011 if (!sges_left) {
1012 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
1013 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
1014 return -ENOMEM;
1015 }
1016
1017 sg_local = &mpi_request->SGL;
1018 sges_in_segment = ioc->max_sges_in_main_message;
1019 if (sges_left <= sges_in_segment)
1020 goto fill_in_last_segment;
1021
1022 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
1023 (sges_in_segment * ioc->sge_size))/4;
1024
1025 /* fill in main message segment when there is a chain following */
1026 while (sges_in_segment) {
1027 if (sges_in_segment == 1)
1028 ioc->base_add_sg_single(sg_local,
1029 sgl_flags_last_element | sg_dma_len(sg_scmd),
1030 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 sges_in_segment--;
1038 }
1039
1040 /* initializing the chain flags and pointers */
1041 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
1042 chain = _scsih_get_chain_buffer(ioc, smid);
1043 chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
1044 do {
1045 sges_in_segment = (sges_left <=
1046 ioc->max_sges_in_chain_message) ? sges_left :
1047 ioc->max_sges_in_chain_message;
1048 chain_offset = (sges_left == sges_in_segment) ?
1049 0 : (sges_in_segment * ioc->sge_size)/4;
1050 chain_length = sges_in_segment * ioc->sge_size;
1051 if (chain_offset) {
1052 chain_offset = chain_offset <<
1053 MPI2_SGE_CHAIN_OFFSET_SHIFT;
1054 chain_length += ioc->sge_size;
1055 }
1056 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
1057 chain_length, chain_dma);
1058 sg_local = chain;
1059 if (!chain_offset)
1060 goto fill_in_last_segment;
1061
1062 /* fill in chain segments */
1063 while (sges_in_segment) {
1064 if (sges_in_segment == 1)
1065 ioc->base_add_sg_single(sg_local,
1066 sgl_flags_last_element |
1067 sg_dma_len(sg_scmd),
1068 sg_dma_address(sg_scmd));
1069 else
1070 ioc->base_add_sg_single(sg_local, sgl_flags |
1071 sg_dma_len(sg_scmd),
1072 sg_dma_address(sg_scmd));
1073 sg_scmd = sg_next(sg_scmd);
1074 sg_local += ioc->sge_size;
1075 sges_left--;
1076 sges_in_segment--;
1077 }
1078
1079 chain_dma += ioc->request_sz;
1080 chain += ioc->request_sz;
1081 } while (1);
1082
1083
1084 fill_in_last_segment:
1085
1086 /* fill the last segment */
1087 while (sges_left) {
1088 if (sges_left == 1)
1089 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1090 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1091 else
1092 ioc->base_add_sg_single(sg_local, sgl_flags |
1093 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1094 sg_scmd = sg_next(sg_scmd);
1095 sg_local += ioc->sge_size;
1096 sges_left--;
1097 }
1098
1099 return 0;
1100}
1101
1102/**
Eric Moored5d135b2009-05-18 13:02:08 -06001103 * _scsih_change_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001104 * @sdev: scsi device struct
1105 * @qdepth: requested queue depth
Mike Christiee881a172009-10-15 17:46:39 -07001106 * @reason: calling context
Eric Moore635374e2009-03-09 01:21:12 -06001107 *
1108 * Returns queue depth.
1109 */
1110static int
Mike Christiee881a172009-10-15 17:46:39 -07001111_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
Eric Moore635374e2009-03-09 01:21:12 -06001112{
1113 struct Scsi_Host *shost = sdev->host;
1114 int max_depth;
1115 int tag_type;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301116 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1117 struct MPT2SAS_DEVICE *sas_device_priv_data;
1118 struct MPT2SAS_TARGET *sas_target_priv_data;
1119 struct _sas_device *sas_device;
1120 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06001121
Mike Christiee881a172009-10-15 17:46:39 -07001122 if (reason != SCSI_QDEPTH_DEFAULT)
1123 return -EOPNOTSUPP;
1124
Eric Moore635374e2009-03-09 01:21:12 -06001125 max_depth = shost->can_queue;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301126
1127 /* limit max device queue for SATA to 32 */
1128 sas_device_priv_data = sdev->hostdata;
1129 if (!sas_device_priv_data)
1130 goto not_sata;
1131 sas_target_priv_data = sas_device_priv_data->sas_target;
1132 if (!sas_target_priv_data)
1133 goto not_sata;
1134 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
1135 goto not_sata;
1136 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1137 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1138 sas_device_priv_data->sas_target->sas_address);
1139 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1140 if (sas_device && sas_device->device_info &
1141 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1142 max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
1143
1144 not_sata:
1145
Eric Moore635374e2009-03-09 01:21:12 -06001146 if (!sdev->tagged_supported)
1147 max_depth = 1;
1148 if (qdepth > max_depth)
1149 qdepth = max_depth;
1150 tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
1151 scsi_adjust_queue_depth(sdev, tag_type, qdepth);
1152
1153 if (sdev->inquiry_len > 7)
1154 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1155 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1156 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1157 sdev->ordered_tags, sdev->scsi_level,
1158 (sdev->inquiry[7] & 2) >> 1);
1159
1160 return sdev->queue_depth;
1161}
1162
1163/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301164 * _scsih_change_queue_type - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001165 * @sdev: scsi device struct
1166 * @tag_type: requested tag type
1167 *
1168 * Returns queue tag type.
1169 */
1170static int
Eric Moored5d135b2009-05-18 13:02:08 -06001171_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001172{
1173 if (sdev->tagged_supported) {
1174 scsi_set_tag_type(sdev, tag_type);
1175 if (tag_type)
1176 scsi_activate_tcq(sdev, sdev->queue_depth);
1177 else
1178 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1179 } else
1180 tag_type = 0;
1181
1182 return tag_type;
1183}
1184
1185/**
Eric Moored5d135b2009-05-18 13:02:08 -06001186 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001187 * @starget: scsi target struct
1188 *
1189 * Returns 0 if ok. Any other return is assumed to be an error and
1190 * the device is ignored.
1191 */
1192static int
Eric Moored5d135b2009-05-18 13:02:08 -06001193_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001194{
1195 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1196 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1197 struct MPT2SAS_TARGET *sas_target_priv_data;
1198 struct _sas_device *sas_device;
1199 struct _raid_device *raid_device;
1200 unsigned long flags;
1201 struct sas_rphy *rphy;
1202
1203 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1204 if (!sas_target_priv_data)
1205 return -ENOMEM;
1206
1207 starget->hostdata = sas_target_priv_data;
1208 sas_target_priv_data->starget = starget;
1209 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1210
1211 /* RAID volumes */
1212 if (starget->channel == RAID_CHANNEL) {
1213 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1214 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1215 starget->channel);
1216 if (raid_device) {
1217 sas_target_priv_data->handle = raid_device->handle;
1218 sas_target_priv_data->sas_address = raid_device->wwid;
1219 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
1220 raid_device->starget = starget;
1221 }
1222 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1223 return 0;
1224 }
1225
1226 /* sas/sata devices */
1227 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1228 rphy = dev_to_rphy(starget->dev.parent);
1229 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1230 rphy->identify.sas_address);
1231
1232 if (sas_device) {
1233 sas_target_priv_data->handle = sas_device->handle;
1234 sas_target_priv_data->sas_address = sas_device->sas_address;
1235 sas_device->starget = starget;
1236 sas_device->id = starget->id;
1237 sas_device->channel = starget->channel;
1238 if (sas_device->hidden_raid_component)
1239 sas_target_priv_data->flags |=
1240 MPT_TARGET_FLAGS_RAID_COMPONENT;
1241 }
1242 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1243
1244 return 0;
1245}
1246
1247/**
Eric Moored5d135b2009-05-18 13:02:08 -06001248 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001249 * @starget: scsi target struct
1250 *
1251 * Returns nothing.
1252 */
1253static void
Eric Moored5d135b2009-05-18 13:02:08 -06001254_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001255{
1256 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1257 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1258 struct MPT2SAS_TARGET *sas_target_priv_data;
1259 struct _sas_device *sas_device;
1260 struct _raid_device *raid_device;
1261 unsigned long flags;
1262 struct sas_rphy *rphy;
1263
1264 sas_target_priv_data = starget->hostdata;
1265 if (!sas_target_priv_data)
1266 return;
1267
1268 if (starget->channel == RAID_CHANNEL) {
1269 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1270 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1271 starget->channel);
1272 if (raid_device) {
1273 raid_device->starget = NULL;
1274 raid_device->sdev = NULL;
1275 }
1276 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1277 goto out;
1278 }
1279
1280 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1281 rphy = dev_to_rphy(starget->dev.parent);
1282 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1283 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001284 if (sas_device && (sas_device->starget == starget) &&
1285 (sas_device->id == starget->id) &&
1286 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001287 sas_device->starget = NULL;
1288
1289 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1290
1291 out:
1292 kfree(sas_target_priv_data);
1293 starget->hostdata = NULL;
1294}
1295
1296/**
Eric Moored5d135b2009-05-18 13:02:08 -06001297 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001298 * @sdev: scsi device struct
1299 *
1300 * Returns 0 if ok. Any other return is assumed to be an error and
1301 * the device is ignored.
1302 */
1303static int
Eric Moored5d135b2009-05-18 13:02:08 -06001304_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001305{
1306 struct Scsi_Host *shost;
1307 struct MPT2SAS_ADAPTER *ioc;
1308 struct MPT2SAS_TARGET *sas_target_priv_data;
1309 struct MPT2SAS_DEVICE *sas_device_priv_data;
1310 struct scsi_target *starget;
1311 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06001312 unsigned long flags;
1313
1314 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1315 if (!sas_device_priv_data)
1316 return -ENOMEM;
1317
1318 sas_device_priv_data->lun = sdev->lun;
1319 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1320
1321 starget = scsi_target(sdev);
1322 sas_target_priv_data = starget->hostdata;
1323 sas_target_priv_data->num_luns++;
1324 sas_device_priv_data->sas_target = sas_target_priv_data;
1325 sdev->hostdata = sas_device_priv_data;
1326 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1327 sdev->no_uld_attach = 1;
1328
1329 shost = dev_to_shost(&starget->dev);
1330 ioc = shost_priv(shost);
1331 if (starget->channel == RAID_CHANNEL) {
1332 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1333 raid_device = _scsih_raid_device_find_by_id(ioc,
1334 starget->id, starget->channel);
1335 if (raid_device)
1336 raid_device->sdev = sdev; /* raid is single lun */
1337 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06001338 }
1339
Eric Moore635374e2009-03-09 01:21:12 -06001340 return 0;
1341}
1342
1343/**
Eric Moored5d135b2009-05-18 13:02:08 -06001344 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001345 * @sdev: scsi device struct
1346 *
1347 * Returns nothing.
1348 */
1349static void
Eric Moored5d135b2009-05-18 13:02:08 -06001350_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001351{
1352 struct MPT2SAS_TARGET *sas_target_priv_data;
1353 struct scsi_target *starget;
1354
1355 if (!sdev->hostdata)
1356 return;
1357
1358 starget = scsi_target(sdev);
1359 sas_target_priv_data = starget->hostdata;
1360 sas_target_priv_data->num_luns--;
1361 kfree(sdev->hostdata);
1362 sdev->hostdata = NULL;
1363}
1364
1365/**
Eric Moored5d135b2009-05-18 13:02:08 -06001366 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001367 * @ioc: per adapter object
1368 * @sas_device: the sas_device object
1369 * @sdev: scsi device struct
1370 */
1371static void
Eric Moored5d135b2009-05-18 13:02:08 -06001372_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06001373 struct _sas_device *sas_device, struct scsi_device *sdev)
1374{
1375 Mpi2ConfigReply_t mpi_reply;
1376 Mpi2SasDevicePage0_t sas_device_pg0;
1377 u32 ioc_status;
1378 u16 flags;
1379 u32 device_info;
1380
1381 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
1382 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
1383 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1384 ioc->name, __FILE__, __LINE__, __func__);
1385 return;
1386 }
1387
1388 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1389 MPI2_IOCSTATUS_MASK;
1390 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1391 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1392 ioc->name, __FILE__, __LINE__, __func__);
1393 return;
1394 }
1395
1396 flags = le16_to_cpu(sas_device_pg0.Flags);
1397 device_info = le16_to_cpu(sas_device_pg0.DeviceInfo);
1398
1399 sdev_printk(KERN_INFO, sdev,
1400 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1401 "sw_preserve(%s)\n",
1402 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1403 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1404 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1405 "n",
1406 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1407 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1408 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1409}
1410
1411/**
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301412 * _scsih_is_raid - return boolean indicating device is raid volume
1413 * @dev the device struct object
1414 */
1415static int
1416_scsih_is_raid(struct device *dev)
1417{
1418 struct scsi_device *sdev = to_scsi_device(dev);
1419
1420 return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
1421}
1422
1423/**
1424 * _scsih_get_resync - get raid volume resync percent complete
1425 * @dev the device struct object
1426 */
1427static void
1428_scsih_get_resync(struct device *dev)
1429{
1430 struct scsi_device *sdev = to_scsi_device(dev);
1431 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1432 static struct _raid_device *raid_device;
1433 unsigned long flags;
1434 Mpi2RaidVolPage0_t vol_pg0;
1435 Mpi2ConfigReply_t mpi_reply;
1436 u32 volume_status_flags;
1437 u8 percent_complete = 0;
1438
1439 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1440 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1441 sdev->channel);
1442 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1443
1444 if (!raid_device)
1445 goto out;
1446
1447 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1448 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1449 sizeof(Mpi2RaidVolPage0_t))) {
1450 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1451 ioc->name, __FILE__, __LINE__, __func__);
1452 goto out;
1453 }
1454
1455 volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1456 if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
1457 percent_complete = raid_device->percent_complete;
1458 out:
1459 raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
1460}
1461
1462/**
1463 * _scsih_get_state - get raid volume level
1464 * @dev the device struct object
1465 */
1466static void
1467_scsih_get_state(struct device *dev)
1468{
1469 struct scsi_device *sdev = to_scsi_device(dev);
1470 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1471 static struct _raid_device *raid_device;
1472 unsigned long flags;
1473 Mpi2RaidVolPage0_t vol_pg0;
1474 Mpi2ConfigReply_t mpi_reply;
1475 u32 volstate;
1476 enum raid_state state = RAID_STATE_UNKNOWN;
1477
1478 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1479 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1480 sdev->channel);
1481 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1482
1483 if (!raid_device)
1484 goto out;
1485
1486 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1487 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1488 sizeof(Mpi2RaidVolPage0_t))) {
1489 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1490 ioc->name, __FILE__, __LINE__, __func__);
1491 goto out;
1492 }
1493
1494 volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1495 if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
1496 state = RAID_STATE_RESYNCING;
1497 goto out;
1498 }
1499
1500 switch (vol_pg0.VolumeState) {
1501 case MPI2_RAID_VOL_STATE_OPTIMAL:
1502 case MPI2_RAID_VOL_STATE_ONLINE:
1503 state = RAID_STATE_ACTIVE;
1504 break;
1505 case MPI2_RAID_VOL_STATE_DEGRADED:
1506 state = RAID_STATE_DEGRADED;
1507 break;
1508 case MPI2_RAID_VOL_STATE_FAILED:
1509 case MPI2_RAID_VOL_STATE_MISSING:
1510 state = RAID_STATE_OFFLINE;
1511 break;
1512 }
1513 out:
1514 raid_set_state(mpt2sas_raid_template, dev, state);
1515}
1516
1517/**
1518 * _scsih_set_level - set raid level
1519 * @sdev: scsi device struct
1520 * @raid_device: raid_device object
1521 */
1522static void
1523_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
1524{
1525 enum raid_level level = RAID_LEVEL_UNKNOWN;
1526
1527 switch (raid_device->volume_type) {
1528 case MPI2_RAID_VOL_TYPE_RAID0:
1529 level = RAID_LEVEL_0;
1530 break;
1531 case MPI2_RAID_VOL_TYPE_RAID10:
1532 level = RAID_LEVEL_10;
1533 break;
1534 case MPI2_RAID_VOL_TYPE_RAID1E:
1535 level = RAID_LEVEL_1E;
1536 break;
1537 case MPI2_RAID_VOL_TYPE_RAID1:
1538 level = RAID_LEVEL_1;
1539 break;
1540 }
1541
1542 raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
1543}
1544
1545/**
Eric Moore635374e2009-03-09 01:21:12 -06001546 * _scsih_get_volume_capabilities - volume capabilities
1547 * @ioc: per adapter object
1548 * @sas_device: the raid_device object
1549 */
1550static void
1551_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1552 struct _raid_device *raid_device)
1553{
1554 Mpi2RaidVolPage0_t *vol_pg0;
1555 Mpi2RaidPhysDiskPage0_t pd_pg0;
1556 Mpi2SasDevicePage0_t sas_device_pg0;
1557 Mpi2ConfigReply_t mpi_reply;
1558 u16 sz;
1559 u8 num_pds;
1560
1561 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1562 &num_pds)) || !num_pds) {
1563 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1564 ioc->name, __FILE__, __LINE__, __func__);
1565 return;
1566 }
1567
1568 raid_device->num_pds = num_pds;
1569 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1570 sizeof(Mpi2RaidVol0PhysDisk_t));
1571 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1572 if (!vol_pg0) {
1573 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1574 ioc->name, __FILE__, __LINE__, __func__);
1575 return;
1576 }
1577
1578 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1579 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1580 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1581 ioc->name, __FILE__, __LINE__, __func__);
1582 kfree(vol_pg0);
1583 return;
1584 }
1585
1586 raid_device->volume_type = vol_pg0->VolumeType;
1587
1588 /* figure out what the underlying devices are by
1589 * obtaining the device_info bits for the 1st device
1590 */
1591 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1592 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1593 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1594 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1595 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1596 le16_to_cpu(pd_pg0.DevHandle)))) {
1597 raid_device->device_info =
1598 le32_to_cpu(sas_device_pg0.DeviceInfo);
1599 }
1600 }
1601
1602 kfree(vol_pg0);
1603}
1604
1605/**
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301606 * _scsih_enable_tlr - setting TLR flags
1607 * @ioc: per adapter object
1608 * @sdev: scsi device struct
1609 *
1610 * Enabling Transaction Layer Retries for tape devices when
1611 * vpd page 0x90 is present
1612 *
1613 */
1614static void
1615_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev)
1616{
1617 /* only for TAPE */
1618 if (sdev->type != TYPE_TAPE)
1619 return;
1620
1621 if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR))
1622 return;
1623
1624 sas_enable_tlr(sdev);
1625 sdev_printk(KERN_INFO, sdev, "TLR %s\n",
1626 sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled");
1627 return;
1628
1629}
1630
1631/**
Eric Moored5d135b2009-05-18 13:02:08 -06001632 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001633 * @sdev: scsi device struct
1634 *
1635 * Returns 0 if ok. Any other return is assumed to be an error and
1636 * the device is ignored.
1637 */
1638static int
Eric Moored5d135b2009-05-18 13:02:08 -06001639_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001640{
1641 struct Scsi_Host *shost = sdev->host;
1642 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1643 struct MPT2SAS_DEVICE *sas_device_priv_data;
1644 struct MPT2SAS_TARGET *sas_target_priv_data;
1645 struct _sas_device *sas_device;
1646 struct _raid_device *raid_device;
1647 unsigned long flags;
1648 int qdepth;
1649 u8 ssp_target = 0;
1650 char *ds = "";
1651 char *r_level = "";
1652
1653 qdepth = 1;
1654 sas_device_priv_data = sdev->hostdata;
1655 sas_device_priv_data->configured_lun = 1;
1656 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1657 sas_target_priv_data = sas_device_priv_data->sas_target;
1658
1659 /* raid volume handling */
1660 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1661
1662 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1663 raid_device = _scsih_raid_device_find_by_handle(ioc,
1664 sas_target_priv_data->handle);
1665 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1666 if (!raid_device) {
1667 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1668 ioc->name, __FILE__, __LINE__, __func__);
1669 return 0;
1670 }
1671
1672 _scsih_get_volume_capabilities(ioc, raid_device);
1673
1674 /* RAID Queue Depth Support
1675 * IS volume = underlying qdepth of drive type, either
1676 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
1677 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
1678 */
1679 if (raid_device->device_info &
1680 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1681 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1682 ds = "SSP";
1683 } else {
1684 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1685 if (raid_device->device_info &
1686 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1687 ds = "SATA";
1688 else
1689 ds = "STP";
1690 }
1691
1692 switch (raid_device->volume_type) {
1693 case MPI2_RAID_VOL_TYPE_RAID0:
1694 r_level = "RAID0";
1695 break;
1696 case MPI2_RAID_VOL_TYPE_RAID1E:
1697 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05301698 if (ioc->manu_pg10.OEMIdentifier &&
1699 (ioc->manu_pg10.GenericFlags0 &
1700 MFG10_GF0_R10_DISPLAY) &&
1701 !(raid_device->num_pds % 2))
1702 r_level = "RAID10";
1703 else
1704 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06001705 break;
1706 case MPI2_RAID_VOL_TYPE_RAID1:
1707 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1708 r_level = "RAID1";
1709 break;
1710 case MPI2_RAID_VOL_TYPE_RAID10:
1711 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1712 r_level = "RAID10";
1713 break;
1714 case MPI2_RAID_VOL_TYPE_UNKNOWN:
1715 default:
1716 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1717 r_level = "RAIDX";
1718 break;
1719 }
1720
1721 sdev_printk(KERN_INFO, sdev, "%s: "
1722 "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
1723 r_level, raid_device->handle,
1724 (unsigned long long)raid_device->wwid,
1725 raid_device->num_pds, ds);
Mike Christiee881a172009-10-15 17:46:39 -07001726 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301727 /* raid transport support */
1728 _scsih_set_level(sdev, raid_device);
Eric Moore635374e2009-03-09 01:21:12 -06001729 return 0;
1730 }
1731
1732 /* non-raid handling */
1733 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1734 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1735 sas_device_priv_data->sas_target->sas_address);
1736 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1737 if (sas_device) {
1738 if (sas_target_priv_data->flags &
1739 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1740 mpt2sas_config_get_volume_handle(ioc,
1741 sas_device->handle, &sas_device->volume_handle);
1742 mpt2sas_config_get_volume_wwid(ioc,
1743 sas_device->volume_handle,
1744 &sas_device->volume_wwid);
1745 }
1746 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1747 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1748 ssp_target = 1;
1749 ds = "SSP";
1750 } else {
1751 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1752 if (sas_device->device_info &
1753 MPI2_SAS_DEVICE_INFO_STP_TARGET)
1754 ds = "STP";
1755 else if (sas_device->device_info &
1756 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1757 ds = "SATA";
1758 }
1759
1760 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
1761 "sas_addr(0x%016llx), device_name(0x%016llx)\n",
1762 ds, sas_device->handle,
1763 (unsigned long long)sas_device->sas_address,
1764 (unsigned long long)sas_device->device_name);
1765 sdev_printk(KERN_INFO, sdev, "%s: "
1766 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
1767 (unsigned long long) sas_device->enclosure_logical_id,
1768 sas_device->slot);
1769
1770 if (!ssp_target)
Eric Moored5d135b2009-05-18 13:02:08 -06001771 _scsih_display_sata_capabilities(ioc, sas_device, sdev);
Eric Moore635374e2009-03-09 01:21:12 -06001772 }
1773
Mike Christiee881a172009-10-15 17:46:39 -07001774 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Eric Moore635374e2009-03-09 01:21:12 -06001775
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301776 if (ssp_target) {
Eric Moore635374e2009-03-09 01:21:12 -06001777 sas_read_port_mode_page(sdev);
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301778 _scsih_enable_tlr(ioc, sdev);
1779 }
Eric Moore635374e2009-03-09 01:21:12 -06001780 return 0;
1781}
1782
1783/**
Eric Moored5d135b2009-05-18 13:02:08 -06001784 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06001785 * @sdev: scsi device struct
1786 * @bdev: pointer to block device context
1787 * @capacity: device size (in 512 byte sectors)
1788 * @params: three element array to place output:
1789 * params[0] number of heads (max 255)
1790 * params[1] number of sectors (max 63)
1791 * params[2] number of cylinders
1792 *
1793 * Return nothing.
1794 */
1795static int
Eric Moored5d135b2009-05-18 13:02:08 -06001796_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06001797 sector_t capacity, int params[])
1798{
1799 int heads;
1800 int sectors;
1801 sector_t cylinders;
1802 ulong dummy;
1803
1804 heads = 64;
1805 sectors = 32;
1806
1807 dummy = heads * sectors;
1808 cylinders = capacity;
1809 sector_div(cylinders, dummy);
1810
1811 /*
1812 * Handle extended translation size for logical drives
1813 * > 1Gb
1814 */
1815 if ((ulong)capacity >= 0x200000) {
1816 heads = 255;
1817 sectors = 63;
1818 dummy = heads * sectors;
1819 cylinders = capacity;
1820 sector_div(cylinders, dummy);
1821 }
1822
1823 /* return result */
1824 params[0] = heads;
1825 params[1] = sectors;
1826 params[2] = cylinders;
1827
1828 return 0;
1829}
1830
1831/**
1832 * _scsih_response_code - translation of device response code
1833 * @ioc: per adapter object
1834 * @response_code: response code returned by the device
1835 *
1836 * Return nothing.
1837 */
1838static void
1839_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
1840{
1841 char *desc;
1842
1843 switch (response_code) {
1844 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1845 desc = "task management request completed";
1846 break;
1847 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1848 desc = "invalid frame";
1849 break;
1850 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1851 desc = "task management request not supported";
1852 break;
1853 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1854 desc = "task management request failed";
1855 break;
1856 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1857 desc = "task management request succeeded";
1858 break;
1859 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1860 desc = "invalid lun";
1861 break;
1862 case 0xA:
1863 desc = "overlapped tag attempted";
1864 break;
1865 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1866 desc = "task queued, however not sent to target";
1867 break;
1868 default:
1869 desc = "unknown";
1870 break;
1871 }
1872 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
1873 ioc->name, response_code, desc);
1874}
1875
1876/**
Eric Moored5d135b2009-05-18 13:02:08 -06001877 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06001878 * @ioc: per adapter object
1879 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301880 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001881 * @reply: reply message frame(lower 32bit addr)
1882 * Context: none.
1883 *
1884 * The callback handler when using scsih_issue_tm.
1885 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301886 * Return 1 meaning mf should be freed from _base_interrupt
1887 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06001888 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301889static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301890_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06001891{
1892 MPI2DefaultReply_t *mpi_reply;
1893
1894 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301895 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001896 if (ioc->tm_cmds.smid != smid)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301897 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001898 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
1899 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
1900 if (mpi_reply) {
1901 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
1902 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
1903 }
1904 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
1905 complete(&ioc->tm_cmds.done);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301906 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001907}
1908
1909/**
1910 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
1911 * @ioc: per adapter object
1912 * @handle: device handle
1913 *
1914 * During taskmangement request, we need to freeze the device queue.
1915 */
1916void
1917mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1918{
1919 struct MPT2SAS_DEVICE *sas_device_priv_data;
1920 struct scsi_device *sdev;
1921 u8 skip = 0;
1922
1923 shost_for_each_device(sdev, ioc->shost) {
1924 if (skip)
1925 continue;
1926 sas_device_priv_data = sdev->hostdata;
1927 if (!sas_device_priv_data)
1928 continue;
1929 if (sas_device_priv_data->sas_target->handle == handle) {
1930 sas_device_priv_data->sas_target->tm_busy = 1;
1931 skip = 1;
1932 ioc->ignore_loginfos = 1;
1933 }
1934 }
1935}
1936
1937/**
1938 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
1939 * @ioc: per adapter object
1940 * @handle: device handle
1941 *
1942 * During taskmangement request, we need to freeze the device queue.
1943 */
1944void
1945mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1946{
1947 struct MPT2SAS_DEVICE *sas_device_priv_data;
1948 struct scsi_device *sdev;
1949 u8 skip = 0;
1950
1951 shost_for_each_device(sdev, ioc->shost) {
1952 if (skip)
1953 continue;
1954 sas_device_priv_data = sdev->hostdata;
1955 if (!sas_device_priv_data)
1956 continue;
1957 if (sas_device_priv_data->sas_target->handle == handle) {
1958 sas_device_priv_data->sas_target->tm_busy = 0;
1959 skip = 1;
1960 ioc->ignore_loginfos = 0;
1961 }
1962 }
1963}
1964
1965/**
1966 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
1967 * @ioc: per adapter struct
1968 * @device_handle: device handle
1969 * @lun: lun number
1970 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
1971 * @smid_task: smid assigned to the task
1972 * @timeout: timeout in seconds
1973 * Context: The calling function needs to acquire the tm_cmds.mutex
1974 *
1975 * A generic API for sending task management requests to firmware.
1976 *
1977 * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling
1978 * this API.
1979 *
1980 * The callback index is set inside `ioc->tm_cb_idx`.
1981 *
1982 * Return nothing.
1983 */
1984void
1985mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
1986 u8 type, u16 smid_task, ulong timeout)
1987{
1988 Mpi2SCSITaskManagementRequest_t *mpi_request;
1989 Mpi2SCSITaskManagementReply_t *mpi_reply;
1990 u16 smid = 0;
1991 u32 ioc_state;
1992 unsigned long timeleft;
Eric Moore635374e2009-03-09 01:21:12 -06001993
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301994 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
1995 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
1996 __func__, ioc->name);
1997 return;
1998 }
1999
2000 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06002001 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2002 __func__, ioc->name);
2003 return;
2004 }
Eric Moore635374e2009-03-09 01:21:12 -06002005
2006 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
2007 if (ioc_state & MPI2_DOORBELL_USED) {
2008 dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
2009 "active!\n", ioc->name));
2010 goto issue_host_reset;
2011 }
2012
2013 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
2014 mpt2sas_base_fault_info(ioc, ioc_state &
2015 MPI2_DOORBELL_DATA_MASK);
2016 goto issue_host_reset;
2017 }
2018
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302019 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06002020 if (!smid) {
2021 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2022 ioc->name, __func__);
2023 return;
2024 }
2025
2026 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302027 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
2028 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06002029 ioc->tm_cmds.status = MPT2_CMD_PENDING;
2030 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2031 ioc->tm_cmds.smid = smid;
2032 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2033 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2034 mpi_request->DevHandle = cpu_to_le16(handle);
2035 mpi_request->TaskType = type;
2036 mpi_request->TaskMID = cpu_to_le16(smid_task);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302037 mpi_request->VP_ID = 0; /* TODO */
2038 mpi_request->VF_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06002039 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
2040 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05302041 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302042 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002043 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
2044 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2045 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
2046 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
2047 ioc->name, __func__);
2048 _debug_dump_mf(mpi_request,
2049 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
2050 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET))
2051 goto issue_host_reset;
2052 }
2053
2054 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
2055 mpi_reply = ioc->tm_cmds.reply;
2056 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
2057 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
2058 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
2059 le32_to_cpu(mpi_reply->IOCLogInfo),
2060 le32_to_cpu(mpi_reply->TerminationCount)));
2061 if (ioc->logging_level & MPT_DEBUG_TM)
2062 _scsih_response_code(ioc, mpi_reply->ResponseCode);
2063 }
2064 return;
2065 issue_host_reset:
2066 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
2067}
2068
2069/**
Eric Moored5d135b2009-05-18 13:02:08 -06002070 * _scsih_abort - eh threads main abort routine
Eric Moore635374e2009-03-09 01:21:12 -06002071 * @sdev: scsi device struct
2072 *
2073 * Returns SUCCESS if command aborted else FAILED
2074 */
2075static int
Eric Moored5d135b2009-05-18 13:02:08 -06002076_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002077{
2078 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2079 struct MPT2SAS_DEVICE *sas_device_priv_data;
2080 u16 smid;
2081 u16 handle;
2082 int r;
2083 struct scsi_cmnd *scmd_lookup;
2084
2085 printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
2086 ioc->name, scmd);
2087 scsi_print_command(scmd);
2088
2089 sas_device_priv_data = scmd->device->hostdata;
2090 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2091 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
2092 ioc->name, scmd);
2093 scmd->result = DID_NO_CONNECT << 16;
2094 scmd->scsi_done(scmd);
2095 r = SUCCESS;
2096 goto out;
2097 }
2098
2099 /* search for the command */
2100 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
2101 if (!smid) {
2102 scmd->result = DID_RESET << 16;
2103 r = SUCCESS;
2104 goto out;
2105 }
2106
2107 /* for hidden raid components and volumes this is not supported */
2108 if (sas_device_priv_data->sas_target->flags &
2109 MPT_TARGET_FLAGS_RAID_COMPONENT ||
2110 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
2111 scmd->result = DID_RESET << 16;
2112 r = FAILED;
2113 goto out;
2114 }
2115
Kashyap, Desaifa7f3162009-09-23 17:26:58 +05302116 mpt2sas_halt_firmware(ioc);
2117
Eric Moore635374e2009-03-09 01:21:12 -06002118 mutex_lock(&ioc->tm_cmds.mutex);
2119 handle = sas_device_priv_data->sas_target->handle;
2120 mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
2121 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30);
2122
2123 /* sanity check - see whether command actually completed */
2124 scmd_lookup = _scsih_scsi_lookup_get(ioc, smid);
2125 if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number))
2126 r = FAILED;
2127 else
2128 r = SUCCESS;
2129 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2130 mutex_unlock(&ioc->tm_cmds.mutex);
2131
2132 out:
2133 printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
2134 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2135 return r;
2136}
2137
Eric Moore635374e2009-03-09 01:21:12 -06002138/**
Eric Moored5d135b2009-05-18 13:02:08 -06002139 * _scsih_dev_reset - eh threads main device reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002140 * @sdev: scsi device struct
2141 *
2142 * Returns SUCCESS if command aborted else FAILED
2143 */
2144static int
Eric Moored5d135b2009-05-18 13:02:08 -06002145_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002146{
2147 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2148 struct MPT2SAS_DEVICE *sas_device_priv_data;
2149 struct _sas_device *sas_device;
2150 unsigned long flags;
2151 u16 handle;
2152 int r;
2153
Eric Moore993e0da2009-05-18 13:00:45 -06002154 printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
Eric Moore635374e2009-03-09 01:21:12 -06002155 ioc->name, scmd);
2156 scsi_print_command(scmd);
2157
2158 sas_device_priv_data = scmd->device->hostdata;
2159 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2160 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
2161 ioc->name, scmd);
2162 scmd->result = DID_NO_CONNECT << 16;
2163 scmd->scsi_done(scmd);
2164 r = SUCCESS;
2165 goto out;
2166 }
2167
2168 /* for hidden raid components obtain the volume_handle */
2169 handle = 0;
2170 if (sas_device_priv_data->sas_target->flags &
2171 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2172 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2173 sas_device = _scsih_sas_device_find_by_handle(ioc,
2174 sas_device_priv_data->sas_target->handle);
2175 if (sas_device)
2176 handle = sas_device->volume_handle;
2177 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2178 } else
2179 handle = sas_device_priv_data->sas_target->handle;
2180
2181 if (!handle) {
2182 scmd->result = DID_RESET << 16;
2183 r = FAILED;
2184 goto out;
2185 }
2186
2187 mutex_lock(&ioc->tm_cmds.mutex);
2188 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore993e0da2009-05-18 13:00:45 -06002189 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun,
2190 30);
2191
2192 /*
2193 * sanity check see whether all commands to this device been
2194 * completed
2195 */
2196 if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id,
2197 scmd->device->lun, scmd->device->channel))
2198 r = FAILED;
2199 else
2200 r = SUCCESS;
2201 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2202 mutex_unlock(&ioc->tm_cmds.mutex);
2203
2204 out:
2205 printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
2206 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2207 return r;
2208}
2209
2210/**
Eric Moored5d135b2009-05-18 13:02:08 -06002211 * _scsih_target_reset - eh threads main target reset routine
Eric Moore993e0da2009-05-18 13:00:45 -06002212 * @sdev: scsi device struct
2213 *
2214 * Returns SUCCESS if command aborted else FAILED
2215 */
2216static int
Eric Moored5d135b2009-05-18 13:02:08 -06002217_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06002218{
2219 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2220 struct MPT2SAS_DEVICE *sas_device_priv_data;
2221 struct _sas_device *sas_device;
2222 unsigned long flags;
2223 u16 handle;
2224 int r;
2225
2226 printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
2227 ioc->name, scmd);
2228 scsi_print_command(scmd);
2229
2230 sas_device_priv_data = scmd->device->hostdata;
2231 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2232 printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
2233 ioc->name, scmd);
2234 scmd->result = DID_NO_CONNECT << 16;
2235 scmd->scsi_done(scmd);
2236 r = SUCCESS;
2237 goto out;
2238 }
2239
2240 /* for hidden raid components obtain the volume_handle */
2241 handle = 0;
2242 if (sas_device_priv_data->sas_target->flags &
2243 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2244 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2245 sas_device = _scsih_sas_device_find_by_handle(ioc,
2246 sas_device_priv_data->sas_target->handle);
2247 if (sas_device)
2248 handle = sas_device->volume_handle;
2249 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2250 } else
2251 handle = sas_device_priv_data->sas_target->handle;
2252
2253 if (!handle) {
2254 scmd->result = DID_RESET << 16;
2255 r = FAILED;
2256 goto out;
2257 }
2258
2259 mutex_lock(&ioc->tm_cmds.mutex);
2260 mpt2sas_scsih_issue_tm(ioc, handle, 0,
Eric Moore635374e2009-03-09 01:21:12 -06002261 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30);
2262
2263 /*
2264 * sanity check see whether all commands to this target been
2265 * completed
2266 */
2267 if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id,
2268 scmd->device->channel))
2269 r = FAILED;
2270 else
2271 r = SUCCESS;
2272 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2273 mutex_unlock(&ioc->tm_cmds.mutex);
2274
2275 out:
2276 printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
2277 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2278 return r;
2279}
2280
2281/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302282 * _scsih_host_reset - eh threads main host reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002283 * @sdev: scsi device struct
2284 *
2285 * Returns SUCCESS if command aborted else FAILED
2286 */
2287static int
Eric Moored5d135b2009-05-18 13:02:08 -06002288_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002289{
2290 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2291 int r, retval;
2292
2293 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2294 ioc->name, scmd);
2295 scsi_print_command(scmd);
2296
2297 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2298 FORCE_BIG_HAMMER);
2299 r = (retval < 0) ? FAILED : SUCCESS;
2300 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2301 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2302
2303 return r;
2304}
2305
2306/**
2307 * _scsih_fw_event_add - insert and queue up fw_event
2308 * @ioc: per adapter object
2309 * @fw_event: object describing the event
2310 * Context: This function will acquire ioc->fw_event_lock.
2311 *
2312 * This adds the firmware event object into link list, then queues it up to
2313 * be processed from user context.
2314 *
2315 * Return nothing.
2316 */
2317static void
2318_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2319{
2320 unsigned long flags;
2321
2322 if (ioc->firmware_event_thread == NULL)
2323 return;
2324
2325 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2326 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002327 INIT_WORK(&fw_event->work, _firmware_event_work);
2328 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002329 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2330}
2331
2332/**
2333 * _scsih_fw_event_free - delete fw_event
2334 * @ioc: per adapter object
2335 * @fw_event: object describing the event
2336 * Context: This function will acquire ioc->fw_event_lock.
2337 *
2338 * This removes firmware event object from link list, frees associated memory.
2339 *
2340 * Return nothing.
2341 */
2342static void
2343_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2344 *fw_event)
2345{
2346 unsigned long flags;
2347
2348 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2349 list_del(&fw_event->list);
2350 kfree(fw_event->event_data);
2351 kfree(fw_event);
2352 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2353}
2354
2355/**
2356 * _scsih_fw_event_add - requeue an event
2357 * @ioc: per adapter object
2358 * @fw_event: object describing the event
2359 * Context: This function will acquire ioc->fw_event_lock.
2360 *
2361 * Return nothing.
2362 */
2363static void
2364_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2365 *fw_event, unsigned long delay)
2366{
2367 unsigned long flags;
2368 if (ioc->firmware_event_thread == NULL)
2369 return;
2370
2371 spin_lock_irqsave(&ioc->fw_event_lock, flags);
Eric Moore6f92a7a2009-04-21 15:43:33 -06002372 queue_work(ioc->firmware_event_thread, &fw_event->work);
Eric Moore635374e2009-03-09 01:21:12 -06002373 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2374}
2375
2376/**
2377 * _scsih_fw_event_off - turn flag off preventing event handling
2378 * @ioc: per adapter object
2379 *
2380 * Used to prevent handling of firmware events during adapter reset
2381 * driver unload.
2382 *
2383 * Return nothing.
2384 */
2385static void
2386_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc)
2387{
2388 unsigned long flags;
2389
2390 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2391 ioc->fw_events_off = 1;
2392 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2393
2394}
2395
2396/**
2397 * _scsih_fw_event_on - turn flag on allowing firmware event handling
2398 * @ioc: per adapter object
2399 *
2400 * Returns nothing.
2401 */
2402static void
2403_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc)
2404{
2405 unsigned long flags;
2406
2407 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2408 ioc->fw_events_off = 0;
2409 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2410}
2411
2412/**
2413 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2414 * @ioc: per adapter object
2415 * @handle: device handle
2416 *
2417 * During device pull we need to appropiately set the sdev state.
2418 */
2419static void
2420_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2421{
2422 struct MPT2SAS_DEVICE *sas_device_priv_data;
2423 struct scsi_device *sdev;
2424
2425 shost_for_each_device(sdev, ioc->shost) {
2426 sas_device_priv_data = sdev->hostdata;
2427 if (!sas_device_priv_data)
2428 continue;
2429 if (!sas_device_priv_data->block)
2430 continue;
2431 if (sas_device_priv_data->sas_target->handle == handle) {
2432 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2433 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2434 "handle(0x%04x)\n", ioc->name, handle));
2435 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302436 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002437 }
2438 }
2439}
2440
2441/**
2442 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2443 * @ioc: per adapter object
2444 * @handle: device handle
2445 *
2446 * During device pull we need to appropiately set the sdev state.
2447 */
2448static void
2449_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2450{
2451 struct MPT2SAS_DEVICE *sas_device_priv_data;
2452 struct scsi_device *sdev;
2453
2454 shost_for_each_device(sdev, ioc->shost) {
2455 sas_device_priv_data = sdev->hostdata;
2456 if (!sas_device_priv_data)
2457 continue;
2458 if (sas_device_priv_data->block)
2459 continue;
2460 if (sas_device_priv_data->sas_target->handle == handle) {
2461 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2462 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2463 "handle(0x%04x)\n", ioc->name, handle));
2464 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302465 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002466 }
2467 }
2468}
2469
2470/**
2471 * _scsih_block_io_to_children_attached_to_ex
2472 * @ioc: per adapter object
2473 * @sas_expander: the sas_device object
2474 *
2475 * This routine set sdev state to SDEV_BLOCK for all devices
2476 * attached to this expander. This function called when expander is
2477 * pulled.
2478 */
2479static void
2480_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2481 struct _sas_node *sas_expander)
2482{
2483 struct _sas_port *mpt2sas_port;
2484 struct _sas_device *sas_device;
2485 struct _sas_node *expander_sibling;
2486 unsigned long flags;
2487
2488 if (!sas_expander)
2489 return;
2490
2491 list_for_each_entry(mpt2sas_port,
2492 &sas_expander->sas_port_list, port_list) {
2493 if (mpt2sas_port->remote_identify.device_type ==
2494 SAS_END_DEVICE) {
2495 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2496 sas_device =
2497 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2498 mpt2sas_port->remote_identify.sas_address);
2499 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2500 if (!sas_device)
2501 continue;
2502 _scsih_block_io_device(ioc, sas_device->handle);
2503 }
2504 }
2505
2506 list_for_each_entry(mpt2sas_port,
2507 &sas_expander->sas_port_list, port_list) {
2508
2509 if (mpt2sas_port->remote_identify.device_type ==
2510 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2511 mpt2sas_port->remote_identify.device_type ==
2512 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2513
2514 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2515 expander_sibling =
2516 mpt2sas_scsih_expander_find_by_sas_address(
2517 ioc, mpt2sas_port->remote_identify.sas_address);
2518 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2519 _scsih_block_io_to_children_attached_to_ex(ioc,
2520 expander_sibling);
2521 }
2522 }
2523}
2524
2525/**
2526 * _scsih_block_io_to_children_attached_directly
2527 * @ioc: per adapter object
2528 * @event_data: topology change event data
2529 *
2530 * This routine set sdev state to SDEV_BLOCK for all devices
2531 * direct attached during device pull.
2532 */
2533static void
2534_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2535 Mpi2EventDataSasTopologyChangeList_t *event_data)
2536{
2537 int i;
2538 u16 handle;
2539 u16 reason_code;
2540 u8 phy_number;
2541
2542 for (i = 0; i < event_data->NumEntries; i++) {
2543 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2544 if (!handle)
2545 continue;
2546 phy_number = event_data->StartPhyNum + i;
2547 reason_code = event_data->PHY[i].PhyStatus &
2548 MPI2_EVENT_SAS_TOPO_RC_MASK;
2549 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2550 _scsih_block_io_device(ioc, handle);
2551 }
2552}
2553
2554/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302555 * _scsih_tm_tr_send - send task management request
2556 * @ioc: per adapter object
2557 * @handle: device handle
2558 * Context: interrupt time.
2559 *
2560 * This code is to initiate the device removal handshake protocal
2561 * with controller firmware. This function will issue target reset
2562 * using high priority request queue. It will send a sas iounit
2563 * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
2564 *
2565 * This is designed to send muliple task management request at the same
2566 * time to the fifo. If the fifo is full, we will append the request,
2567 * and process it in a future completion.
2568 */
2569static void
2570_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2571{
2572 Mpi2SCSITaskManagementRequest_t *mpi_request;
2573 struct MPT2SAS_TARGET *sas_target_priv_data;
2574 u16 smid;
2575 struct _sas_device *sas_device;
2576 unsigned long flags;
2577 struct _tr_list *delayed_tr;
2578
2579 if (ioc->shost_recovery) {
2580 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2581 __func__, ioc->name);
2582 return;
2583 }
2584
2585 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2586 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302587 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2588
2589 /* skip is hidden raid component */
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302590 if (sas_device && sas_device->hidden_raid_component)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302591 return;
2592
2593 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
2594 if (!smid) {
2595 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
2596 if (!delayed_tr)
2597 return;
2598 INIT_LIST_HEAD(&delayed_tr->list);
2599 delayed_tr->handle = handle;
2600 delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
2601 list_add_tail(&delayed_tr->list,
2602 &ioc->delayed_tr_list);
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302603 if (sas_device && sas_device->starget) {
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302604 dewtprintk(ioc, starget_printk(KERN_INFO,
2605 sas_device->starget, "DELAYED:tr:handle(0x%04x), "
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302606 "(open)\n", handle));
2607 } else {
2608 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2609 "DELAYED:tr:handle(0x%04x), (open)\n",
2610 ioc->name, handle));
2611 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302612 return;
2613 }
2614
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302615 if (sas_device) {
2616 sas_device->state |= MPTSAS_STATE_TR_SEND;
2617 sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
2618 if (sas_device->starget && sas_device->starget->hostdata) {
2619 sas_target_priv_data = sas_device->starget->hostdata;
2620 sas_target_priv_data->tm_busy = 1;
2621 dewtprintk(ioc, starget_printk(KERN_INFO,
2622 sas_device->starget, "tr:handle(0x%04x), (open)\n",
2623 handle));
2624 }
2625 } else {
2626 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2627 "tr:handle(0x%04x), (open)\n", ioc->name, handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302628 }
2629
2630 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2631 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2632 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2633 mpi_request->DevHandle = cpu_to_le16(handle);
2634 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302635 mpt2sas_base_put_smid_hi_priority(ioc, smid);
2636}
2637
2638
2639
2640/**
2641 * _scsih_sas_control_complete - completion routine
2642 * @ioc: per adapter object
2643 * @smid: system request message index
2644 * @msix_index: MSIX table index supplied by the OS
2645 * @reply: reply message frame(lower 32bit addr)
2646 * Context: interrupt time.
2647 *
2648 * This is the sas iounit controll completion routine.
2649 * This code is part of the code to initiate the device removal
2650 * handshake protocal with controller firmware.
2651 *
2652 * Return 1 meaning mf should be freed from _base_interrupt
2653 * 0 means the mf is freed from this function.
2654 */
2655static u8
2656_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
2657 u8 msix_index, u32 reply)
2658{
2659 unsigned long flags;
2660 u16 handle;
2661 struct _sas_device *sas_device;
2662 Mpi2SasIoUnitControlReply_t *mpi_reply =
2663 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2664
2665 handle = le16_to_cpu(mpi_reply->DevHandle);
2666
2667 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2668 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302669 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2670
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302671 if (sas_device) {
2672 sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
2673 if (sas_device->starget)
2674 dewtprintk(ioc, starget_printk(KERN_INFO,
2675 sas_device->starget,
2676 "sc_complete:handle(0x%04x), "
2677 "ioc_status(0x%04x), loginfo(0x%08x)\n",
2678 handle, le16_to_cpu(mpi_reply->IOCStatus),
2679 le32_to_cpu(mpi_reply->IOCLogInfo)));
2680 } else {
2681 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302682 "sc_complete:handle(0x%04x), "
2683 "ioc_status(0x%04x), loginfo(0x%08x)\n",
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302684 ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus),
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302685 le32_to_cpu(mpi_reply->IOCLogInfo)));
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302686 }
2687
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302688 return 1;
2689}
2690
2691/**
2692 * _scsih_tm_tr_complete -
2693 * @ioc: per adapter object
2694 * @smid: system request message index
2695 * @msix_index: MSIX table index supplied by the OS
2696 * @reply: reply message frame(lower 32bit addr)
2697 * Context: interrupt time.
2698 *
2699 * This is the target reset completion routine.
2700 * This code is part of the code to initiate the device removal
2701 * handshake protocal with controller firmware.
2702 * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE)
2703 *
2704 * Return 1 meaning mf should be freed from _base_interrupt
2705 * 0 means the mf is freed from this function.
2706 */
2707static u8
2708_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
2709 u32 reply)
2710{
2711 unsigned long flags;
2712 u16 handle;
2713 struct _sas_device *sas_device;
2714 Mpi2SCSITaskManagementReply_t *mpi_reply =
2715 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2716 Mpi2SasIoUnitControlRequest_t *mpi_request;
2717 u16 smid_sas_ctrl;
2718 struct MPT2SAS_TARGET *sas_target_priv_data;
2719 struct _tr_list *delayed_tr;
2720 u8 rc;
2721
2722 handle = le16_to_cpu(mpi_reply->DevHandle);
2723 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2724 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302725 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2726
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302727 if (sas_device) {
2728 sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
2729 if (sas_device->starget) {
2730 dewtprintk(ioc, starget_printk(KERN_INFO,
2731 sas_device->starget, "tr_complete:handle(0x%04x), "
2732 "(%s) ioc_status(0x%04x), loginfo(0x%08x), "
2733 "completed(%d)\n", sas_device->handle,
2734 (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ?
2735 "open" : "active",
2736 le16_to_cpu(mpi_reply->IOCStatus),
2737 le32_to_cpu(mpi_reply->IOCLogInfo),
2738 le32_to_cpu(mpi_reply->TerminationCount)));
2739 if (sas_device->starget->hostdata) {
2740 sas_target_priv_data =
2741 sas_device->starget->hostdata;
2742 sas_target_priv_data->tm_busy = 0;
2743 }
2744 }
2745 } else {
2746 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2747 "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), "
2748 "loginfo(0x%08x), completed(%d)\n", ioc->name,
2749 handle, le16_to_cpu(mpi_reply->IOCStatus),
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302750 le32_to_cpu(mpi_reply->IOCLogInfo),
2751 le32_to_cpu(mpi_reply->TerminationCount)));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302752 }
2753
2754 if (!list_empty(&ioc->delayed_tr_list)) {
2755 delayed_tr = list_entry(ioc->delayed_tr_list.next,
2756 struct _tr_list, list);
2757 mpt2sas_base_free_smid(ioc, smid);
2758 if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL)
2759 _scsih_tm_tr_send(ioc, delayed_tr->handle);
2760 list_del(&delayed_tr->list);
2761 kfree(delayed_tr);
2762 rc = 0; /* tells base_interrupt not to free mf */
2763 } else
2764 rc = 1;
2765
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302766 if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302767 return rc;
2768
2769 if (ioc->shost_recovery) {
2770 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2771 __func__, ioc->name);
2772 return rc;
2773 }
2774
2775 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
2776 if (!smid_sas_ctrl) {
2777 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2778 ioc->name, __func__);
2779 return rc;
2780 }
2781
Kashyap, Desaia28eb222009-09-23 17:22:37 +05302782 if (sas_device)
2783 sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
2784
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302785 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
2786 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
2787 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
2788 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
2789 mpi_request->DevHandle = mpi_reply->DevHandle;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302790 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
2791 return rc;
2792}
2793
2794/**
Eric Moore635374e2009-03-09 01:21:12 -06002795 * _scsih_check_topo_delete_events - sanity check on topo events
2796 * @ioc: per adapter object
2797 * @event_data: the event data payload
2798 *
2799 * This routine added to better handle cable breaker.
2800 *
2801 * This handles the case where driver recieves multiple expander
2802 * add and delete events in a single shot. When there is a delete event
2803 * the routine will void any pending add events waiting in the event queue.
2804 *
2805 * Return nothing.
2806 */
2807static void
2808_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
2809 Mpi2EventDataSasTopologyChangeList_t *event_data)
2810{
2811 struct fw_event_work *fw_event;
2812 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
2813 u16 expander_handle;
2814 struct _sas_node *sas_expander;
2815 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302816 int i, reason_code;
2817 u16 handle;
2818
2819 for (i = 0 ; i < event_data->NumEntries; i++) {
2820 if (event_data->PHY[i].PhyStatus &
2821 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
2822 continue;
2823 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2824 if (!handle)
2825 continue;
2826 reason_code = event_data->PHY[i].PhyStatus &
2827 MPI2_EVENT_SAS_TOPO_RC_MASK;
2828 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
2829 _scsih_tm_tr_send(ioc, handle);
2830 }
Eric Moore635374e2009-03-09 01:21:12 -06002831
2832 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
2833 if (expander_handle < ioc->sas_hba.num_phys) {
2834 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2835 return;
2836 }
2837
2838 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
2839 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
2840 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2841 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
2842 expander_handle);
2843 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2844 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
2845 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
2846 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2847
2848 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
2849 return;
2850
2851 /* mark ignore flag for pending events */
2852 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2853 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
2854 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
2855 fw_event->ignore)
2856 continue;
2857 local_event_data = fw_event->event_data;
2858 if (local_event_data->ExpStatus ==
2859 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
2860 local_event_data->ExpStatus ==
2861 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
2862 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
2863 expander_handle) {
2864 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
2865 "setting ignoring flag\n", ioc->name));
2866 fw_event->ignore = 1;
2867 }
2868 }
2869 }
2870 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2871}
2872
2873/**
Eric Moore635374e2009-03-09 01:21:12 -06002874 * _scsih_flush_running_cmds - completing outstanding commands.
2875 * @ioc: per adapter object
2876 *
2877 * The flushing out of all pending scmd commands following host reset,
2878 * where all IO is dropped to the floor.
2879 *
2880 * Return nothing.
2881 */
2882static void
2883_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
2884{
2885 struct scsi_cmnd *scmd;
2886 u16 smid;
2887 u16 count = 0;
2888
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302889 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
2890 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002891 if (!scmd)
2892 continue;
2893 count++;
2894 mpt2sas_base_free_smid(ioc, smid);
2895 scsi_dma_unmap(scmd);
2896 scmd->result = DID_RESET << 16;
2897 scmd->scsi_done(scmd);
2898 }
2899 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
2900 ioc->name, count));
2901}
2902
2903/**
Eric Moore3c621b32009-05-18 12:59:41 -06002904 * _scsih_setup_eedp - setup MPI request for EEDP transfer
2905 * @scmd: pointer to scsi command object
2906 * @mpi_request: pointer to the SCSI_IO reqest message frame
2907 *
2908 * Supporting protection 1 and 3.
2909 *
2910 * Returns nothing
2911 */
2912static void
2913_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
2914{
2915 u16 eedp_flags;
2916 unsigned char prot_op = scsi_get_prot_op(scmd);
2917 unsigned char prot_type = scsi_get_prot_type(scmd);
2918
2919 if (prot_type == SCSI_PROT_DIF_TYPE0 ||
2920 prot_type == SCSI_PROT_DIF_TYPE2 ||
2921 prot_op == SCSI_PROT_NORMAL)
2922 return;
2923
2924 if (prot_op == SCSI_PROT_READ_STRIP)
2925 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
2926 else if (prot_op == SCSI_PROT_WRITE_INSERT)
2927 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
2928 else
2929 return;
2930
Eric Moore3c621b32009-05-18 12:59:41 -06002931 switch (prot_type) {
2932 case SCSI_PROT_DIF_TYPE1:
2933
2934 /*
2935 * enable ref/guard checking
2936 * auto increment ref tag
2937 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05302938 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
Eric Moore3c621b32009-05-18 12:59:41 -06002939 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2940 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2941 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
2942 cpu_to_be32(scsi_get_lba(scmd));
2943
2944 break;
2945
2946 case SCSI_PROT_DIF_TYPE3:
2947
2948 /*
2949 * enable guard checking
2950 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05302951 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
Eric Moore3c621b32009-05-18 12:59:41 -06002952 break;
2953 }
Kashyap, Desai463217b2009-10-05 15:53:06 +05302954 mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
2955 mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
Eric Moore3c621b32009-05-18 12:59:41 -06002956}
2957
2958/**
2959 * _scsih_eedp_error_handling - return sense code for EEDP errors
2960 * @scmd: pointer to scsi command object
2961 * @ioc_status: ioc status
2962 *
2963 * Returns nothing
2964 */
2965static void
2966_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
2967{
2968 u8 ascq;
2969 u8 sk;
2970 u8 host_byte;
2971
2972 switch (ioc_status) {
2973 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2974 ascq = 0x01;
2975 break;
2976 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2977 ascq = 0x02;
2978 break;
2979 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2980 ascq = 0x03;
2981 break;
2982 default:
2983 ascq = 0x00;
2984 break;
2985 }
2986
2987 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
2988 sk = ILLEGAL_REQUEST;
2989 host_byte = DID_ABORT;
2990 } else {
2991 sk = ABORTED_COMMAND;
2992 host_byte = DID_OK;
2993 }
2994
2995 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
2996 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
2997 SAM_STAT_CHECK_CONDITION;
2998}
2999
3000/**
Eric Moored5d135b2009-05-18 13:02:08 -06003001 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06003002 * @scmd: pointer to scsi command object
3003 * @done: function pointer to be invoked on completion
3004 *
3005 * The callback index is set inside `ioc->scsi_io_cb_idx`.
3006 *
3007 * Returns 0 on success. If there's a failure, return either:
3008 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
3009 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
3010 */
3011static int
Eric Moored5d135b2009-05-18 13:02:08 -06003012_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06003013{
3014 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
3015 struct MPT2SAS_DEVICE *sas_device_priv_data;
3016 struct MPT2SAS_TARGET *sas_target_priv_data;
3017 Mpi2SCSIIORequest_t *mpi_request;
3018 u32 mpi_control;
3019 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06003020
3021 scmd->scsi_done = done;
3022 sas_device_priv_data = scmd->device->hostdata;
3023 if (!sas_device_priv_data) {
3024 scmd->result = DID_NO_CONNECT << 16;
3025 scmd->scsi_done(scmd);
3026 return 0;
3027 }
3028
3029 sas_target_priv_data = sas_device_priv_data->sas_target;
3030 if (!sas_target_priv_data || sas_target_priv_data->handle ==
3031 MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
3032 scmd->result = DID_NO_CONNECT << 16;
3033 scmd->scsi_done(scmd);
3034 return 0;
3035 }
3036
3037 /* see if we are busy with task managment stuff */
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05303038 if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303039 return SCSI_MLQUEUE_DEVICE_BUSY;
3040 else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06003041 return SCSI_MLQUEUE_HOST_BUSY;
Eric Moore635374e2009-03-09 01:21:12 -06003042
3043 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
3044 mpi_control = MPI2_SCSIIO_CONTROL_READ;
3045 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
3046 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
3047 else
3048 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
3049
3050 /* set tags */
3051 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
3052 if (scmd->device->tagged_supported) {
3053 if (scmd->device->ordered_tags)
3054 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
3055 else
3056 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
3057 } else
3058/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
3059/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
3060 */
3061 mpi_control |= (0x500);
3062
3063 } else
3064 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
3065
Kashyap, Desai84f0b042009-12-16 18:56:28 +05303066 if (sas_is_tlr_enabled(scmd->device))
Eric Moore635374e2009-03-09 01:21:12 -06003067 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
3068
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303069 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06003070 if (!smid) {
3071 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
3072 ioc->name, __func__);
3073 goto out;
3074 }
3075 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3076 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06003077 _scsih_setup_eedp(scmd, mpi_request);
Eric Moore635374e2009-03-09 01:21:12 -06003078 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3079 if (sas_device_priv_data->sas_target->flags &
3080 MPT_TARGET_FLAGS_RAID_COMPONENT)
3081 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3082 else
3083 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3084 mpi_request->DevHandle =
3085 cpu_to_le16(sas_device_priv_data->sas_target->handle);
3086 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
3087 mpi_request->Control = cpu_to_le32(mpi_control);
3088 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
3089 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
3090 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
3091 mpi_request->SenseBufferLowAddress =
Kashyap, Desaiec9472c2009-09-23 17:34:13 +05303092 mpt2sas_base_get_sense_buffer_dma(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003093 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
3094 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
3095 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303096 mpi_request->VF_ID = 0; /* TODO */
3097 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003098 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
3099 mpi_request->LUN);
3100 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
3101
3102 if (!mpi_request->DataLength) {
3103 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
3104 } else {
3105 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
3106 mpt2sas_base_free_smid(ioc, smid);
3107 goto out;
3108 }
3109 }
3110
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303111 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Eric Moore635374e2009-03-09 01:21:12 -06003112 sas_device_priv_data->sas_target->handle);
3113 return 0;
3114
3115 out:
3116 return SCSI_MLQUEUE_HOST_BUSY;
3117}
3118
3119/**
3120 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
3121 * @sense_buffer: sense data returned by target
3122 * @data: normalized skey/asc/ascq
3123 *
3124 * Return nothing.
3125 */
3126static void
3127_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
3128{
3129 if ((sense_buffer[0] & 0x7F) >= 0x72) {
3130 /* descriptor format */
3131 data->skey = sense_buffer[1] & 0x0F;
3132 data->asc = sense_buffer[2];
3133 data->ascq = sense_buffer[3];
3134 } else {
3135 /* fixed format */
3136 data->skey = sense_buffer[2] & 0x0F;
3137 data->asc = sense_buffer[12];
3138 data->ascq = sense_buffer[13];
3139 }
3140}
3141
3142#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3143/**
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02003144 * _scsih_scsi_ioc_info - translated non-successfull SCSI_IO request
Eric Moore635374e2009-03-09 01:21:12 -06003145 * @ioc: per adapter object
3146 * @scmd: pointer to scsi command object
3147 * @mpi_reply: reply mf payload returned from firmware
3148 *
3149 * scsi_status - SCSI Status code returned from target device
3150 * scsi_state - state info associated with SCSI_IO determined by ioc
3151 * ioc_status - ioc supplied status info
3152 *
3153 * Return nothing.
3154 */
3155static void
3156_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
3157 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
3158{
3159 u32 response_info;
3160 u8 *response_bytes;
3161 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
3162 MPI2_IOCSTATUS_MASK;
3163 u8 scsi_state = mpi_reply->SCSIState;
3164 u8 scsi_status = mpi_reply->SCSIStatus;
3165 char *desc_ioc_state = NULL;
3166 char *desc_scsi_status = NULL;
3167 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303168 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3169
3170 if (log_info == 0x31170000)
3171 return;
Eric Moore635374e2009-03-09 01:21:12 -06003172
3173 switch (ioc_status) {
3174 case MPI2_IOCSTATUS_SUCCESS:
3175 desc_ioc_state = "success";
3176 break;
3177 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3178 desc_ioc_state = "invalid function";
3179 break;
3180 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3181 desc_ioc_state = "scsi recovered error";
3182 break;
3183 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
3184 desc_ioc_state = "scsi invalid dev handle";
3185 break;
3186 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3187 desc_ioc_state = "scsi device not there";
3188 break;
3189 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3190 desc_ioc_state = "scsi data overrun";
3191 break;
3192 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3193 desc_ioc_state = "scsi data underrun";
3194 break;
3195 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3196 desc_ioc_state = "scsi io data error";
3197 break;
3198 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3199 desc_ioc_state = "scsi protocol error";
3200 break;
3201 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3202 desc_ioc_state = "scsi task terminated";
3203 break;
3204 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3205 desc_ioc_state = "scsi residual mismatch";
3206 break;
3207 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3208 desc_ioc_state = "scsi task mgmt failed";
3209 break;
3210 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3211 desc_ioc_state = "scsi ioc terminated";
3212 break;
3213 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3214 desc_ioc_state = "scsi ext terminated";
3215 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003216 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3217 desc_ioc_state = "eedp guard error";
3218 break;
3219 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3220 desc_ioc_state = "eedp ref tag error";
3221 break;
3222 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3223 desc_ioc_state = "eedp app tag error";
3224 break;
Eric Moore635374e2009-03-09 01:21:12 -06003225 default:
3226 desc_ioc_state = "unknown";
3227 break;
3228 }
3229
3230 switch (scsi_status) {
3231 case MPI2_SCSI_STATUS_GOOD:
3232 desc_scsi_status = "good";
3233 break;
3234 case MPI2_SCSI_STATUS_CHECK_CONDITION:
3235 desc_scsi_status = "check condition";
3236 break;
3237 case MPI2_SCSI_STATUS_CONDITION_MET:
3238 desc_scsi_status = "condition met";
3239 break;
3240 case MPI2_SCSI_STATUS_BUSY:
3241 desc_scsi_status = "busy";
3242 break;
3243 case MPI2_SCSI_STATUS_INTERMEDIATE:
3244 desc_scsi_status = "intermediate";
3245 break;
3246 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
3247 desc_scsi_status = "intermediate condmet";
3248 break;
3249 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
3250 desc_scsi_status = "reservation conflict";
3251 break;
3252 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
3253 desc_scsi_status = "command terminated";
3254 break;
3255 case MPI2_SCSI_STATUS_TASK_SET_FULL:
3256 desc_scsi_status = "task set full";
3257 break;
3258 case MPI2_SCSI_STATUS_ACA_ACTIVE:
3259 desc_scsi_status = "aca active";
3260 break;
3261 case MPI2_SCSI_STATUS_TASK_ABORTED:
3262 desc_scsi_status = "task aborted";
3263 break;
3264 default:
3265 desc_scsi_status = "unknown";
3266 break;
3267 }
3268
3269 desc_scsi_state[0] = '\0';
3270 if (!scsi_state)
3271 desc_scsi_state = " ";
3272 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3273 strcat(desc_scsi_state, "response info ");
3274 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3275 strcat(desc_scsi_state, "state terminated ");
3276 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
3277 strcat(desc_scsi_state, "no status ");
3278 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
3279 strcat(desc_scsi_state, "autosense failed ");
3280 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
3281 strcat(desc_scsi_state, "autosense valid ");
3282
3283 scsi_print_command(scmd);
3284 printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
3285 "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
3286 le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
3287 ioc_status, smid);
3288 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
3289 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
3290 scsi_get_resid(scmd));
3291 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
3292 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
3293 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
3294 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
3295 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
3296 scsi_status, desc_scsi_state, scsi_state);
3297
3298 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3299 struct sense_info data;
3300 _scsih_normalize_sense(scmd->sense_buffer, &data);
3301 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
3302 "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey,
3303 data.asc, data.ascq);
3304 }
3305
3306 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
3307 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
3308 response_bytes = (u8 *)&response_info;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303309 _scsih_response_code(ioc, response_bytes[0]);
Eric Moore635374e2009-03-09 01:21:12 -06003310 }
3311}
3312#endif
3313
3314/**
3315 * _scsih_smart_predicted_fault - illuminate Fault LED
3316 * @ioc: per adapter object
3317 * @handle: device handle
3318 *
3319 * Return nothing.
3320 */
3321static void
3322_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3323{
3324 Mpi2SepReply_t mpi_reply;
3325 Mpi2SepRequest_t mpi_request;
3326 struct scsi_target *starget;
3327 struct MPT2SAS_TARGET *sas_target_priv_data;
3328 Mpi2EventNotificationReply_t *event_reply;
3329 Mpi2EventDataSasDeviceStatusChange_t *event_data;
3330 struct _sas_device *sas_device;
3331 ssize_t sz;
3332 unsigned long flags;
3333
3334 /* only handle non-raid devices */
3335 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3336 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3337 if (!sas_device) {
3338 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3339 return;
3340 }
3341 starget = sas_device->starget;
3342 sas_target_priv_data = starget->hostdata;
3343
3344 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
3345 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
3346 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3347 return;
3348 }
3349 starget_printk(KERN_WARNING, starget, "predicted fault\n");
3350 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3351
3352 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
3353 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
3354 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
3355 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
3356 mpi_request.SlotStatus =
3357 MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
3358 mpi_request.DevHandle = cpu_to_le16(handle);
3359 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
3360 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
3361 &mpi_request)) != 0) {
3362 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3363 ioc->name, __FILE__, __LINE__, __func__);
3364 return;
3365 }
3366
3367 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
3368 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3369 "enclosure_processor: ioc_status (0x%04x), "
3370 "loginfo(0x%08x)\n", ioc->name,
3371 le16_to_cpu(mpi_reply.IOCStatus),
3372 le32_to_cpu(mpi_reply.IOCLogInfo)));
3373 return;
3374 }
3375 }
3376
3377 /* insert into event log */
3378 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
3379 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
3380 event_reply = kzalloc(sz, GFP_KERNEL);
3381 if (!event_reply) {
3382 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3383 ioc->name, __FILE__, __LINE__, __func__);
3384 return;
3385 }
3386
3387 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
3388 event_reply->Event =
3389 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
3390 event_reply->MsgLength = sz/4;
3391 event_reply->EventDataLength =
3392 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
3393 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
3394 event_reply->EventData;
3395 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
3396 event_data->ASC = 0x5D;
3397 event_data->DevHandle = cpu_to_le16(handle);
3398 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
3399 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
3400 kfree(event_reply);
3401}
3402
3403/**
Eric Moored5d135b2009-05-18 13:02:08 -06003404 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06003405 * @ioc: per adapter object
3406 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303407 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06003408 * @reply: reply message frame(lower 32bit addr)
3409 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303410 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06003411 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303412 * Return 1 meaning mf should be freed from _base_interrupt
3413 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06003414 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303415static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303416_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06003417{
3418 Mpi2SCSIIORequest_t *mpi_request;
3419 Mpi2SCSIIOReply_t *mpi_reply;
3420 struct scsi_cmnd *scmd;
3421 u16 ioc_status;
3422 u32 xfer_cnt;
3423 u8 scsi_state;
3424 u8 scsi_status;
3425 u32 log_info;
3426 struct MPT2SAS_DEVICE *sas_device_priv_data;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303427 u32 response_code = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003428
3429 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303430 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003431 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303432 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003433
3434 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3435
3436 if (mpi_reply == NULL) {
3437 scmd->result = DID_OK << 16;
3438 goto out;
3439 }
3440
3441 sas_device_priv_data = scmd->device->hostdata;
3442 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
3443 sas_device_priv_data->sas_target->deleted) {
3444 scmd->result = DID_NO_CONNECT << 16;
3445 goto out;
3446 }
3447
3448 /* turning off TLR */
Kashyap, Desai9982f592009-09-23 17:23:07 +05303449 scsi_state = mpi_reply->SCSIState;
3450 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3451 response_code =
3452 le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
Eric Moore635374e2009-03-09 01:21:12 -06003453 if (!sas_device_priv_data->tlr_snoop_check) {
3454 sas_device_priv_data->tlr_snoop_check++;
Kashyap, Desai84f0b042009-12-16 18:56:28 +05303455 if (sas_is_tlr_enabled(scmd->device) &&
3456 response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
3457 sas_disable_tlr(scmd->device);
3458 sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
3459 }
Eric Moore635374e2009-03-09 01:21:12 -06003460 }
3461
3462 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
3463 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
3464 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
3465 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
3466 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3467 else
3468 log_info = 0;
3469 ioc_status &= MPI2_IOCSTATUS_MASK;
Eric Moore635374e2009-03-09 01:21:12 -06003470 scsi_status = mpi_reply->SCSIStatus;
3471
3472 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
3473 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
3474 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
3475 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
3476 ioc_status = MPI2_IOCSTATUS_SUCCESS;
3477 }
3478
3479 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3480 struct sense_info data;
3481 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
3482 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06003483 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06003484 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06003485 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06003486 _scsih_normalize_sense(scmd->sense_buffer, &data);
3487 /* failure prediction threshold exceeded */
3488 if (data.asc == 0x5D)
3489 _scsih_smart_predicted_fault(ioc,
3490 le16_to_cpu(mpi_reply->DevHandle));
3491 }
3492
3493 switch (ioc_status) {
3494 case MPI2_IOCSTATUS_BUSY:
3495 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3496 scmd->result = SAM_STAT_BUSY;
3497 break;
3498
3499 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3500 scmd->result = DID_NO_CONNECT << 16;
3501 break;
3502
3503 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3504 if (sas_device_priv_data->block) {
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05303505 scmd->result = DID_TRANSPORT_DISRUPTED << 16;
3506 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003507 }
Eric Moore635374e2009-03-09 01:21:12 -06003508 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3509 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3510 scmd->result = DID_RESET << 16;
3511 break;
3512
3513 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3514 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3515 scmd->result = DID_SOFT_ERROR << 16;
3516 else
3517 scmd->result = (DID_OK << 16) | scsi_status;
3518 break;
3519
3520 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3521 scmd->result = (DID_OK << 16) | scsi_status;
3522
3523 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3524 break;
3525
3526 if (xfer_cnt < scmd->underflow) {
3527 if (scsi_status == SAM_STAT_BUSY)
3528 scmd->result = SAM_STAT_BUSY;
3529 else
3530 scmd->result = DID_SOFT_ERROR << 16;
3531 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3532 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3533 scmd->result = DID_SOFT_ERROR << 16;
3534 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3535 scmd->result = DID_RESET << 16;
3536 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3537 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3538 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3539 scmd->result = (DRIVER_SENSE << 24) |
3540 SAM_STAT_CHECK_CONDITION;
3541 scmd->sense_buffer[0] = 0x70;
3542 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3543 scmd->sense_buffer[12] = 0x20;
3544 scmd->sense_buffer[13] = 0;
3545 }
3546 break;
3547
3548 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3549 scsi_set_resid(scmd, 0);
3550 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3551 case MPI2_IOCSTATUS_SUCCESS:
3552 scmd->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303553 if (response_code ==
3554 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
3555 (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3556 MPI2_SCSI_STATE_NO_SCSI_STATUS)))
Eric Moore635374e2009-03-09 01:21:12 -06003557 scmd->result = DID_SOFT_ERROR << 16;
3558 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3559 scmd->result = DID_RESET << 16;
3560 break;
3561
Eric Moore3c621b32009-05-18 12:59:41 -06003562 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3563 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3564 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3565 _scsih_eedp_error_handling(scmd, ioc_status);
3566 break;
Eric Moore635374e2009-03-09 01:21:12 -06003567 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3568 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3569 case MPI2_IOCSTATUS_INVALID_SGL:
3570 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3571 case MPI2_IOCSTATUS_INVALID_FIELD:
3572 case MPI2_IOCSTATUS_INVALID_STATE:
3573 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3574 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3575 default:
3576 scmd->result = DID_SOFT_ERROR << 16;
3577 break;
3578
3579 }
3580
3581#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3582 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3583 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3584#endif
3585
3586 out:
3587 scsi_dma_unmap(scmd);
3588 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303589 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003590}
3591
3592/**
Eric Moore635374e2009-03-09 01:21:12 -06003593 * _scsih_sas_host_refresh - refreshing sas host object contents
3594 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06003595 * Context: user
3596 *
3597 * During port enable, fw will send topology events for every device. Its
3598 * possible that the handles may change from the previous setting, so this
3599 * code keeping handles updating if changed.
3600 *
3601 * Return nothing.
3602 */
3603static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303604_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06003605{
3606 u16 sz;
3607 u16 ioc_status;
3608 int i;
3609 Mpi2ConfigReply_t mpi_reply;
3610 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303611 u16 attached_handle;
Eric Moore635374e2009-03-09 01:21:12 -06003612
3613 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3614 "updating handles for sas_host(0x%016llx)\n",
3615 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3616
3617 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3618 * sizeof(Mpi2SasIOUnit0PhyData_t));
3619 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3620 if (!sas_iounit_pg0) {
3621 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3622 ioc->name, __FILE__, __LINE__, __func__);
3623 return;
3624 }
Eric Moore635374e2009-03-09 01:21:12 -06003625
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303626 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3627 sas_iounit_pg0, sz)) != 0)
3628 goto out;
3629 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
3630 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3631 goto out;
3632 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3633 if (i == 0)
3634 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3635 PhyData[0].ControllerDevHandle);
3636 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
3637 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
3638 AttachedDevHandle);
3639 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
3640 attached_handle, i, sas_iounit_pg0->PhyData[i].
3641 NegotiatedLinkRate >> 4);
3642 }
Eric Moore635374e2009-03-09 01:21:12 -06003643 out:
3644 kfree(sas_iounit_pg0);
3645}
3646
3647/**
3648 * _scsih_sas_host_add - create sas host object
3649 * @ioc: per adapter object
3650 *
3651 * Creating host side data object, stored in ioc->sas_hba
3652 *
3653 * Return nothing.
3654 */
3655static void
3656_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3657{
3658 int i;
3659 Mpi2ConfigReply_t mpi_reply;
3660 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3661 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3662 Mpi2SasPhyPage0_t phy_pg0;
3663 Mpi2SasDevicePage0_t sas_device_pg0;
3664 Mpi2SasEnclosurePage0_t enclosure_pg0;
3665 u16 ioc_status;
3666 u16 sz;
3667 u16 device_missing_delay;
3668
3669 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3670 if (!ioc->sas_hba.num_phys) {
3671 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3672 ioc->name, __FILE__, __LINE__, __func__);
3673 return;
3674 }
3675
3676 /* sas_iounit page 0 */
3677 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3678 sizeof(Mpi2SasIOUnit0PhyData_t));
3679 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3680 if (!sas_iounit_pg0) {
3681 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3682 ioc->name, __FILE__, __LINE__, __func__);
3683 return;
3684 }
3685 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3686 sas_iounit_pg0, sz))) {
3687 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3688 ioc->name, __FILE__, __LINE__, __func__);
3689 goto out;
3690 }
3691 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3692 MPI2_IOCSTATUS_MASK;
3693 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3694 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3695 ioc->name, __FILE__, __LINE__, __func__);
3696 goto out;
3697 }
3698
3699 /* sas_iounit page 1 */
3700 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3701 sizeof(Mpi2SasIOUnit1PhyData_t));
3702 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3703 if (!sas_iounit_pg1) {
3704 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3705 ioc->name, __FILE__, __LINE__, __func__);
3706 goto out;
3707 }
3708 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3709 sas_iounit_pg1, sz))) {
3710 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3711 ioc->name, __FILE__, __LINE__, __func__);
3712 goto out;
3713 }
3714 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3715 MPI2_IOCSTATUS_MASK;
3716 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3717 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3718 ioc->name, __FILE__, __LINE__, __func__);
3719 goto out;
3720 }
3721
3722 ioc->io_missing_delay =
3723 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3724 device_missing_delay =
3725 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3726 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3727 ioc->device_missing_delay = (device_missing_delay &
3728 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3729 else
3730 ioc->device_missing_delay = device_missing_delay &
3731 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3732
3733 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3734 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3735 sizeof(struct _sas_phy), GFP_KERNEL);
3736 if (!ioc->sas_hba.phy) {
3737 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3738 ioc->name, __FILE__, __LINE__, __func__);
3739 goto out;
3740 }
3741 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3742 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3743 i))) {
3744 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3745 ioc->name, __FILE__, __LINE__, __func__);
3746 goto out;
3747 }
3748 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3749 MPI2_IOCSTATUS_MASK;
3750 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3751 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3752 ioc->name, __FILE__, __LINE__, __func__);
3753 goto out;
3754 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303755
3756 if (i == 0)
3757 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3758 PhyData[0].ControllerDevHandle);
3759 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06003760 ioc->sas_hba.phy[i].phy_id = i;
3761 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3762 phy_pg0, ioc->sas_hba.parent_dev);
3763 }
3764 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303765 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06003766 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3767 ioc->name, __FILE__, __LINE__, __func__);
3768 goto out;
3769 }
Eric Moore635374e2009-03-09 01:21:12 -06003770 ioc->sas_hba.enclosure_handle =
3771 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3772 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3773 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3774 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3775 (unsigned long long) ioc->sas_hba.sas_address,
3776 ioc->sas_hba.num_phys) ;
3777
3778 if (ioc->sas_hba.enclosure_handle) {
3779 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3780 &enclosure_pg0,
3781 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3782 ioc->sas_hba.enclosure_handle))) {
3783 ioc->sas_hba.enclosure_logical_id =
3784 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3785 }
3786 }
3787
3788 out:
3789 kfree(sas_iounit_pg1);
3790 kfree(sas_iounit_pg0);
3791}
3792
3793/**
3794 * _scsih_expander_add - creating expander object
3795 * @ioc: per adapter object
3796 * @handle: expander handle
3797 *
3798 * Creating expander object, stored in ioc->sas_expander_list.
3799 *
3800 * Return 0 for success, else error.
3801 */
3802static int
3803_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3804{
3805 struct _sas_node *sas_expander;
3806 Mpi2ConfigReply_t mpi_reply;
3807 Mpi2ExpanderPage0_t expander_pg0;
3808 Mpi2ExpanderPage1_t expander_pg1;
3809 Mpi2SasEnclosurePage0_t enclosure_pg0;
3810 u32 ioc_status;
3811 u16 parent_handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303812 __le64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003813 int i;
3814 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303815 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003816 int rc = 0;
3817
3818 if (!handle)
3819 return -1;
3820
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303821 if (ioc->shost_recovery)
3822 return -1;
3823
Eric Moore635374e2009-03-09 01:21:12 -06003824 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3825 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3826 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3827 ioc->name, __FILE__, __LINE__, __func__);
3828 return -1;
3829 }
3830
3831 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3832 MPI2_IOCSTATUS_MASK;
3833 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3834 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3835 ioc->name, __FILE__, __LINE__, __func__);
3836 return -1;
3837 }
3838
3839 /* handle out of order topology events */
3840 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303841 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
3842 != 0) {
3843 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3844 ioc->name, __FILE__, __LINE__, __func__);
3845 return -1;
3846 }
3847 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06003848 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303849 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3850 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003851 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3852 if (!sas_expander) {
3853 rc = _scsih_expander_add(ioc, parent_handle);
3854 if (rc != 0)
3855 return rc;
3856 }
3857 }
3858
Eric Moore635374e2009-03-09 01:21:12 -06003859 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303860 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06003861 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3862 sas_address);
3863 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3864
3865 if (sas_expander)
3866 return 0;
3867
3868 sas_expander = kzalloc(sizeof(struct _sas_node),
3869 GFP_KERNEL);
3870 if (!sas_expander) {
3871 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3872 ioc->name, __FILE__, __LINE__, __func__);
3873 return -1;
3874 }
3875
3876 sas_expander->handle = handle;
3877 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303878 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06003879 sas_expander->sas_address = sas_address;
3880
3881 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3882 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303883 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06003884 sas_expander->sas_address, sas_expander->num_phys);
3885
3886 if (!sas_expander->num_phys)
3887 goto out_fail;
3888 sas_expander->phy = kcalloc(sas_expander->num_phys,
3889 sizeof(struct _sas_phy), GFP_KERNEL);
3890 if (!sas_expander->phy) {
3891 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3892 ioc->name, __FILE__, __LINE__, __func__);
3893 rc = -1;
3894 goto out_fail;
3895 }
3896
3897 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3898 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303899 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003900 if (!mpt2sas_port) {
3901 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3902 ioc->name, __FILE__, __LINE__, __func__);
3903 rc = -1;
3904 goto out_fail;
3905 }
3906 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3907
3908 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3909 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3910 &expander_pg1, i, handle))) {
3911 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3912 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303913 rc = -1;
3914 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003915 }
3916 sas_expander->phy[i].handle = handle;
3917 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303918
3919 if ((mpt2sas_transport_add_expander_phy(ioc,
3920 &sas_expander->phy[i], expander_pg1,
3921 sas_expander->parent_dev))) {
3922 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3923 ioc->name, __FILE__, __LINE__, __func__);
3924 rc = -1;
3925 goto out_fail;
3926 }
Eric Moore635374e2009-03-09 01:21:12 -06003927 }
3928
3929 if (sas_expander->enclosure_handle) {
3930 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3931 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3932 sas_expander->enclosure_handle))) {
3933 sas_expander->enclosure_logical_id =
3934 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3935 }
3936 }
3937
3938 _scsih_expander_node_add(ioc, sas_expander);
3939 return 0;
3940
3941 out_fail:
3942
Kashyap, Desai20f58952009-08-07 19:34:26 +05303943 if (mpt2sas_port)
3944 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303945 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003946 kfree(sas_expander);
3947 return rc;
3948}
3949
3950/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05303951 * _scsih_done - scsih callback handler.
3952 * @ioc: per adapter object
3953 * @smid: system request message index
3954 * @msix_index: MSIX table index supplied by the OS
3955 * @reply: reply message frame(lower 32bit addr)
3956 *
3957 * Callback handler when sending internal generated message frames.
3958 * The callback index passed is `ioc->scsih_cb_idx`
3959 *
3960 * Return 1 meaning mf should be freed from _base_interrupt
3961 * 0 means the mf is freed from this function.
3962 */
3963static u8
3964_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
3965{
3966 MPI2DefaultReply_t *mpi_reply;
3967
3968 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
3969 if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
3970 return 1;
3971 if (ioc->scsih_cmds.smid != smid)
3972 return 1;
3973 ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
3974 if (mpi_reply) {
3975 memcpy(ioc->scsih_cmds.reply, mpi_reply,
3976 mpi_reply->MsgLength*4);
3977 ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
3978 }
3979 ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
3980 complete(&ioc->scsih_cmds.done);
3981 return 1;
3982}
3983
3984/**
Eric Moore635374e2009-03-09 01:21:12 -06003985 * _scsih_expander_remove - removing expander object
3986 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303987 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06003988 *
3989 * Return nothing.
3990 */
3991static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303992_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06003993{
3994 struct _sas_node *sas_expander;
3995 unsigned long flags;
3996
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303997 if (ioc->shost_recovery)
3998 return;
3999
Eric Moore635374e2009-03-09 01:21:12 -06004000 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304001 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
4002 sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06004003 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4004 _scsih_expander_node_remove(ioc, sas_expander);
4005}
4006
4007/**
4008 * _scsih_add_device - creating sas device object
4009 * @ioc: per adapter object
4010 * @handle: sas device handle
4011 * @phy_num: phy number end device attached to
4012 * @is_pd: is this hidden raid component
4013 *
4014 * Creating end device object, stored in ioc->sas_device_list.
4015 *
4016 * Returns 0 for success, non-zero for failure.
4017 */
4018static int
4019_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
4020{
4021 Mpi2ConfigReply_t mpi_reply;
4022 Mpi2SasDevicePage0_t sas_device_pg0;
4023 Mpi2SasEnclosurePage0_t enclosure_pg0;
4024 struct _sas_device *sas_device;
4025 u32 ioc_status;
4026 __le64 sas_address;
4027 u32 device_info;
4028 unsigned long flags;
4029
4030 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4031 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4032 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4033 ioc->name, __FILE__, __LINE__, __func__);
4034 return -1;
4035 }
4036
4037 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4038 MPI2_IOCSTATUS_MASK;
4039 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4040 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4041 ioc->name, __FILE__, __LINE__, __func__);
4042 return -1;
4043 }
4044
4045 /* check if device is present */
4046 if (!(le16_to_cpu(sas_device_pg0.Flags) &
4047 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
4048 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4049 ioc->name, __FILE__, __LINE__, __func__);
4050 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
4051 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
4052 return -1;
4053 }
4054
4055 /* check if there were any issus with discovery */
4056 if (sas_device_pg0.AccessStatus ==
4057 MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
4058 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4059 ioc->name, __FILE__, __LINE__, __func__);
4060 printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
4061 ioc->name, sas_device_pg0.AccessStatus);
4062 return -1;
4063 }
4064
4065 /* check if this is end device */
4066 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4067 if (!(_scsih_is_end_device(device_info))) {
4068 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4069 ioc->name, __FILE__, __LINE__, __func__);
4070 return -1;
4071 }
4072
4073 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4074
4075 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4076 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4077 sas_address);
4078 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4079
4080 if (sas_device) {
4081 _scsih_ublock_io_device(ioc, handle);
4082 return 0;
4083 }
4084
4085 sas_device = kzalloc(sizeof(struct _sas_device),
4086 GFP_KERNEL);
4087 if (!sas_device) {
4088 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4089 ioc->name, __FILE__, __LINE__, __func__);
4090 return -1;
4091 }
4092
4093 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304094 if (_scsih_get_sas_address(ioc, le16_to_cpu
4095 (sas_device_pg0.ParentDevHandle),
4096 &sas_device->sas_address_parent) != 0)
4097 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4098 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06004099 sas_device->enclosure_handle =
4100 le16_to_cpu(sas_device_pg0.EnclosureHandle);
4101 sas_device->slot =
4102 le16_to_cpu(sas_device_pg0.Slot);
4103 sas_device->device_info = device_info;
4104 sas_device->sas_address = sas_address;
4105 sas_device->hidden_raid_component = is_pd;
4106
4107 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05304108 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
4109 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4110 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06004111 sas_device->enclosure_logical_id =
4112 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06004113
4114 /* get device name */
4115 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
4116
4117 if (ioc->wait_for_port_enable_to_complete)
4118 _scsih_sas_device_init_add(ioc, sas_device);
4119 else
4120 _scsih_sas_device_add(ioc, sas_device);
4121
4122 return 0;
4123}
4124
4125/**
4126 * _scsih_remove_device - removing sas device object
4127 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304128 * @sas_device: the sas_device object
Eric Moore635374e2009-03-09 01:21:12 -06004129 *
4130 * Return nothing.
4131 */
4132static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304133_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
4134 *sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06004135{
4136 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06004137 Mpi2SasIoUnitControlReply_t mpi_reply;
4138 Mpi2SasIoUnitControlRequest_t mpi_request;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304139 u16 device_handle, handle;
Eric Moore635374e2009-03-09 01:21:12 -06004140
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304141 if (!sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06004142 return;
Eric Moore635374e2009-03-09 01:21:12 -06004143
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304144 handle = sas_device->handle;
4145 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
4146 " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
4147 (unsigned long long) sas_device->sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06004148
4149 if (sas_device->starget && sas_device->starget->hostdata) {
4150 sas_target_priv_data = sas_device->starget->hostdata;
4151 sas_target_priv_data->deleted = 1;
4152 }
Eric Moore635374e2009-03-09 01:21:12 -06004153
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304154 if (ioc->remove_host || ioc->shost_recovery || !handle)
Eric Moore635374e2009-03-09 01:21:12 -06004155 goto out;
4156
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304157 if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
4158 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304159 "target_reset handle(0x%04x)\n", ioc->name,
4160 handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304161 goto skip_tr;
4162 }
4163
Eric Moore635374e2009-03-09 01:21:12 -06004164 /* Target Reset to flush out all the outstanding IO */
4165 device_handle = (sas_device->hidden_raid_component) ?
4166 sas_device->volume_handle : handle;
4167 if (device_handle) {
4168 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
4169 "handle(0x%04x)\n", ioc->name, device_handle));
4170 mutex_lock(&ioc->tm_cmds.mutex);
4171 mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
4172 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
4173 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
4174 mutex_unlock(&ioc->tm_cmds.mutex);
4175 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
4176 "done: handle(0x%04x)\n", ioc->name, device_handle));
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304177 if (ioc->shost_recovery)
4178 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06004179 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304180 skip_tr:
4181
4182 if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) {
4183 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
4184 "sas_cntrl handle(0x%04x)\n", ioc->name, handle));
4185 goto out;
4186 }
Eric Moore635374e2009-03-09 01:21:12 -06004187
4188 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
4189 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
4190 "(0x%04x)\n", ioc->name, handle));
4191 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
4192 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
4193 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
4194 mpi_request.DevHandle = handle;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304195 mpi_request.VF_ID = 0; /* TODO */
4196 mpi_request.VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004197 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
4198 &mpi_request)) != 0) {
4199 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4200 ioc->name, __FILE__, __LINE__, __func__);
4201 }
4202
4203 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
4204 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
4205 le16_to_cpu(mpi_reply.IOCStatus),
4206 le32_to_cpu(mpi_reply.IOCLogInfo)));
4207
4208 out:
Kashyap, Desai34a03be2009-08-20 13:23:19 +05304209
4210 _scsih_ublock_io_device(ioc, handle);
4211
Eric Moore635374e2009-03-09 01:21:12 -06004212 mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304213 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004214
4215 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304216 "(0x%016llx)\n", ioc->name, handle,
Eric Moore635374e2009-03-09 01:21:12 -06004217 (unsigned long long) sas_device->sas_address);
4218 _scsih_sas_device_remove(ioc, sas_device);
4219
4220 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
4221 "(0x%04x)\n", ioc->name, __func__, handle));
4222}
4223
4224#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4225/**
4226 * _scsih_sas_topology_change_event_debug - debug for topology event
4227 * @ioc: per adapter object
4228 * @event_data: event data payload
4229 * Context: user.
4230 */
4231static void
4232_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4233 Mpi2EventDataSasTopologyChangeList_t *event_data)
4234{
4235 int i;
4236 u16 handle;
4237 u16 reason_code;
4238 u8 phy_number;
4239 char *status_str = NULL;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304240 u8 link_rate, prev_link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06004241
4242 switch (event_data->ExpStatus) {
4243 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
4244 status_str = "add";
4245 break;
4246 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
4247 status_str = "remove";
4248 break;
4249 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304250 case 0:
Eric Moore635374e2009-03-09 01:21:12 -06004251 status_str = "responding";
4252 break;
4253 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
4254 status_str = "remove delay";
4255 break;
4256 default:
4257 status_str = "unknown status";
4258 break;
4259 }
4260 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
4261 ioc->name, status_str);
4262 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
4263 "start_phy(%02d), count(%d)\n",
4264 le16_to_cpu(event_data->ExpanderDevHandle),
4265 le16_to_cpu(event_data->EnclosureHandle),
4266 event_data->StartPhyNum, event_data->NumEntries);
4267 for (i = 0; i < event_data->NumEntries; i++) {
4268 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4269 if (!handle)
4270 continue;
4271 phy_number = event_data->StartPhyNum + i;
4272 reason_code = event_data->PHY[i].PhyStatus &
4273 MPI2_EVENT_SAS_TOPO_RC_MASK;
4274 switch (reason_code) {
4275 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304276 status_str = "target add";
Eric Moore635374e2009-03-09 01:21:12 -06004277 break;
4278 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304279 status_str = "target remove";
Eric Moore635374e2009-03-09 01:21:12 -06004280 break;
4281 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304282 status_str = "delay target remove";
Eric Moore635374e2009-03-09 01:21:12 -06004283 break;
4284 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304285 status_str = "link rate change";
Eric Moore635374e2009-03-09 01:21:12 -06004286 break;
4287 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304288 status_str = "target responding";
Eric Moore635374e2009-03-09 01:21:12 -06004289 break;
4290 default:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304291 status_str = "unknown";
Eric Moore635374e2009-03-09 01:21:12 -06004292 break;
4293 }
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304294 link_rate = event_data->PHY[i].LinkRate >> 4;
4295 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
4296 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:"
4297 " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
4298 handle, status_str, link_rate, prev_link_rate);
4299
Eric Moore635374e2009-03-09 01:21:12 -06004300 }
4301}
4302#endif
4303
4304/**
4305 * _scsih_sas_topology_change_event - handle topology changes
4306 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304307 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004308 * Context: user.
4309 *
4310 */
4311static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304312_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06004313 struct fw_event_work *fw_event)
4314{
4315 int i;
4316 u16 parent_handle, handle;
4317 u16 reason_code;
4318 u8 phy_number;
4319 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304320 struct _sas_device *sas_device;
4321 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004322 unsigned long flags;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304323 u8 link_rate, prev_link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304324 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004325
4326#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4327 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4328 _scsih_sas_topology_change_event_debug(ioc, event_data);
4329#endif
4330
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304331 if (ioc->shost_recovery)
4332 return;
4333
Eric Moore635374e2009-03-09 01:21:12 -06004334 if (!ioc->sas_hba.num_phys)
4335 _scsih_sas_host_add(ioc);
4336 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304337 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06004338
4339 if (fw_event->ignore) {
4340 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
4341 "event\n", ioc->name));
4342 return;
4343 }
4344
4345 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
4346
4347 /* handle expander add */
4348 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
4349 if (_scsih_expander_add(ioc, parent_handle) != 0)
4350 return;
4351
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304352 spin_lock_irqsave(&ioc->sas_node_lock, flags);
4353 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
4354 parent_handle);
4355 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4356 if (sas_expander)
4357 sas_address = sas_expander->sas_address;
4358 else if (parent_handle < ioc->sas_hba.num_phys)
4359 sas_address = ioc->sas_hba.sas_address;
4360 else
4361 return;
4362
Eric Moore635374e2009-03-09 01:21:12 -06004363 /* handle siblings events */
4364 for (i = 0; i < event_data->NumEntries; i++) {
4365 if (fw_event->ignore) {
4366 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
4367 "expander event\n", ioc->name));
4368 return;
4369 }
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304370 if (ioc->shost_recovery)
4371 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05304372 phy_number = event_data->StartPhyNum + i;
4373 reason_code = event_data->PHY[i].PhyStatus &
4374 MPI2_EVENT_SAS_TOPO_RC_MASK;
4375 if ((event_data->PHY[i].PhyStatus &
4376 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
4377 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06004378 continue;
4379 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4380 if (!handle)
4381 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304382 link_rate = event_data->PHY[i].LinkRate >> 4;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304383 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Eric Moore635374e2009-03-09 01:21:12 -06004384 switch (reason_code) {
4385 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304386
4387 if (link_rate == prev_link_rate)
4388 break;
4389
4390 mpt2sas_transport_update_links(ioc, sas_address,
4391 handle, phy_number, link_rate);
4392
4393 if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
4394 _scsih_ublock_io_device(ioc, handle);
4395 break;
Eric Moore635374e2009-03-09 01:21:12 -06004396 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304397
4398 mpt2sas_transport_update_links(ioc, sas_address,
4399 handle, phy_number, link_rate);
4400
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304401 _scsih_add_device(ioc, handle, phy_number, 0);
Eric Moore635374e2009-03-09 01:21:12 -06004402 break;
4403 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304404
4405 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4406 sas_device = _scsih_sas_device_find_by_handle(ioc,
4407 handle);
4408 if (!sas_device) {
4409 spin_unlock_irqrestore(&ioc->sas_device_lock,
4410 flags);
4411 break;
4412 }
4413 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4414 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004415 break;
4416 }
4417 }
4418
4419 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304420 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
4421 sas_expander)
4422 _scsih_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06004423
4424}
4425
4426#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4427/**
4428 * _scsih_sas_device_status_change_event_debug - debug for device event
4429 * @event_data: event data payload
4430 * Context: user.
4431 *
4432 * Return nothing.
4433 */
4434static void
4435_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4436 Mpi2EventDataSasDeviceStatusChange_t *event_data)
4437{
4438 char *reason_str = NULL;
4439
4440 switch (event_data->ReasonCode) {
4441 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
4442 reason_str = "smart data";
4443 break;
4444 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
4445 reason_str = "unsupported device discovered";
4446 break;
4447 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
4448 reason_str = "internal device reset";
4449 break;
4450 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
4451 reason_str = "internal task abort";
4452 break;
4453 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
4454 reason_str = "internal task abort set";
4455 break;
4456 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
4457 reason_str = "internal clear task set";
4458 break;
4459 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
4460 reason_str = "internal query task";
4461 break;
4462 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
4463 reason_str = "sata init failure";
4464 break;
4465 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
4466 reason_str = "internal device reset complete";
4467 break;
4468 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
4469 reason_str = "internal task abort complete";
4470 break;
4471 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
4472 reason_str = "internal async notification";
4473 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05304474 case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
4475 reason_str = "expander reduced functionality";
4476 break;
4477 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
4478 reason_str = "expander reduced functionality complete";
4479 break;
Eric Moore635374e2009-03-09 01:21:12 -06004480 default:
4481 reason_str = "unknown reason";
4482 break;
4483 }
4484 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
4485 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
4486 reason_str, le16_to_cpu(event_data->DevHandle),
4487 (unsigned long long)le64_to_cpu(event_data->SASAddress));
4488 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
4489 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
4490 event_data->ASC, event_data->ASCQ);
4491 printk(KERN_INFO "\n");
4492}
4493#endif
4494
4495/**
4496 * _scsih_sas_device_status_change_event - handle device status change
4497 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304498 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004499 * Context: user.
4500 *
4501 * Return nothing.
4502 */
4503static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304504_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
4505 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004506{
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304507 struct MPT2SAS_TARGET *target_priv_data;
4508 struct _sas_device *sas_device;
4509 __le64 sas_address;
4510 unsigned long flags;
4511 Mpi2EventDataSasDeviceStatusChange_t *event_data =
4512 fw_event->event_data;
4513
Eric Moore635374e2009-03-09 01:21:12 -06004514#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4515 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304516 _scsih_sas_device_status_change_event_debug(ioc,
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304517 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004518#endif
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304519
4520 if (!(event_data->ReasonCode ==
4521 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
4522 event_data->ReasonCode ==
4523 MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET))
4524 return;
4525
4526 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4527 sas_address = le64_to_cpu(event_data->SASAddress);
4528 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4529 sas_address);
4530 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4531
4532 if (!sas_device || !sas_device->starget)
4533 return;
4534
4535 target_priv_data = sas_device->starget->hostdata;
4536 if (!target_priv_data)
4537 return;
4538
4539 if (event_data->ReasonCode ==
4540 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
4541 target_priv_data->tm_busy = 1;
4542 else
4543 target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004544}
4545
4546#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4547/**
4548 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
4549 * @ioc: per adapter object
4550 * @event_data: event data payload
4551 * Context: user.
4552 *
4553 * Return nothing.
4554 */
4555static void
4556_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4557 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
4558{
4559 char *reason_str = NULL;
4560
4561 switch (event_data->ReasonCode) {
4562 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
4563 reason_str = "enclosure add";
4564 break;
4565 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
4566 reason_str = "enclosure remove";
4567 break;
4568 default:
4569 reason_str = "unknown reason";
4570 break;
4571 }
4572
4573 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
4574 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
4575 " number slots(%d)\n", ioc->name, reason_str,
4576 le16_to_cpu(event_data->EnclosureHandle),
4577 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
4578 le16_to_cpu(event_data->StartSlot));
4579}
4580#endif
4581
4582/**
4583 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
4584 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304585 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004586 * Context: user.
4587 *
4588 * Return nothing.
4589 */
4590static void
4591_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304592 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004593{
4594#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4595 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4596 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304597 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004598#endif
4599}
4600
4601/**
4602 * _scsih_sas_broadcast_primative_event - handle broadcast events
4603 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304604 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004605 * Context: user.
4606 *
4607 * Return nothing.
4608 */
4609static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304610_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4611 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004612{
4613 struct scsi_cmnd *scmd;
4614 u16 smid, handle;
4615 u32 lun;
4616 struct MPT2SAS_DEVICE *sas_device_priv_data;
4617 u32 termination_count;
4618 u32 query_count;
4619 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304620#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4621 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4622#endif
Kashyap, Desai463217b2009-10-05 15:53:06 +05304623 u16 ioc_status;
Eric Moore635374e2009-03-09 01:21:12 -06004624 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4625 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4626 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004627 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4628 __func__));
4629
4630 mutex_lock(&ioc->tm_cmds.mutex);
4631 termination_count = 0;
4632 query_count = 0;
4633 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304634 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06004635 scmd = _scsih_scsi_lookup_get(ioc, smid);
4636 if (!scmd)
4637 continue;
4638 sas_device_priv_data = scmd->device->hostdata;
4639 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4640 continue;
4641 /* skip hidden raid components */
4642 if (sas_device_priv_data->sas_target->flags &
4643 MPT_TARGET_FLAGS_RAID_COMPONENT)
4644 continue;
4645 /* skip volumes */
4646 if (sas_device_priv_data->sas_target->flags &
4647 MPT_TARGET_FLAGS_VOLUME)
4648 continue;
4649
4650 handle = sas_device_priv_data->sas_target->handle;
4651 lun = sas_device_priv_data->lun;
4652 query_count++;
4653
4654 mpt2sas_scsih_issue_tm(ioc, handle, lun,
4655 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
Eric Moore8901cbb2009-04-21 15:41:32 -06004656 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Kashyap, Desai463217b2009-10-05 15:53:06 +05304657 ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
4658 & MPI2_IOCSTATUS_MASK;
4659 if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) &&
Eric Moore635374e2009-03-09 01:21:12 -06004660 (mpi_reply->ResponseCode ==
4661 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4662 mpi_reply->ResponseCode ==
4663 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4664 continue;
4665
4666 mpt2sas_scsih_issue_tm(ioc, handle, lun,
Eric Moore8901cbb2009-04-21 15:41:32 -06004667 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30);
4668 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Eric Moore635374e2009-03-09 01:21:12 -06004669 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4670 }
Eric Moore635374e2009-03-09 01:21:12 -06004671 ioc->broadcast_aen_busy = 0;
4672 mutex_unlock(&ioc->tm_cmds.mutex);
4673
4674 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4675 "%s - exit, query_count = %d termination_count = %d\n",
4676 ioc->name, __func__, query_count, termination_count));
4677}
4678
4679/**
4680 * _scsih_sas_discovery_event - handle discovery events
4681 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304682 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004683 * Context: user.
4684 *
4685 * Return nothing.
4686 */
4687static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304688_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4689 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004690{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304691 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4692
Eric Moore635374e2009-03-09 01:21:12 -06004693#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4694 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4695 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4696 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4697 "start" : "stop");
4698 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304699 printk("discovery_status(0x%08x)",
4700 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06004701 printk("\n");
4702 }
4703#endif
4704
4705 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4706 !ioc->sas_hba.num_phys)
4707 _scsih_sas_host_add(ioc);
4708}
4709
4710/**
4711 * _scsih_reprobe_lun - reprobing lun
4712 * @sdev: scsi device struct
4713 * @no_uld_attach: sdev->no_uld_attach flag setting
4714 *
4715 **/
4716static void
4717_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4718{
4719 int rc;
4720
4721 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4722 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4723 sdev->no_uld_attach ? "hidding" : "exposing");
4724 rc = scsi_device_reprobe(sdev);
4725}
4726
4727/**
4728 * _scsih_reprobe_target - reprobing target
4729 * @starget: scsi target struct
4730 * @no_uld_attach: sdev->no_uld_attach flag setting
4731 *
4732 * Note: no_uld_attach flag determines whether the disk device is attached
4733 * to block layer. A value of `1` means to not attach.
4734 **/
4735static void
4736_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4737{
4738 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4739
4740 if (no_uld_attach)
4741 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4742 else
4743 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4744
4745 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4746 _scsih_reprobe_lun);
4747}
4748/**
4749 * _scsih_sas_volume_add - add new volume
4750 * @ioc: per adapter object
4751 * @element: IR config element data
4752 * Context: user.
4753 *
4754 * Return nothing.
4755 */
4756static void
4757_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4758 Mpi2EventIrConfigElement_t *element)
4759{
4760 struct _raid_device *raid_device;
4761 unsigned long flags;
4762 u64 wwid;
4763 u16 handle = le16_to_cpu(element->VolDevHandle);
4764 int rc;
4765
Eric Moore635374e2009-03-09 01:21:12 -06004766 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4767 if (!wwid) {
4768 printk(MPT2SAS_ERR_FMT
4769 "failure at %s:%d/%s()!\n", ioc->name,
4770 __FILE__, __LINE__, __func__);
4771 return;
4772 }
4773
4774 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4775 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4776 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4777
4778 if (raid_device)
4779 return;
4780
4781 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4782 if (!raid_device) {
4783 printk(MPT2SAS_ERR_FMT
4784 "failure at %s:%d/%s()!\n", ioc->name,
4785 __FILE__, __LINE__, __func__);
4786 return;
4787 }
4788
4789 raid_device->id = ioc->sas_id++;
4790 raid_device->channel = RAID_CHANNEL;
4791 raid_device->handle = handle;
4792 raid_device->wwid = wwid;
4793 _scsih_raid_device_add(ioc, raid_device);
4794 if (!ioc->wait_for_port_enable_to_complete) {
4795 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4796 raid_device->id, 0);
4797 if (rc)
4798 _scsih_raid_device_remove(ioc, raid_device);
4799 } else
4800 _scsih_determine_boot_device(ioc, raid_device, 1);
4801}
4802
4803/**
4804 * _scsih_sas_volume_delete - delete volume
4805 * @ioc: per adapter object
4806 * @element: IR config element data
4807 * Context: user.
4808 *
4809 * Return nothing.
4810 */
4811static void
4812_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4813 Mpi2EventIrConfigElement_t *element)
4814{
4815 struct _raid_device *raid_device;
4816 u16 handle = le16_to_cpu(element->VolDevHandle);
4817 unsigned long flags;
4818 struct MPT2SAS_TARGET *sas_target_priv_data;
4819
Eric Moore635374e2009-03-09 01:21:12 -06004820 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4821 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4822 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4823 if (!raid_device)
4824 return;
4825 if (raid_device->starget) {
4826 sas_target_priv_data = raid_device->starget->hostdata;
4827 sas_target_priv_data->deleted = 1;
4828 scsi_remove_target(&raid_device->starget->dev);
4829 }
4830 _scsih_raid_device_remove(ioc, raid_device);
4831}
4832
4833/**
4834 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4835 * @ioc: per adapter object
4836 * @element: IR config element data
4837 * Context: user.
4838 *
4839 * Return nothing.
4840 */
4841static void
4842_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4843 Mpi2EventIrConfigElement_t *element)
4844{
4845 struct _sas_device *sas_device;
4846 unsigned long flags;
4847 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4848
4849 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4850 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4851 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4852 if (!sas_device)
4853 return;
4854
4855 /* exposing raid component */
4856 sas_device->volume_handle = 0;
4857 sas_device->volume_wwid = 0;
4858 sas_device->hidden_raid_component = 0;
4859 _scsih_reprobe_target(sas_device->starget, 0);
4860}
4861
4862/**
4863 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4864 * @ioc: per adapter object
4865 * @element: IR config element data
4866 * Context: user.
4867 *
4868 * Return nothing.
4869 */
4870static void
4871_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4872 Mpi2EventIrConfigElement_t *element)
4873{
4874 struct _sas_device *sas_device;
4875 unsigned long flags;
4876 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
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 if (!sas_device)
4882 return;
4883
4884 /* hiding raid component */
4885 mpt2sas_config_get_volume_handle(ioc, handle,
4886 &sas_device->volume_handle);
4887 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4888 &sas_device->volume_wwid);
4889 sas_device->hidden_raid_component = 1;
4890 _scsih_reprobe_target(sas_device->starget, 1);
4891}
4892
4893/**
4894 * _scsih_sas_pd_delete - delete pd component
4895 * @ioc: per adapter object
4896 * @element: IR config element data
4897 * Context: user.
4898 *
4899 * Return nothing.
4900 */
4901static void
4902_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4903 Mpi2EventIrConfigElement_t *element)
4904{
4905 struct _sas_device *sas_device;
4906 unsigned long flags;
4907 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4908
4909 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4910 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4911 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4912 if (!sas_device)
4913 return;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304914 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004915}
4916
4917/**
4918 * _scsih_sas_pd_add - remove pd component
4919 * @ioc: per adapter object
4920 * @element: IR config element data
4921 * Context: user.
4922 *
4923 * Return nothing.
4924 */
4925static void
4926_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
4927 Mpi2EventIrConfigElement_t *element)
4928{
4929 struct _sas_device *sas_device;
4930 unsigned long flags;
4931 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304932 Mpi2ConfigReply_t mpi_reply;
4933 Mpi2SasDevicePage0_t sas_device_pg0;
4934 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304935 u64 sas_address;
4936 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06004937
4938 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4939 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4940 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304941 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06004942 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05304943 return;
4944 }
4945
4946 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4947 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4948 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4949 ioc->name, __FILE__, __LINE__, __func__);
4950 return;
4951 }
4952
4953 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4954 MPI2_IOCSTATUS_MASK;
4955 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4956 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4957 ioc->name, __FILE__, __LINE__, __func__);
4958 return;
4959 }
4960
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304961 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
4962 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
4963 mpt2sas_transport_update_links(ioc, sas_address, handle,
4964 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05304965
4966 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06004967}
4968
4969#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4970/**
4971 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
4972 * @ioc: per adapter object
4973 * @event_data: event data payload
4974 * Context: user.
4975 *
4976 * Return nothing.
4977 */
4978static void
4979_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4980 Mpi2EventDataIrConfigChangeList_t *event_data)
4981{
4982 Mpi2EventIrConfigElement_t *element;
4983 u8 element_type;
4984 int i;
4985 char *reason_str = NULL, *element_str = NULL;
4986
4987 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
4988
4989 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
4990 ioc->name, (le32_to_cpu(event_data->Flags) &
4991 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
4992 "foreign" : "native", event_data->NumElements);
4993 for (i = 0; i < event_data->NumElements; i++, element++) {
4994 switch (element->ReasonCode) {
4995 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
4996 reason_str = "add";
4997 break;
4998 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
4999 reason_str = "remove";
5000 break;
5001 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
5002 reason_str = "no change";
5003 break;
5004 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
5005 reason_str = "hide";
5006 break;
5007 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
5008 reason_str = "unhide";
5009 break;
5010 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
5011 reason_str = "volume_created";
5012 break;
5013 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
5014 reason_str = "volume_deleted";
5015 break;
5016 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
5017 reason_str = "pd_created";
5018 break;
5019 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
5020 reason_str = "pd_deleted";
5021 break;
5022 default:
5023 reason_str = "unknown reason";
5024 break;
5025 }
5026 element_type = le16_to_cpu(element->ElementFlags) &
5027 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
5028 switch (element_type) {
5029 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
5030 element_str = "volume";
5031 break;
5032 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
5033 element_str = "phys disk";
5034 break;
5035 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
5036 element_str = "hot spare";
5037 break;
5038 default:
5039 element_str = "unknown element";
5040 break;
5041 }
5042 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
5043 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
5044 reason_str, le16_to_cpu(element->VolDevHandle),
5045 le16_to_cpu(element->PhysDiskDevHandle),
5046 element->PhysDiskNum);
5047 }
5048}
5049#endif
5050
5051/**
5052 * _scsih_sas_ir_config_change_event - handle ir configuration change events
5053 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305054 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005055 * Context: user.
5056 *
5057 * Return nothing.
5058 */
5059static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305060_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
5061 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005062{
5063 Mpi2EventIrConfigElement_t *element;
5064 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305065 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305066 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005067
5068#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5069 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5070 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
5071
5072#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05305073 foreign_config = (le32_to_cpu(event_data->Flags) &
5074 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06005075
5076 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
5077 for (i = 0; i < event_data->NumElements; i++, element++) {
5078
5079 switch (element->ReasonCode) {
5080 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
5081 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305082 if (!foreign_config)
5083 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06005084 break;
5085 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
5086 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305087 if (!foreign_config)
5088 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06005089 break;
5090 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
5091 _scsih_sas_pd_hide(ioc, element);
5092 break;
5093 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
5094 _scsih_sas_pd_expose(ioc, element);
5095 break;
5096 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
5097 _scsih_sas_pd_add(ioc, element);
5098 break;
5099 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
5100 _scsih_sas_pd_delete(ioc, element);
5101 break;
5102 }
5103 }
5104}
5105
5106/**
5107 * _scsih_sas_ir_volume_event - IR volume event
5108 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305109 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005110 * Context: user.
5111 *
5112 * Return nothing.
5113 */
5114static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305115_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
5116 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005117{
5118 u64 wwid;
5119 unsigned long flags;
5120 struct _raid_device *raid_device;
5121 u16 handle;
5122 u32 state;
5123 int rc;
5124 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305125 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005126
5127 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
5128 return;
5129
5130 handle = le16_to_cpu(event_data->VolDevHandle);
5131 state = le32_to_cpu(event_data->NewValue);
5132 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
5133 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
5134 le32_to_cpu(event_data->PreviousValue), state));
5135
5136 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5137 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5138 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5139
5140 switch (state) {
5141 case MPI2_RAID_VOL_STATE_MISSING:
5142 case MPI2_RAID_VOL_STATE_FAILED:
5143 if (!raid_device)
5144 break;
5145 if (raid_device->starget) {
5146 sas_target_priv_data = raid_device->starget->hostdata;
5147 sas_target_priv_data->deleted = 1;
5148 scsi_remove_target(&raid_device->starget->dev);
5149 }
5150 _scsih_raid_device_remove(ioc, raid_device);
5151 break;
5152
5153 case MPI2_RAID_VOL_STATE_ONLINE:
5154 case MPI2_RAID_VOL_STATE_DEGRADED:
5155 case MPI2_RAID_VOL_STATE_OPTIMAL:
5156 if (raid_device)
5157 break;
5158
5159 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
5160 if (!wwid) {
5161 printk(MPT2SAS_ERR_FMT
5162 "failure at %s:%d/%s()!\n", ioc->name,
5163 __FILE__, __LINE__, __func__);
5164 break;
5165 }
5166
5167 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
5168 if (!raid_device) {
5169 printk(MPT2SAS_ERR_FMT
5170 "failure at %s:%d/%s()!\n", ioc->name,
5171 __FILE__, __LINE__, __func__);
5172 break;
5173 }
5174
5175 raid_device->id = ioc->sas_id++;
5176 raid_device->channel = RAID_CHANNEL;
5177 raid_device->handle = handle;
5178 raid_device->wwid = wwid;
5179 _scsih_raid_device_add(ioc, raid_device);
5180 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5181 raid_device->id, 0);
5182 if (rc)
5183 _scsih_raid_device_remove(ioc, raid_device);
5184 break;
5185
5186 case MPI2_RAID_VOL_STATE_INITIALIZING:
5187 default:
5188 break;
5189 }
5190}
5191
5192/**
5193 * _scsih_sas_ir_physical_disk_event - PD event
5194 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305195 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005196 * Context: user.
5197 *
5198 * Return nothing.
5199 */
5200static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305201_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
5202 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005203{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305204 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06005205 u32 state;
5206 struct _sas_device *sas_device;
5207 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305208 Mpi2ConfigReply_t mpi_reply;
5209 Mpi2SasDevicePage0_t sas_device_pg0;
5210 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305211 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305212 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06005213
5214 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
5215 return;
5216
5217 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
5218 state = le32_to_cpu(event_data->NewValue);
5219
5220 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
5221 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
5222 le32_to_cpu(event_data->PreviousValue), state));
5223
5224 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5225 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5226 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5227
5228 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06005229 case MPI2_RAID_PD_STATE_ONLINE:
5230 case MPI2_RAID_PD_STATE_DEGRADED:
5231 case MPI2_RAID_PD_STATE_REBUILDING:
5232 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305233 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06005234 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305235 return;
5236 }
5237
5238 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5239 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
5240 handle))) {
5241 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5242 ioc->name, __FILE__, __LINE__, __func__);
5243 return;
5244 }
5245
5246 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5247 MPI2_IOCSTATUS_MASK;
5248 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5249 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5250 ioc->name, __FILE__, __LINE__, __func__);
5251 return;
5252 }
5253
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305254 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
5255 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
5256 mpt2sas_transport_update_links(ioc, sas_address, handle,
5257 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305258
5259 _scsih_add_device(ioc, handle, 0, 1);
5260
Eric Moore635374e2009-03-09 01:21:12 -06005261 break;
5262
Kashyap, Desai62727a72009-08-07 19:35:18 +05305263 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06005264 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
5265 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
5266 case MPI2_RAID_PD_STATE_HOT_SPARE:
5267 default:
5268 break;
5269 }
5270}
5271
5272#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5273/**
5274 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
5275 * @ioc: per adapter object
5276 * @event_data: event data payload
5277 * Context: user.
5278 *
5279 * Return nothing.
5280 */
5281static void
5282_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
5283 Mpi2EventDataIrOperationStatus_t *event_data)
5284{
5285 char *reason_str = NULL;
5286
5287 switch (event_data->RAIDOperation) {
5288 case MPI2_EVENT_IR_RAIDOP_RESYNC:
5289 reason_str = "resync";
5290 break;
5291 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
5292 reason_str = "online capacity expansion";
5293 break;
5294 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
5295 reason_str = "consistency check";
5296 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305297 case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
5298 reason_str = "background init";
5299 break;
5300 case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
5301 reason_str = "make data consistent";
Eric Moore635374e2009-03-09 01:21:12 -06005302 break;
5303 }
5304
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305305 if (!reason_str)
5306 return;
5307
Eric Moore635374e2009-03-09 01:21:12 -06005308 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
5309 "\thandle(0x%04x), percent complete(%d)\n",
5310 ioc->name, reason_str,
5311 le16_to_cpu(event_data->VolDevHandle),
5312 event_data->PercentComplete);
5313}
5314#endif
5315
5316/**
5317 * _scsih_sas_ir_operation_status_event - handle RAID operation events
5318 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305319 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005320 * Context: user.
5321 *
5322 * Return nothing.
5323 */
5324static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305325_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
5326 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005327{
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305328 Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data;
5329 static struct _raid_device *raid_device;
5330 unsigned long flags;
5331 u16 handle;
5332
Eric Moore635374e2009-03-09 01:21:12 -06005333#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5334 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305335 _scsih_sas_ir_operation_status_event_debug(ioc,
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305336 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005337#endif
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305338
5339 /* code added for raid transport support */
5340 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
5341
5342 handle = le16_to_cpu(event_data->VolDevHandle);
5343
5344 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5345 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5346 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5347
5348 if (!raid_device)
5349 return;
5350
5351 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
5352 raid_device->percent_complete =
5353 event_data->PercentComplete;
5354 }
Eric Moore635374e2009-03-09 01:21:12 -06005355}
5356
5357/**
5358 * _scsih_task_set_full - handle task set full
5359 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305360 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005361 * Context: user.
5362 *
5363 * Throttle back qdepth.
5364 */
5365static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305366_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
5367 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005368{
5369 unsigned long flags;
5370 struct _sas_device *sas_device;
5371 static struct _raid_device *raid_device;
5372 struct scsi_device *sdev;
5373 int depth;
5374 u16 current_depth;
5375 u16 handle;
5376 int id, channel;
5377 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305378 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005379
5380 current_depth = le16_to_cpu(event_data->CurrentDepth);
5381 handle = le16_to_cpu(event_data->DevHandle);
5382 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5383 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5384 if (!sas_device) {
5385 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5386 return;
5387 }
5388 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5389 id = sas_device->id;
5390 channel = sas_device->channel;
5391 sas_address = sas_device->sas_address;
5392
5393 /* if hidden raid component, then change to volume characteristics */
5394 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
5395 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5396 raid_device = _scsih_raid_device_find_by_handle(
5397 ioc, sas_device->volume_handle);
5398 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5399 if (raid_device) {
5400 id = raid_device->id;
5401 channel = raid_device->channel;
5402 handle = raid_device->handle;
5403 sas_address = raid_device->wwid;
5404 }
5405 }
5406
5407 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
5408 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
5409 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
5410 handle, (unsigned long long)sas_address, current_depth);
5411
5412 shost_for_each_device(sdev, ioc->shost) {
5413 if (sdev->id == id && sdev->channel == channel) {
5414 if (current_depth > sdev->queue_depth) {
5415 if (ioc->logging_level &
5416 MPT_DEBUG_TASK_SET_FULL)
5417 sdev_printk(KERN_INFO, sdev, "strange "
5418 "observation, the queue depth is"
5419 " (%d) meanwhile fw queue depth "
5420 "is (%d)\n", sdev->queue_depth,
5421 current_depth);
5422 continue;
5423 }
5424 depth = scsi_track_queue_full(sdev,
5425 current_depth - 1);
5426 if (depth > 0)
5427 sdev_printk(KERN_INFO, sdev, "Queue depth "
5428 "reduced to (%d)\n", depth);
5429 else if (depth < 0)
5430 sdev_printk(KERN_INFO, sdev, "Tagged Command "
5431 "Queueing is being disabled\n");
5432 else if (depth == 0)
5433 if (ioc->logging_level &
5434 MPT_DEBUG_TASK_SET_FULL)
5435 sdev_printk(KERN_INFO, sdev,
5436 "Queue depth not changed yet\n");
5437 }
5438 }
5439}
5440
5441/**
5442 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
5443 * @ioc: per adapter object
5444 * @sas_address: sas address
5445 * @slot: enclosure slot id
5446 * @handle: device handle
5447 *
5448 * After host reset, find out whether devices are still responding.
5449 * Used in _scsi_remove_unresponsive_sas_devices.
5450 *
5451 * Return nothing.
5452 */
5453static void
5454_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5455 u16 slot, u16 handle)
5456{
5457 struct MPT2SAS_TARGET *sas_target_priv_data;
5458 struct scsi_target *starget;
5459 struct _sas_device *sas_device;
5460 unsigned long flags;
5461
5462 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5463 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
5464 if (sas_device->sas_address == sas_address &&
5465 sas_device->slot == slot && sas_device->starget) {
5466 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305467 sas_device->state = 0;
5468 starget = sas_device->starget;
5469 sas_target_priv_data = starget->hostdata;
5470 sas_target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06005471 starget_printk(KERN_INFO, sas_device->starget,
5472 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
5473 "logical id(0x%016llx), slot(%d)\n", handle,
5474 (unsigned long long)sas_device->sas_address,
5475 (unsigned long long)
5476 sas_device->enclosure_logical_id,
5477 sas_device->slot);
5478 if (sas_device->handle == handle)
5479 goto out;
5480 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5481 sas_device->handle);
5482 sas_device->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005483 sas_target_priv_data->handle = handle;
5484 goto out;
5485 }
5486 }
5487 out:
5488 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5489}
5490
5491/**
5492 * _scsih_search_responding_sas_devices -
5493 * @ioc: per adapter object
5494 *
5495 * After host reset, find out whether devices are still responding.
5496 * If not remove.
5497 *
5498 * Return nothing.
5499 */
5500static void
5501_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
5502{
5503 Mpi2SasDevicePage0_t sas_device_pg0;
5504 Mpi2ConfigReply_t mpi_reply;
5505 u16 ioc_status;
5506 __le64 sas_address;
5507 u16 handle;
5508 u32 device_info;
5509 u16 slot;
5510
5511 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5512
5513 if (list_empty(&ioc->sas_device_list))
5514 return;
5515
5516 handle = 0xFFFF;
5517 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5518 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
5519 handle))) {
5520 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5521 MPI2_IOCSTATUS_MASK;
5522 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5523 break;
5524 handle = le16_to_cpu(sas_device_pg0.DevHandle);
5525 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5526 if (!(_scsih_is_end_device(device_info)))
5527 continue;
5528 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5529 slot = le16_to_cpu(sas_device_pg0.Slot);
5530 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
5531 handle);
5532 }
5533}
5534
5535/**
5536 * _scsih_mark_responding_raid_device - mark a raid_device as responding
5537 * @ioc: per adapter object
5538 * @wwid: world wide identifier for raid volume
5539 * @handle: device handle
5540 *
5541 * After host reset, find out whether devices are still responding.
5542 * Used in _scsi_remove_unresponsive_raid_devices.
5543 *
5544 * Return nothing.
5545 */
5546static void
5547_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
5548 u16 handle)
5549{
5550 struct MPT2SAS_TARGET *sas_target_priv_data;
5551 struct scsi_target *starget;
5552 struct _raid_device *raid_device;
5553 unsigned long flags;
5554
5555 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5556 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
5557 if (raid_device->wwid == wwid && raid_device->starget) {
5558 raid_device->responding = 1;
5559 starget_printk(KERN_INFO, raid_device->starget,
5560 "handle(0x%04x), wwid(0x%016llx)\n", handle,
5561 (unsigned long long)raid_device->wwid);
5562 if (raid_device->handle == handle)
5563 goto out;
5564 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5565 raid_device->handle);
5566 raid_device->handle = handle;
5567 starget = raid_device->starget;
5568 sas_target_priv_data = starget->hostdata;
5569 sas_target_priv_data->handle = handle;
5570 goto out;
5571 }
5572 }
5573 out:
5574 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5575}
5576
5577/**
5578 * _scsih_search_responding_raid_devices -
5579 * @ioc: per adapter object
5580 *
5581 * After host reset, find out whether devices are still responding.
5582 * If not remove.
5583 *
5584 * Return nothing.
5585 */
5586static void
5587_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
5588{
5589 Mpi2RaidVolPage1_t volume_pg1;
5590 Mpi2ConfigReply_t mpi_reply;
5591 u16 ioc_status;
5592 u16 handle;
5593
5594 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5595
5596 if (list_empty(&ioc->raid_device_list))
5597 return;
5598
5599 handle = 0xFFFF;
5600 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
5601 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
5602 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5603 MPI2_IOCSTATUS_MASK;
5604 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5605 break;
5606 handle = le16_to_cpu(volume_pg1.DevHandle);
5607 _scsih_mark_responding_raid_device(ioc,
5608 le64_to_cpu(volume_pg1.WWID), handle);
5609 }
5610}
5611
5612/**
5613 * _scsih_mark_responding_expander - mark a expander as responding
5614 * @ioc: per adapter object
5615 * @sas_address: sas address
5616 * @handle:
5617 *
5618 * After host reset, find out whether devices are still responding.
5619 * Used in _scsi_remove_unresponsive_expanders.
5620 *
5621 * Return nothing.
5622 */
5623static void
5624_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5625 u16 handle)
5626{
5627 struct _sas_node *sas_expander;
5628 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305629 int i;
Eric Moore635374e2009-03-09 01:21:12 -06005630
5631 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5632 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305633 if (sas_expander->sas_address != sas_address)
5634 continue;
5635 sas_expander->responding = 1;
5636 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06005637 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305638 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
5639 " from(0x%04x) to (0x%04x)!!!\n",
5640 (unsigned long long)sas_expander->sas_address,
5641 sas_expander->handle, handle);
5642 sas_expander->handle = handle;
5643 for (i = 0 ; i < sas_expander->num_phys ; i++)
5644 sas_expander->phy[i].handle = handle;
5645 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06005646 }
5647 out:
5648 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5649}
5650
5651/**
5652 * _scsih_search_responding_expanders -
5653 * @ioc: per adapter object
5654 *
5655 * After host reset, find out whether devices are still responding.
5656 * If not remove.
5657 *
5658 * Return nothing.
5659 */
5660static void
5661_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5662{
5663 Mpi2ExpanderPage0_t expander_pg0;
5664 Mpi2ConfigReply_t mpi_reply;
5665 u16 ioc_status;
5666 __le64 sas_address;
5667 u16 handle;
5668
5669 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5670
5671 if (list_empty(&ioc->sas_expander_list))
5672 return;
5673
5674 handle = 0xFFFF;
5675 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5676 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5677
5678 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5679 MPI2_IOCSTATUS_MASK;
5680 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5681 break;
5682
5683 handle = le16_to_cpu(expander_pg0.DevHandle);
5684 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5685 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5686 "sas_addr(0x%016llx)\n", handle,
5687 (unsigned long long)sas_address);
5688 _scsih_mark_responding_expander(ioc, sas_address, handle);
5689 }
5690
5691}
5692
5693/**
5694 * _scsih_remove_unresponding_devices - removing unresponding devices
5695 * @ioc: per adapter object
5696 *
5697 * Return nothing.
5698 */
5699static void
5700_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
5701{
5702 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305703 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005704 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005705
Eric Moore635374e2009-03-09 01:21:12 -06005706
5707 list_for_each_entry_safe(sas_device, sas_device_next,
5708 &ioc->sas_device_list, list) {
5709 if (sas_device->responding) {
5710 sas_device->responding = 0;
5711 continue;
5712 }
5713 if (sas_device->starget)
5714 starget_printk(KERN_INFO, sas_device->starget,
5715 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5716 "enclosure logical id(0x%016llx), slot(%d)\n",
5717 sas_device->handle,
5718 (unsigned long long)sas_device->sas_address,
5719 (unsigned long long)
5720 sas_device->enclosure_logical_id,
5721 sas_device->slot);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305722 /* invalidate the device handle */
5723 sas_device->handle = 0;
5724 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005725 }
5726
5727 list_for_each_entry_safe(raid_device, raid_device_next,
5728 &ioc->raid_device_list, list) {
5729 if (raid_device->responding) {
5730 raid_device->responding = 0;
5731 continue;
5732 }
5733 if (raid_device->starget) {
5734 starget_printk(KERN_INFO, raid_device->starget,
5735 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5736 raid_device->handle,
5737 (unsigned long long)raid_device->wwid);
5738 scsi_remove_target(&raid_device->starget->dev);
5739 }
5740 _scsih_raid_device_remove(ioc, raid_device);
5741 }
5742
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305743 retry_expander_search:
5744 sas_expander = NULL;
5745 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005746 if (sas_expander->responding) {
5747 sas_expander->responding = 0;
5748 continue;
5749 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305750 _scsih_expander_remove(ioc, sas_expander->sas_address);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305751 goto retry_expander_search;
5752 }
5753}
5754
5755/**
5756 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5757 * @ioc: per adapter object
5758 * @reset_phase: phase
5759 *
5760 * The handler for doing any required cleanup or initialization.
5761 *
5762 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5763 * MPT2_IOC_DONE_RESET
5764 *
5765 * Return nothing.
5766 */
5767void
5768mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5769{
5770 switch (reset_phase) {
5771 case MPT2_IOC_PRE_RESET:
5772 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5773 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
5774 _scsih_fw_event_off(ioc);
5775 break;
5776 case MPT2_IOC_AFTER_RESET:
5777 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5778 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
5779 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5780 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5781 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5782 complete(&ioc->tm_cmds.done);
5783 }
5784 _scsih_fw_event_on(ioc);
5785 _scsih_flush_running_cmds(ioc);
5786 break;
5787 case MPT2_IOC_DONE_RESET:
5788 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5789 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305790 _scsih_sas_host_refresh(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305791 _scsih_search_responding_sas_devices(ioc);
5792 _scsih_search_responding_raid_devices(ioc);
5793 _scsih_search_responding_expanders(ioc);
5794 break;
5795 case MPT2_IOC_RUNNING:
5796 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5797 "MPT2_IOC_RUNNING\n", ioc->name, __func__));
5798 _scsih_remove_unresponding_devices(ioc);
5799 break;
Eric Moore635374e2009-03-09 01:21:12 -06005800 }
5801}
5802
5803/**
5804 * _firmware_event_work - delayed task for processing firmware events
5805 * @ioc: per adapter object
5806 * @work: equal to the fw_event_work object
5807 * Context: user.
5808 *
5809 * Return nothing.
5810 */
5811static void
5812_firmware_event_work(struct work_struct *work)
5813{
5814 struct fw_event_work *fw_event = container_of(work,
Eric Moore6f92a7a2009-04-21 15:43:33 -06005815 struct fw_event_work, work);
Eric Moore635374e2009-03-09 01:21:12 -06005816 unsigned long flags;
5817 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5818
Eric Moore635374e2009-03-09 01:21:12 -06005819 /* the queue is being flushed so ignore this event */
5820 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5821 if (ioc->fw_events_off || ioc->remove_host) {
5822 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5823 _scsih_fw_event_free(ioc, fw_event);
5824 return;
5825 }
5826 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5827
Eric Moore635374e2009-03-09 01:21:12 -06005828 if (ioc->shost_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06005829 _scsih_fw_event_requeue(ioc, fw_event, 1000);
5830 return;
5831 }
Eric Moore635374e2009-03-09 01:21:12 -06005832
5833 switch (fw_event->event) {
5834 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305835 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005836 break;
5837 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305838 _scsih_sas_device_status_change_event(ioc,
5839 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005840 break;
5841 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305842 _scsih_sas_discovery_event(ioc,
5843 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005844 break;
5845 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305846 _scsih_sas_broadcast_primative_event(ioc,
5847 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005848 break;
5849 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5850 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305851 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005852 break;
5853 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305854 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005855 break;
5856 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305857 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005858 break;
5859 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305860 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005861 break;
5862 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305863 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005864 break;
5865 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305866 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005867 break;
5868 }
5869 _scsih_fw_event_free(ioc, fw_event);
5870}
5871
5872/**
5873 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5874 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305875 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06005876 * @reply: reply message frame(lower 32bit addr)
5877 * Context: interrupt.
5878 *
5879 * This function merely adds a new work task into ioc->firmware_event_thread.
5880 * The tasks are worked from _firmware_event_work in user context.
5881 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305882 * Return 1 meaning mf should be freed from _base_interrupt
5883 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06005884 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305885u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305886mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
5887 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06005888{
5889 struct fw_event_work *fw_event;
5890 Mpi2EventNotificationReply_t *mpi_reply;
5891 unsigned long flags;
5892 u16 event;
5893
5894 /* events turned off due to host reset or driver unloading */
5895 spin_lock_irqsave(&ioc->fw_event_lock, flags);
5896 if (ioc->fw_events_off || ioc->remove_host) {
5897 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305898 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005899 }
5900 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
5901
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305902 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06005903 event = le16_to_cpu(mpi_reply->Event);
5904
5905 switch (event) {
5906 /* handle these */
5907 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
5908 {
5909 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
5910 (Mpi2EventDataSasBroadcastPrimitive_t *)
5911 mpi_reply->EventData;
5912
5913 if (baen_data->Primitive !=
5914 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
5915 ioc->broadcast_aen_busy)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305916 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005917 ioc->broadcast_aen_busy = 1;
5918 break;
5919 }
5920
5921 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
5922 _scsih_check_topo_delete_events(ioc,
5923 (Mpi2EventDataSasTopologyChangeList_t *)
5924 mpi_reply->EventData);
5925 break;
5926
5927 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
5928 case MPI2_EVENT_IR_OPERATION_STATUS:
5929 case MPI2_EVENT_SAS_DISCOVERY:
5930 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5931 case MPI2_EVENT_IR_VOLUME:
5932 case MPI2_EVENT_IR_PHYSICAL_DISK:
5933 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
5934 case MPI2_EVENT_TASK_SET_FULL:
5935 break;
5936
5937 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305938 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005939 }
5940
5941 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
5942 if (!fw_event) {
5943 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5944 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305945 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005946 }
5947 fw_event->event_data =
5948 kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
5949 if (!fw_event->event_data) {
5950 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5951 ioc->name, __FILE__, __LINE__, __func__);
5952 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305953 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005954 }
5955
5956 memcpy(fw_event->event_data, mpi_reply->EventData,
5957 mpi_reply->EventDataLength*4);
5958 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305959 fw_event->VF_ID = mpi_reply->VF_ID;
5960 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06005961 fw_event->event = event;
5962 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305963 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06005964}
5965
5966/* shost template */
5967static struct scsi_host_template scsih_driver_template = {
5968 .module = THIS_MODULE,
5969 .name = "Fusion MPT SAS Host",
5970 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06005971 .queuecommand = _scsih_qcmd,
5972 .target_alloc = _scsih_target_alloc,
5973 .slave_alloc = _scsih_slave_alloc,
5974 .slave_configure = _scsih_slave_configure,
5975 .target_destroy = _scsih_target_destroy,
5976 .slave_destroy = _scsih_slave_destroy,
5977 .change_queue_depth = _scsih_change_queue_depth,
5978 .change_queue_type = _scsih_change_queue_type,
5979 .eh_abort_handler = _scsih_abort,
5980 .eh_device_reset_handler = _scsih_dev_reset,
5981 .eh_target_reset_handler = _scsih_target_reset,
5982 .eh_host_reset_handler = _scsih_host_reset,
5983 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06005984 .can_queue = 1,
5985 .this_id = -1,
5986 .sg_tablesize = MPT2SAS_SG_DEPTH,
5987 .max_sectors = 8192,
5988 .cmd_per_lun = 7,
5989 .use_clustering = ENABLE_CLUSTERING,
5990 .shost_attrs = mpt2sas_host_attrs,
5991 .sdev_attrs = mpt2sas_dev_attrs,
5992};
5993
5994/**
5995 * _scsih_expander_node_remove - removing expander device from list.
5996 * @ioc: per adapter object
5997 * @sas_expander: the sas_device object
5998 * Context: Calling function should acquire ioc->sas_node_lock.
5999 *
6000 * Removing object and freeing associated memory from the
6001 * ioc->sas_expander_list.
6002 *
6003 * Return nothing.
6004 */
6005static void
6006_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
6007 struct _sas_node *sas_expander)
6008{
6009 struct _sas_port *mpt2sas_port;
6010 struct _sas_device *sas_device;
6011 struct _sas_node *expander_sibling;
6012 unsigned long flags;
6013
6014 if (!sas_expander)
6015 return;
6016
6017 /* remove sibling ports attached to this expander */
6018 retry_device_search:
6019 list_for_each_entry(mpt2sas_port,
6020 &sas_expander->sas_port_list, port_list) {
6021 if (mpt2sas_port->remote_identify.device_type ==
6022 SAS_END_DEVICE) {
6023 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6024 sas_device =
6025 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
6026 mpt2sas_port->remote_identify.sas_address);
6027 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6028 if (!sas_device)
6029 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306030 _scsih_remove_device(ioc, sas_device);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05306031 if (ioc->shost_recovery)
6032 return;
Eric Moore635374e2009-03-09 01:21:12 -06006033 goto retry_device_search;
6034 }
6035 }
6036
6037 retry_expander_search:
6038 list_for_each_entry(mpt2sas_port,
6039 &sas_expander->sas_port_list, port_list) {
6040
6041 if (mpt2sas_port->remote_identify.device_type ==
6042 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
6043 mpt2sas_port->remote_identify.device_type ==
6044 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
6045
6046 spin_lock_irqsave(&ioc->sas_node_lock, flags);
6047 expander_sibling =
6048 mpt2sas_scsih_expander_find_by_sas_address(
6049 ioc, mpt2sas_port->remote_identify.sas_address);
6050 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
6051 if (!expander_sibling)
6052 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306053 _scsih_expander_remove(ioc,
6054 expander_sibling->sas_address);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05306055 if (ioc->shost_recovery)
6056 return;
Eric Moore635374e2009-03-09 01:21:12 -06006057 goto retry_expander_search;
6058 }
6059 }
6060
6061 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306062 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006063
6064 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
6065 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
6066 sas_expander->handle, (unsigned long long)
6067 sas_expander->sas_address);
6068
6069 list_del(&sas_expander->list);
6070 kfree(sas_expander->phy);
6071 kfree(sas_expander);
6072}
6073
6074/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05306075 * _scsih_ir_shutdown - IR shutdown notification
6076 * @ioc: per adapter object
6077 *
6078 * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
6079 * the host system is shutting down.
6080 *
6081 * Return nothing.
6082 */
6083static void
6084_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
6085{
6086 Mpi2RaidActionRequest_t *mpi_request;
6087 Mpi2RaidActionReply_t *mpi_reply;
6088 u16 smid;
6089
6090 /* is IR firmware build loaded ? */
6091 if (!ioc->ir_firmware)
6092 return;
6093
6094 /* are there any volumes ? */
6095 if (list_empty(&ioc->raid_device_list))
6096 return;
6097
6098 mutex_lock(&ioc->scsih_cmds.mutex);
6099
6100 if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
6101 printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
6102 ioc->name, __func__);
6103 goto out;
6104 }
6105 ioc->scsih_cmds.status = MPT2_CMD_PENDING;
6106
6107 smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
6108 if (!smid) {
6109 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
6110 ioc->name, __func__);
6111 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
6112 goto out;
6113 }
6114
6115 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
6116 ioc->scsih_cmds.smid = smid;
6117 memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
6118
6119 mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
6120 mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
6121
6122 printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
6123 init_completion(&ioc->scsih_cmds.done);
6124 mpt2sas_base_put_smid_default(ioc, smid);
6125 wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
6126
6127 if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
6128 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
6129 ioc->name, __func__);
6130 goto out;
6131 }
6132
6133 if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
6134 mpi_reply = ioc->scsih_cmds.reply;
6135
6136 printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
6137 "ioc_status(0x%04x), loginfo(0x%08x)\n",
6138 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
6139 le32_to_cpu(mpi_reply->IOCLogInfo));
6140 }
6141
6142 out:
6143 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
6144 mutex_unlock(&ioc->scsih_cmds.mutex);
6145}
6146
6147/**
6148 * _scsih_shutdown - routine call during system shutdown
6149 * @pdev: PCI device struct
6150 *
6151 * Return nothing.
6152 */
6153static void
6154_scsih_shutdown(struct pci_dev *pdev)
6155{
6156 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6157 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6158
6159 _scsih_ir_shutdown(ioc);
6160 mpt2sas_base_detach(ioc);
6161}
6162
6163/**
Eric Moored5d135b2009-05-18 13:02:08 -06006164 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06006165 * @pdev: PCI device struct
6166 *
Kashyap, Desai744090d2009-10-05 15:56:56 +05306167 * Routine called when unloading the driver.
Eric Moore635374e2009-03-09 01:21:12 -06006168 * Return nothing.
6169 */
6170static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06006171_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006172{
6173 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6174 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6175 struct _sas_port *mpt2sas_port;
6176 struct _sas_device *sas_device;
6177 struct _sas_node *expander_sibling;
Kashyap, Desaid7384b22009-12-16 18:50:06 +05306178 struct _raid_device *raid_device, *next;
6179 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06006180 struct workqueue_struct *wq;
6181 unsigned long flags;
6182
6183 ioc->remove_host = 1;
6184 _scsih_fw_event_off(ioc);
6185
6186 spin_lock_irqsave(&ioc->fw_event_lock, flags);
6187 wq = ioc->firmware_event_thread;
6188 ioc->firmware_event_thread = NULL;
6189 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
6190 if (wq)
6191 destroy_workqueue(wq);
6192
Kashyap, Desaid7384b22009-12-16 18:50:06 +05306193 /* release all the volumes */
6194 list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
6195 list) {
6196 if (raid_device->starget) {
6197 sas_target_priv_data =
6198 raid_device->starget->hostdata;
6199 sas_target_priv_data->deleted = 1;
6200 scsi_remove_target(&raid_device->starget->dev);
6201 }
6202 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
6203 "(0x%016llx)\n", ioc->name, raid_device->handle,
6204 (unsigned long long) raid_device->wwid);
6205 _scsih_raid_device_remove(ioc, raid_device);
6206 }
6207
Eric Moore635374e2009-03-09 01:21:12 -06006208 /* free ports attached to the sas_host */
6209 retry_again:
6210 list_for_each_entry(mpt2sas_port,
6211 &ioc->sas_hba.sas_port_list, port_list) {
6212 if (mpt2sas_port->remote_identify.device_type ==
6213 SAS_END_DEVICE) {
6214 sas_device =
6215 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
6216 mpt2sas_port->remote_identify.sas_address);
6217 if (sas_device) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306218 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06006219 goto retry_again;
6220 }
6221 } else {
6222 expander_sibling =
6223 mpt2sas_scsih_expander_find_by_sas_address(ioc,
6224 mpt2sas_port->remote_identify.sas_address);
6225 if (expander_sibling) {
6226 _scsih_expander_remove(ioc,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306227 expander_sibling->sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06006228 goto retry_again;
6229 }
6230 }
6231 }
6232
6233 /* free phys attached to the sas_host */
6234 if (ioc->sas_hba.num_phys) {
6235 kfree(ioc->sas_hba.phy);
6236 ioc->sas_hba.phy = NULL;
6237 ioc->sas_hba.num_phys = 0;
6238 }
6239
6240 sas_remove_host(shost);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306241 _scsih_shutdown(pdev);
Eric Moore635374e2009-03-09 01:21:12 -06006242 list_del(&ioc->list);
6243 scsi_remove_host(shost);
6244 scsi_host_put(shost);
6245}
6246
6247/**
6248 * _scsih_probe_boot_devices - reports 1st device
6249 * @ioc: per adapter object
6250 *
6251 * If specified in bios page 2, this routine reports the 1st
6252 * device scsi-ml or sas transport for persistent boot device
6253 * purposes. Please refer to function _scsih_determine_boot_device()
6254 */
6255static void
6256_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
6257{
6258 u8 is_raid;
6259 void *device;
6260 struct _sas_device *sas_device;
6261 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306262 u16 handle;
6263 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06006264 u64 sas_address;
6265 unsigned long flags;
6266 int rc;
6267
6268 device = NULL;
6269 if (ioc->req_boot_device.device) {
6270 device = ioc->req_boot_device.device;
6271 is_raid = ioc->req_boot_device.is_raid;
6272 } else if (ioc->req_alt_boot_device.device) {
6273 device = ioc->req_alt_boot_device.device;
6274 is_raid = ioc->req_alt_boot_device.is_raid;
6275 } else if (ioc->current_boot_device.device) {
6276 device = ioc->current_boot_device.device;
6277 is_raid = ioc->current_boot_device.is_raid;
6278 }
6279
6280 if (!device)
6281 return;
6282
6283 if (is_raid) {
6284 raid_device = device;
6285 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6286 raid_device->id, 0);
6287 if (rc)
6288 _scsih_raid_device_remove(ioc, raid_device);
6289 } else {
6290 sas_device = device;
6291 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306292 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06006293 sas_address = sas_device->sas_address;
6294 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6295 list_move_tail(&sas_device->list, &ioc->sas_device_list);
6296 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6297 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306298 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06006299 _scsih_sas_device_remove(ioc, sas_device);
6300 } else if (!sas_device->starget) {
6301 mpt2sas_transport_port_remove(ioc, sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306302 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006303 _scsih_sas_device_remove(ioc, sas_device);
6304 }
6305 }
6306}
6307
6308/**
6309 * _scsih_probe_raid - reporting raid volumes to scsi-ml
6310 * @ioc: per adapter object
6311 *
6312 * Called during initial loading of the driver.
6313 */
6314static void
6315_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
6316{
6317 struct _raid_device *raid_device, *raid_next;
6318 int rc;
6319
6320 list_for_each_entry_safe(raid_device, raid_next,
6321 &ioc->raid_device_list, list) {
6322 if (raid_device->starget)
6323 continue;
6324 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6325 raid_device->id, 0);
6326 if (rc)
6327 _scsih_raid_device_remove(ioc, raid_device);
6328 }
6329}
6330
6331/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306332 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06006333 * @ioc: per adapter object
6334 *
6335 * Called during initial loading of the driver.
6336 */
6337static void
6338_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
6339{
6340 struct _sas_device *sas_device, *next;
6341 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06006342
6343 /* SAS Device List */
6344 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
6345 list) {
6346 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6347 list_move_tail(&sas_device->list, &ioc->sas_device_list);
6348 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6349
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306350 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
6351 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06006352 _scsih_sas_device_remove(ioc, sas_device);
6353 } else if (!sas_device->starget) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306354 mpt2sas_transport_port_remove(ioc,
6355 sas_device->sas_address,
6356 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006357 _scsih_sas_device_remove(ioc, sas_device);
6358 }
6359 }
6360}
6361
6362/**
6363 * _scsih_probe_devices - probing for devices
6364 * @ioc: per adapter object
6365 *
6366 * Called during initial loading of the driver.
6367 */
6368static void
6369_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
6370{
6371 u16 volume_mapping_flags =
6372 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
6373 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
6374
6375 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
6376 return; /* return when IOC doesn't support initiator mode */
6377
6378 _scsih_probe_boot_devices(ioc);
6379
6380 if (ioc->ir_firmware) {
6381 if ((volume_mapping_flags &
6382 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
6383 _scsih_probe_sas(ioc);
6384 _scsih_probe_raid(ioc);
6385 } else {
6386 _scsih_probe_raid(ioc);
6387 _scsih_probe_sas(ioc);
6388 }
6389 } else
6390 _scsih_probe_sas(ioc);
6391}
6392
6393/**
Eric Moored5d135b2009-05-18 13:02:08 -06006394 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06006395 * @pdev: PCI device struct
6396 * @id: pci device id
6397 *
6398 * Returns 0 success, anything else error.
6399 */
6400static int
Eric Moored5d135b2009-05-18 13:02:08 -06006401_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06006402{
6403 struct MPT2SAS_ADAPTER *ioc;
6404 struct Scsi_Host *shost;
6405
6406 shost = scsi_host_alloc(&scsih_driver_template,
6407 sizeof(struct MPT2SAS_ADAPTER));
6408 if (!shost)
6409 return -ENODEV;
6410
6411 /* init local params */
6412 ioc = shost_priv(shost);
6413 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
6414 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06006415 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06006416 ioc->shost = shost;
6417 ioc->id = mpt_ids++;
6418 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
6419 ioc->pdev = pdev;
6420 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
6421 ioc->tm_cb_idx = tm_cb_idx;
6422 ioc->ctl_cb_idx = ctl_cb_idx;
6423 ioc->base_cb_idx = base_cb_idx;
6424 ioc->transport_cb_idx = transport_cb_idx;
Kashyap, Desai744090d2009-10-05 15:56:56 +05306425 ioc->scsih_cb_idx = scsih_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006426 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306427 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
6428 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006429 ioc->logging_level = logging_level;
6430 /* misc semaphores and spin locks */
6431 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
6432 spin_lock_init(&ioc->scsi_lookup_lock);
6433 spin_lock_init(&ioc->sas_device_lock);
6434 spin_lock_init(&ioc->sas_node_lock);
6435 spin_lock_init(&ioc->fw_event_lock);
6436 spin_lock_init(&ioc->raid_device_lock);
6437
6438 INIT_LIST_HEAD(&ioc->sas_device_list);
6439 INIT_LIST_HEAD(&ioc->sas_device_init_list);
6440 INIT_LIST_HEAD(&ioc->sas_expander_list);
6441 INIT_LIST_HEAD(&ioc->fw_event_list);
6442 INIT_LIST_HEAD(&ioc->raid_device_list);
6443 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306444 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Eric Moore635374e2009-03-09 01:21:12 -06006445
6446 /* init shost parameters */
6447 shost->max_cmd_len = 16;
6448 shost->max_lun = max_lun;
6449 shost->transportt = mpt2sas_transport_template;
6450 shost->unique_id = ioc->id;
6451
6452 if ((scsi_add_host(shost, &pdev->dev))) {
6453 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6454 ioc->name, __FILE__, __LINE__, __func__);
6455 list_del(&ioc->list);
6456 goto out_add_shost_fail;
6457 }
6458
Eric Moore3c621b32009-05-18 12:59:41 -06006459 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
6460 | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306461 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06006462
Eric Moore635374e2009-03-09 01:21:12 -06006463 /* event thread */
6464 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
6465 "fw_event%d", ioc->id);
6466 ioc->firmware_event_thread = create_singlethread_workqueue(
6467 ioc->firmware_event_name);
6468 if (!ioc->firmware_event_thread) {
6469 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6470 ioc->name, __FILE__, __LINE__, __func__);
6471 goto out_thread_fail;
6472 }
6473
6474 ioc->wait_for_port_enable_to_complete = 1;
6475 if ((mpt2sas_base_attach(ioc))) {
6476 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6477 ioc->name, __FILE__, __LINE__, __func__);
6478 goto out_attach_fail;
6479 }
6480
6481 ioc->wait_for_port_enable_to_complete = 0;
6482 _scsih_probe_devices(ioc);
6483 return 0;
6484
6485 out_attach_fail:
6486 destroy_workqueue(ioc->firmware_event_thread);
6487 out_thread_fail:
6488 list_del(&ioc->list);
6489 scsi_remove_host(shost);
6490 out_add_shost_fail:
6491 return -ENODEV;
6492}
6493
6494#ifdef CONFIG_PM
6495/**
Eric Moored5d135b2009-05-18 13:02:08 -06006496 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006497 * @pdev: PCI device struct
6498 * @state: PM state change to (usually PCI_D3)
6499 *
6500 * Returns 0 success, anything else error.
6501 */
6502static int
Eric Moored5d135b2009-05-18 13:02:08 -06006503_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06006504{
6505 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6506 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6507 u32 device_state;
6508
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306509 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006510 flush_scheduled_work();
6511 scsi_block_requests(shost);
6512 device_state = pci_choose_state(pdev, state);
6513 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
6514 "operating state [D%d]\n", ioc->name, pdev,
6515 pci_name(pdev), device_state);
6516
6517 mpt2sas_base_free_resources(ioc);
6518 pci_save_state(pdev);
6519 pci_disable_device(pdev);
6520 pci_set_power_state(pdev, device_state);
6521 return 0;
6522}
6523
6524/**
Eric Moored5d135b2009-05-18 13:02:08 -06006525 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006526 * @pdev: PCI device struct
6527 *
6528 * Returns 0 success, anything else error.
6529 */
6530static int
Eric Moored5d135b2009-05-18 13:02:08 -06006531_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006532{
6533 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6534 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6535 u32 device_state = pdev->current_state;
6536 int r;
6537
6538 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
6539 "operating state [D%d]\n", ioc->name, pdev,
6540 pci_name(pdev), device_state);
6541
6542 pci_set_power_state(pdev, PCI_D0);
6543 pci_enable_wake(pdev, PCI_D0, 0);
6544 pci_restore_state(pdev);
6545 ioc->pdev = pdev;
6546 r = mpt2sas_base_map_resources(ioc);
6547 if (r)
6548 return r;
6549
6550 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
6551 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306552 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006553 return 0;
6554}
6555#endif /* CONFIG_PM */
6556
6557
6558static struct pci_driver scsih_driver = {
6559 .name = MPT2SAS_DRIVER_NAME,
6560 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06006561 .probe = _scsih_probe,
6562 .remove = __devexit_p(_scsih_remove),
Kashyap, Desai744090d2009-10-05 15:56:56 +05306563 .shutdown = _scsih_shutdown,
Eric Moore635374e2009-03-09 01:21:12 -06006564#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06006565 .suspend = _scsih_suspend,
6566 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06006567#endif
6568};
6569
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306570/* raid transport support */
6571static struct raid_function_template mpt2sas_raid_functions = {
6572 .cookie = &scsih_driver_template,
6573 .is_raid = _scsih_is_raid,
6574 .get_resync = _scsih_get_resync,
6575 .get_state = _scsih_get_state,
6576};
Eric Moore635374e2009-03-09 01:21:12 -06006577
6578/**
Eric Moored5d135b2009-05-18 13:02:08 -06006579 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06006580 *
6581 * Returns 0 success, anything else error.
6582 */
6583static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06006584_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06006585{
6586 int error;
6587
6588 mpt_ids = 0;
6589 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
6590 MPT2SAS_DRIVER_VERSION);
6591
6592 mpt2sas_transport_template =
6593 sas_attach_transport(&mpt2sas_transport_functions);
6594 if (!mpt2sas_transport_template)
6595 return -ENODEV;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306596 /* raid transport support */
6597 mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
6598 if (!mpt2sas_raid_template) {
6599 sas_release_transport(mpt2sas_transport_template);
6600 return -ENODEV;
6601 }
Eric Moore635374e2009-03-09 01:21:12 -06006602
6603 mpt2sas_base_initialize_callback_handler();
6604
6605 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06006606 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06006607
6608 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06006609 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06006610
6611 /* base internal commands callback handler */
6612 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
6613
6614 /* transport internal commands callback handler */
6615 transport_cb_idx = mpt2sas_base_register_callback_handler(
6616 mpt2sas_transport_done);
6617
Kashyap, Desai744090d2009-10-05 15:56:56 +05306618 /* scsih internal commands callback handler */
6619 scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
6620
Eric Moore635374e2009-03-09 01:21:12 -06006621 /* configuration page API internal commands callback handler */
6622 config_cb_idx = mpt2sas_base_register_callback_handler(
6623 mpt2sas_config_done);
6624
6625 /* ctl module callback handler */
6626 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
6627
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306628 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
6629 _scsih_tm_tr_complete);
6630 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
6631 _scsih_sas_control_complete);
6632
Eric Moore635374e2009-03-09 01:21:12 -06006633 mpt2sas_ctl_init();
6634
6635 error = pci_register_driver(&scsih_driver);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306636 if (error) {
6637 /* raid transport support */
6638 raid_class_release(mpt2sas_raid_template);
Eric Moore635374e2009-03-09 01:21:12 -06006639 sas_release_transport(mpt2sas_transport_template);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306640 }
Eric Moore635374e2009-03-09 01:21:12 -06006641
6642 return error;
6643}
6644
6645/**
Eric Moored5d135b2009-05-18 13:02:08 -06006646 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06006647 *
6648 * Returns 0 success, anything else error.
6649 */
6650static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06006651_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06006652{
6653 printk(KERN_INFO "mpt2sas version %s unloading\n",
6654 MPT2SAS_DRIVER_VERSION);
6655
6656 pci_unregister_driver(&scsih_driver);
6657
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306658 mpt2sas_ctl_exit();
6659
Eric Moore635374e2009-03-09 01:21:12 -06006660 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
6661 mpt2sas_base_release_callback_handler(tm_cb_idx);
6662 mpt2sas_base_release_callback_handler(base_cb_idx);
6663 mpt2sas_base_release_callback_handler(transport_cb_idx);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306664 mpt2sas_base_release_callback_handler(scsih_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06006665 mpt2sas_base_release_callback_handler(config_cb_idx);
6666 mpt2sas_base_release_callback_handler(ctl_cb_idx);
6667
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306668 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
6669 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
6670
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306671 /* raid transport support */
6672 raid_class_release(mpt2sas_raid_template);
6673 sas_release_transport(mpt2sas_transport_template);
6674
Eric Moore635374e2009-03-09 01:21:12 -06006675}
6676
Eric Moored5d135b2009-05-18 13:02:08 -06006677module_init(_scsih_init);
6678module_exit(_scsih_exit);