blob: 87c686525f07879d955fed8fc979cd68dea7f3b9 [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, Desai31b7f2e2010-03-17 16:28:04 +05305 * Copyright (C) 2007-2010 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, Desaief7c80c2010-04-05 14:20:07 +053055#include <linux/aer.h>
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +053056#include <linux/raid_class.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090057#include <linux/slab.h>
Eric Moore635374e2009-03-09 01:21:12 -060058
59#include "mpt2sas_base.h"
60
61MODULE_AUTHOR(MPT2SAS_AUTHOR);
62MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
63MODULE_LICENSE("GPL");
64MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
65
66#define RAID_CHANNEL 1
67
68/* forward proto's */
69static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
70 struct _sas_node *sas_expander);
71static void _firmware_event_work(struct work_struct *work);
72
73/* global parameters */
Eric Mooreba33fad2009-03-15 21:37:18 -060074LIST_HEAD(mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -060075
76/* local parameters */
Eric Moore635374e2009-03-09 01:21:12 -060077static u8 scsi_io_cb_idx = -1;
78static u8 tm_cb_idx = -1;
79static u8 ctl_cb_idx = -1;
80static u8 base_cb_idx = -1;
81static u8 transport_cb_idx = -1;
Kashyap, Desai744090d2009-10-05 15:56:56 +053082static u8 scsih_cb_idx = -1;
Eric Moore635374e2009-03-09 01:21:12 -060083static u8 config_cb_idx = -1;
84static int mpt_ids;
85
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053086static u8 tm_tr_cb_idx = -1 ;
87static u8 tm_sas_control_cb_idx = -1;
88
Eric Moore635374e2009-03-09 01:21:12 -060089/* command line options */
Eric Mooreba33fad2009-03-15 21:37:18 -060090static u32 logging_level;
Eric Moore635374e2009-03-09 01:21:12 -060091MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
92 "(default=0)");
93
94/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
95#define MPT2SAS_MAX_LUN (16895)
96static int max_lun = MPT2SAS_MAX_LUN;
97module_param(max_lun, int, 0);
98MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
99
100/**
101 * struct sense_info - common structure for obtaining sense keys
102 * @skey: sense key
103 * @asc: additional sense code
104 * @ascq: additional sense code qualifier
105 */
106struct sense_info {
107 u8 skey;
108 u8 asc;
109 u8 ascq;
110};
111
112
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530113#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF)
114
Eric Moore635374e2009-03-09 01:21:12 -0600115/**
116 * struct fw_event_work - firmware event struct
117 * @list: link list framework
118 * @work: work object (ioc->fault_reset_work_q)
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530119 * @cancel_pending_work: flag set during reset handling
Eric Moore635374e2009-03-09 01:21:12 -0600120 * @ioc: per adapter object
121 * @VF_ID: virtual function id
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530122 * @VP_ID: virtual port id
Eric Moore635374e2009-03-09 01:21:12 -0600123 * @ignore: flag meaning this event has been marked to ignore
124 * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
125 * @event_data: reply event data payload follows
126 *
127 * This object stored on ioc->fw_event_list.
128 */
129struct fw_event_work {
130 struct list_head list;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530131 u8 cancel_pending_work;
132 struct delayed_work delayed_work;
Eric Moore635374e2009-03-09 01:21:12 -0600133 struct MPT2SAS_ADAPTER *ioc;
134 u8 VF_ID;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530135 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600136 u8 ignore;
137 u16 event;
138 void *event_data;
139};
140
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +0530141/* raid transport support */
142static struct raid_template *mpt2sas_raid_template;
143
Eric Moore635374e2009-03-09 01:21:12 -0600144/**
145 * struct _scsi_io_transfer - scsi io transfer
146 * @handle: sas device handle (assigned by firmware)
147 * @is_raid: flag set for hidden raid components
148 * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
149 * @data_length: data transfer length
150 * @data_dma: dma pointer to data
151 * @sense: sense data
152 * @lun: lun number
153 * @cdb_length: cdb length
154 * @cdb: cdb contents
Eric Moore635374e2009-03-09 01:21:12 -0600155 * @timeout: timeout for this command
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530156 * @VF_ID: virtual function id
157 * @VP_ID: virtual port id
158 * @valid_reply: flag set for reply message
Eric Moore635374e2009-03-09 01:21:12 -0600159 * @sense_length: sense length
160 * @ioc_status: ioc status
161 * @scsi_state: scsi state
162 * @scsi_status: scsi staus
163 * @log_info: log information
164 * @transfer_length: data length transfer when there is a reply message
165 *
166 * Used for sending internal scsi commands to devices within this module.
167 * Refer to _scsi_send_scsi_io().
168 */
169struct _scsi_io_transfer {
170 u16 handle;
171 u8 is_raid;
172 enum dma_data_direction dir;
173 u32 data_length;
174 dma_addr_t data_dma;
175 u8 sense[SCSI_SENSE_BUFFERSIZE];
176 u32 lun;
177 u8 cdb_length;
178 u8 cdb[32];
179 u8 timeout;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530180 u8 VF_ID;
181 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600182 u8 valid_reply;
183 /* the following bits are only valid when 'valid_reply = 1' */
184 u32 sense_length;
185 u16 ioc_status;
186 u8 scsi_state;
187 u8 scsi_status;
188 u32 log_info;
189 u32 transfer_length;
190};
191
192/*
193 * The pci device ids are defined in mpi/mpi2_cnfg.h.
194 */
195static struct pci_device_id scsih_pci_table[] = {
196 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
197 PCI_ANY_ID, PCI_ANY_ID },
198 /* Falcon ~ 2008*/
199 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
200 PCI_ANY_ID, PCI_ANY_ID },
201 /* Liberator ~ 2108 */
202 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
203 PCI_ANY_ID, PCI_ANY_ID },
204 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
205 PCI_ANY_ID, PCI_ANY_ID },
206 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
207 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530208 /* Meteor ~ 2116 */
Eric Moore635374e2009-03-09 01:21:12 -0600209 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
210 PCI_ANY_ID, PCI_ANY_ID },
211 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
212 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530213 /* Thunderbolt ~ 2208 */
214 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
215 PCI_ANY_ID, PCI_ANY_ID },
216 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
217 PCI_ANY_ID, PCI_ANY_ID },
218 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
219 PCI_ANY_ID, PCI_ANY_ID },
220 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
221 PCI_ANY_ID, PCI_ANY_ID },
222 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
223 PCI_ANY_ID, PCI_ANY_ID },
224 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
225 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desai203d65b2010-06-17 13:37:59 +0530226 /* Mustang ~ 2308 */
227 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
Kashyap, Desaidb271362009-09-23 17:24:27 +0530228 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desai203d65b2010-06-17 13:37:59 +0530229 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
230 PCI_ANY_ID, PCI_ANY_ID },
231 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
Kashyap, Desaidb271362009-09-23 17:24:27 +0530232 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore635374e2009-03-09 01:21:12 -0600233 {0} /* Terminating entry */
234};
235MODULE_DEVICE_TABLE(pci, scsih_pci_table);
236
237/**
Eric Moored5d135b2009-05-18 13:02:08 -0600238 * _scsih_set_debug_level - global setting of ioc->logging_level.
Eric Moore635374e2009-03-09 01:21:12 -0600239 *
240 * Note: The logging levels are defined in mpt2sas_debug.h.
241 */
242static int
Eric Moored5d135b2009-05-18 13:02:08 -0600243_scsih_set_debug_level(const char *val, struct kernel_param *kp)
Eric Moore635374e2009-03-09 01:21:12 -0600244{
245 int ret = param_set_int(val, kp);
246 struct MPT2SAS_ADAPTER *ioc;
247
248 if (ret)
249 return ret;
250
251 printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
Eric Mooreba33fad2009-03-15 21:37:18 -0600252 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
Eric Moore635374e2009-03-09 01:21:12 -0600253 ioc->logging_level = logging_level;
254 return 0;
255}
Eric Moored5d135b2009-05-18 13:02:08 -0600256module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
Eric Moore635374e2009-03-09 01:21:12 -0600257 &logging_level, 0644);
258
259/**
260 * _scsih_srch_boot_sas_address - search based on sas_address
261 * @sas_address: sas address
262 * @boot_device: boot device object from bios page 2
263 *
264 * Returns 1 when there's a match, 0 means no match.
265 */
266static inline int
267_scsih_srch_boot_sas_address(u64 sas_address,
268 Mpi2BootDeviceSasWwid_t *boot_device)
269{
270 return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
271}
272
273/**
274 * _scsih_srch_boot_device_name - search based on device name
275 * @device_name: device name specified in INDENTIFY fram
276 * @boot_device: boot device object from bios page 2
277 *
278 * Returns 1 when there's a match, 0 means no match.
279 */
280static inline int
281_scsih_srch_boot_device_name(u64 device_name,
282 Mpi2BootDeviceDeviceName_t *boot_device)
283{
284 return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
285}
286
287/**
288 * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
289 * @enclosure_logical_id: enclosure logical id
290 * @slot_number: slot number
291 * @boot_device: boot device object from bios page 2
292 *
293 * Returns 1 when there's a match, 0 means no match.
294 */
295static inline int
296_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
297 Mpi2BootDeviceEnclosureSlot_t *boot_device)
298{
299 return (enclosure_logical_id == le64_to_cpu(boot_device->
300 EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
301 SlotNumber)) ? 1 : 0;
302}
303
304/**
305 * _scsih_is_boot_device - search for matching boot device.
306 * @sas_address: sas address
307 * @device_name: device name specified in INDENTIFY fram
308 * @enclosure_logical_id: enclosure logical id
309 * @slot_number: slot number
310 * @form: specifies boot device form
311 * @boot_device: boot device object from bios page 2
312 *
313 * Returns 1 when there's a match, 0 means no match.
314 */
315static int
316_scsih_is_boot_device(u64 sas_address, u64 device_name,
317 u64 enclosure_logical_id, u16 slot, u8 form,
318 Mpi2BiosPage2BootDevice_t *boot_device)
319{
320 int rc = 0;
321
322 switch (form) {
323 case MPI2_BIOSPAGE2_FORM_SAS_WWID:
324 if (!sas_address)
325 break;
326 rc = _scsih_srch_boot_sas_address(
327 sas_address, &boot_device->SasWwid);
328 break;
329 case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
330 if (!enclosure_logical_id)
331 break;
332 rc = _scsih_srch_boot_encl_slot(
333 enclosure_logical_id,
334 slot, &boot_device->EnclosureSlot);
335 break;
336 case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
337 if (!device_name)
338 break;
339 rc = _scsih_srch_boot_device_name(
340 device_name, &boot_device->DeviceName);
341 break;
342 case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
343 break;
344 }
345
346 return rc;
347}
348
349/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530350 * _scsih_get_sas_address - set the sas_address for given device handle
351 * @handle: device handle
352 * @sas_address: sas address
353 *
354 * Returns 0 success, non-zero when failure
355 */
356static int
357_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
358 u64 *sas_address)
359{
360 Mpi2SasDevicePage0_t sas_device_pg0;
361 Mpi2ConfigReply_t mpi_reply;
362 u32 ioc_status;
363
364 if (handle <= ioc->sas_hba.num_phys) {
365 *sas_address = ioc->sas_hba.sas_address;
366 return 0;
367 } else
368 *sas_address = 0;
369
370 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
371 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
372 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
373 ioc->name, __FILE__, __LINE__, __func__);
374 return -ENXIO;
375 }
376
377 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
378 MPI2_IOCSTATUS_MASK;
379 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
380 printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
381 "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
382 __FILE__, __LINE__, __func__);
383 return -EIO;
384 }
385
386 *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
387 return 0;
388}
389
390/**
Eric Moore635374e2009-03-09 01:21:12 -0600391 * _scsih_determine_boot_device - determine boot device.
392 * @ioc: per adapter object
393 * @device: either sas_device or raid_device object
394 * @is_raid: [flag] 1 = raid object, 0 = sas object
395 *
396 * Determines whether this device should be first reported device to
397 * to scsi-ml or sas transport, this purpose is for persistant boot device.
398 * There are primary, alternate, and current entries in bios page 2. The order
399 * priority is primary, alternate, then current. This routine saves
400 * the corresponding device object and is_raid flag in the ioc object.
401 * The saved data to be used later in _scsih_probe_boot_devices().
402 */
403static void
404_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
405 void *device, u8 is_raid)
406{
407 struct _sas_device *sas_device;
408 struct _raid_device *raid_device;
409 u64 sas_address;
410 u64 device_name;
411 u64 enclosure_logical_id;
412 u16 slot;
413
414 /* only process this function when driver loads */
415 if (!ioc->wait_for_port_enable_to_complete)
416 return;
417
418 if (!is_raid) {
419 sas_device = device;
420 sas_address = sas_device->sas_address;
421 device_name = sas_device->device_name;
422 enclosure_logical_id = sas_device->enclosure_logical_id;
423 slot = sas_device->slot;
424 } else {
425 raid_device = device;
426 sas_address = raid_device->wwid;
427 device_name = 0;
428 enclosure_logical_id = 0;
429 slot = 0;
430 }
431
432 if (!ioc->req_boot_device.device) {
433 if (_scsih_is_boot_device(sas_address, device_name,
434 enclosure_logical_id, slot,
435 (ioc->bios_pg2.ReqBootDeviceForm &
436 MPI2_BIOSPAGE2_FORM_MASK),
437 &ioc->bios_pg2.RequestedBootDevice)) {
438 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
439 "%s: req_boot_device(0x%016llx)\n",
440 ioc->name, __func__,
441 (unsigned long long)sas_address));
442 ioc->req_boot_device.device = device;
443 ioc->req_boot_device.is_raid = is_raid;
444 }
445 }
446
447 if (!ioc->req_alt_boot_device.device) {
448 if (_scsih_is_boot_device(sas_address, device_name,
449 enclosure_logical_id, slot,
450 (ioc->bios_pg2.ReqAltBootDeviceForm &
451 MPI2_BIOSPAGE2_FORM_MASK),
452 &ioc->bios_pg2.RequestedAltBootDevice)) {
453 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
454 "%s: req_alt_boot_device(0x%016llx)\n",
455 ioc->name, __func__,
456 (unsigned long long)sas_address));
457 ioc->req_alt_boot_device.device = device;
458 ioc->req_alt_boot_device.is_raid = is_raid;
459 }
460 }
461
462 if (!ioc->current_boot_device.device) {
463 if (_scsih_is_boot_device(sas_address, device_name,
464 enclosure_logical_id, slot,
465 (ioc->bios_pg2.CurrentBootDeviceForm &
466 MPI2_BIOSPAGE2_FORM_MASK),
467 &ioc->bios_pg2.CurrentBootDevice)) {
468 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
469 "%s: current_boot_device(0x%016llx)\n",
470 ioc->name, __func__,
471 (unsigned long long)sas_address));
472 ioc->current_boot_device.device = device;
473 ioc->current_boot_device.is_raid = is_raid;
474 }
475 }
476}
477
478/**
479 * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
480 * @ioc: per adapter object
481 * @sas_address: sas address
482 * Context: Calling function should acquire ioc->sas_device_lock
483 *
484 * This searches for sas_device based on sas_address, then return sas_device
485 * object.
486 */
487struct _sas_device *
488mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
489 u64 sas_address)
490{
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530491 struct _sas_device *sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600492
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530493 list_for_each_entry(sas_device, &ioc->sas_device_list, list)
494 if (sas_device->sas_address == sas_address)
495 return sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600496
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530497 list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
498 if (sas_device->sas_address == sas_address)
499 return sas_device;
500
501 return NULL;
Eric Moore635374e2009-03-09 01:21:12 -0600502}
503
504/**
505 * _scsih_sas_device_find_by_handle - sas device search
506 * @ioc: per adapter object
507 * @handle: sas device handle (assigned by firmware)
508 * Context: Calling function should acquire ioc->sas_device_lock
509 *
510 * This searches for sas_device based on sas_address, then return sas_device
511 * object.
512 */
513static struct _sas_device *
514_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
515{
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530516 struct _sas_device *sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600517
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530518 list_for_each_entry(sas_device, &ioc->sas_device_list, list)
519 if (sas_device->handle == handle)
520 return sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600521
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530522 list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
523 if (sas_device->handle == handle)
524 return sas_device;
525
526 return NULL;
Eric Moore635374e2009-03-09 01:21:12 -0600527}
528
529/**
530 * _scsih_sas_device_remove - remove sas_device from list.
531 * @ioc: per adapter object
532 * @sas_device: the sas_device object
533 * Context: This function will acquire ioc->sas_device_lock.
534 *
535 * Removing object and freeing associated memory from the ioc->sas_device_list.
536 */
537static void
538_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
539 struct _sas_device *sas_device)
540{
541 unsigned long flags;
542
Kashyap, Desai980ead32010-04-08 17:55:22 +0530543 if (!sas_device)
544 return;
545
Eric Moore635374e2009-03-09 01:21:12 -0600546 spin_lock_irqsave(&ioc->sas_device_lock, flags);
Kashyap, Desai980ead32010-04-08 17:55:22 +0530547 if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
548 sas_device->sas_address)) {
549 list_del(&sas_device->list);
550 kfree(sas_device);
551 }
Eric Moore635374e2009-03-09 01:21:12 -0600552 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
553}
554
555/**
556 * _scsih_sas_device_add - insert sas_device to the list.
557 * @ioc: per adapter object
558 * @sas_device: the sas_device object
559 * Context: This function will acquire ioc->sas_device_lock.
560 *
561 * Adding new object to the ioc->sas_device_list.
562 */
563static void
564_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
565 struct _sas_device *sas_device)
566{
567 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -0600568
569 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
570 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
571 sas_device->handle, (unsigned long long)sas_device->sas_address));
572
573 spin_lock_irqsave(&ioc->sas_device_lock, flags);
574 list_add_tail(&sas_device->list, &ioc->sas_device_list);
575 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
576
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530577 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
578 sas_device->sas_address_parent))
Eric Moore635374e2009-03-09 01:21:12 -0600579 _scsih_sas_device_remove(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -0600580}
581
582/**
583 * _scsih_sas_device_init_add - insert sas_device to the list.
584 * @ioc: per adapter object
585 * @sas_device: the sas_device object
586 * Context: This function will acquire ioc->sas_device_lock.
587 *
588 * Adding new object at driver load time to the ioc->sas_device_init_list.
589 */
590static void
591_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
592 struct _sas_device *sas_device)
593{
594 unsigned long flags;
595
596 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
597 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
598 sas_device->handle, (unsigned long long)sas_device->sas_address));
599
600 spin_lock_irqsave(&ioc->sas_device_lock, flags);
601 list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
602 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
603 _scsih_determine_boot_device(ioc, sas_device, 0);
604}
605
606/**
Eric Moore635374e2009-03-09 01:21:12 -0600607 * _scsih_raid_device_find_by_id - raid device search
608 * @ioc: per adapter object
609 * @id: sas device target id
610 * @channel: sas device channel
611 * Context: Calling function should acquire ioc->raid_device_lock
612 *
613 * This searches for raid_device based on target id, then return raid_device
614 * object.
615 */
616static struct _raid_device *
617_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
618{
619 struct _raid_device *raid_device, *r;
620
621 r = NULL;
622 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
623 if (raid_device->id == id && raid_device->channel == channel) {
624 r = raid_device;
625 goto out;
626 }
627 }
628
629 out:
630 return r;
631}
632
633/**
634 * _scsih_raid_device_find_by_handle - raid device search
635 * @ioc: per adapter object
636 * @handle: sas device handle (assigned by firmware)
637 * Context: Calling function should acquire ioc->raid_device_lock
638 *
639 * This searches for raid_device based on handle, then return raid_device
640 * object.
641 */
642static struct _raid_device *
643_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
644{
645 struct _raid_device *raid_device, *r;
646
647 r = NULL;
648 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
649 if (raid_device->handle != handle)
650 continue;
651 r = raid_device;
652 goto out;
653 }
654
655 out:
656 return r;
657}
658
659/**
660 * _scsih_raid_device_find_by_wwid - raid device search
661 * @ioc: per adapter object
662 * @handle: sas device handle (assigned by firmware)
663 * Context: Calling function should acquire ioc->raid_device_lock
664 *
665 * This searches for raid_device based on wwid, then return raid_device
666 * object.
667 */
668static struct _raid_device *
669_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
670{
671 struct _raid_device *raid_device, *r;
672
673 r = NULL;
674 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
675 if (raid_device->wwid != wwid)
676 continue;
677 r = raid_device;
678 goto out;
679 }
680
681 out:
682 return r;
683}
684
685/**
686 * _scsih_raid_device_add - add raid_device object
687 * @ioc: per adapter object
688 * @raid_device: raid_device object
689 *
690 * This is added to the raid_device_list link list.
691 */
692static void
693_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
694 struct _raid_device *raid_device)
695{
696 unsigned long flags;
697
698 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
699 "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
700 raid_device->handle, (unsigned long long)raid_device->wwid));
701
702 spin_lock_irqsave(&ioc->raid_device_lock, flags);
703 list_add_tail(&raid_device->list, &ioc->raid_device_list);
704 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
705}
706
707/**
708 * _scsih_raid_device_remove - delete raid_device object
709 * @ioc: per adapter object
710 * @raid_device: raid_device object
711 *
712 * This is removed from the raid_device_list link list.
713 */
714static void
715_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
716 struct _raid_device *raid_device)
717{
718 unsigned long flags;
719
720 spin_lock_irqsave(&ioc->raid_device_lock, flags);
721 list_del(&raid_device->list);
722 memset(raid_device, 0, sizeof(struct _raid_device));
723 kfree(raid_device);
724 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
725}
726
727/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530728 * mpt2sas_scsih_expander_find_by_handle - expander device search
729 * @ioc: per adapter object
730 * @handle: expander handle (assigned by firmware)
731 * Context: Calling function should acquire ioc->sas_device_lock
732 *
733 * This searches for expander device based on handle, then returns the
734 * sas_node object.
735 */
736struct _sas_node *
737mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
738{
739 struct _sas_node *sas_expander, *r;
740
741 r = NULL;
742 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
743 if (sas_expander->handle != handle)
744 continue;
745 r = sas_expander;
746 goto out;
747 }
748 out:
749 return r;
750}
751
752/**
Eric Moore635374e2009-03-09 01:21:12 -0600753 * mpt2sas_scsih_expander_find_by_sas_address - expander device search
754 * @ioc: per adapter object
755 * @sas_address: sas address
756 * Context: Calling function should acquire ioc->sas_node_lock.
757 *
758 * This searches for expander device based on sas_address, then returns the
759 * sas_node object.
760 */
761struct _sas_node *
762mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
763 u64 sas_address)
764{
765 struct _sas_node *sas_expander, *r;
766
767 r = NULL;
768 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
769 if (sas_expander->sas_address != sas_address)
770 continue;
771 r = sas_expander;
772 goto out;
773 }
774 out:
775 return r;
776}
777
778/**
779 * _scsih_expander_node_add - insert expander device to the list.
780 * @ioc: per adapter object
781 * @sas_expander: the sas_device object
782 * Context: This function will acquire ioc->sas_node_lock.
783 *
784 * Adding new object to the ioc->sas_expander_list.
785 *
786 * Return nothing.
787 */
788static void
789_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
790 struct _sas_node *sas_expander)
791{
792 unsigned long flags;
793
794 spin_lock_irqsave(&ioc->sas_node_lock, flags);
795 list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
796 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
797}
798
799/**
800 * _scsih_is_end_device - determines if device is an end device
801 * @device_info: bitfield providing information about the device.
802 * Context: none
803 *
804 * Returns 1 if end device.
805 */
806static int
807_scsih_is_end_device(u32 device_info)
808{
809 if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
810 ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
811 (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
812 (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
813 return 1;
814 else
815 return 0;
816}
817
818/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530819 * mptscsih_get_scsi_lookup - returns scmd entry
Eric Moore635374e2009-03-09 01:21:12 -0600820 * @ioc: per adapter object
821 * @smid: system request message index
Eric Moore635374e2009-03-09 01:21:12 -0600822 *
823 * Returns the smid stored scmd pointer.
824 */
825static struct scsi_cmnd *
826_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
827{
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530828 return ioc->scsi_lookup[smid - 1].scmd;
Eric Moore635374e2009-03-09 01:21:12 -0600829}
830
831/**
832 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
833 * @ioc: per adapter object
834 * @smid: system request message index
835 * @scmd: pointer to scsi command object
836 * Context: This function will acquire ioc->scsi_lookup_lock.
837 *
838 * This will search for a scmd pointer in the scsi_lookup array,
839 * returning the revelent smid. A returned value of zero means invalid.
840 */
841static u16
842_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
843 *scmd)
844{
845 u16 smid;
846 unsigned long flags;
847 int i;
848
849 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
850 smid = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530851 for (i = 0; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600852 if (ioc->scsi_lookup[i].scmd == scmd) {
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530853 smid = ioc->scsi_lookup[i].smid;
Eric Moore635374e2009-03-09 01:21:12 -0600854 goto out;
855 }
856 }
857 out:
858 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
859 return smid;
860}
861
862/**
863 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
864 * @ioc: per adapter object
865 * @id: target id
866 * @channel: channel
867 * Context: This function will acquire ioc->scsi_lookup_lock.
868 *
869 * This will search for a matching channel:id in the scsi_lookup array,
870 * returning 1 if found.
871 */
872static u8
873_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
874 int channel)
875{
876 u8 found;
877 unsigned long flags;
878 int i;
879
880 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
881 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530882 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600883 if (ioc->scsi_lookup[i].scmd &&
884 (ioc->scsi_lookup[i].scmd->device->id == id &&
885 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
886 found = 1;
887 goto out;
888 }
889 }
890 out:
891 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
892 return found;
893}
894
895/**
Eric Moore993e0da2009-05-18 13:00:45 -0600896 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
897 * @ioc: per adapter object
898 * @id: target id
899 * @lun: lun number
900 * @channel: channel
901 * Context: This function will acquire ioc->scsi_lookup_lock.
902 *
903 * This will search for a matching channel:id:lun in the scsi_lookup array,
904 * returning 1 if found.
905 */
906static u8
907_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
908 unsigned int lun, int channel)
909{
910 u8 found;
911 unsigned long flags;
912 int i;
913
914 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
915 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530916 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore993e0da2009-05-18 13:00:45 -0600917 if (ioc->scsi_lookup[i].scmd &&
918 (ioc->scsi_lookup[i].scmd->device->id == id &&
919 ioc->scsi_lookup[i].scmd->device->channel == channel &&
920 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
921 found = 1;
922 goto out;
923 }
924 }
925 out:
926 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
927 return found;
928}
929
930/**
Eric Moore635374e2009-03-09 01:21:12 -0600931 * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
932 * @ioc: per adapter object
933 * @smid: system request message index
934 *
935 * Returns phys pointer to chain buffer.
936 */
937static dma_addr_t
938_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
939{
940 return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
941 ioc->chains_needed_per_io));
942}
943
944/**
945 * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
946 * @ioc: per adapter object
947 * @smid: system request message index
948 *
949 * Returns virt pointer to chain buffer.
950 */
951static void *
952_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
953{
954 return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
955 ioc->chains_needed_per_io)));
956}
957
958/**
959 * _scsih_build_scatter_gather - main sg creation routine
960 * @ioc: per adapter object
961 * @scmd: scsi command
962 * @smid: system request message index
963 * Context: none.
964 *
965 * The main routine that builds scatter gather table from a given
966 * scsi request sent via the .queuecommand main handler.
967 *
968 * Returns 0 success, anything else error
969 */
970static int
971_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
972 struct scsi_cmnd *scmd, u16 smid)
973{
974 Mpi2SCSIIORequest_t *mpi_request;
975 dma_addr_t chain_dma;
976 struct scatterlist *sg_scmd;
977 void *sg_local, *chain;
978 u32 chain_offset;
979 u32 chain_length;
980 u32 chain_flags;
FUJITA Tomonoribb789d02010-03-09 11:09:50 +0900981 int sges_left;
Eric Moore635374e2009-03-09 01:21:12 -0600982 u32 sges_in_segment;
983 u32 sgl_flags;
984 u32 sgl_flags_last_element;
985 u32 sgl_flags_end_buffer;
986
987 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
988
989 /* init scatter gather flags */
990 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
991 if (scmd->sc_data_direction == DMA_TO_DEVICE)
992 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
993 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
994 << MPI2_SGE_FLAGS_SHIFT;
995 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
996 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
997 << MPI2_SGE_FLAGS_SHIFT;
998 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
999
1000 sg_scmd = scsi_sglist(scmd);
1001 sges_left = scsi_dma_map(scmd);
FUJITA Tomonoribb789d02010-03-09 11:09:50 +09001002 if (sges_left < 0) {
Eric Moore635374e2009-03-09 01:21:12 -06001003 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
1004 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
1005 return -ENOMEM;
1006 }
1007
1008 sg_local = &mpi_request->SGL;
1009 sges_in_segment = ioc->max_sges_in_main_message;
1010 if (sges_left <= sges_in_segment)
1011 goto fill_in_last_segment;
1012
1013 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
1014 (sges_in_segment * ioc->sge_size))/4;
1015
1016 /* fill in main message segment when there is a chain following */
1017 while (sges_in_segment) {
1018 if (sges_in_segment == 1)
1019 ioc->base_add_sg_single(sg_local,
1020 sgl_flags_last_element | sg_dma_len(sg_scmd),
1021 sg_dma_address(sg_scmd));
1022 else
1023 ioc->base_add_sg_single(sg_local, sgl_flags |
1024 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1025 sg_scmd = sg_next(sg_scmd);
1026 sg_local += ioc->sge_size;
1027 sges_left--;
1028 sges_in_segment--;
1029 }
1030
1031 /* initializing the chain flags and pointers */
1032 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
1033 chain = _scsih_get_chain_buffer(ioc, smid);
1034 chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
1035 do {
1036 sges_in_segment = (sges_left <=
1037 ioc->max_sges_in_chain_message) ? sges_left :
1038 ioc->max_sges_in_chain_message;
1039 chain_offset = (sges_left == sges_in_segment) ?
1040 0 : (sges_in_segment * ioc->sge_size)/4;
1041 chain_length = sges_in_segment * ioc->sge_size;
1042 if (chain_offset) {
1043 chain_offset = chain_offset <<
1044 MPI2_SGE_CHAIN_OFFSET_SHIFT;
1045 chain_length += ioc->sge_size;
1046 }
1047 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
1048 chain_length, chain_dma);
1049 sg_local = chain;
1050 if (!chain_offset)
1051 goto fill_in_last_segment;
1052
1053 /* fill in chain segments */
1054 while (sges_in_segment) {
1055 if (sges_in_segment == 1)
1056 ioc->base_add_sg_single(sg_local,
1057 sgl_flags_last_element |
1058 sg_dma_len(sg_scmd),
1059 sg_dma_address(sg_scmd));
1060 else
1061 ioc->base_add_sg_single(sg_local, sgl_flags |
1062 sg_dma_len(sg_scmd),
1063 sg_dma_address(sg_scmd));
1064 sg_scmd = sg_next(sg_scmd);
1065 sg_local += ioc->sge_size;
1066 sges_left--;
1067 sges_in_segment--;
1068 }
1069
1070 chain_dma += ioc->request_sz;
1071 chain += ioc->request_sz;
1072 } while (1);
1073
1074
1075 fill_in_last_segment:
1076
1077 /* fill the last segment */
1078 while (sges_left) {
1079 if (sges_left == 1)
1080 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1081 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1082 else
1083 ioc->base_add_sg_single(sg_local, sgl_flags |
1084 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1085 sg_scmd = sg_next(sg_scmd);
1086 sg_local += ioc->sge_size;
1087 sges_left--;
1088 }
1089
1090 return 0;
1091}
1092
1093/**
Eric Moored5d135b2009-05-18 13:02:08 -06001094 * _scsih_change_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001095 * @sdev: scsi device struct
1096 * @qdepth: requested queue depth
Mike Christiee881a172009-10-15 17:46:39 -07001097 * @reason: calling context
Eric Moore635374e2009-03-09 01:21:12 -06001098 *
1099 * Returns queue depth.
1100 */
1101static int
Mike Christiee881a172009-10-15 17:46:39 -07001102_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
Eric Moore635374e2009-03-09 01:21:12 -06001103{
1104 struct Scsi_Host *shost = sdev->host;
1105 int max_depth;
1106 int tag_type;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301107 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1108 struct MPT2SAS_DEVICE *sas_device_priv_data;
1109 struct MPT2SAS_TARGET *sas_target_priv_data;
1110 struct _sas_device *sas_device;
1111 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06001112
Mike Christiee881a172009-10-15 17:46:39 -07001113 if (reason != SCSI_QDEPTH_DEFAULT)
1114 return -EOPNOTSUPP;
1115
Eric Moore635374e2009-03-09 01:21:12 -06001116 max_depth = shost->can_queue;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301117
1118 /* limit max device queue for SATA to 32 */
1119 sas_device_priv_data = sdev->hostdata;
1120 if (!sas_device_priv_data)
1121 goto not_sata;
1122 sas_target_priv_data = sas_device_priv_data->sas_target;
1123 if (!sas_target_priv_data)
1124 goto not_sata;
1125 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
1126 goto not_sata;
1127 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1128 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1129 sas_device_priv_data->sas_target->sas_address);
1130 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1131 if (sas_device && sas_device->device_info &
1132 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1133 max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
1134
1135 not_sata:
1136
Eric Moore635374e2009-03-09 01:21:12 -06001137 if (!sdev->tagged_supported)
1138 max_depth = 1;
1139 if (qdepth > max_depth)
1140 qdepth = max_depth;
1141 tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
1142 scsi_adjust_queue_depth(sdev, tag_type, qdepth);
1143
1144 if (sdev->inquiry_len > 7)
1145 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1146 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1147 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1148 sdev->ordered_tags, sdev->scsi_level,
1149 (sdev->inquiry[7] & 2) >> 1);
1150
1151 return sdev->queue_depth;
1152}
1153
1154/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301155 * _scsih_change_queue_type - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001156 * @sdev: scsi device struct
1157 * @tag_type: requested tag type
1158 *
1159 * Returns queue tag type.
1160 */
1161static int
Eric Moored5d135b2009-05-18 13:02:08 -06001162_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001163{
1164 if (sdev->tagged_supported) {
1165 scsi_set_tag_type(sdev, tag_type);
1166 if (tag_type)
1167 scsi_activate_tcq(sdev, sdev->queue_depth);
1168 else
1169 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1170 } else
1171 tag_type = 0;
1172
1173 return tag_type;
1174}
1175
1176/**
Eric Moored5d135b2009-05-18 13:02:08 -06001177 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001178 * @starget: scsi target struct
1179 *
1180 * Returns 0 if ok. Any other return is assumed to be an error and
1181 * the device is ignored.
1182 */
1183static int
Eric Moored5d135b2009-05-18 13:02:08 -06001184_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001185{
1186 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1187 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1188 struct MPT2SAS_TARGET *sas_target_priv_data;
1189 struct _sas_device *sas_device;
1190 struct _raid_device *raid_device;
1191 unsigned long flags;
1192 struct sas_rphy *rphy;
1193
1194 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1195 if (!sas_target_priv_data)
1196 return -ENOMEM;
1197
1198 starget->hostdata = sas_target_priv_data;
1199 sas_target_priv_data->starget = starget;
1200 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1201
1202 /* RAID volumes */
1203 if (starget->channel == RAID_CHANNEL) {
1204 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1205 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1206 starget->channel);
1207 if (raid_device) {
1208 sas_target_priv_data->handle = raid_device->handle;
1209 sas_target_priv_data->sas_address = raid_device->wwid;
1210 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
1211 raid_device->starget = starget;
1212 }
1213 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1214 return 0;
1215 }
1216
1217 /* sas/sata devices */
1218 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1219 rphy = dev_to_rphy(starget->dev.parent);
1220 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1221 rphy->identify.sas_address);
1222
1223 if (sas_device) {
1224 sas_target_priv_data->handle = sas_device->handle;
1225 sas_target_priv_data->sas_address = sas_device->sas_address;
1226 sas_device->starget = starget;
1227 sas_device->id = starget->id;
1228 sas_device->channel = starget->channel;
1229 if (sas_device->hidden_raid_component)
1230 sas_target_priv_data->flags |=
1231 MPT_TARGET_FLAGS_RAID_COMPONENT;
1232 }
1233 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1234
1235 return 0;
1236}
1237
1238/**
Eric Moored5d135b2009-05-18 13:02:08 -06001239 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001240 * @starget: scsi target struct
1241 *
1242 * Returns nothing.
1243 */
1244static void
Eric Moored5d135b2009-05-18 13:02:08 -06001245_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001246{
1247 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1248 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1249 struct MPT2SAS_TARGET *sas_target_priv_data;
1250 struct _sas_device *sas_device;
1251 struct _raid_device *raid_device;
1252 unsigned long flags;
1253 struct sas_rphy *rphy;
1254
1255 sas_target_priv_data = starget->hostdata;
1256 if (!sas_target_priv_data)
1257 return;
1258
1259 if (starget->channel == RAID_CHANNEL) {
1260 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1261 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1262 starget->channel);
1263 if (raid_device) {
1264 raid_device->starget = NULL;
1265 raid_device->sdev = NULL;
1266 }
1267 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1268 goto out;
1269 }
1270
1271 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1272 rphy = dev_to_rphy(starget->dev.parent);
1273 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1274 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001275 if (sas_device && (sas_device->starget == starget) &&
1276 (sas_device->id == starget->id) &&
1277 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001278 sas_device->starget = NULL;
1279
1280 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1281
1282 out:
1283 kfree(sas_target_priv_data);
1284 starget->hostdata = NULL;
1285}
1286
1287/**
Eric Moored5d135b2009-05-18 13:02:08 -06001288 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001289 * @sdev: scsi device struct
1290 *
1291 * Returns 0 if ok. Any other return is assumed to be an error and
1292 * the device is ignored.
1293 */
1294static int
Eric Moored5d135b2009-05-18 13:02:08 -06001295_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001296{
1297 struct Scsi_Host *shost;
1298 struct MPT2SAS_ADAPTER *ioc;
1299 struct MPT2SAS_TARGET *sas_target_priv_data;
1300 struct MPT2SAS_DEVICE *sas_device_priv_data;
1301 struct scsi_target *starget;
1302 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06001303 unsigned long flags;
1304
1305 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1306 if (!sas_device_priv_data)
1307 return -ENOMEM;
1308
1309 sas_device_priv_data->lun = sdev->lun;
1310 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1311
1312 starget = scsi_target(sdev);
1313 sas_target_priv_data = starget->hostdata;
1314 sas_target_priv_data->num_luns++;
1315 sas_device_priv_data->sas_target = sas_target_priv_data;
1316 sdev->hostdata = sas_device_priv_data;
1317 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1318 sdev->no_uld_attach = 1;
1319
1320 shost = dev_to_shost(&starget->dev);
1321 ioc = shost_priv(shost);
1322 if (starget->channel == RAID_CHANNEL) {
1323 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1324 raid_device = _scsih_raid_device_find_by_id(ioc,
1325 starget->id, starget->channel);
1326 if (raid_device)
1327 raid_device->sdev = sdev; /* raid is single lun */
1328 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06001329 }
1330
Eric Moore635374e2009-03-09 01:21:12 -06001331 return 0;
1332}
1333
1334/**
Eric Moored5d135b2009-05-18 13:02:08 -06001335 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001336 * @sdev: scsi device struct
1337 *
1338 * Returns nothing.
1339 */
1340static void
Eric Moored5d135b2009-05-18 13:02:08 -06001341_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001342{
1343 struct MPT2SAS_TARGET *sas_target_priv_data;
1344 struct scsi_target *starget;
1345
1346 if (!sdev->hostdata)
1347 return;
1348
1349 starget = scsi_target(sdev);
1350 sas_target_priv_data = starget->hostdata;
1351 sas_target_priv_data->num_luns--;
1352 kfree(sdev->hostdata);
1353 sdev->hostdata = NULL;
1354}
1355
1356/**
Eric Moored5d135b2009-05-18 13:02:08 -06001357 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001358 * @ioc: per adapter object
1359 * @sas_device: the sas_device object
1360 * @sdev: scsi device struct
1361 */
1362static void
Eric Moored5d135b2009-05-18 13:02:08 -06001363_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06001364 struct _sas_device *sas_device, struct scsi_device *sdev)
1365{
1366 Mpi2ConfigReply_t mpi_reply;
1367 Mpi2SasDevicePage0_t sas_device_pg0;
1368 u32 ioc_status;
1369 u16 flags;
1370 u32 device_info;
1371
1372 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
1373 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
1374 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1375 ioc->name, __FILE__, __LINE__, __func__);
1376 return;
1377 }
1378
1379 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1380 MPI2_IOCSTATUS_MASK;
1381 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1382 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1383 ioc->name, __FILE__, __LINE__, __func__);
1384 return;
1385 }
1386
1387 flags = le16_to_cpu(sas_device_pg0.Flags);
Kashyap, Desaie94f6742010-03-17 16:24:52 +05301388 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
Eric Moore635374e2009-03-09 01:21:12 -06001389
1390 sdev_printk(KERN_INFO, sdev,
1391 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1392 "sw_preserve(%s)\n",
1393 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1394 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1395 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1396 "n",
1397 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1398 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1399 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1400}
1401
1402/**
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301403 * _scsih_is_raid - return boolean indicating device is raid volume
1404 * @dev the device struct object
1405 */
1406static int
1407_scsih_is_raid(struct device *dev)
1408{
1409 struct scsi_device *sdev = to_scsi_device(dev);
1410
1411 return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
1412}
1413
1414/**
1415 * _scsih_get_resync - get raid volume resync percent complete
1416 * @dev the device struct object
1417 */
1418static void
1419_scsih_get_resync(struct device *dev)
1420{
1421 struct scsi_device *sdev = to_scsi_device(dev);
1422 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1423 static struct _raid_device *raid_device;
1424 unsigned long flags;
1425 Mpi2RaidVolPage0_t vol_pg0;
1426 Mpi2ConfigReply_t mpi_reply;
1427 u32 volume_status_flags;
1428 u8 percent_complete = 0;
1429
1430 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1431 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1432 sdev->channel);
1433 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1434
1435 if (!raid_device)
1436 goto out;
1437
1438 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1439 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1440 sizeof(Mpi2RaidVolPage0_t))) {
1441 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1442 ioc->name, __FILE__, __LINE__, __func__);
1443 goto out;
1444 }
1445
1446 volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1447 if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
1448 percent_complete = raid_device->percent_complete;
1449 out:
1450 raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
1451}
1452
1453/**
1454 * _scsih_get_state - get raid volume level
1455 * @dev the device struct object
1456 */
1457static void
1458_scsih_get_state(struct device *dev)
1459{
1460 struct scsi_device *sdev = to_scsi_device(dev);
1461 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1462 static struct _raid_device *raid_device;
1463 unsigned long flags;
1464 Mpi2RaidVolPage0_t vol_pg0;
1465 Mpi2ConfigReply_t mpi_reply;
1466 u32 volstate;
1467 enum raid_state state = RAID_STATE_UNKNOWN;
1468
1469 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1470 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1471 sdev->channel);
1472 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1473
1474 if (!raid_device)
1475 goto out;
1476
1477 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1478 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1479 sizeof(Mpi2RaidVolPage0_t))) {
1480 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1481 ioc->name, __FILE__, __LINE__, __func__);
1482 goto out;
1483 }
1484
1485 volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1486 if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
1487 state = RAID_STATE_RESYNCING;
1488 goto out;
1489 }
1490
1491 switch (vol_pg0.VolumeState) {
1492 case MPI2_RAID_VOL_STATE_OPTIMAL:
1493 case MPI2_RAID_VOL_STATE_ONLINE:
1494 state = RAID_STATE_ACTIVE;
1495 break;
1496 case MPI2_RAID_VOL_STATE_DEGRADED:
1497 state = RAID_STATE_DEGRADED;
1498 break;
1499 case MPI2_RAID_VOL_STATE_FAILED:
1500 case MPI2_RAID_VOL_STATE_MISSING:
1501 state = RAID_STATE_OFFLINE;
1502 break;
1503 }
1504 out:
1505 raid_set_state(mpt2sas_raid_template, dev, state);
1506}
1507
1508/**
1509 * _scsih_set_level - set raid level
1510 * @sdev: scsi device struct
1511 * @raid_device: raid_device object
1512 */
1513static void
1514_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
1515{
1516 enum raid_level level = RAID_LEVEL_UNKNOWN;
1517
1518 switch (raid_device->volume_type) {
1519 case MPI2_RAID_VOL_TYPE_RAID0:
1520 level = RAID_LEVEL_0;
1521 break;
1522 case MPI2_RAID_VOL_TYPE_RAID10:
1523 level = RAID_LEVEL_10;
1524 break;
1525 case MPI2_RAID_VOL_TYPE_RAID1E:
1526 level = RAID_LEVEL_1E;
1527 break;
1528 case MPI2_RAID_VOL_TYPE_RAID1:
1529 level = RAID_LEVEL_1;
1530 break;
1531 }
1532
1533 raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
1534}
1535
1536/**
Eric Moore635374e2009-03-09 01:21:12 -06001537 * _scsih_get_volume_capabilities - volume capabilities
1538 * @ioc: per adapter object
1539 * @sas_device: the raid_device object
1540 */
1541static void
1542_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1543 struct _raid_device *raid_device)
1544{
1545 Mpi2RaidVolPage0_t *vol_pg0;
1546 Mpi2RaidPhysDiskPage0_t pd_pg0;
1547 Mpi2SasDevicePage0_t sas_device_pg0;
1548 Mpi2ConfigReply_t mpi_reply;
1549 u16 sz;
1550 u8 num_pds;
1551
1552 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1553 &num_pds)) || !num_pds) {
1554 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1555 ioc->name, __FILE__, __LINE__, __func__);
1556 return;
1557 }
1558
1559 raid_device->num_pds = num_pds;
1560 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1561 sizeof(Mpi2RaidVol0PhysDisk_t));
1562 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1563 if (!vol_pg0) {
1564 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1565 ioc->name, __FILE__, __LINE__, __func__);
1566 return;
1567 }
1568
1569 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1570 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1571 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1572 ioc->name, __FILE__, __LINE__, __func__);
1573 kfree(vol_pg0);
1574 return;
1575 }
1576
1577 raid_device->volume_type = vol_pg0->VolumeType;
1578
1579 /* figure out what the underlying devices are by
1580 * obtaining the device_info bits for the 1st device
1581 */
1582 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1583 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1584 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1585 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1586 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1587 le16_to_cpu(pd_pg0.DevHandle)))) {
1588 raid_device->device_info =
1589 le32_to_cpu(sas_device_pg0.DeviceInfo);
1590 }
1591 }
1592
1593 kfree(vol_pg0);
1594}
1595
1596/**
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301597 * _scsih_enable_tlr - setting TLR flags
1598 * @ioc: per adapter object
1599 * @sdev: scsi device struct
1600 *
1601 * Enabling Transaction Layer Retries for tape devices when
1602 * vpd page 0x90 is present
1603 *
1604 */
1605static void
1606_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev)
1607{
1608 /* only for TAPE */
1609 if (sdev->type != TYPE_TAPE)
1610 return;
1611
1612 if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR))
1613 return;
1614
1615 sas_enable_tlr(sdev);
1616 sdev_printk(KERN_INFO, sdev, "TLR %s\n",
1617 sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled");
1618 return;
1619
1620}
1621
1622/**
Eric Moored5d135b2009-05-18 13:02:08 -06001623 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001624 * @sdev: scsi device struct
1625 *
1626 * Returns 0 if ok. Any other return is assumed to be an error and
1627 * the device is ignored.
1628 */
1629static int
Eric Moored5d135b2009-05-18 13:02:08 -06001630_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001631{
1632 struct Scsi_Host *shost = sdev->host;
1633 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1634 struct MPT2SAS_DEVICE *sas_device_priv_data;
1635 struct MPT2SAS_TARGET *sas_target_priv_data;
1636 struct _sas_device *sas_device;
1637 struct _raid_device *raid_device;
1638 unsigned long flags;
1639 int qdepth;
1640 u8 ssp_target = 0;
1641 char *ds = "";
1642 char *r_level = "";
1643
1644 qdepth = 1;
1645 sas_device_priv_data = sdev->hostdata;
1646 sas_device_priv_data->configured_lun = 1;
1647 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1648 sas_target_priv_data = sas_device_priv_data->sas_target;
1649
1650 /* raid volume handling */
1651 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1652
1653 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1654 raid_device = _scsih_raid_device_find_by_handle(ioc,
1655 sas_target_priv_data->handle);
1656 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1657 if (!raid_device) {
1658 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1659 ioc->name, __FILE__, __LINE__, __func__);
1660 return 0;
1661 }
1662
1663 _scsih_get_volume_capabilities(ioc, raid_device);
1664
1665 /* RAID Queue Depth Support
1666 * IS volume = underlying qdepth of drive type, either
1667 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
1668 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
1669 */
1670 if (raid_device->device_info &
1671 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1672 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1673 ds = "SSP";
1674 } else {
1675 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1676 if (raid_device->device_info &
1677 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1678 ds = "SATA";
1679 else
1680 ds = "STP";
1681 }
1682
1683 switch (raid_device->volume_type) {
1684 case MPI2_RAID_VOL_TYPE_RAID0:
1685 r_level = "RAID0";
1686 break;
1687 case MPI2_RAID_VOL_TYPE_RAID1E:
1688 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05301689 if (ioc->manu_pg10.OEMIdentifier &&
1690 (ioc->manu_pg10.GenericFlags0 &
1691 MFG10_GF0_R10_DISPLAY) &&
1692 !(raid_device->num_pds % 2))
1693 r_level = "RAID10";
1694 else
1695 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06001696 break;
1697 case MPI2_RAID_VOL_TYPE_RAID1:
1698 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1699 r_level = "RAID1";
1700 break;
1701 case MPI2_RAID_VOL_TYPE_RAID10:
1702 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1703 r_level = "RAID10";
1704 break;
1705 case MPI2_RAID_VOL_TYPE_UNKNOWN:
1706 default:
1707 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1708 r_level = "RAIDX";
1709 break;
1710 }
1711
1712 sdev_printk(KERN_INFO, sdev, "%s: "
1713 "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
1714 r_level, raid_device->handle,
1715 (unsigned long long)raid_device->wwid,
1716 raid_device->num_pds, ds);
Mike Christiee881a172009-10-15 17:46:39 -07001717 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301718 /* raid transport support */
1719 _scsih_set_level(sdev, raid_device);
Eric Moore635374e2009-03-09 01:21:12 -06001720 return 0;
1721 }
1722
1723 /* non-raid handling */
1724 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1725 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1726 sas_device_priv_data->sas_target->sas_address);
1727 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1728 if (sas_device) {
1729 if (sas_target_priv_data->flags &
1730 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1731 mpt2sas_config_get_volume_handle(ioc,
1732 sas_device->handle, &sas_device->volume_handle);
1733 mpt2sas_config_get_volume_wwid(ioc,
1734 sas_device->volume_handle,
1735 &sas_device->volume_wwid);
1736 }
1737 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1738 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1739 ssp_target = 1;
1740 ds = "SSP";
1741 } else {
1742 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1743 if (sas_device->device_info &
1744 MPI2_SAS_DEVICE_INFO_STP_TARGET)
1745 ds = "STP";
1746 else if (sas_device->device_info &
1747 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1748 ds = "SATA";
1749 }
1750
1751 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
1752 "sas_addr(0x%016llx), device_name(0x%016llx)\n",
1753 ds, sas_device->handle,
1754 (unsigned long long)sas_device->sas_address,
1755 (unsigned long long)sas_device->device_name);
1756 sdev_printk(KERN_INFO, sdev, "%s: "
1757 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
1758 (unsigned long long) sas_device->enclosure_logical_id,
1759 sas_device->slot);
1760
1761 if (!ssp_target)
Eric Moored5d135b2009-05-18 13:02:08 -06001762 _scsih_display_sata_capabilities(ioc, sas_device, sdev);
Eric Moore635374e2009-03-09 01:21:12 -06001763 }
1764
Mike Christiee881a172009-10-15 17:46:39 -07001765 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Eric Moore635374e2009-03-09 01:21:12 -06001766
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301767 if (ssp_target) {
Eric Moore635374e2009-03-09 01:21:12 -06001768 sas_read_port_mode_page(sdev);
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301769 _scsih_enable_tlr(ioc, sdev);
1770 }
Eric Moore635374e2009-03-09 01:21:12 -06001771 return 0;
1772}
1773
1774/**
Eric Moored5d135b2009-05-18 13:02:08 -06001775 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06001776 * @sdev: scsi device struct
1777 * @bdev: pointer to block device context
1778 * @capacity: device size (in 512 byte sectors)
1779 * @params: three element array to place output:
1780 * params[0] number of heads (max 255)
1781 * params[1] number of sectors (max 63)
1782 * params[2] number of cylinders
1783 *
1784 * Return nothing.
1785 */
1786static int
Eric Moored5d135b2009-05-18 13:02:08 -06001787_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06001788 sector_t capacity, int params[])
1789{
1790 int heads;
1791 int sectors;
1792 sector_t cylinders;
1793 ulong dummy;
1794
1795 heads = 64;
1796 sectors = 32;
1797
1798 dummy = heads * sectors;
1799 cylinders = capacity;
1800 sector_div(cylinders, dummy);
1801
1802 /*
1803 * Handle extended translation size for logical drives
1804 * > 1Gb
1805 */
1806 if ((ulong)capacity >= 0x200000) {
1807 heads = 255;
1808 sectors = 63;
1809 dummy = heads * sectors;
1810 cylinders = capacity;
1811 sector_div(cylinders, dummy);
1812 }
1813
1814 /* return result */
1815 params[0] = heads;
1816 params[1] = sectors;
1817 params[2] = cylinders;
1818
1819 return 0;
1820}
1821
1822/**
1823 * _scsih_response_code - translation of device response code
1824 * @ioc: per adapter object
1825 * @response_code: response code returned by the device
1826 *
1827 * Return nothing.
1828 */
1829static void
1830_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
1831{
1832 char *desc;
1833
1834 switch (response_code) {
1835 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1836 desc = "task management request completed";
1837 break;
1838 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1839 desc = "invalid frame";
1840 break;
1841 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1842 desc = "task management request not supported";
1843 break;
1844 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1845 desc = "task management request failed";
1846 break;
1847 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1848 desc = "task management request succeeded";
1849 break;
1850 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1851 desc = "invalid lun";
1852 break;
1853 case 0xA:
1854 desc = "overlapped tag attempted";
1855 break;
1856 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1857 desc = "task queued, however not sent to target";
1858 break;
1859 default:
1860 desc = "unknown";
1861 break;
1862 }
1863 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
1864 ioc->name, response_code, desc);
1865}
1866
1867/**
Eric Moored5d135b2009-05-18 13:02:08 -06001868 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06001869 * @ioc: per adapter object
1870 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301871 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001872 * @reply: reply message frame(lower 32bit addr)
1873 * Context: none.
1874 *
1875 * The callback handler when using scsih_issue_tm.
1876 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301877 * Return 1 meaning mf should be freed from _base_interrupt
1878 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06001879 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301880static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301881_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06001882{
1883 MPI2DefaultReply_t *mpi_reply;
1884
1885 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301886 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001887 if (ioc->tm_cmds.smid != smid)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301888 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001889 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
1890 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
1891 if (mpi_reply) {
1892 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
1893 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
1894 }
1895 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
1896 complete(&ioc->tm_cmds.done);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301897 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001898}
1899
1900/**
1901 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
1902 * @ioc: per adapter object
1903 * @handle: device handle
1904 *
1905 * During taskmangement request, we need to freeze the device queue.
1906 */
1907void
1908mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1909{
1910 struct MPT2SAS_DEVICE *sas_device_priv_data;
1911 struct scsi_device *sdev;
1912 u8 skip = 0;
1913
1914 shost_for_each_device(sdev, ioc->shost) {
1915 if (skip)
1916 continue;
1917 sas_device_priv_data = sdev->hostdata;
1918 if (!sas_device_priv_data)
1919 continue;
1920 if (sas_device_priv_data->sas_target->handle == handle) {
1921 sas_device_priv_data->sas_target->tm_busy = 1;
1922 skip = 1;
1923 ioc->ignore_loginfos = 1;
1924 }
1925 }
1926}
1927
1928/**
1929 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
1930 * @ioc: per adapter object
1931 * @handle: device handle
1932 *
1933 * During taskmangement request, we need to freeze the device queue.
1934 */
1935void
1936mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1937{
1938 struct MPT2SAS_DEVICE *sas_device_priv_data;
1939 struct scsi_device *sdev;
1940 u8 skip = 0;
1941
1942 shost_for_each_device(sdev, ioc->shost) {
1943 if (skip)
1944 continue;
1945 sas_device_priv_data = sdev->hostdata;
1946 if (!sas_device_priv_data)
1947 continue;
1948 if (sas_device_priv_data->sas_target->handle == handle) {
1949 sas_device_priv_data->sas_target->tm_busy = 0;
1950 skip = 1;
1951 ioc->ignore_loginfos = 0;
1952 }
1953 }
1954}
1955
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301956
Eric Moore635374e2009-03-09 01:21:12 -06001957/**
1958 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
1959 * @ioc: per adapter struct
1960 * @device_handle: device handle
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301961 * @channel: the channel assigned by the OS
1962 * @id: the id assigned by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001963 * @lun: lun number
1964 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
1965 * @smid_task: smid assigned to the task
1966 * @timeout: timeout in seconds
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301967 * Context: user
Eric Moore635374e2009-03-09 01:21:12 -06001968 *
1969 * A generic API for sending task management requests to firmware.
1970 *
Eric Moore635374e2009-03-09 01:21:12 -06001971 * The callback index is set inside `ioc->tm_cb_idx`.
1972 *
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301973 * Return SUCCESS or FAILED.
Eric Moore635374e2009-03-09 01:21:12 -06001974 */
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301975int
1976mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
1977 uint id, uint lun, u8 type, u16 smid_task, ulong timeout,
1978 struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001979{
1980 Mpi2SCSITaskManagementRequest_t *mpi_request;
1981 Mpi2SCSITaskManagementReply_t *mpi_reply;
1982 u16 smid = 0;
1983 u32 ioc_state;
1984 unsigned long timeleft;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301985 struct scsi_cmnd *scmd_lookup;
1986 int rc;
Eric Moore635374e2009-03-09 01:21:12 -06001987
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301988 mutex_lock(&ioc->tm_cmds.mutex);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301989 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
1990 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
1991 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301992 rc = FAILED;
1993 goto err_out;
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301994 }
1995
Kashyap, Desai6558bbb2010-03-17 16:23:36 +05301996 if (ioc->shost_recovery || ioc->remove_host) {
Eric Moore635374e2009-03-09 01:21:12 -06001997 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1998 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301999 rc = FAILED;
2000 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002001 }
Eric Moore635374e2009-03-09 01:21:12 -06002002
2003 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
2004 if (ioc_state & MPI2_DOORBELL_USED) {
2005 dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
2006 "active!\n", ioc->name));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302007 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2008 FORCE_BIG_HAMMER);
2009 rc = SUCCESS;
2010 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002011 }
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);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302016 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2017 FORCE_BIG_HAMMER);
2018 rc = SUCCESS;
2019 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002020 }
2021
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302022 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06002023 if (!smid) {
2024 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2025 ioc->name, __func__);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302026 rc = FAILED;
2027 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002028 }
2029
2030 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302031 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
2032 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06002033 ioc->tm_cmds.status = MPT2_CMD_PENDING;
2034 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2035 ioc->tm_cmds.smid = smid;
2036 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2037 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2038 mpi_request->DevHandle = cpu_to_le16(handle);
2039 mpi_request->TaskType = type;
2040 mpi_request->TaskMID = cpu_to_le16(smid_task);
2041 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
2042 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05302043 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302044 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002045 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
Eric Moore635374e2009-03-09 01:21:12 -06002046 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
2047 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
2048 ioc->name, __func__);
2049 _debug_dump_mf(mpi_request,
2050 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302051 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) {
2052 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2053 FORCE_BIG_HAMMER);
2054 rc = SUCCESS;
2055 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2056 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2057 goto err_out;
2058 }
Eric Moore635374e2009-03-09 01:21:12 -06002059 }
2060
2061 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
2062 mpi_reply = ioc->tm_cmds.reply;
2063 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
2064 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
2065 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
2066 le32_to_cpu(mpi_reply->IOCLogInfo),
2067 le32_to_cpu(mpi_reply->TerminationCount)));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302068 if (ioc->logging_level & MPT_DEBUG_TM) {
Eric Moore635374e2009-03-09 01:21:12 -06002069 _scsih_response_code(ioc, mpi_reply->ResponseCode);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302070 if (mpi_reply->IOCStatus)
2071 _debug_dump_mf(mpi_request,
2072 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
2073 }
Eric Moore635374e2009-03-09 01:21:12 -06002074 }
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302075
2076 /* sanity check:
2077 * Check to see the commands were terminated.
2078 * This is only needed for eh callbacks, hence the scmd check.
2079 */
2080 rc = FAILED;
2081 if (scmd == NULL)
2082 goto bypass_sanity_checks;
2083 switch (type) {
2084 case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2085 scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task);
2086 if (scmd_lookup && (scmd_lookup->serial_number ==
2087 scmd->serial_number))
2088 rc = FAILED;
2089 else
2090 rc = SUCCESS;
2091 break;
2092
2093 case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2094 if (_scsih_scsi_lookup_find_by_target(ioc, id, channel))
2095 rc = FAILED;
2096 else
2097 rc = SUCCESS;
2098 break;
2099
2100 case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
2101 if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel))
2102 rc = FAILED;
2103 else
2104 rc = SUCCESS;
2105 break;
2106 }
2107
2108 bypass_sanity_checks:
2109
2110 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2111 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2112 mutex_unlock(&ioc->tm_cmds.mutex);
2113
2114 return rc;
2115
2116 err_out:
2117 mutex_unlock(&ioc->tm_cmds.mutex);
2118 return rc;
Eric Moore635374e2009-03-09 01:21:12 -06002119}
2120
2121/**
Eric Moored5d135b2009-05-18 13:02:08 -06002122 * _scsih_abort - eh threads main abort routine
Eric Moore635374e2009-03-09 01:21:12 -06002123 * @sdev: scsi device struct
2124 *
2125 * Returns SUCCESS if command aborted else FAILED
2126 */
2127static int
Eric Moored5d135b2009-05-18 13:02:08 -06002128_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002129{
2130 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2131 struct MPT2SAS_DEVICE *sas_device_priv_data;
2132 u16 smid;
2133 u16 handle;
2134 int r;
Eric Moore635374e2009-03-09 01:21:12 -06002135
2136 printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
2137 ioc->name, scmd);
2138 scsi_print_command(scmd);
2139
2140 sas_device_priv_data = scmd->device->hostdata;
2141 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2142 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
2143 ioc->name, scmd);
2144 scmd->result = DID_NO_CONNECT << 16;
2145 scmd->scsi_done(scmd);
2146 r = SUCCESS;
2147 goto out;
2148 }
2149
2150 /* search for the command */
2151 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
2152 if (!smid) {
2153 scmd->result = DID_RESET << 16;
2154 r = SUCCESS;
2155 goto out;
2156 }
2157
2158 /* for hidden raid components and volumes this is not supported */
2159 if (sas_device_priv_data->sas_target->flags &
2160 MPT_TARGET_FLAGS_RAID_COMPONENT ||
2161 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
2162 scmd->result = DID_RESET << 16;
2163 r = FAILED;
2164 goto out;
2165 }
2166
Kashyap, Desaifa7f3162009-09-23 17:26:58 +05302167 mpt2sas_halt_firmware(ioc);
2168
Eric Moore635374e2009-03-09 01:21:12 -06002169 handle = sas_device_priv_data->sas_target->handle;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302170 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2171 scmd->device->id, scmd->device->lun,
2172 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002173
2174 out:
2175 printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
2176 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2177 return r;
2178}
2179
Eric Moore635374e2009-03-09 01:21:12 -06002180/**
Eric Moored5d135b2009-05-18 13:02:08 -06002181 * _scsih_dev_reset - eh threads main device reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002182 * @sdev: scsi device struct
2183 *
2184 * Returns SUCCESS if command aborted else FAILED
2185 */
2186static int
Eric Moored5d135b2009-05-18 13:02:08 -06002187_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002188{
2189 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2190 struct MPT2SAS_DEVICE *sas_device_priv_data;
2191 struct _sas_device *sas_device;
2192 unsigned long flags;
2193 u16 handle;
2194 int r;
2195
Eric Moore993e0da2009-05-18 13:00:45 -06002196 printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
Eric Moore635374e2009-03-09 01:21:12 -06002197 ioc->name, scmd);
2198 scsi_print_command(scmd);
2199
2200 sas_device_priv_data = scmd->device->hostdata;
2201 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2202 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
2203 ioc->name, scmd);
2204 scmd->result = DID_NO_CONNECT << 16;
2205 scmd->scsi_done(scmd);
2206 r = SUCCESS;
2207 goto out;
2208 }
2209
2210 /* for hidden raid components obtain the volume_handle */
2211 handle = 0;
2212 if (sas_device_priv_data->sas_target->flags &
2213 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2214 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2215 sas_device = _scsih_sas_device_find_by_handle(ioc,
2216 sas_device_priv_data->sas_target->handle);
2217 if (sas_device)
2218 handle = sas_device->volume_handle;
2219 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2220 } else
2221 handle = sas_device_priv_data->sas_target->handle;
2222
2223 if (!handle) {
2224 scmd->result = DID_RESET << 16;
2225 r = FAILED;
2226 goto out;
2227 }
2228
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302229 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2230 scmd->device->id, scmd->device->lun,
2231 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002232
2233 out:
2234 printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
2235 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2236 return r;
2237}
2238
2239/**
Eric Moored5d135b2009-05-18 13:02:08 -06002240 * _scsih_target_reset - eh threads main target reset routine
Eric Moore993e0da2009-05-18 13:00:45 -06002241 * @sdev: scsi device struct
2242 *
2243 * Returns SUCCESS if command aborted else FAILED
2244 */
2245static int
Eric Moored5d135b2009-05-18 13:02:08 -06002246_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06002247{
2248 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2249 struct MPT2SAS_DEVICE *sas_device_priv_data;
2250 struct _sas_device *sas_device;
2251 unsigned long flags;
2252 u16 handle;
2253 int r;
2254
2255 printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
2256 ioc->name, scmd);
2257 scsi_print_command(scmd);
2258
2259 sas_device_priv_data = scmd->device->hostdata;
2260 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2261 printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
2262 ioc->name, scmd);
2263 scmd->result = DID_NO_CONNECT << 16;
2264 scmd->scsi_done(scmd);
2265 r = SUCCESS;
2266 goto out;
2267 }
2268
2269 /* for hidden raid components obtain the volume_handle */
2270 handle = 0;
2271 if (sas_device_priv_data->sas_target->flags &
2272 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2273 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2274 sas_device = _scsih_sas_device_find_by_handle(ioc,
2275 sas_device_priv_data->sas_target->handle);
2276 if (sas_device)
2277 handle = sas_device->volume_handle;
2278 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2279 } else
2280 handle = sas_device_priv_data->sas_target->handle;
2281
2282 if (!handle) {
2283 scmd->result = DID_RESET << 16;
2284 r = FAILED;
2285 goto out;
2286 }
2287
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302288 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2289 scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
2290 30, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002291
2292 out:
2293 printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
2294 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2295 return r;
2296}
2297
2298/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302299 * _scsih_host_reset - eh threads main host reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002300 * @sdev: scsi device struct
2301 *
2302 * Returns SUCCESS if command aborted else FAILED
2303 */
2304static int
Eric Moored5d135b2009-05-18 13:02:08 -06002305_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002306{
2307 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2308 int r, retval;
2309
2310 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2311 ioc->name, scmd);
2312 scsi_print_command(scmd);
2313
2314 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2315 FORCE_BIG_HAMMER);
2316 r = (retval < 0) ? FAILED : SUCCESS;
2317 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2318 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2319
2320 return r;
2321}
2322
2323/**
2324 * _scsih_fw_event_add - insert and queue up fw_event
2325 * @ioc: per adapter object
2326 * @fw_event: object describing the event
2327 * Context: This function will acquire ioc->fw_event_lock.
2328 *
2329 * This adds the firmware event object into link list, then queues it up to
2330 * be processed from user context.
2331 *
2332 * Return nothing.
2333 */
2334static void
2335_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2336{
2337 unsigned long flags;
2338
2339 if (ioc->firmware_event_thread == NULL)
2340 return;
2341
2342 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2343 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302344 INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work);
2345 queue_delayed_work(ioc->firmware_event_thread,
2346 &fw_event->delayed_work, 0);
Eric Moore635374e2009-03-09 01:21:12 -06002347 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2348}
2349
2350/**
2351 * _scsih_fw_event_free - delete fw_event
2352 * @ioc: per adapter object
2353 * @fw_event: object describing the event
2354 * Context: This function will acquire ioc->fw_event_lock.
2355 *
2356 * This removes firmware event object from link list, frees associated memory.
2357 *
2358 * Return nothing.
2359 */
2360static void
2361_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2362 *fw_event)
2363{
2364 unsigned long flags;
2365
2366 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2367 list_del(&fw_event->list);
2368 kfree(fw_event->event_data);
2369 kfree(fw_event);
2370 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2371}
2372
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302373
Eric Moore635374e2009-03-09 01:21:12 -06002374/**
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302375 * _scsih_queue_rescan - queue a topology rescan from user context
Eric Moore635374e2009-03-09 01:21:12 -06002376 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06002377 *
2378 * Return nothing.
2379 */
2380static void
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302381_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06002382{
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302383 struct fw_event_work *fw_event;
2384
2385 if (ioc->wait_for_port_enable_to_complete)
2386 return;
2387 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
2388 if (!fw_event)
2389 return;
2390 fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET;
2391 fw_event->ioc = ioc;
2392 _scsih_fw_event_add(ioc, fw_event);
2393}
2394
2395/**
2396 * _scsih_fw_event_cleanup_queue - cleanup event queue
2397 * @ioc: per adapter object
2398 *
2399 * Walk the firmware event queue, either killing timers, or waiting
2400 * for outstanding events to complete
2401 *
2402 * Return nothing.
2403 */
2404static void
2405_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)
2406{
2407 struct fw_event_work *fw_event, *next;
2408
2409 if (list_empty(&ioc->fw_event_list) ||
2410 !ioc->firmware_event_thread || in_interrupt())
Eric Moore635374e2009-03-09 01:21:12 -06002411 return;
2412
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302413 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
2414 if (cancel_delayed_work(&fw_event->delayed_work)) {
2415 _scsih_fw_event_free(ioc, fw_event);
2416 continue;
2417 }
2418 fw_event->cancel_pending_work = 1;
2419 }
Eric Moore635374e2009-03-09 01:21:12 -06002420}
2421
Eric Moore635374e2009-03-09 01:21:12 -06002422/**
2423 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2424 * @ioc: per adapter object
2425 * @handle: device handle
2426 *
2427 * During device pull we need to appropiately set the sdev state.
2428 */
2429static void
2430_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2431{
2432 struct MPT2SAS_DEVICE *sas_device_priv_data;
2433 struct scsi_device *sdev;
2434
2435 shost_for_each_device(sdev, ioc->shost) {
2436 sas_device_priv_data = sdev->hostdata;
2437 if (!sas_device_priv_data)
2438 continue;
2439 if (!sas_device_priv_data->block)
2440 continue;
2441 if (sas_device_priv_data->sas_target->handle == handle) {
2442 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2443 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2444 "handle(0x%04x)\n", ioc->name, handle));
2445 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302446 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002447 }
2448 }
2449}
2450
2451/**
2452 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2453 * @ioc: per adapter object
2454 * @handle: device handle
2455 *
2456 * During device pull we need to appropiately set the sdev state.
2457 */
2458static void
2459_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2460{
2461 struct MPT2SAS_DEVICE *sas_device_priv_data;
2462 struct scsi_device *sdev;
2463
2464 shost_for_each_device(sdev, ioc->shost) {
2465 sas_device_priv_data = sdev->hostdata;
2466 if (!sas_device_priv_data)
2467 continue;
2468 if (sas_device_priv_data->block)
2469 continue;
2470 if (sas_device_priv_data->sas_target->handle == handle) {
2471 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2472 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2473 "handle(0x%04x)\n", ioc->name, handle));
2474 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302475 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002476 }
2477 }
2478}
2479
2480/**
2481 * _scsih_block_io_to_children_attached_to_ex
2482 * @ioc: per adapter object
2483 * @sas_expander: the sas_device object
2484 *
2485 * This routine set sdev state to SDEV_BLOCK for all devices
2486 * attached to this expander. This function called when expander is
2487 * pulled.
2488 */
2489static void
2490_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2491 struct _sas_node *sas_expander)
2492{
2493 struct _sas_port *mpt2sas_port;
2494 struct _sas_device *sas_device;
2495 struct _sas_node *expander_sibling;
2496 unsigned long flags;
2497
2498 if (!sas_expander)
2499 return;
2500
2501 list_for_each_entry(mpt2sas_port,
2502 &sas_expander->sas_port_list, port_list) {
2503 if (mpt2sas_port->remote_identify.device_type ==
2504 SAS_END_DEVICE) {
2505 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2506 sas_device =
2507 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2508 mpt2sas_port->remote_identify.sas_address);
2509 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2510 if (!sas_device)
2511 continue;
2512 _scsih_block_io_device(ioc, sas_device->handle);
2513 }
2514 }
2515
2516 list_for_each_entry(mpt2sas_port,
2517 &sas_expander->sas_port_list, port_list) {
2518
2519 if (mpt2sas_port->remote_identify.device_type ==
2520 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2521 mpt2sas_port->remote_identify.device_type ==
2522 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2523
2524 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2525 expander_sibling =
2526 mpt2sas_scsih_expander_find_by_sas_address(
2527 ioc, mpt2sas_port->remote_identify.sas_address);
2528 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2529 _scsih_block_io_to_children_attached_to_ex(ioc,
2530 expander_sibling);
2531 }
2532 }
2533}
2534
2535/**
2536 * _scsih_block_io_to_children_attached_directly
2537 * @ioc: per adapter object
2538 * @event_data: topology change event data
2539 *
2540 * This routine set sdev state to SDEV_BLOCK for all devices
2541 * direct attached during device pull.
2542 */
2543static void
2544_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2545 Mpi2EventDataSasTopologyChangeList_t *event_data)
2546{
2547 int i;
2548 u16 handle;
2549 u16 reason_code;
2550 u8 phy_number;
2551
2552 for (i = 0; i < event_data->NumEntries; i++) {
2553 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2554 if (!handle)
2555 continue;
2556 phy_number = event_data->StartPhyNum + i;
2557 reason_code = event_data->PHY[i].PhyStatus &
2558 MPI2_EVENT_SAS_TOPO_RC_MASK;
2559 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2560 _scsih_block_io_device(ioc, handle);
2561 }
2562}
2563
2564/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302565 * _scsih_tm_tr_send - send task management request
2566 * @ioc: per adapter object
2567 * @handle: device handle
2568 * Context: interrupt time.
2569 *
2570 * This code is to initiate the device removal handshake protocal
2571 * with controller firmware. This function will issue target reset
2572 * using high priority request queue. It will send a sas iounit
2573 * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
2574 *
2575 * This is designed to send muliple task management request at the same
2576 * time to the fifo. If the fifo is full, we will append the request,
2577 * and process it in a future completion.
2578 */
2579static void
2580_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2581{
2582 Mpi2SCSITaskManagementRequest_t *mpi_request;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302583 u16 smid;
2584 struct _sas_device *sas_device;
2585 unsigned long flags;
2586 struct _tr_list *delayed_tr;
2587
Kashyap, Desai1278b112010-03-09 17:34:13 +05302588 if (ioc->shost_recovery || ioc->remove_host) {
2589 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
2590 "progress!\n", __func__, ioc->name));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302591 return;
2592 }
2593
2594 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2595 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai1278b112010-03-09 17:34:13 +05302596 if (sas_device && sas_device->hidden_raid_component) {
2597 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302598 return;
Kashyap, Desai1278b112010-03-09 17:34:13 +05302599 }
2600 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302601
2602 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
2603 if (!smid) {
2604 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
2605 if (!delayed_tr)
2606 return;
2607 INIT_LIST_HEAD(&delayed_tr->list);
2608 delayed_tr->handle = handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05302609 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
2610 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2611 "DELAYED:tr:handle(0x%04x), (open)\n",
2612 ioc->name, handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302613 return;
2614 }
2615
Kashyap, Desai1278b112010-03-09 17:34:13 +05302616 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
2617 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
2618 ioc->tm_tr_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302619 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2620 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2621 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2622 mpi_request->DevHandle = cpu_to_le16(handle);
2623 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302624 mpt2sas_base_put_smid_hi_priority(ioc, smid);
2625}
2626
2627
2628
2629/**
2630 * _scsih_sas_control_complete - completion routine
2631 * @ioc: per adapter object
2632 * @smid: system request message index
2633 * @msix_index: MSIX table index supplied by the OS
2634 * @reply: reply message frame(lower 32bit addr)
2635 * Context: interrupt time.
2636 *
2637 * This is the sas iounit controll completion routine.
2638 * This code is part of the code to initiate the device removal
2639 * handshake protocal with controller firmware.
2640 *
2641 * Return 1 meaning mf should be freed from _base_interrupt
2642 * 0 means the mf is freed from this function.
2643 */
2644static u8
2645_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
2646 u8 msix_index, u32 reply)
2647{
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302648 Mpi2SasIoUnitControlReply_t *mpi_reply =
2649 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2650
Kashyap, Desai1278b112010-03-09 17:34:13 +05302651 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2652 "sc_complete:handle(0x%04x), (open) "
2653 "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
2654 ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
2655 le16_to_cpu(mpi_reply->IOCStatus),
2656 le32_to_cpu(mpi_reply->IOCLogInfo)));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302657 return 1;
2658}
2659
2660/**
2661 * _scsih_tm_tr_complete -
2662 * @ioc: per adapter object
2663 * @smid: system request message index
2664 * @msix_index: MSIX table index supplied by the OS
2665 * @reply: reply message frame(lower 32bit addr)
2666 * Context: interrupt time.
2667 *
2668 * This is the target reset completion routine.
2669 * This code is part of the code to initiate the device removal
2670 * handshake protocal with controller firmware.
2671 * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE)
2672 *
2673 * Return 1 meaning mf should be freed from _base_interrupt
2674 * 0 means the mf is freed from this function.
2675 */
2676static u8
2677_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
2678 u32 reply)
2679{
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302680 u16 handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05302681 Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302682 Mpi2SCSITaskManagementReply_t *mpi_reply =
2683 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2684 Mpi2SasIoUnitControlRequest_t *mpi_request;
2685 u16 smid_sas_ctrl;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302686 struct _tr_list *delayed_tr;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302687
Kashyap, Desai1278b112010-03-09 17:34:13 +05302688 if (ioc->shost_recovery || ioc->remove_host) {
2689 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
2690 "progress!\n", __func__, ioc->name));
2691 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302692 }
2693
Kashyap, Desai1278b112010-03-09 17:34:13 +05302694 mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
2695 handle = le16_to_cpu(mpi_request_tm->DevHandle);
2696 if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
2697 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: "
2698 "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle,
2699 le16_to_cpu(mpi_reply->DevHandle), smid));
2700 return 0;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302701 }
2702
Kashyap, Desai1278b112010-03-09 17:34:13 +05302703 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2704 "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
2705 "loginfo(0x%08x), completed(%d)\n", ioc->name,
2706 handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
2707 le32_to_cpu(mpi_reply->IOCLogInfo),
2708 le32_to_cpu(mpi_reply->TerminationCount)));
2709
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302710 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
2711 if (!smid_sas_ctrl) {
2712 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2713 ioc->name, __func__);
Kashyap, Desai1278b112010-03-09 17:34:13 +05302714 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302715 }
2716
Kashyap, Desai1278b112010-03-09 17:34:13 +05302717 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), "
2718 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl,
2719 ioc->tm_sas_control_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302720 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
2721 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
2722 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
2723 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
Kashyap, Desai1278b112010-03-09 17:34:13 +05302724 mpi_request->DevHandle = mpi_request_tm->DevHandle;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302725 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
Kashyap, Desai1278b112010-03-09 17:34:13 +05302726
2727 if (!list_empty(&ioc->delayed_tr_list)) {
2728 delayed_tr = list_entry(ioc->delayed_tr_list.next,
2729 struct _tr_list, list);
2730 mpt2sas_base_free_smid(ioc, smid);
2731 _scsih_tm_tr_send(ioc, delayed_tr->handle);
2732 list_del(&delayed_tr->list);
2733 kfree(delayed_tr);
2734 return 0; /* tells base_interrupt not to free mf */
2735 }
2736 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302737}
2738
2739/**
Eric Moore635374e2009-03-09 01:21:12 -06002740 * _scsih_check_topo_delete_events - sanity check on topo events
2741 * @ioc: per adapter object
2742 * @event_data: the event data payload
2743 *
2744 * This routine added to better handle cable breaker.
2745 *
2746 * This handles the case where driver recieves multiple expander
2747 * add and delete events in a single shot. When there is a delete event
2748 * the routine will void any pending add events waiting in the event queue.
2749 *
2750 * Return nothing.
2751 */
2752static void
2753_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
2754 Mpi2EventDataSasTopologyChangeList_t *event_data)
2755{
2756 struct fw_event_work *fw_event;
2757 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
2758 u16 expander_handle;
2759 struct _sas_node *sas_expander;
2760 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302761 int i, reason_code;
2762 u16 handle;
2763
2764 for (i = 0 ; i < event_data->NumEntries; i++) {
2765 if (event_data->PHY[i].PhyStatus &
2766 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
2767 continue;
2768 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2769 if (!handle)
2770 continue;
2771 reason_code = event_data->PHY[i].PhyStatus &
2772 MPI2_EVENT_SAS_TOPO_RC_MASK;
2773 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
2774 _scsih_tm_tr_send(ioc, handle);
2775 }
Eric Moore635374e2009-03-09 01:21:12 -06002776
2777 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
2778 if (expander_handle < ioc->sas_hba.num_phys) {
2779 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2780 return;
2781 }
2782
2783 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
2784 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
2785 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2786 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
2787 expander_handle);
2788 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2789 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
2790 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
2791 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2792
2793 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
2794 return;
2795
2796 /* mark ignore flag for pending events */
2797 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2798 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
2799 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
2800 fw_event->ignore)
2801 continue;
2802 local_event_data = fw_event->event_data;
2803 if (local_event_data->ExpStatus ==
2804 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
2805 local_event_data->ExpStatus ==
2806 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
2807 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
2808 expander_handle) {
2809 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
2810 "setting ignoring flag\n", ioc->name));
2811 fw_event->ignore = 1;
2812 }
2813 }
2814 }
2815 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2816}
2817
2818/**
Eric Moore635374e2009-03-09 01:21:12 -06002819 * _scsih_flush_running_cmds - completing outstanding commands.
2820 * @ioc: per adapter object
2821 *
2822 * The flushing out of all pending scmd commands following host reset,
2823 * where all IO is dropped to the floor.
2824 *
2825 * Return nothing.
2826 */
2827static void
2828_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
2829{
2830 struct scsi_cmnd *scmd;
2831 u16 smid;
2832 u16 count = 0;
2833
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302834 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
2835 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002836 if (!scmd)
2837 continue;
2838 count++;
2839 mpt2sas_base_free_smid(ioc, smid);
2840 scsi_dma_unmap(scmd);
2841 scmd->result = DID_RESET << 16;
2842 scmd->scsi_done(scmd);
2843 }
2844 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
2845 ioc->name, count));
2846}
2847
2848/**
Eric Moore3c621b32009-05-18 12:59:41 -06002849 * _scsih_setup_eedp - setup MPI request for EEDP transfer
2850 * @scmd: pointer to scsi command object
2851 * @mpi_request: pointer to the SCSI_IO reqest message frame
2852 *
2853 * Supporting protection 1 and 3.
2854 *
2855 * Returns nothing
2856 */
2857static void
2858_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
2859{
2860 u16 eedp_flags;
2861 unsigned char prot_op = scsi_get_prot_op(scmd);
2862 unsigned char prot_type = scsi_get_prot_type(scmd);
2863
Eric Moored334aa72010-04-22 10:47:40 -06002864 if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL)
Eric Moore3c621b32009-05-18 12:59:41 -06002865 return;
2866
2867 if (prot_op == SCSI_PROT_READ_STRIP)
2868 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
2869 else if (prot_op == SCSI_PROT_WRITE_INSERT)
2870 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
2871 else
2872 return;
2873
Eric Moore3c621b32009-05-18 12:59:41 -06002874 switch (prot_type) {
2875 case SCSI_PROT_DIF_TYPE1:
2876
2877 /*
2878 * enable ref/guard checking
2879 * auto increment ref tag
2880 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05302881 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
Eric Moore3c621b32009-05-18 12:59:41 -06002882 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2883 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2884 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
2885 cpu_to_be32(scsi_get_lba(scmd));
Eric Moored334aa72010-04-22 10:47:40 -06002886 break;
Eric Moore3c621b32009-05-18 12:59:41 -06002887
Eric Moored334aa72010-04-22 10:47:40 -06002888 case SCSI_PROT_DIF_TYPE2:
2889
2890 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
2891 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2892 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
Eric Moore3c621b32009-05-18 12:59:41 -06002893 break;
2894
2895 case SCSI_PROT_DIF_TYPE3:
2896
2897 /*
2898 * enable guard checking
2899 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05302900 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
Eric Moore3c621b32009-05-18 12:59:41 -06002901 break;
2902 }
Kashyap, Desai463217b2009-10-05 15:53:06 +05302903 mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
2904 mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
Eric Moore3c621b32009-05-18 12:59:41 -06002905}
2906
2907/**
2908 * _scsih_eedp_error_handling - return sense code for EEDP errors
2909 * @scmd: pointer to scsi command object
2910 * @ioc_status: ioc status
2911 *
2912 * Returns nothing
2913 */
2914static void
2915_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
2916{
2917 u8 ascq;
2918 u8 sk;
2919 u8 host_byte;
2920
2921 switch (ioc_status) {
2922 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2923 ascq = 0x01;
2924 break;
2925 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2926 ascq = 0x02;
2927 break;
2928 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2929 ascq = 0x03;
2930 break;
2931 default:
2932 ascq = 0x00;
2933 break;
2934 }
2935
2936 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
2937 sk = ILLEGAL_REQUEST;
2938 host_byte = DID_ABORT;
2939 } else {
2940 sk = ABORTED_COMMAND;
2941 host_byte = DID_OK;
2942 }
2943
2944 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
2945 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
2946 SAM_STAT_CHECK_CONDITION;
2947}
2948
2949/**
Eric Moored5d135b2009-05-18 13:02:08 -06002950 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06002951 * @scmd: pointer to scsi command object
2952 * @done: function pointer to be invoked on completion
2953 *
2954 * The callback index is set inside `ioc->scsi_io_cb_idx`.
2955 *
2956 * Returns 0 on success. If there's a failure, return either:
2957 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
2958 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
2959 */
2960static int
Eric Moored5d135b2009-05-18 13:02:08 -06002961_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06002962{
2963 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2964 struct MPT2SAS_DEVICE *sas_device_priv_data;
2965 struct MPT2SAS_TARGET *sas_target_priv_data;
2966 Mpi2SCSIIORequest_t *mpi_request;
2967 u32 mpi_control;
2968 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06002969
2970 scmd->scsi_done = done;
2971 sas_device_priv_data = scmd->device->hostdata;
Kashyap, Desai130b9582010-04-08 17:54:32 +05302972 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Eric Moore635374e2009-03-09 01:21:12 -06002973 scmd->result = DID_NO_CONNECT << 16;
2974 scmd->scsi_done(scmd);
2975 return 0;
2976 }
2977
2978 sas_target_priv_data = sas_device_priv_data->sas_target;
Kashyap, Desai130b9582010-04-08 17:54:32 +05302979 /* invalid device handle */
2980 if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
Eric Moore635374e2009-03-09 01:21:12 -06002981 scmd->result = DID_NO_CONNECT << 16;
2982 scmd->scsi_done(scmd);
2983 return 0;
2984 }
2985
Kashyap, Desai130b9582010-04-08 17:54:32 +05302986 /* host recovery or link resets sent via IOCTLs */
2987 if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06002988 return SCSI_MLQUEUE_HOST_BUSY;
Kashyap, Desai130b9582010-04-08 17:54:32 +05302989 /* device busy with task managment */
2990 else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
2991 return SCSI_MLQUEUE_DEVICE_BUSY;
2992 /* device has been deleted */
2993 else if (sas_target_priv_data->deleted) {
2994 scmd->result = DID_NO_CONNECT << 16;
2995 scmd->scsi_done(scmd);
2996 return 0;
2997 }
Eric Moore635374e2009-03-09 01:21:12 -06002998
2999 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
3000 mpi_control = MPI2_SCSIIO_CONTROL_READ;
3001 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
3002 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
3003 else
3004 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
3005
3006 /* set tags */
3007 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
3008 if (scmd->device->tagged_supported) {
3009 if (scmd->device->ordered_tags)
3010 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
3011 else
3012 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
3013 } else
3014/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
3015/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
3016 */
3017 mpi_control |= (0x500);
3018
3019 } else
3020 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
Kashyap, Desai3ed21522010-02-17 16:08:36 +05303021 /* Make sure Device is not raid volume */
3022 if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
Eric Moored334aa72010-04-22 10:47:40 -06003023 sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
Eric Moore635374e2009-03-09 01:21:12 -06003024 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
3025
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303026 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06003027 if (!smid) {
3028 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
3029 ioc->name, __func__);
3030 goto out;
3031 }
3032 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3033 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06003034 _scsih_setup_eedp(scmd, mpi_request);
Eric Moored334aa72010-04-22 10:47:40 -06003035 if (scmd->cmd_len == 32)
3036 mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
Eric Moore635374e2009-03-09 01:21:12 -06003037 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3038 if (sas_device_priv_data->sas_target->flags &
3039 MPT_TARGET_FLAGS_RAID_COMPONENT)
3040 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3041 else
3042 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3043 mpi_request->DevHandle =
3044 cpu_to_le16(sas_device_priv_data->sas_target->handle);
3045 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
3046 mpi_request->Control = cpu_to_le32(mpi_control);
3047 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
3048 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
3049 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
3050 mpi_request->SenseBufferLowAddress =
Kashyap, Desaiec9472c2009-09-23 17:34:13 +05303051 mpt2sas_base_get_sense_buffer_dma(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003052 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
3053 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
3054 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303055 mpi_request->VF_ID = 0; /* TODO */
3056 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003057 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
3058 mpi_request->LUN);
3059 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
3060
3061 if (!mpi_request->DataLength) {
3062 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
3063 } else {
3064 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
3065 mpt2sas_base_free_smid(ioc, smid);
3066 goto out;
3067 }
3068 }
3069
Kashyap, Desai58287fd2010-03-17 16:27:25 +05303070 if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST))
3071 mpt2sas_base_put_smid_scsi_io(ioc, smid,
3072 sas_device_priv_data->sas_target->handle);
3073 else
3074 mpt2sas_base_put_smid_default(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003075 return 0;
3076
3077 out:
3078 return SCSI_MLQUEUE_HOST_BUSY;
3079}
3080
3081/**
3082 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
3083 * @sense_buffer: sense data returned by target
3084 * @data: normalized skey/asc/ascq
3085 *
3086 * Return nothing.
3087 */
3088static void
3089_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
3090{
3091 if ((sense_buffer[0] & 0x7F) >= 0x72) {
3092 /* descriptor format */
3093 data->skey = sense_buffer[1] & 0x0F;
3094 data->asc = sense_buffer[2];
3095 data->ascq = sense_buffer[3];
3096 } else {
3097 /* fixed format */
3098 data->skey = sense_buffer[2] & 0x0F;
3099 data->asc = sense_buffer[12];
3100 data->ascq = sense_buffer[13];
3101 }
3102}
3103
3104#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3105/**
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02003106 * _scsih_scsi_ioc_info - translated non-successfull SCSI_IO request
Eric Moore635374e2009-03-09 01:21:12 -06003107 * @ioc: per adapter object
3108 * @scmd: pointer to scsi command object
3109 * @mpi_reply: reply mf payload returned from firmware
3110 *
3111 * scsi_status - SCSI Status code returned from target device
3112 * scsi_state - state info associated with SCSI_IO determined by ioc
3113 * ioc_status - ioc supplied status info
3114 *
3115 * Return nothing.
3116 */
3117static void
3118_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
3119 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
3120{
3121 u32 response_info;
3122 u8 *response_bytes;
3123 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
3124 MPI2_IOCSTATUS_MASK;
3125 u8 scsi_state = mpi_reply->SCSIState;
3126 u8 scsi_status = mpi_reply->SCSIStatus;
3127 char *desc_ioc_state = NULL;
3128 char *desc_scsi_status = NULL;
3129 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303130 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3131
3132 if (log_info == 0x31170000)
3133 return;
Eric Moore635374e2009-03-09 01:21:12 -06003134
3135 switch (ioc_status) {
3136 case MPI2_IOCSTATUS_SUCCESS:
3137 desc_ioc_state = "success";
3138 break;
3139 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3140 desc_ioc_state = "invalid function";
3141 break;
3142 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3143 desc_ioc_state = "scsi recovered error";
3144 break;
3145 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
3146 desc_ioc_state = "scsi invalid dev handle";
3147 break;
3148 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3149 desc_ioc_state = "scsi device not there";
3150 break;
3151 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3152 desc_ioc_state = "scsi data overrun";
3153 break;
3154 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3155 desc_ioc_state = "scsi data underrun";
3156 break;
3157 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3158 desc_ioc_state = "scsi io data error";
3159 break;
3160 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3161 desc_ioc_state = "scsi protocol error";
3162 break;
3163 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3164 desc_ioc_state = "scsi task terminated";
3165 break;
3166 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3167 desc_ioc_state = "scsi residual mismatch";
3168 break;
3169 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3170 desc_ioc_state = "scsi task mgmt failed";
3171 break;
3172 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3173 desc_ioc_state = "scsi ioc terminated";
3174 break;
3175 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3176 desc_ioc_state = "scsi ext terminated";
3177 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003178 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3179 desc_ioc_state = "eedp guard error";
3180 break;
3181 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3182 desc_ioc_state = "eedp ref tag error";
3183 break;
3184 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3185 desc_ioc_state = "eedp app tag error";
3186 break;
Eric Moore635374e2009-03-09 01:21:12 -06003187 default:
3188 desc_ioc_state = "unknown";
3189 break;
3190 }
3191
3192 switch (scsi_status) {
3193 case MPI2_SCSI_STATUS_GOOD:
3194 desc_scsi_status = "good";
3195 break;
3196 case MPI2_SCSI_STATUS_CHECK_CONDITION:
3197 desc_scsi_status = "check condition";
3198 break;
3199 case MPI2_SCSI_STATUS_CONDITION_MET:
3200 desc_scsi_status = "condition met";
3201 break;
3202 case MPI2_SCSI_STATUS_BUSY:
3203 desc_scsi_status = "busy";
3204 break;
3205 case MPI2_SCSI_STATUS_INTERMEDIATE:
3206 desc_scsi_status = "intermediate";
3207 break;
3208 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
3209 desc_scsi_status = "intermediate condmet";
3210 break;
3211 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
3212 desc_scsi_status = "reservation conflict";
3213 break;
3214 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
3215 desc_scsi_status = "command terminated";
3216 break;
3217 case MPI2_SCSI_STATUS_TASK_SET_FULL:
3218 desc_scsi_status = "task set full";
3219 break;
3220 case MPI2_SCSI_STATUS_ACA_ACTIVE:
3221 desc_scsi_status = "aca active";
3222 break;
3223 case MPI2_SCSI_STATUS_TASK_ABORTED:
3224 desc_scsi_status = "task aborted";
3225 break;
3226 default:
3227 desc_scsi_status = "unknown";
3228 break;
3229 }
3230
3231 desc_scsi_state[0] = '\0';
3232 if (!scsi_state)
3233 desc_scsi_state = " ";
3234 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3235 strcat(desc_scsi_state, "response info ");
3236 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3237 strcat(desc_scsi_state, "state terminated ");
3238 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
3239 strcat(desc_scsi_state, "no status ");
3240 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
3241 strcat(desc_scsi_state, "autosense failed ");
3242 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
3243 strcat(desc_scsi_state, "autosense valid ");
3244
3245 scsi_print_command(scmd);
3246 printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
3247 "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
3248 le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
3249 ioc_status, smid);
3250 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
3251 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
3252 scsi_get_resid(scmd));
3253 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
3254 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
3255 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
3256 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
3257 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
3258 scsi_status, desc_scsi_state, scsi_state);
3259
3260 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3261 struct sense_info data;
3262 _scsih_normalize_sense(scmd->sense_buffer, &data);
3263 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
Kashyap, Desaie94f6742010-03-17 16:24:52 +05303264 "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey,
3265 data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));
Eric Moore635374e2009-03-09 01:21:12 -06003266 }
3267
3268 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
3269 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
3270 response_bytes = (u8 *)&response_info;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303271 _scsih_response_code(ioc, response_bytes[0]);
Eric Moore635374e2009-03-09 01:21:12 -06003272 }
3273}
3274#endif
3275
3276/**
3277 * _scsih_smart_predicted_fault - illuminate Fault LED
3278 * @ioc: per adapter object
3279 * @handle: device handle
3280 *
3281 * Return nothing.
3282 */
3283static void
3284_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3285{
3286 Mpi2SepReply_t mpi_reply;
3287 Mpi2SepRequest_t mpi_request;
3288 struct scsi_target *starget;
3289 struct MPT2SAS_TARGET *sas_target_priv_data;
3290 Mpi2EventNotificationReply_t *event_reply;
3291 Mpi2EventDataSasDeviceStatusChange_t *event_data;
3292 struct _sas_device *sas_device;
3293 ssize_t sz;
3294 unsigned long flags;
3295
3296 /* only handle non-raid devices */
3297 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3298 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3299 if (!sas_device) {
3300 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3301 return;
3302 }
3303 starget = sas_device->starget;
3304 sas_target_priv_data = starget->hostdata;
3305
3306 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
3307 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
3308 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3309 return;
3310 }
3311 starget_printk(KERN_WARNING, starget, "predicted fault\n");
3312 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3313
3314 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
3315 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
3316 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
3317 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
3318 mpi_request.SlotStatus =
Kashyap, Desaie94f6742010-03-17 16:24:52 +05303319 cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
Eric Moore635374e2009-03-09 01:21:12 -06003320 mpi_request.DevHandle = cpu_to_le16(handle);
3321 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
3322 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
3323 &mpi_request)) != 0) {
3324 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3325 ioc->name, __FILE__, __LINE__, __func__);
3326 return;
3327 }
3328
3329 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
3330 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3331 "enclosure_processor: ioc_status (0x%04x), "
3332 "loginfo(0x%08x)\n", ioc->name,
3333 le16_to_cpu(mpi_reply.IOCStatus),
3334 le32_to_cpu(mpi_reply.IOCLogInfo)));
3335 return;
3336 }
3337 }
3338
3339 /* insert into event log */
3340 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
3341 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
3342 event_reply = kzalloc(sz, GFP_KERNEL);
3343 if (!event_reply) {
3344 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3345 ioc->name, __FILE__, __LINE__, __func__);
3346 return;
3347 }
3348
3349 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
3350 event_reply->Event =
3351 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
3352 event_reply->MsgLength = sz/4;
3353 event_reply->EventDataLength =
3354 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
3355 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
3356 event_reply->EventData;
3357 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
3358 event_data->ASC = 0x5D;
3359 event_data->DevHandle = cpu_to_le16(handle);
3360 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
3361 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
3362 kfree(event_reply);
3363}
3364
3365/**
Eric Moored5d135b2009-05-18 13:02:08 -06003366 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06003367 * @ioc: per adapter object
3368 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303369 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06003370 * @reply: reply message frame(lower 32bit addr)
3371 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303372 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06003373 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303374 * Return 1 meaning mf should be freed from _base_interrupt
3375 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06003376 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303377static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303378_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06003379{
3380 Mpi2SCSIIORequest_t *mpi_request;
3381 Mpi2SCSIIOReply_t *mpi_reply;
3382 struct scsi_cmnd *scmd;
3383 u16 ioc_status;
3384 u32 xfer_cnt;
3385 u8 scsi_state;
3386 u8 scsi_status;
3387 u32 log_info;
3388 struct MPT2SAS_DEVICE *sas_device_priv_data;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303389 u32 response_code = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003390
3391 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303392 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003393 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303394 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003395
3396 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3397
3398 if (mpi_reply == NULL) {
3399 scmd->result = DID_OK << 16;
3400 goto out;
3401 }
3402
3403 sas_device_priv_data = scmd->device->hostdata;
3404 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
3405 sas_device_priv_data->sas_target->deleted) {
3406 scmd->result = DID_NO_CONNECT << 16;
3407 goto out;
3408 }
3409
3410 /* turning off TLR */
Kashyap, Desai9982f592009-09-23 17:23:07 +05303411 scsi_state = mpi_reply->SCSIState;
3412 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3413 response_code =
3414 le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
Eric Moore635374e2009-03-09 01:21:12 -06003415 if (!sas_device_priv_data->tlr_snoop_check) {
3416 sas_device_priv_data->tlr_snoop_check++;
Kashyap, Desai3ed21522010-02-17 16:08:36 +05303417 if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
3418 sas_is_tlr_enabled(scmd->device) &&
Kashyap, Desai84f0b042009-12-16 18:56:28 +05303419 response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
3420 sas_disable_tlr(scmd->device);
3421 sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
3422 }
Eric Moore635374e2009-03-09 01:21:12 -06003423 }
3424
3425 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
3426 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
3427 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
3428 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
3429 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3430 else
3431 log_info = 0;
3432 ioc_status &= MPI2_IOCSTATUS_MASK;
Eric Moore635374e2009-03-09 01:21:12 -06003433 scsi_status = mpi_reply->SCSIStatus;
3434
3435 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
3436 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
3437 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
3438 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
3439 ioc_status = MPI2_IOCSTATUS_SUCCESS;
3440 }
3441
3442 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3443 struct sense_info data;
3444 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
3445 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06003446 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06003447 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06003448 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06003449 _scsih_normalize_sense(scmd->sense_buffer, &data);
3450 /* failure prediction threshold exceeded */
3451 if (data.asc == 0x5D)
3452 _scsih_smart_predicted_fault(ioc,
3453 le16_to_cpu(mpi_reply->DevHandle));
3454 }
3455
3456 switch (ioc_status) {
3457 case MPI2_IOCSTATUS_BUSY:
3458 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3459 scmd->result = SAM_STAT_BUSY;
3460 break;
3461
3462 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3463 scmd->result = DID_NO_CONNECT << 16;
3464 break;
3465
3466 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3467 if (sas_device_priv_data->block) {
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05303468 scmd->result = DID_TRANSPORT_DISRUPTED << 16;
3469 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003470 }
Eric Moore635374e2009-03-09 01:21:12 -06003471 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3472 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3473 scmd->result = DID_RESET << 16;
3474 break;
3475
3476 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3477 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3478 scmd->result = DID_SOFT_ERROR << 16;
3479 else
3480 scmd->result = (DID_OK << 16) | scsi_status;
3481 break;
3482
3483 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3484 scmd->result = (DID_OK << 16) | scsi_status;
3485
3486 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3487 break;
3488
3489 if (xfer_cnt < scmd->underflow) {
3490 if (scsi_status == SAM_STAT_BUSY)
3491 scmd->result = SAM_STAT_BUSY;
3492 else
3493 scmd->result = DID_SOFT_ERROR << 16;
3494 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3495 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3496 scmd->result = DID_SOFT_ERROR << 16;
3497 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3498 scmd->result = DID_RESET << 16;
3499 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3500 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3501 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3502 scmd->result = (DRIVER_SENSE << 24) |
3503 SAM_STAT_CHECK_CONDITION;
3504 scmd->sense_buffer[0] = 0x70;
3505 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3506 scmd->sense_buffer[12] = 0x20;
3507 scmd->sense_buffer[13] = 0;
3508 }
3509 break;
3510
3511 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3512 scsi_set_resid(scmd, 0);
3513 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3514 case MPI2_IOCSTATUS_SUCCESS:
3515 scmd->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303516 if (response_code ==
3517 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
3518 (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3519 MPI2_SCSI_STATE_NO_SCSI_STATUS)))
Eric Moore635374e2009-03-09 01:21:12 -06003520 scmd->result = DID_SOFT_ERROR << 16;
3521 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3522 scmd->result = DID_RESET << 16;
3523 break;
3524
Eric Moore3c621b32009-05-18 12:59:41 -06003525 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3526 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3527 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3528 _scsih_eedp_error_handling(scmd, ioc_status);
3529 break;
Eric Moore635374e2009-03-09 01:21:12 -06003530 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3531 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3532 case MPI2_IOCSTATUS_INVALID_SGL:
3533 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3534 case MPI2_IOCSTATUS_INVALID_FIELD:
3535 case MPI2_IOCSTATUS_INVALID_STATE:
3536 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3537 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3538 default:
3539 scmd->result = DID_SOFT_ERROR << 16;
3540 break;
3541
3542 }
3543
3544#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3545 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3546 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3547#endif
3548
3549 out:
3550 scsi_dma_unmap(scmd);
3551 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303552 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003553}
3554
3555/**
Eric Moore635374e2009-03-09 01:21:12 -06003556 * _scsih_sas_host_refresh - refreshing sas host object contents
3557 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06003558 * Context: user
3559 *
3560 * During port enable, fw will send topology events for every device. Its
3561 * possible that the handles may change from the previous setting, so this
3562 * code keeping handles updating if changed.
3563 *
3564 * Return nothing.
3565 */
3566static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303567_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06003568{
3569 u16 sz;
3570 u16 ioc_status;
3571 int i;
3572 Mpi2ConfigReply_t mpi_reply;
3573 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303574 u16 attached_handle;
Eric Moore635374e2009-03-09 01:21:12 -06003575
3576 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3577 "updating handles for sas_host(0x%016llx)\n",
3578 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3579
3580 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3581 * sizeof(Mpi2SasIOUnit0PhyData_t));
3582 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3583 if (!sas_iounit_pg0) {
3584 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3585 ioc->name, __FILE__, __LINE__, __func__);
3586 return;
3587 }
Eric Moore635374e2009-03-09 01:21:12 -06003588
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303589 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3590 sas_iounit_pg0, sz)) != 0)
3591 goto out;
3592 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
3593 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3594 goto out;
3595 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3596 if (i == 0)
3597 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3598 PhyData[0].ControllerDevHandle);
3599 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
3600 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
3601 AttachedDevHandle);
3602 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
3603 attached_handle, i, sas_iounit_pg0->PhyData[i].
3604 NegotiatedLinkRate >> 4);
3605 }
Eric Moore635374e2009-03-09 01:21:12 -06003606 out:
3607 kfree(sas_iounit_pg0);
3608}
3609
3610/**
3611 * _scsih_sas_host_add - create sas host object
3612 * @ioc: per adapter object
3613 *
3614 * Creating host side data object, stored in ioc->sas_hba
3615 *
3616 * Return nothing.
3617 */
3618static void
3619_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3620{
3621 int i;
3622 Mpi2ConfigReply_t mpi_reply;
3623 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3624 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3625 Mpi2SasPhyPage0_t phy_pg0;
3626 Mpi2SasDevicePage0_t sas_device_pg0;
3627 Mpi2SasEnclosurePage0_t enclosure_pg0;
3628 u16 ioc_status;
3629 u16 sz;
3630 u16 device_missing_delay;
3631
3632 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3633 if (!ioc->sas_hba.num_phys) {
3634 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3635 ioc->name, __FILE__, __LINE__, __func__);
3636 return;
3637 }
3638
3639 /* sas_iounit page 0 */
3640 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3641 sizeof(Mpi2SasIOUnit0PhyData_t));
3642 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3643 if (!sas_iounit_pg0) {
3644 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3645 ioc->name, __FILE__, __LINE__, __func__);
3646 return;
3647 }
3648 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3649 sas_iounit_pg0, sz))) {
3650 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3651 ioc->name, __FILE__, __LINE__, __func__);
3652 goto out;
3653 }
3654 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3655 MPI2_IOCSTATUS_MASK;
3656 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3657 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3658 ioc->name, __FILE__, __LINE__, __func__);
3659 goto out;
3660 }
3661
3662 /* sas_iounit page 1 */
3663 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3664 sizeof(Mpi2SasIOUnit1PhyData_t));
3665 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3666 if (!sas_iounit_pg1) {
3667 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3668 ioc->name, __FILE__, __LINE__, __func__);
3669 goto out;
3670 }
3671 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3672 sas_iounit_pg1, sz))) {
3673 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3674 ioc->name, __FILE__, __LINE__, __func__);
3675 goto out;
3676 }
3677 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3678 MPI2_IOCSTATUS_MASK;
3679 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3680 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3681 ioc->name, __FILE__, __LINE__, __func__);
3682 goto out;
3683 }
3684
3685 ioc->io_missing_delay =
3686 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3687 device_missing_delay =
3688 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3689 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3690 ioc->device_missing_delay = (device_missing_delay &
3691 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3692 else
3693 ioc->device_missing_delay = device_missing_delay &
3694 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3695
3696 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3697 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3698 sizeof(struct _sas_phy), GFP_KERNEL);
3699 if (!ioc->sas_hba.phy) {
3700 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3701 ioc->name, __FILE__, __LINE__, __func__);
3702 goto out;
3703 }
3704 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3705 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3706 i))) {
3707 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3708 ioc->name, __FILE__, __LINE__, __func__);
3709 goto out;
3710 }
3711 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3712 MPI2_IOCSTATUS_MASK;
3713 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3714 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3715 ioc->name, __FILE__, __LINE__, __func__);
3716 goto out;
3717 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303718
3719 if (i == 0)
3720 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3721 PhyData[0].ControllerDevHandle);
3722 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06003723 ioc->sas_hba.phy[i].phy_id = i;
3724 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3725 phy_pg0, ioc->sas_hba.parent_dev);
3726 }
3727 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303728 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06003729 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3730 ioc->name, __FILE__, __LINE__, __func__);
3731 goto out;
3732 }
Eric Moore635374e2009-03-09 01:21:12 -06003733 ioc->sas_hba.enclosure_handle =
3734 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3735 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3736 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3737 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3738 (unsigned long long) ioc->sas_hba.sas_address,
3739 ioc->sas_hba.num_phys) ;
3740
3741 if (ioc->sas_hba.enclosure_handle) {
3742 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3743 &enclosure_pg0,
3744 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3745 ioc->sas_hba.enclosure_handle))) {
3746 ioc->sas_hba.enclosure_logical_id =
3747 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3748 }
3749 }
3750
3751 out:
3752 kfree(sas_iounit_pg1);
3753 kfree(sas_iounit_pg0);
3754}
3755
3756/**
3757 * _scsih_expander_add - creating expander object
3758 * @ioc: per adapter object
3759 * @handle: expander handle
3760 *
3761 * Creating expander object, stored in ioc->sas_expander_list.
3762 *
3763 * Return 0 for success, else error.
3764 */
3765static int
3766_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3767{
3768 struct _sas_node *sas_expander;
3769 Mpi2ConfigReply_t mpi_reply;
3770 Mpi2ExpanderPage0_t expander_pg0;
3771 Mpi2ExpanderPage1_t expander_pg1;
3772 Mpi2SasEnclosurePage0_t enclosure_pg0;
3773 u32 ioc_status;
3774 u16 parent_handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303775 __le64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003776 int i;
3777 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303778 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003779 int rc = 0;
3780
3781 if (!handle)
3782 return -1;
3783
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303784 if (ioc->shost_recovery)
3785 return -1;
3786
Eric Moore635374e2009-03-09 01:21:12 -06003787 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3788 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3789 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3790 ioc->name, __FILE__, __LINE__, __func__);
3791 return -1;
3792 }
3793
3794 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3795 MPI2_IOCSTATUS_MASK;
3796 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3797 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3798 ioc->name, __FILE__, __LINE__, __func__);
3799 return -1;
3800 }
3801
3802 /* handle out of order topology events */
3803 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303804 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
3805 != 0) {
3806 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3807 ioc->name, __FILE__, __LINE__, __func__);
3808 return -1;
3809 }
3810 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06003811 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303812 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3813 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003814 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3815 if (!sas_expander) {
3816 rc = _scsih_expander_add(ioc, parent_handle);
3817 if (rc != 0)
3818 return rc;
3819 }
3820 }
3821
Eric Moore635374e2009-03-09 01:21:12 -06003822 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303823 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06003824 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3825 sas_address);
3826 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3827
3828 if (sas_expander)
3829 return 0;
3830
3831 sas_expander = kzalloc(sizeof(struct _sas_node),
3832 GFP_KERNEL);
3833 if (!sas_expander) {
3834 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3835 ioc->name, __FILE__, __LINE__, __func__);
3836 return -1;
3837 }
3838
3839 sas_expander->handle = handle;
3840 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303841 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06003842 sas_expander->sas_address = sas_address;
3843
3844 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3845 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303846 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06003847 sas_expander->sas_address, sas_expander->num_phys);
3848
3849 if (!sas_expander->num_phys)
3850 goto out_fail;
3851 sas_expander->phy = kcalloc(sas_expander->num_phys,
3852 sizeof(struct _sas_phy), GFP_KERNEL);
3853 if (!sas_expander->phy) {
3854 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3855 ioc->name, __FILE__, __LINE__, __func__);
3856 rc = -1;
3857 goto out_fail;
3858 }
3859
3860 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3861 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303862 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003863 if (!mpt2sas_port) {
3864 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3865 ioc->name, __FILE__, __LINE__, __func__);
3866 rc = -1;
3867 goto out_fail;
3868 }
3869 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3870
3871 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3872 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3873 &expander_pg1, i, handle))) {
3874 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3875 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303876 rc = -1;
3877 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003878 }
3879 sas_expander->phy[i].handle = handle;
3880 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303881
3882 if ((mpt2sas_transport_add_expander_phy(ioc,
3883 &sas_expander->phy[i], expander_pg1,
3884 sas_expander->parent_dev))) {
3885 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3886 ioc->name, __FILE__, __LINE__, __func__);
3887 rc = -1;
3888 goto out_fail;
3889 }
Eric Moore635374e2009-03-09 01:21:12 -06003890 }
3891
3892 if (sas_expander->enclosure_handle) {
3893 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3894 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3895 sas_expander->enclosure_handle))) {
3896 sas_expander->enclosure_logical_id =
3897 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3898 }
3899 }
3900
3901 _scsih_expander_node_add(ioc, sas_expander);
3902 return 0;
3903
3904 out_fail:
3905
Kashyap, Desai20f58952009-08-07 19:34:26 +05303906 if (mpt2sas_port)
3907 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303908 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003909 kfree(sas_expander);
3910 return rc;
3911}
3912
3913/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05303914 * _scsih_done - scsih callback handler.
3915 * @ioc: per adapter object
3916 * @smid: system request message index
3917 * @msix_index: MSIX table index supplied by the OS
3918 * @reply: reply message frame(lower 32bit addr)
3919 *
3920 * Callback handler when sending internal generated message frames.
3921 * The callback index passed is `ioc->scsih_cb_idx`
3922 *
3923 * Return 1 meaning mf should be freed from _base_interrupt
3924 * 0 means the mf is freed from this function.
3925 */
3926static u8
3927_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
3928{
3929 MPI2DefaultReply_t *mpi_reply;
3930
3931 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
3932 if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
3933 return 1;
3934 if (ioc->scsih_cmds.smid != smid)
3935 return 1;
3936 ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
3937 if (mpi_reply) {
3938 memcpy(ioc->scsih_cmds.reply, mpi_reply,
3939 mpi_reply->MsgLength*4);
3940 ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
3941 }
3942 ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
3943 complete(&ioc->scsih_cmds.done);
3944 return 1;
3945}
3946
3947/**
Eric Moore635374e2009-03-09 01:21:12 -06003948 * _scsih_expander_remove - removing expander object
3949 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303950 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06003951 *
3952 * Return nothing.
3953 */
3954static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303955_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06003956{
3957 struct _sas_node *sas_expander;
3958 unsigned long flags;
3959
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303960 if (ioc->shost_recovery)
3961 return;
3962
Eric Moore635374e2009-03-09 01:21:12 -06003963 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303964 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3965 sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06003966 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3967 _scsih_expander_node_remove(ioc, sas_expander);
3968}
3969
3970/**
Kashyap, Desaib4344272010-03-17 16:24:14 +05303971 * _scsih_check_access_status - check access flags
3972 * @ioc: per adapter object
3973 * @sas_address: sas address
3974 * @handle: sas device handle
3975 * @access_flags: errors returned during discovery of the device
3976 *
3977 * Return 0 for success, else failure
3978 */
3979static u8
3980_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
3981 u16 handle, u8 access_status)
3982{
3983 u8 rc = 1;
3984 char *desc = NULL;
3985
3986 switch (access_status) {
3987 case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS:
3988 case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION:
3989 rc = 0;
3990 break;
3991 case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED:
3992 desc = "sata capability failed";
3993 break;
3994 case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT:
3995 desc = "sata affiliation conflict";
3996 break;
3997 case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE:
3998 desc = "route not addressable";
3999 break;
4000 case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE:
4001 desc = "smp error not addressable";
4002 break;
4003 case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED:
4004 desc = "device blocked";
4005 break;
4006 case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED:
4007 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN:
4008 case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT:
4009 case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG:
4010 case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION:
4011 case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER:
4012 case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN:
4013 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN:
4014 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN:
4015 case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION:
4016 case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE:
4017 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX:
4018 desc = "sata initialization failed";
4019 break;
4020 default:
4021 desc = "unknown";
4022 break;
4023 }
4024
4025 if (!rc)
4026 return 0;
4027
4028 printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), "
4029 "handle(0x%04x)\n", ioc->name, desc,
4030 (unsigned long long)sas_address, handle);
4031 return rc;
4032}
4033
4034static void
4035_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4036{
4037 Mpi2ConfigReply_t mpi_reply;
4038 Mpi2SasDevicePage0_t sas_device_pg0;
4039 struct _sas_device *sas_device;
4040 u32 ioc_status;
4041 unsigned long flags;
4042 u64 sas_address;
4043 struct scsi_target *starget;
4044 struct MPT2SAS_TARGET *sas_target_priv_data;
4045 u32 device_info;
4046
4047 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4048 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
4049 return;
4050
4051 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
4052 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
4053 return;
4054
4055 /* check if this is end device */
4056 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4057 if (!(_scsih_is_end_device(device_info)))
4058 return;
4059
4060 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4061 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4062 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4063 sas_address);
4064
4065 if (!sas_device) {
4066 printk(MPT2SAS_ERR_FMT "device is not present "
4067 "handle(0x%04x), no sas_device!!!\n", ioc->name, handle);
4068 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4069 return;
4070 }
4071
4072 if (unlikely(sas_device->handle != handle)) {
4073 starget = sas_device->starget;
4074 sas_target_priv_data = starget->hostdata;
4075 starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)"
4076 " to (0x%04x)!!!\n", sas_device->handle, handle);
4077 sas_target_priv_data->handle = handle;
4078 sas_device->handle = handle;
4079 }
4080 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4081
4082 /* check if device is present */
4083 if (!(le16_to_cpu(sas_device_pg0.Flags) &
4084 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
4085 printk(MPT2SAS_ERR_FMT "device is not present "
4086 "handle(0x%04x), flags!!!\n", ioc->name, handle);
4087 return;
4088 }
4089
4090 /* check if there were any issues with discovery */
4091 if (_scsih_check_access_status(ioc, sas_address, handle,
4092 sas_device_pg0.AccessStatus))
4093 return;
4094 _scsih_ublock_io_device(ioc, handle);
4095
4096}
4097
4098/**
Eric Moore635374e2009-03-09 01:21:12 -06004099 * _scsih_add_device - creating sas device object
4100 * @ioc: per adapter object
4101 * @handle: sas device handle
4102 * @phy_num: phy number end device attached to
4103 * @is_pd: is this hidden raid component
4104 *
4105 * Creating end device object, stored in ioc->sas_device_list.
4106 *
4107 * Returns 0 for success, non-zero for failure.
4108 */
4109static int
4110_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
4111{
4112 Mpi2ConfigReply_t mpi_reply;
4113 Mpi2SasDevicePage0_t sas_device_pg0;
4114 Mpi2SasEnclosurePage0_t enclosure_pg0;
4115 struct _sas_device *sas_device;
4116 u32 ioc_status;
4117 __le64 sas_address;
4118 u32 device_info;
4119 unsigned long flags;
4120
4121 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4122 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4123 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4124 ioc->name, __FILE__, __LINE__, __func__);
4125 return -1;
4126 }
4127
4128 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4129 MPI2_IOCSTATUS_MASK;
4130 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4131 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4132 ioc->name, __FILE__, __LINE__, __func__);
4133 return -1;
4134 }
4135
Kashyap, Desaib4344272010-03-17 16:24:14 +05304136 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4137
Eric Moore635374e2009-03-09 01:21:12 -06004138 /* check if device is present */
4139 if (!(le16_to_cpu(sas_device_pg0.Flags) &
4140 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
4141 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4142 ioc->name, __FILE__, __LINE__, __func__);
4143 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
4144 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
4145 return -1;
4146 }
4147
Kashyap, Desaib4344272010-03-17 16:24:14 +05304148 /* check if there were any issues with discovery */
4149 if (_scsih_check_access_status(ioc, sas_address, handle,
4150 sas_device_pg0.AccessStatus))
Eric Moore635374e2009-03-09 01:21:12 -06004151 return -1;
Eric Moore635374e2009-03-09 01:21:12 -06004152
4153 /* check if this is end device */
4154 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4155 if (!(_scsih_is_end_device(device_info))) {
4156 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4157 ioc->name, __FILE__, __LINE__, __func__);
4158 return -1;
4159 }
4160
Eric Moore635374e2009-03-09 01:21:12 -06004161
4162 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4163 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4164 sas_address);
4165 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4166
Kashyap, Desaib4344272010-03-17 16:24:14 +05304167 if (sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06004168 return 0;
Eric Moore635374e2009-03-09 01:21:12 -06004169
4170 sas_device = kzalloc(sizeof(struct _sas_device),
4171 GFP_KERNEL);
4172 if (!sas_device) {
4173 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4174 ioc->name, __FILE__, __LINE__, __func__);
4175 return -1;
4176 }
4177
4178 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304179 if (_scsih_get_sas_address(ioc, le16_to_cpu
4180 (sas_device_pg0.ParentDevHandle),
4181 &sas_device->sas_address_parent) != 0)
4182 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4183 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06004184 sas_device->enclosure_handle =
4185 le16_to_cpu(sas_device_pg0.EnclosureHandle);
4186 sas_device->slot =
4187 le16_to_cpu(sas_device_pg0.Slot);
4188 sas_device->device_info = device_info;
4189 sas_device->sas_address = sas_address;
4190 sas_device->hidden_raid_component = is_pd;
4191
4192 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05304193 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
4194 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4195 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06004196 sas_device->enclosure_logical_id =
4197 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06004198
4199 /* get device name */
4200 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
4201
4202 if (ioc->wait_for_port_enable_to_complete)
4203 _scsih_sas_device_init_add(ioc, sas_device);
4204 else
4205 _scsih_sas_device_add(ioc, sas_device);
4206
4207 return 0;
4208}
4209
4210/**
Kashyap, Desai1278b112010-03-09 17:34:13 +05304211 * _scsih_remove_pd_device - removing sas device pd object
Eric Moore635374e2009-03-09 01:21:12 -06004212 * @ioc: per adapter object
Kashyap, Desai1278b112010-03-09 17:34:13 +05304213 * @sas_device_delete: the sas_device object
Eric Moore635374e2009-03-09 01:21:12 -06004214 *
Kashyap, Desai1278b112010-03-09 17:34:13 +05304215 * For hidden raid components, we do driver-fw handshake from
4216 * hotplug work threads.
Eric Moore635374e2009-03-09 01:21:12 -06004217 * Return nothing.
4218 */
4219static void
Kashyap, Desai1278b112010-03-09 17:34:13 +05304220_scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
4221 sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06004222{
Eric Moore635374e2009-03-09 01:21:12 -06004223 Mpi2SasIoUnitControlReply_t mpi_reply;
4224 Mpi2SasIoUnitControlRequest_t mpi_request;
Kashyap, Desai1278b112010-03-09 17:34:13 +05304225 u16 vol_handle, handle;
Eric Moore635374e2009-03-09 01:21:12 -06004226
Kashyap, Desai1278b112010-03-09 17:34:13 +05304227 handle = sas_device.handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304228 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
4229 " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
Kashyap, Desai1278b112010-03-09 17:34:13 +05304230 (unsigned long long) sas_device.sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06004231
Kashyap, Desai1278b112010-03-09 17:34:13 +05304232 vol_handle = sas_device.volume_handle;
4233 if (!vol_handle)
4234 return;
4235 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
4236 "handle(0x%04x)\n", ioc->name, vol_handle));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05304237 mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0,
4238 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL);
Kashyap, Desai1278b112010-03-09 17:34:13 +05304239 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
4240 "done: handle(0x%04x)\n", ioc->name, vol_handle));
4241 if (ioc->shost_recovery)
4242 return;
Eric Moore635374e2009-03-09 01:21:12 -06004243
4244 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
4245 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
4246 "(0x%04x)\n", ioc->name, handle));
4247 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
4248 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
4249 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
Kashyap, Desai1278b112010-03-09 17:34:13 +05304250 mpi_request.DevHandle = cpu_to_le16(handle);
Eric Moore635374e2009-03-09 01:21:12 -06004251 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
Kashyap, Desai1278b112010-03-09 17:34:13 +05304252 &mpi_request)) != 0)
Eric Moore635374e2009-03-09 01:21:12 -06004253 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4254 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06004255
4256 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
4257 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
4258 le16_to_cpu(mpi_reply.IOCStatus),
4259 le32_to_cpu(mpi_reply.IOCLogInfo)));
4260
Kashyap, Desai1278b112010-03-09 17:34:13 +05304261 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x),"
4262 " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
4263 (unsigned long long) sas_device.sas_address));
4264}
Kashyap, Desai34a03be2009-08-20 13:23:19 +05304265
Kashyap, Desai1278b112010-03-09 17:34:13 +05304266/**
4267 * _scsih_remove_device - removing sas device object
4268 * @ioc: per adapter object
4269 * @sas_device_delete: the sas_device object
4270 *
4271 * Return nothing.
4272 */
4273static void
4274_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
4275 struct _sas_device *sas_device)
4276{
4277 struct _sas_device sas_device_backup;
4278 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05304279
Kashyap, Desai1278b112010-03-09 17:34:13 +05304280 if (!sas_device)
4281 return;
Eric Moore635374e2009-03-09 01:21:12 -06004282
Kashyap, Desai1278b112010-03-09 17:34:13 +05304283 memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));
Eric Moore635374e2009-03-09 01:21:12 -06004284 _scsih_sas_device_remove(ioc, sas_device);
4285
Kashyap, Desai1278b112010-03-09 17:34:13 +05304286 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
4287 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
4288 sas_device_backup.handle, (unsigned long long)
4289 sas_device_backup.sas_address));
4290
4291 if (sas_device_backup.starget && sas_device_backup.starget->hostdata) {
4292 sas_target_priv_data = sas_device_backup.starget->hostdata;
4293 sas_target_priv_data->deleted = 1;
4294 }
4295
4296 if (sas_device_backup.hidden_raid_component)
4297 _scsih_remove_pd_device(ioc, sas_device_backup);
4298
4299 _scsih_ublock_io_device(ioc, sas_device_backup.handle);
4300
4301 mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address,
4302 sas_device_backup.sas_address_parent);
4303
4304 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
4305 "(0x%016llx)\n", ioc->name, sas_device_backup.handle,
4306 (unsigned long long) sas_device_backup.sas_address);
4307
4308 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
4309 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
4310 sas_device_backup.handle, (unsigned long long)
4311 sas_device_backup.sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06004312}
4313
4314#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4315/**
4316 * _scsih_sas_topology_change_event_debug - debug for topology event
4317 * @ioc: per adapter object
4318 * @event_data: event data payload
4319 * Context: user.
4320 */
4321static void
4322_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4323 Mpi2EventDataSasTopologyChangeList_t *event_data)
4324{
4325 int i;
4326 u16 handle;
4327 u16 reason_code;
4328 u8 phy_number;
4329 char *status_str = NULL;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304330 u8 link_rate, prev_link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06004331
4332 switch (event_data->ExpStatus) {
4333 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
4334 status_str = "add";
4335 break;
4336 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
4337 status_str = "remove";
4338 break;
4339 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304340 case 0:
Eric Moore635374e2009-03-09 01:21:12 -06004341 status_str = "responding";
4342 break;
4343 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
4344 status_str = "remove delay";
4345 break;
4346 default:
4347 status_str = "unknown status";
4348 break;
4349 }
4350 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
4351 ioc->name, status_str);
4352 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
4353 "start_phy(%02d), count(%d)\n",
4354 le16_to_cpu(event_data->ExpanderDevHandle),
4355 le16_to_cpu(event_data->EnclosureHandle),
4356 event_data->StartPhyNum, event_data->NumEntries);
4357 for (i = 0; i < event_data->NumEntries; i++) {
4358 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4359 if (!handle)
4360 continue;
4361 phy_number = event_data->StartPhyNum + i;
4362 reason_code = event_data->PHY[i].PhyStatus &
4363 MPI2_EVENT_SAS_TOPO_RC_MASK;
4364 switch (reason_code) {
4365 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304366 status_str = "target add";
Eric Moore635374e2009-03-09 01:21:12 -06004367 break;
4368 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304369 status_str = "target remove";
Eric Moore635374e2009-03-09 01:21:12 -06004370 break;
4371 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304372 status_str = "delay target remove";
Eric Moore635374e2009-03-09 01:21:12 -06004373 break;
4374 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304375 status_str = "link rate change";
Eric Moore635374e2009-03-09 01:21:12 -06004376 break;
4377 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304378 status_str = "target responding";
Eric Moore635374e2009-03-09 01:21:12 -06004379 break;
4380 default:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304381 status_str = "unknown";
Eric Moore635374e2009-03-09 01:21:12 -06004382 break;
4383 }
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304384 link_rate = event_data->PHY[i].LinkRate >> 4;
4385 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
4386 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:"
4387 " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
4388 handle, status_str, link_rate, prev_link_rate);
4389
Eric Moore635374e2009-03-09 01:21:12 -06004390 }
4391}
4392#endif
4393
4394/**
4395 * _scsih_sas_topology_change_event - handle topology changes
4396 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304397 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004398 * Context: user.
4399 *
4400 */
4401static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304402_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06004403 struct fw_event_work *fw_event)
4404{
4405 int i;
4406 u16 parent_handle, handle;
4407 u16 reason_code;
4408 u8 phy_number;
4409 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304410 struct _sas_device *sas_device;
4411 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004412 unsigned long flags;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304413 u8 link_rate, prev_link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304414 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004415
4416#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4417 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4418 _scsih_sas_topology_change_event_debug(ioc, event_data);
4419#endif
4420
Kashyap, Desai6558bbb2010-03-17 16:23:36 +05304421 if (ioc->shost_recovery || ioc->remove_host)
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304422 return;
4423
Eric Moore635374e2009-03-09 01:21:12 -06004424 if (!ioc->sas_hba.num_phys)
4425 _scsih_sas_host_add(ioc);
4426 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304427 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06004428
4429 if (fw_event->ignore) {
4430 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
4431 "event\n", ioc->name));
4432 return;
4433 }
4434
4435 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
4436
4437 /* handle expander add */
4438 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
4439 if (_scsih_expander_add(ioc, parent_handle) != 0)
4440 return;
4441
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304442 spin_lock_irqsave(&ioc->sas_node_lock, flags);
4443 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
4444 parent_handle);
4445 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4446 if (sas_expander)
4447 sas_address = sas_expander->sas_address;
4448 else if (parent_handle < ioc->sas_hba.num_phys)
4449 sas_address = ioc->sas_hba.sas_address;
4450 else
4451 return;
4452
Eric Moore635374e2009-03-09 01:21:12 -06004453 /* handle siblings events */
4454 for (i = 0; i < event_data->NumEntries; i++) {
4455 if (fw_event->ignore) {
4456 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
4457 "expander event\n", ioc->name));
4458 return;
4459 }
Kashyap, Desai6558bbb2010-03-17 16:23:36 +05304460 if (ioc->shost_recovery || ioc->remove_host)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304461 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05304462 phy_number = event_data->StartPhyNum + i;
4463 reason_code = event_data->PHY[i].PhyStatus &
4464 MPI2_EVENT_SAS_TOPO_RC_MASK;
4465 if ((event_data->PHY[i].PhyStatus &
4466 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
4467 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06004468 continue;
4469 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4470 if (!handle)
4471 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304472 link_rate = event_data->PHY[i].LinkRate >> 4;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304473 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Eric Moore635374e2009-03-09 01:21:12 -06004474 switch (reason_code) {
4475 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304476
4477 if (link_rate == prev_link_rate)
4478 break;
4479
4480 mpt2sas_transport_update_links(ioc, sas_address,
4481 handle, phy_number, link_rate);
4482
Kashyap, Desaib4344272010-03-17 16:24:14 +05304483 if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
4484 break;
4485
4486 _scsih_check_device(ioc, handle);
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304487 break;
Eric Moore635374e2009-03-09 01:21:12 -06004488 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304489
4490 mpt2sas_transport_update_links(ioc, sas_address,
4491 handle, phy_number, link_rate);
4492
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304493 _scsih_add_device(ioc, handle, phy_number, 0);
Eric Moore635374e2009-03-09 01:21:12 -06004494 break;
4495 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304496
4497 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4498 sas_device = _scsih_sas_device_find_by_handle(ioc,
4499 handle);
4500 if (!sas_device) {
4501 spin_unlock_irqrestore(&ioc->sas_device_lock,
4502 flags);
4503 break;
4504 }
4505 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4506 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004507 break;
4508 }
4509 }
4510
4511 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304512 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
4513 sas_expander)
4514 _scsih_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06004515
4516}
4517
4518#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4519/**
4520 * _scsih_sas_device_status_change_event_debug - debug for device event
4521 * @event_data: event data payload
4522 * Context: user.
4523 *
4524 * Return nothing.
4525 */
4526static void
4527_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4528 Mpi2EventDataSasDeviceStatusChange_t *event_data)
4529{
4530 char *reason_str = NULL;
4531
4532 switch (event_data->ReasonCode) {
4533 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
4534 reason_str = "smart data";
4535 break;
4536 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
4537 reason_str = "unsupported device discovered";
4538 break;
4539 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
4540 reason_str = "internal device reset";
4541 break;
4542 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
4543 reason_str = "internal task abort";
4544 break;
4545 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
4546 reason_str = "internal task abort set";
4547 break;
4548 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
4549 reason_str = "internal clear task set";
4550 break;
4551 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
4552 reason_str = "internal query task";
4553 break;
4554 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
4555 reason_str = "sata init failure";
4556 break;
4557 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
4558 reason_str = "internal device reset complete";
4559 break;
4560 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
4561 reason_str = "internal task abort complete";
4562 break;
4563 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
4564 reason_str = "internal async notification";
4565 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05304566 case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
4567 reason_str = "expander reduced functionality";
4568 break;
4569 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
4570 reason_str = "expander reduced functionality complete";
4571 break;
Eric Moore635374e2009-03-09 01:21:12 -06004572 default:
4573 reason_str = "unknown reason";
4574 break;
4575 }
4576 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
4577 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
4578 reason_str, le16_to_cpu(event_data->DevHandle),
4579 (unsigned long long)le64_to_cpu(event_data->SASAddress));
4580 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
4581 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
4582 event_data->ASC, event_data->ASCQ);
4583 printk(KERN_INFO "\n");
4584}
4585#endif
4586
4587/**
4588 * _scsih_sas_device_status_change_event - handle device status change
4589 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304590 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004591 * Context: user.
4592 *
4593 * Return nothing.
4594 */
4595static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304596_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
4597 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004598{
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304599 struct MPT2SAS_TARGET *target_priv_data;
4600 struct _sas_device *sas_device;
4601 __le64 sas_address;
4602 unsigned long flags;
4603 Mpi2EventDataSasDeviceStatusChange_t *event_data =
4604 fw_event->event_data;
4605
Eric Moore635374e2009-03-09 01:21:12 -06004606#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4607 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304608 _scsih_sas_device_status_change_event_debug(ioc,
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304609 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004610#endif
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304611
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05304612 if (event_data->ReasonCode !=
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304613 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05304614 event_data->ReasonCode !=
4615 MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304616 return;
4617
4618 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4619 sas_address = le64_to_cpu(event_data->SASAddress);
4620 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4621 sas_address);
4622 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4623
4624 if (!sas_device || !sas_device->starget)
4625 return;
4626
4627 target_priv_data = sas_device->starget->hostdata;
4628 if (!target_priv_data)
4629 return;
4630
4631 if (event_data->ReasonCode ==
4632 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
4633 target_priv_data->tm_busy = 1;
4634 else
4635 target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004636}
4637
4638#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4639/**
4640 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
4641 * @ioc: per adapter object
4642 * @event_data: event data payload
4643 * Context: user.
4644 *
4645 * Return nothing.
4646 */
4647static void
4648_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4649 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
4650{
4651 char *reason_str = NULL;
4652
4653 switch (event_data->ReasonCode) {
4654 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
4655 reason_str = "enclosure add";
4656 break;
4657 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
4658 reason_str = "enclosure remove";
4659 break;
4660 default:
4661 reason_str = "unknown reason";
4662 break;
4663 }
4664
4665 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
4666 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
4667 " number slots(%d)\n", ioc->name, reason_str,
4668 le16_to_cpu(event_data->EnclosureHandle),
4669 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
4670 le16_to_cpu(event_data->StartSlot));
4671}
4672#endif
4673
4674/**
4675 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
4676 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304677 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004678 * Context: user.
4679 *
4680 * Return nothing.
4681 */
4682static void
4683_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304684 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004685{
4686#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4687 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4688 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304689 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004690#endif
4691}
4692
4693/**
4694 * _scsih_sas_broadcast_primative_event - handle broadcast events
4695 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304696 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004697 * Context: user.
4698 *
4699 * Return nothing.
4700 */
4701static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304702_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4703 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004704{
4705 struct scsi_cmnd *scmd;
4706 u16 smid, handle;
4707 u32 lun;
4708 struct MPT2SAS_DEVICE *sas_device_priv_data;
4709 u32 termination_count;
4710 u32 query_count;
4711 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304712#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4713 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4714#endif
Kashyap, Desai463217b2009-10-05 15:53:06 +05304715 u16 ioc_status;
Eric Moore635374e2009-03-09 01:21:12 -06004716 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4717 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4718 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004719 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4720 __func__));
4721
Eric Moore635374e2009-03-09 01:21:12 -06004722 termination_count = 0;
4723 query_count = 0;
4724 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304725 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06004726 scmd = _scsih_scsi_lookup_get(ioc, smid);
4727 if (!scmd)
4728 continue;
4729 sas_device_priv_data = scmd->device->hostdata;
4730 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4731 continue;
4732 /* skip hidden raid components */
4733 if (sas_device_priv_data->sas_target->flags &
4734 MPT_TARGET_FLAGS_RAID_COMPONENT)
4735 continue;
4736 /* skip volumes */
4737 if (sas_device_priv_data->sas_target->flags &
4738 MPT_TARGET_FLAGS_VOLUME)
4739 continue;
4740
4741 handle = sas_device_priv_data->sas_target->handle;
4742 lun = sas_device_priv_data->lun;
4743 query_count++;
4744
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05304745 mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
4746 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL);
Eric Moore8901cbb2009-04-21 15:41:32 -06004747 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Kashyap, Desai463217b2009-10-05 15:53:06 +05304748 ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
4749 & MPI2_IOCSTATUS_MASK;
4750 if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) &&
Eric Moore635374e2009-03-09 01:21:12 -06004751 (mpi_reply->ResponseCode ==
4752 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4753 mpi_reply->ResponseCode ==
4754 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4755 continue;
4756
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05304757 mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
4758 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL);
Eric Moore635374e2009-03-09 01:21:12 -06004759 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4760 }
Eric Moore635374e2009-03-09 01:21:12 -06004761 ioc->broadcast_aen_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004762
4763 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4764 "%s - exit, query_count = %d termination_count = %d\n",
4765 ioc->name, __func__, query_count, termination_count));
4766}
4767
4768/**
4769 * _scsih_sas_discovery_event - handle discovery events
4770 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304771 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004772 * Context: user.
4773 *
4774 * Return nothing.
4775 */
4776static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304777_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4778 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004779{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304780 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4781
Eric Moore635374e2009-03-09 01:21:12 -06004782#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4783 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4784 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4785 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4786 "start" : "stop");
4787 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304788 printk("discovery_status(0x%08x)",
4789 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06004790 printk("\n");
4791 }
4792#endif
4793
4794 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4795 !ioc->sas_hba.num_phys)
4796 _scsih_sas_host_add(ioc);
4797}
4798
4799/**
4800 * _scsih_reprobe_lun - reprobing lun
4801 * @sdev: scsi device struct
4802 * @no_uld_attach: sdev->no_uld_attach flag setting
4803 *
4804 **/
4805static void
4806_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4807{
4808 int rc;
4809
4810 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4811 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4812 sdev->no_uld_attach ? "hidding" : "exposing");
4813 rc = scsi_device_reprobe(sdev);
4814}
4815
4816/**
4817 * _scsih_reprobe_target - reprobing target
4818 * @starget: scsi target struct
4819 * @no_uld_attach: sdev->no_uld_attach flag setting
4820 *
4821 * Note: no_uld_attach flag determines whether the disk device is attached
4822 * to block layer. A value of `1` means to not attach.
4823 **/
4824static void
4825_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4826{
4827 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4828
4829 if (no_uld_attach)
4830 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4831 else
4832 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4833
4834 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4835 _scsih_reprobe_lun);
4836}
4837/**
4838 * _scsih_sas_volume_add - add new volume
4839 * @ioc: per adapter object
4840 * @element: IR config element data
4841 * Context: user.
4842 *
4843 * Return nothing.
4844 */
4845static void
4846_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4847 Mpi2EventIrConfigElement_t *element)
4848{
4849 struct _raid_device *raid_device;
4850 unsigned long flags;
4851 u64 wwid;
4852 u16 handle = le16_to_cpu(element->VolDevHandle);
4853 int rc;
4854
Eric Moore635374e2009-03-09 01:21:12 -06004855 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4856 if (!wwid) {
4857 printk(MPT2SAS_ERR_FMT
4858 "failure at %s:%d/%s()!\n", ioc->name,
4859 __FILE__, __LINE__, __func__);
4860 return;
4861 }
4862
4863 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4864 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4865 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4866
4867 if (raid_device)
4868 return;
4869
4870 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4871 if (!raid_device) {
4872 printk(MPT2SAS_ERR_FMT
4873 "failure at %s:%d/%s()!\n", ioc->name,
4874 __FILE__, __LINE__, __func__);
4875 return;
4876 }
4877
4878 raid_device->id = ioc->sas_id++;
4879 raid_device->channel = RAID_CHANNEL;
4880 raid_device->handle = handle;
4881 raid_device->wwid = wwid;
4882 _scsih_raid_device_add(ioc, raid_device);
4883 if (!ioc->wait_for_port_enable_to_complete) {
4884 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4885 raid_device->id, 0);
4886 if (rc)
4887 _scsih_raid_device_remove(ioc, raid_device);
4888 } else
4889 _scsih_determine_boot_device(ioc, raid_device, 1);
4890}
4891
4892/**
4893 * _scsih_sas_volume_delete - delete volume
4894 * @ioc: per adapter object
4895 * @element: IR config element data
4896 * Context: user.
4897 *
4898 * Return nothing.
4899 */
4900static void
4901_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4902 Mpi2EventIrConfigElement_t *element)
4903{
4904 struct _raid_device *raid_device;
4905 u16 handle = le16_to_cpu(element->VolDevHandle);
4906 unsigned long flags;
4907 struct MPT2SAS_TARGET *sas_target_priv_data;
4908
Eric Moore635374e2009-03-09 01:21:12 -06004909 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4910 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4911 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4912 if (!raid_device)
4913 return;
4914 if (raid_device->starget) {
4915 sas_target_priv_data = raid_device->starget->hostdata;
4916 sas_target_priv_data->deleted = 1;
4917 scsi_remove_target(&raid_device->starget->dev);
4918 }
4919 _scsih_raid_device_remove(ioc, raid_device);
4920}
4921
4922/**
4923 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4924 * @ioc: per adapter object
4925 * @element: IR config element data
4926 * Context: user.
4927 *
4928 * Return nothing.
4929 */
4930static void
4931_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4932 Mpi2EventIrConfigElement_t *element)
4933{
4934 struct _sas_device *sas_device;
4935 unsigned long flags;
4936 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4937
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);
4941 if (!sas_device)
4942 return;
4943
4944 /* exposing raid component */
4945 sas_device->volume_handle = 0;
4946 sas_device->volume_wwid = 0;
4947 sas_device->hidden_raid_component = 0;
4948 _scsih_reprobe_target(sas_device->starget, 0);
4949}
4950
4951/**
4952 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4953 * @ioc: per adapter object
4954 * @element: IR config element data
4955 * Context: user.
4956 *
4957 * Return nothing.
4958 */
4959static void
4960_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4961 Mpi2EventIrConfigElement_t *element)
4962{
4963 struct _sas_device *sas_device;
4964 unsigned long flags;
4965 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4966
4967 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4968 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4969 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4970 if (!sas_device)
4971 return;
4972
4973 /* hiding raid component */
4974 mpt2sas_config_get_volume_handle(ioc, handle,
4975 &sas_device->volume_handle);
4976 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4977 &sas_device->volume_wwid);
4978 sas_device->hidden_raid_component = 1;
4979 _scsih_reprobe_target(sas_device->starget, 1);
4980}
4981
4982/**
4983 * _scsih_sas_pd_delete - delete pd component
4984 * @ioc: per adapter object
4985 * @element: IR config element data
4986 * Context: user.
4987 *
4988 * Return nothing.
4989 */
4990static void
4991_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4992 Mpi2EventIrConfigElement_t *element)
4993{
4994 struct _sas_device *sas_device;
4995 unsigned long flags;
4996 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4997
4998 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4999 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5000 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5001 if (!sas_device)
5002 return;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305003 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005004}
5005
5006/**
5007 * _scsih_sas_pd_add - remove pd component
5008 * @ioc: per adapter object
5009 * @element: IR config element data
5010 * Context: user.
5011 *
5012 * Return nothing.
5013 */
5014static void
5015_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
5016 Mpi2EventIrConfigElement_t *element)
5017{
5018 struct _sas_device *sas_device;
5019 unsigned long flags;
5020 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305021 Mpi2ConfigReply_t mpi_reply;
5022 Mpi2SasDevicePage0_t sas_device_pg0;
5023 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305024 u64 sas_address;
5025 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06005026
5027 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5028 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5029 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305030 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06005031 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305032 return;
5033 }
5034
5035 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
5036 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
5037 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5038 ioc->name, __FILE__, __LINE__, __func__);
5039 return;
5040 }
5041
5042 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5043 MPI2_IOCSTATUS_MASK;
5044 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5045 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5046 ioc->name, __FILE__, __LINE__, __func__);
5047 return;
5048 }
5049
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305050 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
5051 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
5052 mpt2sas_transport_update_links(ioc, sas_address, handle,
5053 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305054
5055 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06005056}
5057
5058#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5059/**
5060 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
5061 * @ioc: per adapter object
5062 * @event_data: event data payload
5063 * Context: user.
5064 *
5065 * Return nothing.
5066 */
5067static void
5068_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5069 Mpi2EventDataIrConfigChangeList_t *event_data)
5070{
5071 Mpi2EventIrConfigElement_t *element;
5072 u8 element_type;
5073 int i;
5074 char *reason_str = NULL, *element_str = NULL;
5075
5076 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
5077
5078 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
5079 ioc->name, (le32_to_cpu(event_data->Flags) &
5080 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
5081 "foreign" : "native", event_data->NumElements);
5082 for (i = 0; i < event_data->NumElements; i++, element++) {
5083 switch (element->ReasonCode) {
5084 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
5085 reason_str = "add";
5086 break;
5087 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
5088 reason_str = "remove";
5089 break;
5090 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
5091 reason_str = "no change";
5092 break;
5093 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
5094 reason_str = "hide";
5095 break;
5096 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
5097 reason_str = "unhide";
5098 break;
5099 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
5100 reason_str = "volume_created";
5101 break;
5102 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
5103 reason_str = "volume_deleted";
5104 break;
5105 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
5106 reason_str = "pd_created";
5107 break;
5108 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
5109 reason_str = "pd_deleted";
5110 break;
5111 default:
5112 reason_str = "unknown reason";
5113 break;
5114 }
5115 element_type = le16_to_cpu(element->ElementFlags) &
5116 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
5117 switch (element_type) {
5118 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
5119 element_str = "volume";
5120 break;
5121 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
5122 element_str = "phys disk";
5123 break;
5124 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
5125 element_str = "hot spare";
5126 break;
5127 default:
5128 element_str = "unknown element";
5129 break;
5130 }
5131 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
5132 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
5133 reason_str, le16_to_cpu(element->VolDevHandle),
5134 le16_to_cpu(element->PhysDiskDevHandle),
5135 element->PhysDiskNum);
5136 }
5137}
5138#endif
5139
5140/**
5141 * _scsih_sas_ir_config_change_event - handle ir configuration change events
5142 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305143 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005144 * Context: user.
5145 *
5146 * Return nothing.
5147 */
5148static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305149_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
5150 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005151{
5152 Mpi2EventIrConfigElement_t *element;
5153 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305154 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305155 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005156
5157#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5158 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5159 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
5160
5161#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05305162 foreign_config = (le32_to_cpu(event_data->Flags) &
5163 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06005164
5165 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
5166 for (i = 0; i < event_data->NumElements; i++, element++) {
5167
5168 switch (element->ReasonCode) {
5169 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
5170 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305171 if (!foreign_config)
5172 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06005173 break;
5174 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
5175 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305176 if (!foreign_config)
5177 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06005178 break;
5179 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
5180 _scsih_sas_pd_hide(ioc, element);
5181 break;
5182 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
5183 _scsih_sas_pd_expose(ioc, element);
5184 break;
5185 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
5186 _scsih_sas_pd_add(ioc, element);
5187 break;
5188 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
5189 _scsih_sas_pd_delete(ioc, element);
5190 break;
5191 }
5192 }
5193}
5194
5195/**
5196 * _scsih_sas_ir_volume_event - IR volume event
5197 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305198 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005199 * Context: user.
5200 *
5201 * Return nothing.
5202 */
5203static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305204_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
5205 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005206{
5207 u64 wwid;
5208 unsigned long flags;
5209 struct _raid_device *raid_device;
5210 u16 handle;
5211 u32 state;
5212 int rc;
5213 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305214 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005215
5216 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
5217 return;
5218
5219 handle = le16_to_cpu(event_data->VolDevHandle);
5220 state = le32_to_cpu(event_data->NewValue);
5221 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
5222 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
5223 le32_to_cpu(event_data->PreviousValue), state));
5224
5225 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5226 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5227 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5228
5229 switch (state) {
5230 case MPI2_RAID_VOL_STATE_MISSING:
5231 case MPI2_RAID_VOL_STATE_FAILED:
5232 if (!raid_device)
5233 break;
5234 if (raid_device->starget) {
5235 sas_target_priv_data = raid_device->starget->hostdata;
5236 sas_target_priv_data->deleted = 1;
5237 scsi_remove_target(&raid_device->starget->dev);
5238 }
5239 _scsih_raid_device_remove(ioc, raid_device);
5240 break;
5241
5242 case MPI2_RAID_VOL_STATE_ONLINE:
5243 case MPI2_RAID_VOL_STATE_DEGRADED:
5244 case MPI2_RAID_VOL_STATE_OPTIMAL:
5245 if (raid_device)
5246 break;
5247
5248 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
5249 if (!wwid) {
5250 printk(MPT2SAS_ERR_FMT
5251 "failure at %s:%d/%s()!\n", ioc->name,
5252 __FILE__, __LINE__, __func__);
5253 break;
5254 }
5255
5256 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
5257 if (!raid_device) {
5258 printk(MPT2SAS_ERR_FMT
5259 "failure at %s:%d/%s()!\n", ioc->name,
5260 __FILE__, __LINE__, __func__);
5261 break;
5262 }
5263
5264 raid_device->id = ioc->sas_id++;
5265 raid_device->channel = RAID_CHANNEL;
5266 raid_device->handle = handle;
5267 raid_device->wwid = wwid;
5268 _scsih_raid_device_add(ioc, raid_device);
5269 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5270 raid_device->id, 0);
5271 if (rc)
5272 _scsih_raid_device_remove(ioc, raid_device);
5273 break;
5274
5275 case MPI2_RAID_VOL_STATE_INITIALIZING:
5276 default:
5277 break;
5278 }
5279}
5280
5281/**
5282 * _scsih_sas_ir_physical_disk_event - PD event
5283 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305284 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005285 * Context: user.
5286 *
5287 * Return nothing.
5288 */
5289static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305290_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
5291 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005292{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305293 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06005294 u32 state;
5295 struct _sas_device *sas_device;
5296 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305297 Mpi2ConfigReply_t mpi_reply;
5298 Mpi2SasDevicePage0_t sas_device_pg0;
5299 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305300 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305301 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06005302
5303 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
5304 return;
5305
5306 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
5307 state = le32_to_cpu(event_data->NewValue);
5308
5309 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
5310 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
5311 le32_to_cpu(event_data->PreviousValue), state));
5312
5313 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5314 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5315 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5316
5317 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06005318 case MPI2_RAID_PD_STATE_ONLINE:
5319 case MPI2_RAID_PD_STATE_DEGRADED:
5320 case MPI2_RAID_PD_STATE_REBUILDING:
5321 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305322 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06005323 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305324 return;
5325 }
5326
5327 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5328 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
5329 handle))) {
5330 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5331 ioc->name, __FILE__, __LINE__, __func__);
5332 return;
5333 }
5334
5335 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5336 MPI2_IOCSTATUS_MASK;
5337 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5338 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5339 ioc->name, __FILE__, __LINE__, __func__);
5340 return;
5341 }
5342
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305343 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
5344 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
5345 mpt2sas_transport_update_links(ioc, sas_address, handle,
5346 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305347
5348 _scsih_add_device(ioc, handle, 0, 1);
5349
Eric Moore635374e2009-03-09 01:21:12 -06005350 break;
5351
Kashyap, Desai62727a72009-08-07 19:35:18 +05305352 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06005353 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
5354 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
5355 case MPI2_RAID_PD_STATE_HOT_SPARE:
5356 default:
5357 break;
5358 }
5359}
5360
5361#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5362/**
5363 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
5364 * @ioc: per adapter object
5365 * @event_data: event data payload
5366 * Context: user.
5367 *
5368 * Return nothing.
5369 */
5370static void
5371_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
5372 Mpi2EventDataIrOperationStatus_t *event_data)
5373{
5374 char *reason_str = NULL;
5375
5376 switch (event_data->RAIDOperation) {
5377 case MPI2_EVENT_IR_RAIDOP_RESYNC:
5378 reason_str = "resync";
5379 break;
5380 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
5381 reason_str = "online capacity expansion";
5382 break;
5383 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
5384 reason_str = "consistency check";
5385 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305386 case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
5387 reason_str = "background init";
5388 break;
5389 case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
5390 reason_str = "make data consistent";
Eric Moore635374e2009-03-09 01:21:12 -06005391 break;
5392 }
5393
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305394 if (!reason_str)
5395 return;
5396
Eric Moore635374e2009-03-09 01:21:12 -06005397 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
5398 "\thandle(0x%04x), percent complete(%d)\n",
5399 ioc->name, reason_str,
5400 le16_to_cpu(event_data->VolDevHandle),
5401 event_data->PercentComplete);
5402}
5403#endif
5404
5405/**
5406 * _scsih_sas_ir_operation_status_event - handle RAID operation events
5407 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305408 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005409 * Context: user.
5410 *
5411 * Return nothing.
5412 */
5413static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305414_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
5415 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005416{
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305417 Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data;
5418 static struct _raid_device *raid_device;
5419 unsigned long flags;
5420 u16 handle;
5421
Eric Moore635374e2009-03-09 01:21:12 -06005422#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5423 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305424 _scsih_sas_ir_operation_status_event_debug(ioc,
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305425 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005426#endif
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305427
5428 /* code added for raid transport support */
5429 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
5430
5431 handle = le16_to_cpu(event_data->VolDevHandle);
5432
5433 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5434 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5435 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5436
5437 if (!raid_device)
5438 return;
5439
5440 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
5441 raid_device->percent_complete =
5442 event_data->PercentComplete;
5443 }
Eric Moore635374e2009-03-09 01:21:12 -06005444}
5445
5446/**
5447 * _scsih_task_set_full - handle task set full
5448 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305449 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005450 * Context: user.
5451 *
5452 * Throttle back qdepth.
5453 */
5454static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305455_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
5456 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005457{
5458 unsigned long flags;
5459 struct _sas_device *sas_device;
5460 static struct _raid_device *raid_device;
5461 struct scsi_device *sdev;
5462 int depth;
5463 u16 current_depth;
5464 u16 handle;
5465 int id, channel;
5466 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305467 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005468
5469 current_depth = le16_to_cpu(event_data->CurrentDepth);
5470 handle = le16_to_cpu(event_data->DevHandle);
5471 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5472 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5473 if (!sas_device) {
5474 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5475 return;
5476 }
5477 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5478 id = sas_device->id;
5479 channel = sas_device->channel;
5480 sas_address = sas_device->sas_address;
5481
5482 /* if hidden raid component, then change to volume characteristics */
5483 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
5484 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5485 raid_device = _scsih_raid_device_find_by_handle(
5486 ioc, sas_device->volume_handle);
5487 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5488 if (raid_device) {
5489 id = raid_device->id;
5490 channel = raid_device->channel;
5491 handle = raid_device->handle;
5492 sas_address = raid_device->wwid;
5493 }
5494 }
5495
5496 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
5497 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
5498 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
5499 handle, (unsigned long long)sas_address, current_depth);
5500
5501 shost_for_each_device(sdev, ioc->shost) {
5502 if (sdev->id == id && sdev->channel == channel) {
5503 if (current_depth > sdev->queue_depth) {
5504 if (ioc->logging_level &
5505 MPT_DEBUG_TASK_SET_FULL)
5506 sdev_printk(KERN_INFO, sdev, "strange "
5507 "observation, the queue depth is"
5508 " (%d) meanwhile fw queue depth "
5509 "is (%d)\n", sdev->queue_depth,
5510 current_depth);
5511 continue;
5512 }
5513 depth = scsi_track_queue_full(sdev,
5514 current_depth - 1);
5515 if (depth > 0)
5516 sdev_printk(KERN_INFO, sdev, "Queue depth "
5517 "reduced to (%d)\n", depth);
5518 else if (depth < 0)
5519 sdev_printk(KERN_INFO, sdev, "Tagged Command "
5520 "Queueing is being disabled\n");
5521 else if (depth == 0)
5522 if (ioc->logging_level &
5523 MPT_DEBUG_TASK_SET_FULL)
5524 sdev_printk(KERN_INFO, sdev,
5525 "Queue depth not changed yet\n");
5526 }
5527 }
5528}
5529
5530/**
Kashyap, Desai14695852010-03-30 10:52:44 +05305531 * _scsih_prep_device_scan - initialize parameters prior to device scan
5532 * @ioc: per adapter object
5533 *
5534 * Set the deleted flag prior to device scan. If the device is found during
5535 * the scan, then we clear the deleted flag.
5536 */
5537static void
5538_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc)
5539{
5540 struct MPT2SAS_DEVICE *sas_device_priv_data;
5541 struct scsi_device *sdev;
5542
5543 shost_for_each_device(sdev, ioc->shost) {
5544 sas_device_priv_data = sdev->hostdata;
5545 if (sas_device_priv_data && sas_device_priv_data->sas_target)
5546 sas_device_priv_data->sas_target->deleted = 1;
5547 }
5548}
5549
5550/**
Eric Moore635374e2009-03-09 01:21:12 -06005551 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
5552 * @ioc: per adapter object
5553 * @sas_address: sas address
5554 * @slot: enclosure slot id
5555 * @handle: device handle
5556 *
5557 * After host reset, find out whether devices are still responding.
5558 * Used in _scsi_remove_unresponsive_sas_devices.
5559 *
5560 * Return nothing.
5561 */
5562static void
5563_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5564 u16 slot, u16 handle)
5565{
5566 struct MPT2SAS_TARGET *sas_target_priv_data;
5567 struct scsi_target *starget;
5568 struct _sas_device *sas_device;
5569 unsigned long flags;
5570
5571 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5572 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
5573 if (sas_device->sas_address == sas_address &&
5574 sas_device->slot == slot && sas_device->starget) {
5575 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305576 starget = sas_device->starget;
Kashyap, Desai14695852010-03-30 10:52:44 +05305577 if (starget && starget->hostdata) {
5578 sas_target_priv_data = starget->hostdata;
5579 sas_target_priv_data->tm_busy = 0;
5580 sas_target_priv_data->deleted = 0;
5581 } else
5582 sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06005583 starget_printk(KERN_INFO, sas_device->starget,
5584 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
5585 "logical id(0x%016llx), slot(%d)\n", handle,
5586 (unsigned long long)sas_device->sas_address,
5587 (unsigned long long)
5588 sas_device->enclosure_logical_id,
5589 sas_device->slot);
5590 if (sas_device->handle == handle)
5591 goto out;
5592 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5593 sas_device->handle);
5594 sas_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05305595 if (sas_target_priv_data)
5596 sas_target_priv_data->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005597 goto out;
5598 }
5599 }
5600 out:
5601 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5602}
5603
5604/**
5605 * _scsih_search_responding_sas_devices -
5606 * @ioc: per adapter object
5607 *
5608 * After host reset, find out whether devices are still responding.
5609 * If not remove.
5610 *
5611 * Return nothing.
5612 */
5613static void
5614_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
5615{
5616 Mpi2SasDevicePage0_t sas_device_pg0;
5617 Mpi2ConfigReply_t mpi_reply;
5618 u16 ioc_status;
5619 __le64 sas_address;
5620 u16 handle;
5621 u32 device_info;
5622 u16 slot;
5623
5624 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5625
5626 if (list_empty(&ioc->sas_device_list))
5627 return;
5628
5629 handle = 0xFFFF;
5630 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5631 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
5632 handle))) {
5633 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5634 MPI2_IOCSTATUS_MASK;
5635 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5636 break;
5637 handle = le16_to_cpu(sas_device_pg0.DevHandle);
5638 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5639 if (!(_scsih_is_end_device(device_info)))
5640 continue;
5641 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5642 slot = le16_to_cpu(sas_device_pg0.Slot);
5643 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
5644 handle);
5645 }
5646}
5647
5648/**
5649 * _scsih_mark_responding_raid_device - mark a raid_device as responding
5650 * @ioc: per adapter object
5651 * @wwid: world wide identifier for raid volume
5652 * @handle: device handle
5653 *
5654 * After host reset, find out whether devices are still responding.
5655 * Used in _scsi_remove_unresponsive_raid_devices.
5656 *
5657 * Return nothing.
5658 */
5659static void
5660_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
5661 u16 handle)
5662{
5663 struct MPT2SAS_TARGET *sas_target_priv_data;
5664 struct scsi_target *starget;
5665 struct _raid_device *raid_device;
5666 unsigned long flags;
5667
5668 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5669 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
5670 if (raid_device->wwid == wwid && raid_device->starget) {
Kashyap, Desai14695852010-03-30 10:52:44 +05305671 starget = raid_device->starget;
5672 if (starget && starget->hostdata) {
5673 sas_target_priv_data = starget->hostdata;
5674 sas_target_priv_data->deleted = 0;
5675 } else
5676 sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06005677 raid_device->responding = 1;
5678 starget_printk(KERN_INFO, raid_device->starget,
5679 "handle(0x%04x), wwid(0x%016llx)\n", handle,
5680 (unsigned long long)raid_device->wwid);
5681 if (raid_device->handle == handle)
5682 goto out;
5683 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5684 raid_device->handle);
5685 raid_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05305686 if (sas_target_priv_data)
5687 sas_target_priv_data->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005688 goto out;
5689 }
5690 }
5691 out:
5692 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5693}
5694
5695/**
5696 * _scsih_search_responding_raid_devices -
5697 * @ioc: per adapter object
5698 *
5699 * After host reset, find out whether devices are still responding.
5700 * If not remove.
5701 *
5702 * Return nothing.
5703 */
5704static void
5705_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
5706{
5707 Mpi2RaidVolPage1_t volume_pg1;
5708 Mpi2ConfigReply_t mpi_reply;
5709 u16 ioc_status;
5710 u16 handle;
5711
5712 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5713
5714 if (list_empty(&ioc->raid_device_list))
5715 return;
5716
5717 handle = 0xFFFF;
5718 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
5719 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
5720 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5721 MPI2_IOCSTATUS_MASK;
5722 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5723 break;
5724 handle = le16_to_cpu(volume_pg1.DevHandle);
5725 _scsih_mark_responding_raid_device(ioc,
5726 le64_to_cpu(volume_pg1.WWID), handle);
5727 }
5728}
5729
5730/**
5731 * _scsih_mark_responding_expander - mark a expander as responding
5732 * @ioc: per adapter object
5733 * @sas_address: sas address
5734 * @handle:
5735 *
5736 * After host reset, find out whether devices are still responding.
5737 * Used in _scsi_remove_unresponsive_expanders.
5738 *
5739 * Return nothing.
5740 */
5741static void
5742_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5743 u16 handle)
5744{
5745 struct _sas_node *sas_expander;
5746 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305747 int i;
Eric Moore635374e2009-03-09 01:21:12 -06005748
5749 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5750 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305751 if (sas_expander->sas_address != sas_address)
5752 continue;
5753 sas_expander->responding = 1;
5754 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06005755 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305756 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
5757 " from(0x%04x) to (0x%04x)!!!\n",
5758 (unsigned long long)sas_expander->sas_address,
5759 sas_expander->handle, handle);
5760 sas_expander->handle = handle;
5761 for (i = 0 ; i < sas_expander->num_phys ; i++)
5762 sas_expander->phy[i].handle = handle;
5763 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06005764 }
5765 out:
5766 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5767}
5768
5769/**
5770 * _scsih_search_responding_expanders -
5771 * @ioc: per adapter object
5772 *
5773 * After host reset, find out whether devices are still responding.
5774 * If not remove.
5775 *
5776 * Return nothing.
5777 */
5778static void
5779_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5780{
5781 Mpi2ExpanderPage0_t expander_pg0;
5782 Mpi2ConfigReply_t mpi_reply;
5783 u16 ioc_status;
5784 __le64 sas_address;
5785 u16 handle;
5786
5787 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5788
5789 if (list_empty(&ioc->sas_expander_list))
5790 return;
5791
5792 handle = 0xFFFF;
5793 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5794 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5795
5796 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5797 MPI2_IOCSTATUS_MASK;
5798 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5799 break;
5800
5801 handle = le16_to_cpu(expander_pg0.DevHandle);
5802 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5803 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5804 "sas_addr(0x%016llx)\n", handle,
5805 (unsigned long long)sas_address);
5806 _scsih_mark_responding_expander(ioc, sas_address, handle);
5807 }
5808
5809}
5810
5811/**
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305812 * _scsih_remove_unresponding_sas_devices - removing unresponding devices
Eric Moore635374e2009-03-09 01:21:12 -06005813 * @ioc: per adapter object
5814 *
5815 * Return nothing.
5816 */
5817static void
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305818_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06005819{
5820 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305821 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005822 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005823
Eric Moore635374e2009-03-09 01:21:12 -06005824
5825 list_for_each_entry_safe(sas_device, sas_device_next,
5826 &ioc->sas_device_list, list) {
5827 if (sas_device->responding) {
5828 sas_device->responding = 0;
5829 continue;
5830 }
5831 if (sas_device->starget)
5832 starget_printk(KERN_INFO, sas_device->starget,
5833 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5834 "enclosure logical id(0x%016llx), slot(%d)\n",
5835 sas_device->handle,
5836 (unsigned long long)sas_device->sas_address,
5837 (unsigned long long)
5838 sas_device->enclosure_logical_id,
5839 sas_device->slot);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305840 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005841 }
5842
5843 list_for_each_entry_safe(raid_device, raid_device_next,
5844 &ioc->raid_device_list, list) {
5845 if (raid_device->responding) {
5846 raid_device->responding = 0;
5847 continue;
5848 }
5849 if (raid_device->starget) {
5850 starget_printk(KERN_INFO, raid_device->starget,
5851 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5852 raid_device->handle,
5853 (unsigned long long)raid_device->wwid);
5854 scsi_remove_target(&raid_device->starget->dev);
5855 }
5856 _scsih_raid_device_remove(ioc, raid_device);
5857 }
5858
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305859 retry_expander_search:
5860 sas_expander = NULL;
5861 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005862 if (sas_expander->responding) {
5863 sas_expander->responding = 0;
5864 continue;
5865 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305866 _scsih_expander_remove(ioc, sas_expander->sas_address);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305867 goto retry_expander_search;
5868 }
5869}
5870
5871/**
5872 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5873 * @ioc: per adapter object
5874 * @reset_phase: phase
5875 *
5876 * The handler for doing any required cleanup or initialization.
5877 *
5878 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5879 * MPT2_IOC_DONE_RESET
5880 *
5881 * Return nothing.
5882 */
5883void
5884mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5885{
5886 switch (reset_phase) {
5887 case MPT2_IOC_PRE_RESET:
5888 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5889 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305890 break;
5891 case MPT2_IOC_AFTER_RESET:
5892 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5893 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305894 if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
5895 ioc->scsih_cmds.status |= MPT2_CMD_RESET;
5896 mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
5897 complete(&ioc->scsih_cmds.done);
5898 }
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305899 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5900 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5901 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5902 complete(&ioc->tm_cmds.done);
5903 }
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305904 _scsih_fw_event_cleanup_queue(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305905 _scsih_flush_running_cmds(ioc);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305906 _scsih_queue_rescan(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305907 break;
5908 case MPT2_IOC_DONE_RESET:
5909 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5910 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305911 _scsih_sas_host_refresh(ioc);
Kashyap, Desai14695852010-03-30 10:52:44 +05305912 _scsih_prep_device_scan(ioc);
5913 _scsih_search_responding_sas_devices(ioc);
5914 _scsih_search_responding_raid_devices(ioc);
5915 _scsih_search_responding_expanders(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305916 break;
Eric Moore635374e2009-03-09 01:21:12 -06005917 }
5918}
5919
5920/**
5921 * _firmware_event_work - delayed task for processing firmware events
5922 * @ioc: per adapter object
5923 * @work: equal to the fw_event_work object
5924 * Context: user.
5925 *
5926 * Return nothing.
5927 */
5928static void
5929_firmware_event_work(struct work_struct *work)
5930{
5931 struct fw_event_work *fw_event = container_of(work,
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305932 struct fw_event_work, delayed_work.work);
Eric Moore635374e2009-03-09 01:21:12 -06005933 unsigned long flags;
5934 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5935
Eric Moore635374e2009-03-09 01:21:12 -06005936 /* the queue is being flushed so ignore this event */
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305937 if (ioc->remove_host || fw_event->cancel_pending_work) {
Eric Moore635374e2009-03-09 01:21:12 -06005938 _scsih_fw_event_free(ioc, fw_event);
5939 return;
5940 }
Eric Moore635374e2009-03-09 01:21:12 -06005941
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305942 if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) {
5943 _scsih_fw_event_free(ioc, fw_event);
5944 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
5945 if (ioc->shost_recovery) {
5946 init_completion(&ioc->shost_recovery_done);
5947 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
5948 flags);
5949 wait_for_completion(&ioc->shost_recovery_done);
5950 } else
5951 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
5952 flags);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305953 _scsih_remove_unresponding_sas_devices(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005954 return;
5955 }
Eric Moore635374e2009-03-09 01:21:12 -06005956
5957 switch (fw_event->event) {
5958 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305959 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005960 break;
5961 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305962 _scsih_sas_device_status_change_event(ioc,
5963 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005964 break;
5965 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305966 _scsih_sas_discovery_event(ioc,
5967 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005968 break;
5969 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305970 _scsih_sas_broadcast_primative_event(ioc,
5971 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005972 break;
5973 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5974 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305975 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005976 break;
5977 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305978 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005979 break;
5980 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305981 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005982 break;
5983 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305984 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005985 break;
5986 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305987 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005988 break;
5989 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305990 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005991 break;
5992 }
5993 _scsih_fw_event_free(ioc, fw_event);
5994}
5995
5996/**
5997 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5998 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305999 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06006000 * @reply: reply message frame(lower 32bit addr)
6001 * Context: interrupt.
6002 *
6003 * This function merely adds a new work task into ioc->firmware_event_thread.
6004 * The tasks are worked from _firmware_event_work in user context.
6005 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306006 * Return 1 meaning mf should be freed from _base_interrupt
6007 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06006008 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306009u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306010mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
6011 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06006012{
6013 struct fw_event_work *fw_event;
6014 Mpi2EventNotificationReply_t *mpi_reply;
Eric Moore635374e2009-03-09 01:21:12 -06006015 u16 event;
Kashyap, Desaie94f6742010-03-17 16:24:52 +05306016 u16 sz;
Eric Moore635374e2009-03-09 01:21:12 -06006017
6018 /* events turned off due to host reset or driver unloading */
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306019 if (ioc->remove_host)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306020 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006021
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306022 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06006023 event = le16_to_cpu(mpi_reply->Event);
6024
6025 switch (event) {
6026 /* handle these */
6027 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
6028 {
6029 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
6030 (Mpi2EventDataSasBroadcastPrimitive_t *)
6031 mpi_reply->EventData;
6032
6033 if (baen_data->Primitive !=
6034 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
6035 ioc->broadcast_aen_busy)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306036 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006037 ioc->broadcast_aen_busy = 1;
6038 break;
6039 }
6040
6041 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
6042 _scsih_check_topo_delete_events(ioc,
6043 (Mpi2EventDataSasTopologyChangeList_t *)
6044 mpi_reply->EventData);
6045 break;
6046
6047 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
6048 case MPI2_EVENT_IR_OPERATION_STATUS:
6049 case MPI2_EVENT_SAS_DISCOVERY:
6050 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
6051 case MPI2_EVENT_IR_VOLUME:
6052 case MPI2_EVENT_IR_PHYSICAL_DISK:
6053 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
6054 case MPI2_EVENT_TASK_SET_FULL:
6055 break;
6056
6057 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306058 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006059 }
6060
6061 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
6062 if (!fw_event) {
6063 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6064 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306065 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006066 }
Kashyap, Desaie94f6742010-03-17 16:24:52 +05306067 sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
6068 fw_event->event_data = kzalloc(sz, GFP_ATOMIC);
Eric Moore635374e2009-03-09 01:21:12 -06006069 if (!fw_event->event_data) {
6070 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6071 ioc->name, __FILE__, __LINE__, __func__);
6072 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306073 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006074 }
6075
6076 memcpy(fw_event->event_data, mpi_reply->EventData,
Kashyap, Desaie94f6742010-03-17 16:24:52 +05306077 sz);
Eric Moore635374e2009-03-09 01:21:12 -06006078 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306079 fw_event->VF_ID = mpi_reply->VF_ID;
6080 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06006081 fw_event->event = event;
6082 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306083 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006084}
6085
6086/* shost template */
6087static struct scsi_host_template scsih_driver_template = {
6088 .module = THIS_MODULE,
6089 .name = "Fusion MPT SAS Host",
6090 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06006091 .queuecommand = _scsih_qcmd,
6092 .target_alloc = _scsih_target_alloc,
6093 .slave_alloc = _scsih_slave_alloc,
6094 .slave_configure = _scsih_slave_configure,
6095 .target_destroy = _scsih_target_destroy,
6096 .slave_destroy = _scsih_slave_destroy,
6097 .change_queue_depth = _scsih_change_queue_depth,
6098 .change_queue_type = _scsih_change_queue_type,
6099 .eh_abort_handler = _scsih_abort,
6100 .eh_device_reset_handler = _scsih_dev_reset,
6101 .eh_target_reset_handler = _scsih_target_reset,
6102 .eh_host_reset_handler = _scsih_host_reset,
6103 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06006104 .can_queue = 1,
6105 .this_id = -1,
6106 .sg_tablesize = MPT2SAS_SG_DEPTH,
6107 .max_sectors = 8192,
6108 .cmd_per_lun = 7,
6109 .use_clustering = ENABLE_CLUSTERING,
6110 .shost_attrs = mpt2sas_host_attrs,
6111 .sdev_attrs = mpt2sas_dev_attrs,
6112};
6113
6114/**
6115 * _scsih_expander_node_remove - removing expander device from list.
6116 * @ioc: per adapter object
6117 * @sas_expander: the sas_device object
6118 * Context: Calling function should acquire ioc->sas_node_lock.
6119 *
6120 * Removing object and freeing associated memory from the
6121 * ioc->sas_expander_list.
6122 *
6123 * Return nothing.
6124 */
6125static void
6126_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
6127 struct _sas_node *sas_expander)
6128{
6129 struct _sas_port *mpt2sas_port;
6130 struct _sas_device *sas_device;
6131 struct _sas_node *expander_sibling;
6132 unsigned long flags;
6133
6134 if (!sas_expander)
6135 return;
6136
6137 /* remove sibling ports attached to this expander */
6138 retry_device_search:
6139 list_for_each_entry(mpt2sas_port,
6140 &sas_expander->sas_port_list, port_list) {
6141 if (mpt2sas_port->remote_identify.device_type ==
6142 SAS_END_DEVICE) {
6143 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6144 sas_device =
6145 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
6146 mpt2sas_port->remote_identify.sas_address);
6147 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6148 if (!sas_device)
6149 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306150 _scsih_remove_device(ioc, sas_device);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05306151 if (ioc->shost_recovery)
6152 return;
Eric Moore635374e2009-03-09 01:21:12 -06006153 goto retry_device_search;
6154 }
6155 }
6156
6157 retry_expander_search:
6158 list_for_each_entry(mpt2sas_port,
6159 &sas_expander->sas_port_list, port_list) {
6160
6161 if (mpt2sas_port->remote_identify.device_type ==
6162 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
6163 mpt2sas_port->remote_identify.device_type ==
6164 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
6165
6166 spin_lock_irqsave(&ioc->sas_node_lock, flags);
6167 expander_sibling =
6168 mpt2sas_scsih_expander_find_by_sas_address(
6169 ioc, mpt2sas_port->remote_identify.sas_address);
6170 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
6171 if (!expander_sibling)
6172 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306173 _scsih_expander_remove(ioc,
6174 expander_sibling->sas_address);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05306175 if (ioc->shost_recovery)
6176 return;
Eric Moore635374e2009-03-09 01:21:12 -06006177 goto retry_expander_search;
6178 }
6179 }
6180
6181 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306182 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006183
6184 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
6185 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
6186 sas_expander->handle, (unsigned long long)
6187 sas_expander->sas_address);
6188
6189 list_del(&sas_expander->list);
6190 kfree(sas_expander->phy);
6191 kfree(sas_expander);
6192}
6193
6194/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05306195 * _scsih_ir_shutdown - IR shutdown notification
6196 * @ioc: per adapter object
6197 *
6198 * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
6199 * the host system is shutting down.
6200 *
6201 * Return nothing.
6202 */
6203static void
6204_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
6205{
6206 Mpi2RaidActionRequest_t *mpi_request;
6207 Mpi2RaidActionReply_t *mpi_reply;
6208 u16 smid;
6209
6210 /* is IR firmware build loaded ? */
6211 if (!ioc->ir_firmware)
6212 return;
6213
6214 /* are there any volumes ? */
6215 if (list_empty(&ioc->raid_device_list))
6216 return;
6217
6218 mutex_lock(&ioc->scsih_cmds.mutex);
6219
6220 if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
6221 printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
6222 ioc->name, __func__);
6223 goto out;
6224 }
6225 ioc->scsih_cmds.status = MPT2_CMD_PENDING;
6226
6227 smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
6228 if (!smid) {
6229 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
6230 ioc->name, __func__);
6231 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
6232 goto out;
6233 }
6234
6235 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
6236 ioc->scsih_cmds.smid = smid;
6237 memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
6238
6239 mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
6240 mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
6241
6242 printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
6243 init_completion(&ioc->scsih_cmds.done);
6244 mpt2sas_base_put_smid_default(ioc, smid);
6245 wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
6246
6247 if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
6248 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
6249 ioc->name, __func__);
6250 goto out;
6251 }
6252
6253 if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
6254 mpi_reply = ioc->scsih_cmds.reply;
6255
6256 printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
6257 "ioc_status(0x%04x), loginfo(0x%08x)\n",
6258 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
6259 le32_to_cpu(mpi_reply->IOCLogInfo));
6260 }
6261
6262 out:
6263 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
6264 mutex_unlock(&ioc->scsih_cmds.mutex);
6265}
6266
6267/**
6268 * _scsih_shutdown - routine call during system shutdown
6269 * @pdev: PCI device struct
6270 *
6271 * Return nothing.
6272 */
6273static void
6274_scsih_shutdown(struct pci_dev *pdev)
6275{
6276 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6277 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306278 struct workqueue_struct *wq;
6279 unsigned long flags;
6280
6281 ioc->remove_host = 1;
6282 _scsih_fw_event_cleanup_queue(ioc);
6283
6284 spin_lock_irqsave(&ioc->fw_event_lock, flags);
6285 wq = ioc->firmware_event_thread;
6286 ioc->firmware_event_thread = NULL;
6287 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
6288 if (wq)
6289 destroy_workqueue(wq);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306290
6291 _scsih_ir_shutdown(ioc);
6292 mpt2sas_base_detach(ioc);
6293}
6294
6295/**
Eric Moored5d135b2009-05-18 13:02:08 -06006296 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06006297 * @pdev: PCI device struct
6298 *
Kashyap, Desai744090d2009-10-05 15:56:56 +05306299 * Routine called when unloading the driver.
Eric Moore635374e2009-03-09 01:21:12 -06006300 * Return nothing.
6301 */
6302static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06006303_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006304{
6305 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6306 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6307 struct _sas_port *mpt2sas_port;
6308 struct _sas_device *sas_device;
6309 struct _sas_node *expander_sibling;
Kashyap, Desaid7384b22009-12-16 18:50:06 +05306310 struct _raid_device *raid_device, *next;
6311 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06006312 struct workqueue_struct *wq;
6313 unsigned long flags;
6314
6315 ioc->remove_host = 1;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306316 _scsih_fw_event_cleanup_queue(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006317
6318 spin_lock_irqsave(&ioc->fw_event_lock, flags);
6319 wq = ioc->firmware_event_thread;
6320 ioc->firmware_event_thread = NULL;
6321 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
6322 if (wq)
6323 destroy_workqueue(wq);
6324
Kashyap, Desaid7384b22009-12-16 18:50:06 +05306325 /* release all the volumes */
6326 list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
6327 list) {
6328 if (raid_device->starget) {
6329 sas_target_priv_data =
6330 raid_device->starget->hostdata;
6331 sas_target_priv_data->deleted = 1;
6332 scsi_remove_target(&raid_device->starget->dev);
6333 }
6334 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
6335 "(0x%016llx)\n", ioc->name, raid_device->handle,
6336 (unsigned long long) raid_device->wwid);
6337 _scsih_raid_device_remove(ioc, raid_device);
6338 }
6339
Eric Moore635374e2009-03-09 01:21:12 -06006340 /* free ports attached to the sas_host */
6341 retry_again:
6342 list_for_each_entry(mpt2sas_port,
6343 &ioc->sas_hba.sas_port_list, port_list) {
6344 if (mpt2sas_port->remote_identify.device_type ==
6345 SAS_END_DEVICE) {
6346 sas_device =
6347 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
6348 mpt2sas_port->remote_identify.sas_address);
6349 if (sas_device) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306350 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06006351 goto retry_again;
6352 }
6353 } else {
6354 expander_sibling =
6355 mpt2sas_scsih_expander_find_by_sas_address(ioc,
6356 mpt2sas_port->remote_identify.sas_address);
6357 if (expander_sibling) {
6358 _scsih_expander_remove(ioc,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306359 expander_sibling->sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06006360 goto retry_again;
6361 }
6362 }
6363 }
6364
6365 /* free phys attached to the sas_host */
6366 if (ioc->sas_hba.num_phys) {
6367 kfree(ioc->sas_hba.phy);
6368 ioc->sas_hba.phy = NULL;
6369 ioc->sas_hba.num_phys = 0;
6370 }
6371
6372 sas_remove_host(shost);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306373 _scsih_shutdown(pdev);
Eric Moore635374e2009-03-09 01:21:12 -06006374 list_del(&ioc->list);
6375 scsi_remove_host(shost);
6376 scsi_host_put(shost);
6377}
6378
6379/**
6380 * _scsih_probe_boot_devices - reports 1st device
6381 * @ioc: per adapter object
6382 *
6383 * If specified in bios page 2, this routine reports the 1st
6384 * device scsi-ml or sas transport for persistent boot device
6385 * purposes. Please refer to function _scsih_determine_boot_device()
6386 */
6387static void
6388_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
6389{
6390 u8 is_raid;
6391 void *device;
6392 struct _sas_device *sas_device;
6393 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306394 u16 handle;
6395 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06006396 u64 sas_address;
6397 unsigned long flags;
6398 int rc;
6399
6400 device = NULL;
6401 if (ioc->req_boot_device.device) {
6402 device = ioc->req_boot_device.device;
6403 is_raid = ioc->req_boot_device.is_raid;
6404 } else if (ioc->req_alt_boot_device.device) {
6405 device = ioc->req_alt_boot_device.device;
6406 is_raid = ioc->req_alt_boot_device.is_raid;
6407 } else if (ioc->current_boot_device.device) {
6408 device = ioc->current_boot_device.device;
6409 is_raid = ioc->current_boot_device.is_raid;
6410 }
6411
6412 if (!device)
6413 return;
6414
6415 if (is_raid) {
6416 raid_device = device;
6417 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6418 raid_device->id, 0);
6419 if (rc)
6420 _scsih_raid_device_remove(ioc, raid_device);
6421 } else {
6422 sas_device = device;
6423 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306424 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06006425 sas_address = sas_device->sas_address;
6426 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6427 list_move_tail(&sas_device->list, &ioc->sas_device_list);
6428 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6429 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306430 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06006431 _scsih_sas_device_remove(ioc, sas_device);
6432 } else if (!sas_device->starget) {
6433 mpt2sas_transport_port_remove(ioc, sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306434 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006435 _scsih_sas_device_remove(ioc, sas_device);
6436 }
6437 }
6438}
6439
6440/**
6441 * _scsih_probe_raid - reporting raid volumes to scsi-ml
6442 * @ioc: per adapter object
6443 *
6444 * Called during initial loading of the driver.
6445 */
6446static void
6447_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
6448{
6449 struct _raid_device *raid_device, *raid_next;
6450 int rc;
6451
6452 list_for_each_entry_safe(raid_device, raid_next,
6453 &ioc->raid_device_list, list) {
6454 if (raid_device->starget)
6455 continue;
6456 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6457 raid_device->id, 0);
6458 if (rc)
6459 _scsih_raid_device_remove(ioc, raid_device);
6460 }
6461}
6462
6463/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306464 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06006465 * @ioc: per adapter object
6466 *
6467 * Called during initial loading of the driver.
6468 */
6469static void
6470_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
6471{
6472 struct _sas_device *sas_device, *next;
6473 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06006474
6475 /* SAS Device List */
6476 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
6477 list) {
6478 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6479 list_move_tail(&sas_device->list, &ioc->sas_device_list);
6480 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6481
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306482 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
6483 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06006484 _scsih_sas_device_remove(ioc, sas_device);
6485 } else if (!sas_device->starget) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306486 mpt2sas_transport_port_remove(ioc,
6487 sas_device->sas_address,
6488 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006489 _scsih_sas_device_remove(ioc, sas_device);
6490 }
6491 }
6492}
6493
6494/**
6495 * _scsih_probe_devices - probing for devices
6496 * @ioc: per adapter object
6497 *
6498 * Called during initial loading of the driver.
6499 */
6500static void
6501_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
6502{
6503 u16 volume_mapping_flags =
6504 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
6505 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
6506
6507 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
6508 return; /* return when IOC doesn't support initiator mode */
6509
6510 _scsih_probe_boot_devices(ioc);
6511
6512 if (ioc->ir_firmware) {
6513 if ((volume_mapping_flags &
6514 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
6515 _scsih_probe_sas(ioc);
6516 _scsih_probe_raid(ioc);
6517 } else {
6518 _scsih_probe_raid(ioc);
6519 _scsih_probe_sas(ioc);
6520 }
6521 } else
6522 _scsih_probe_sas(ioc);
6523}
6524
6525/**
Eric Moored5d135b2009-05-18 13:02:08 -06006526 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06006527 * @pdev: PCI device struct
6528 * @id: pci device id
6529 *
6530 * Returns 0 success, anything else error.
6531 */
6532static int
Eric Moored5d135b2009-05-18 13:02:08 -06006533_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06006534{
6535 struct MPT2SAS_ADAPTER *ioc;
6536 struct Scsi_Host *shost;
6537
6538 shost = scsi_host_alloc(&scsih_driver_template,
6539 sizeof(struct MPT2SAS_ADAPTER));
6540 if (!shost)
6541 return -ENODEV;
6542
6543 /* init local params */
6544 ioc = shost_priv(shost);
6545 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
6546 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06006547 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06006548 ioc->shost = shost;
6549 ioc->id = mpt_ids++;
6550 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
6551 ioc->pdev = pdev;
6552 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
6553 ioc->tm_cb_idx = tm_cb_idx;
6554 ioc->ctl_cb_idx = ctl_cb_idx;
6555 ioc->base_cb_idx = base_cb_idx;
6556 ioc->transport_cb_idx = transport_cb_idx;
Kashyap, Desai744090d2009-10-05 15:56:56 +05306557 ioc->scsih_cb_idx = scsih_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006558 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306559 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
6560 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006561 ioc->logging_level = logging_level;
6562 /* misc semaphores and spin locks */
Kashyap, Desaid2742132010-06-17 13:28:55 +05306563 mutex_init(&ioc->reset_in_progress_mutex);
Eric Moore635374e2009-03-09 01:21:12 -06006564 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
6565 spin_lock_init(&ioc->scsi_lookup_lock);
6566 spin_lock_init(&ioc->sas_device_lock);
6567 spin_lock_init(&ioc->sas_node_lock);
6568 spin_lock_init(&ioc->fw_event_lock);
6569 spin_lock_init(&ioc->raid_device_lock);
6570
6571 INIT_LIST_HEAD(&ioc->sas_device_list);
6572 INIT_LIST_HEAD(&ioc->sas_device_init_list);
6573 INIT_LIST_HEAD(&ioc->sas_expander_list);
6574 INIT_LIST_HEAD(&ioc->fw_event_list);
6575 INIT_LIST_HEAD(&ioc->raid_device_list);
6576 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306577 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Eric Moore635374e2009-03-09 01:21:12 -06006578
6579 /* init shost parameters */
Eric Moored334aa72010-04-22 10:47:40 -06006580 shost->max_cmd_len = 32;
Eric Moore635374e2009-03-09 01:21:12 -06006581 shost->max_lun = max_lun;
6582 shost->transportt = mpt2sas_transport_template;
6583 shost->unique_id = ioc->id;
6584
6585 if ((scsi_add_host(shost, &pdev->dev))) {
6586 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6587 ioc->name, __FILE__, __LINE__, __func__);
6588 list_del(&ioc->list);
6589 goto out_add_shost_fail;
6590 }
6591
Eric Moore3c621b32009-05-18 12:59:41 -06006592 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
Eric Moored334aa72010-04-22 10:47:40 -06006593 | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306594 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06006595
Eric Moore635374e2009-03-09 01:21:12 -06006596 /* event thread */
6597 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
6598 "fw_event%d", ioc->id);
6599 ioc->firmware_event_thread = create_singlethread_workqueue(
6600 ioc->firmware_event_name);
6601 if (!ioc->firmware_event_thread) {
6602 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6603 ioc->name, __FILE__, __LINE__, __func__);
6604 goto out_thread_fail;
6605 }
6606
6607 ioc->wait_for_port_enable_to_complete = 1;
6608 if ((mpt2sas_base_attach(ioc))) {
6609 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6610 ioc->name, __FILE__, __LINE__, __func__);
6611 goto out_attach_fail;
6612 }
6613
6614 ioc->wait_for_port_enable_to_complete = 0;
6615 _scsih_probe_devices(ioc);
6616 return 0;
6617
6618 out_attach_fail:
6619 destroy_workqueue(ioc->firmware_event_thread);
6620 out_thread_fail:
6621 list_del(&ioc->list);
6622 scsi_remove_host(shost);
6623 out_add_shost_fail:
6624 return -ENODEV;
6625}
6626
6627#ifdef CONFIG_PM
6628/**
Eric Moored5d135b2009-05-18 13:02:08 -06006629 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006630 * @pdev: PCI device struct
6631 * @state: PM state change to (usually PCI_D3)
6632 *
6633 * Returns 0 success, anything else error.
6634 */
6635static int
Eric Moored5d135b2009-05-18 13:02:08 -06006636_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06006637{
6638 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6639 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6640 u32 device_state;
6641
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306642 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006643 flush_scheduled_work();
6644 scsi_block_requests(shost);
6645 device_state = pci_choose_state(pdev, state);
6646 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
6647 "operating state [D%d]\n", ioc->name, pdev,
6648 pci_name(pdev), device_state);
6649
6650 mpt2sas_base_free_resources(ioc);
6651 pci_save_state(pdev);
6652 pci_disable_device(pdev);
6653 pci_set_power_state(pdev, device_state);
6654 return 0;
6655}
6656
6657/**
Eric Moored5d135b2009-05-18 13:02:08 -06006658 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006659 * @pdev: PCI device struct
6660 *
6661 * Returns 0 success, anything else error.
6662 */
6663static int
Eric Moored5d135b2009-05-18 13:02:08 -06006664_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006665{
6666 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6667 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6668 u32 device_state = pdev->current_state;
6669 int r;
6670
6671 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
6672 "operating state [D%d]\n", ioc->name, pdev,
6673 pci_name(pdev), device_state);
6674
6675 pci_set_power_state(pdev, PCI_D0);
6676 pci_enable_wake(pdev, PCI_D0, 0);
6677 pci_restore_state(pdev);
6678 ioc->pdev = pdev;
6679 r = mpt2sas_base_map_resources(ioc);
6680 if (r)
6681 return r;
6682
6683 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
6684 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306685 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006686 return 0;
6687}
6688#endif /* CONFIG_PM */
6689
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05306690/**
6691 * _scsih_pci_error_detected - Called when a PCI error is detected.
6692 * @pdev: PCI device struct
6693 * @state: PCI channel state
6694 *
6695 * Description: Called when a PCI error is detected.
6696 *
6697 * Return value:
6698 * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
6699 */
6700static pci_ers_result_t
6701_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
6702{
6703 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6704 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6705
6706 printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n",
6707 ioc->name, state);
6708
6709 switch (state) {
6710 case pci_channel_io_normal:
6711 return PCI_ERS_RESULT_CAN_RECOVER;
6712 case pci_channel_io_frozen:
6713 scsi_block_requests(ioc->shost);
6714 mpt2sas_base_stop_watchdog(ioc);
6715 mpt2sas_base_free_resources(ioc);
6716 return PCI_ERS_RESULT_NEED_RESET;
6717 case pci_channel_io_perm_failure:
6718 _scsih_remove(pdev);
6719 return PCI_ERS_RESULT_DISCONNECT;
6720 }
6721 return PCI_ERS_RESULT_NEED_RESET;
6722}
6723
6724/**
6725 * _scsih_pci_slot_reset - Called when PCI slot has been reset.
6726 * @pdev: PCI device struct
6727 *
6728 * Description: This routine is called by the pci error recovery
6729 * code after the PCI slot has been reset, just before we
6730 * should resume normal operations.
6731 */
6732static pci_ers_result_t
6733_scsih_pci_slot_reset(struct pci_dev *pdev)
6734{
6735 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6736 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6737 int rc;
6738
6739 printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
6740 ioc->name);
6741
6742 ioc->pdev = pdev;
6743 rc = mpt2sas_base_map_resources(ioc);
6744 if (rc)
6745 return PCI_ERS_RESULT_DISCONNECT;
6746
6747
6748 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
6749 FORCE_BIG_HAMMER);
6750
6751 printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name,
6752 (rc == 0) ? "success" : "failed");
6753
6754 if (!rc)
6755 return PCI_ERS_RESULT_RECOVERED;
6756 else
6757 return PCI_ERS_RESULT_DISCONNECT;
6758}
6759
6760/**
6761 * _scsih_pci_resume() - resume normal ops after PCI reset
6762 * @pdev: pointer to PCI device
6763 *
6764 * Called when the error recovery driver tells us that its
6765 * OK to resume normal operation. Use completion to allow
6766 * halted scsi ops to resume.
6767 */
6768static void
6769_scsih_pci_resume(struct pci_dev *pdev)
6770{
6771 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6772 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6773
6774 printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name);
6775
6776 pci_cleanup_aer_uncorrect_error_status(pdev);
6777 mpt2sas_base_start_watchdog(ioc);
6778 scsi_unblock_requests(ioc->shost);
6779}
6780
6781/**
6782 * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
6783 * @pdev: pointer to PCI device
6784 */
6785static pci_ers_result_t
6786_scsih_pci_mmio_enabled(struct pci_dev *pdev)
6787{
6788 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6789 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6790
6791 printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n",
6792 ioc->name);
6793
6794 /* TODO - dump whatever for debugging purposes */
6795
6796 /* Request a slot reset. */
6797 return PCI_ERS_RESULT_NEED_RESET;
6798}
6799
6800static struct pci_error_handlers _scsih_err_handler = {
6801 .error_detected = _scsih_pci_error_detected,
6802 .mmio_enabled = _scsih_pci_mmio_enabled,
6803 .slot_reset = _scsih_pci_slot_reset,
6804 .resume = _scsih_pci_resume,
6805};
Eric Moore635374e2009-03-09 01:21:12 -06006806
6807static struct pci_driver scsih_driver = {
6808 .name = MPT2SAS_DRIVER_NAME,
6809 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06006810 .probe = _scsih_probe,
6811 .remove = __devexit_p(_scsih_remove),
Kashyap, Desai744090d2009-10-05 15:56:56 +05306812 .shutdown = _scsih_shutdown,
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05306813 .err_handler = &_scsih_err_handler,
Eric Moore635374e2009-03-09 01:21:12 -06006814#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06006815 .suspend = _scsih_suspend,
6816 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06006817#endif
6818};
6819
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306820/* raid transport support */
6821static struct raid_function_template mpt2sas_raid_functions = {
6822 .cookie = &scsih_driver_template,
6823 .is_raid = _scsih_is_raid,
6824 .get_resync = _scsih_get_resync,
6825 .get_state = _scsih_get_state,
6826};
Eric Moore635374e2009-03-09 01:21:12 -06006827
6828/**
Eric Moored5d135b2009-05-18 13:02:08 -06006829 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06006830 *
6831 * Returns 0 success, anything else error.
6832 */
6833static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06006834_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06006835{
6836 int error;
6837
6838 mpt_ids = 0;
6839 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
6840 MPT2SAS_DRIVER_VERSION);
6841
6842 mpt2sas_transport_template =
6843 sas_attach_transport(&mpt2sas_transport_functions);
6844 if (!mpt2sas_transport_template)
6845 return -ENODEV;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306846 /* raid transport support */
6847 mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
6848 if (!mpt2sas_raid_template) {
6849 sas_release_transport(mpt2sas_transport_template);
6850 return -ENODEV;
6851 }
Eric Moore635374e2009-03-09 01:21:12 -06006852
6853 mpt2sas_base_initialize_callback_handler();
6854
6855 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06006856 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06006857
6858 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06006859 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06006860
6861 /* base internal commands callback handler */
6862 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
6863
6864 /* transport internal commands callback handler */
6865 transport_cb_idx = mpt2sas_base_register_callback_handler(
6866 mpt2sas_transport_done);
6867
Kashyap, Desai744090d2009-10-05 15:56:56 +05306868 /* scsih internal commands callback handler */
6869 scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
6870
Eric Moore635374e2009-03-09 01:21:12 -06006871 /* configuration page API internal commands callback handler */
6872 config_cb_idx = mpt2sas_base_register_callback_handler(
6873 mpt2sas_config_done);
6874
6875 /* ctl module callback handler */
6876 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
6877
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306878 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
6879 _scsih_tm_tr_complete);
6880 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
6881 _scsih_sas_control_complete);
6882
Eric Moore635374e2009-03-09 01:21:12 -06006883 mpt2sas_ctl_init();
6884
6885 error = pci_register_driver(&scsih_driver);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306886 if (error) {
6887 /* raid transport support */
6888 raid_class_release(mpt2sas_raid_template);
Eric Moore635374e2009-03-09 01:21:12 -06006889 sas_release_transport(mpt2sas_transport_template);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306890 }
Eric Moore635374e2009-03-09 01:21:12 -06006891
6892 return error;
6893}
6894
6895/**
Eric Moored5d135b2009-05-18 13:02:08 -06006896 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06006897 *
6898 * Returns 0 success, anything else error.
6899 */
6900static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06006901_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06006902{
6903 printk(KERN_INFO "mpt2sas version %s unloading\n",
6904 MPT2SAS_DRIVER_VERSION);
6905
6906 pci_unregister_driver(&scsih_driver);
6907
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306908 mpt2sas_ctl_exit();
6909
Eric Moore635374e2009-03-09 01:21:12 -06006910 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
6911 mpt2sas_base_release_callback_handler(tm_cb_idx);
6912 mpt2sas_base_release_callback_handler(base_cb_idx);
6913 mpt2sas_base_release_callback_handler(transport_cb_idx);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306914 mpt2sas_base_release_callback_handler(scsih_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06006915 mpt2sas_base_release_callback_handler(config_cb_idx);
6916 mpt2sas_base_release_callback_handler(ctl_cb_idx);
6917
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306918 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
6919 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
6920
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306921 /* raid transport support */
6922 raid_class_release(mpt2sas_raid_template);
6923 sas_release_transport(mpt2sas_transport_template);
6924
Eric Moore635374e2009-03-09 01:21:12 -06006925}
6926
Eric Moored5d135b2009-05-18 13:02:08 -06006927module_init(_scsih_init);
6928module_exit(_scsih_exit);