blob: 7c762b9dda54ff24608c599a696a798d396dd12c [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
Kashyap, Desaif3eedd62010-06-17 13:46:13 +053073static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid);
74
Eric Moore635374e2009-03-09 01:21:12 -060075/* global parameters */
Eric Mooreba33fad2009-03-15 21:37:18 -060076LIST_HEAD(mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -060077
78/* local parameters */
Eric Moore635374e2009-03-09 01:21:12 -060079static u8 scsi_io_cb_idx = -1;
80static u8 tm_cb_idx = -1;
81static u8 ctl_cb_idx = -1;
82static u8 base_cb_idx = -1;
83static u8 transport_cb_idx = -1;
Kashyap, Desai744090d2009-10-05 15:56:56 +053084static u8 scsih_cb_idx = -1;
Eric Moore635374e2009-03-09 01:21:12 -060085static u8 config_cb_idx = -1;
86static int mpt_ids;
87
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053088static u8 tm_tr_cb_idx = -1 ;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +053089static u8 tm_tr_volume_cb_idx = -1 ;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053090static u8 tm_sas_control_cb_idx = -1;
91
Eric Moore635374e2009-03-09 01:21:12 -060092/* command line options */
Eric Mooreba33fad2009-03-15 21:37:18 -060093static u32 logging_level;
Eric Moore635374e2009-03-09 01:21:12 -060094MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
95 "(default=0)");
96
Kashyap, Desaia3e1e552011-06-14 10:56:12 +053097static ushort max_sectors = 0xFFFF;
98module_param(max_sectors, ushort, 0);
99MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 8192 default=8192");
100
Eric Moore635374e2009-03-09 01:21:12 -0600101/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
102#define MPT2SAS_MAX_LUN (16895)
103static int max_lun = MPT2SAS_MAX_LUN;
104module_param(max_lun, int, 0);
105MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
106
107/**
108 * struct sense_info - common structure for obtaining sense keys
109 * @skey: sense key
110 * @asc: additional sense code
111 * @ascq: additional sense code qualifier
112 */
113struct sense_info {
114 u8 skey;
115 u8 asc;
116 u8 ascq;
117};
118
119
Kashyap, Desai3ace8e02011-05-04 16:35:58 +0530120#define MPT2SAS_TURN_ON_FAULT_LED (0xFFFC)
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530121#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF)
122
Eric Moore635374e2009-03-09 01:21:12 -0600123/**
124 * struct fw_event_work - firmware event struct
125 * @list: link list framework
126 * @work: work object (ioc->fault_reset_work_q)
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530127 * @cancel_pending_work: flag set during reset handling
Eric Moore635374e2009-03-09 01:21:12 -0600128 * @ioc: per adapter object
Kashyap, Desai3ace8e02011-05-04 16:35:58 +0530129 * @device_handle: device handle
Eric Moore635374e2009-03-09 01:21:12 -0600130 * @VF_ID: virtual function id
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530131 * @VP_ID: virtual port id
Eric Moore635374e2009-03-09 01:21:12 -0600132 * @ignore: flag meaning this event has been marked to ignore
133 * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
134 * @event_data: reply event data payload follows
135 *
136 * This object stored on ioc->fw_event_list.
137 */
138struct fw_event_work {
139 struct list_head list;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530140 u8 cancel_pending_work;
141 struct delayed_work delayed_work;
Eric Moore635374e2009-03-09 01:21:12 -0600142 struct MPT2SAS_ADAPTER *ioc;
Kashyap, Desai3ace8e02011-05-04 16:35:58 +0530143 u16 device_handle;
Eric Moore635374e2009-03-09 01:21:12 -0600144 u8 VF_ID;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530145 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600146 u8 ignore;
147 u16 event;
148 void *event_data;
149};
150
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +0530151/* raid transport support */
152static struct raid_template *mpt2sas_raid_template;
153
Eric Moore635374e2009-03-09 01:21:12 -0600154/**
155 * struct _scsi_io_transfer - scsi io transfer
156 * @handle: sas device handle (assigned by firmware)
157 * @is_raid: flag set for hidden raid components
158 * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
159 * @data_length: data transfer length
160 * @data_dma: dma pointer to data
161 * @sense: sense data
162 * @lun: lun number
163 * @cdb_length: cdb length
164 * @cdb: cdb contents
Eric Moore635374e2009-03-09 01:21:12 -0600165 * @timeout: timeout for this command
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530166 * @VF_ID: virtual function id
167 * @VP_ID: virtual port id
168 * @valid_reply: flag set for reply message
Eric Moore635374e2009-03-09 01:21:12 -0600169 * @sense_length: sense length
170 * @ioc_status: ioc status
171 * @scsi_state: scsi state
172 * @scsi_status: scsi staus
173 * @log_info: log information
174 * @transfer_length: data length transfer when there is a reply message
175 *
176 * Used for sending internal scsi commands to devices within this module.
177 * Refer to _scsi_send_scsi_io().
178 */
179struct _scsi_io_transfer {
180 u16 handle;
181 u8 is_raid;
182 enum dma_data_direction dir;
183 u32 data_length;
184 dma_addr_t data_dma;
185 u8 sense[SCSI_SENSE_BUFFERSIZE];
186 u32 lun;
187 u8 cdb_length;
188 u8 cdb[32];
189 u8 timeout;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530190 u8 VF_ID;
191 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600192 u8 valid_reply;
193 /* the following bits are only valid when 'valid_reply = 1' */
194 u32 sense_length;
195 u16 ioc_status;
196 u8 scsi_state;
197 u8 scsi_status;
198 u32 log_info;
199 u32 transfer_length;
200};
201
202/*
203 * The pci device ids are defined in mpi/mpi2_cnfg.h.
204 */
205static struct pci_device_id scsih_pci_table[] = {
206 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
207 PCI_ANY_ID, PCI_ANY_ID },
208 /* Falcon ~ 2008*/
209 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
210 PCI_ANY_ID, PCI_ANY_ID },
211 /* Liberator ~ 2108 */
212 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
213 PCI_ANY_ID, PCI_ANY_ID },
214 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
215 PCI_ANY_ID, PCI_ANY_ID },
216 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
217 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530218 /* Meteor ~ 2116 */
Eric Moore635374e2009-03-09 01:21:12 -0600219 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
220 PCI_ANY_ID, PCI_ANY_ID },
221 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
222 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530223 /* Thunderbolt ~ 2208 */
224 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
225 PCI_ANY_ID, PCI_ANY_ID },
226 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
227 PCI_ANY_ID, PCI_ANY_ID },
228 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
229 PCI_ANY_ID, PCI_ANY_ID },
230 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
231 PCI_ANY_ID, PCI_ANY_ID },
232 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
233 PCI_ANY_ID, PCI_ANY_ID },
234 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
235 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desai203d65b2010-06-17 13:37:59 +0530236 /* Mustang ~ 2308 */
237 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
Kashyap, Desaidb271362009-09-23 17:24:27 +0530238 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desai203d65b2010-06-17 13:37:59 +0530239 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
240 PCI_ANY_ID, PCI_ANY_ID },
241 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
Kashyap, Desaidb271362009-09-23 17:24:27 +0530242 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +0530243 /* SSS6200 */
244 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
245 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore635374e2009-03-09 01:21:12 -0600246 {0} /* Terminating entry */
247};
248MODULE_DEVICE_TABLE(pci, scsih_pci_table);
249
250/**
Eric Moored5d135b2009-05-18 13:02:08 -0600251 * _scsih_set_debug_level - global setting of ioc->logging_level.
Eric Moore635374e2009-03-09 01:21:12 -0600252 *
253 * Note: The logging levels are defined in mpt2sas_debug.h.
254 */
255static int
Eric Moored5d135b2009-05-18 13:02:08 -0600256_scsih_set_debug_level(const char *val, struct kernel_param *kp)
Eric Moore635374e2009-03-09 01:21:12 -0600257{
258 int ret = param_set_int(val, kp);
259 struct MPT2SAS_ADAPTER *ioc;
260
261 if (ret)
262 return ret;
263
264 printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
Eric Mooreba33fad2009-03-15 21:37:18 -0600265 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
Eric Moore635374e2009-03-09 01:21:12 -0600266 ioc->logging_level = logging_level;
267 return 0;
268}
Eric Moored5d135b2009-05-18 13:02:08 -0600269module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
Eric Moore635374e2009-03-09 01:21:12 -0600270 &logging_level, 0644);
271
272/**
273 * _scsih_srch_boot_sas_address - search based on sas_address
274 * @sas_address: sas address
275 * @boot_device: boot device object from bios page 2
276 *
277 * Returns 1 when there's a match, 0 means no match.
278 */
279static inline int
280_scsih_srch_boot_sas_address(u64 sas_address,
281 Mpi2BootDeviceSasWwid_t *boot_device)
282{
283 return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
284}
285
286/**
287 * _scsih_srch_boot_device_name - search based on device name
288 * @device_name: device name specified in INDENTIFY fram
289 * @boot_device: boot device object from bios page 2
290 *
291 * Returns 1 when there's a match, 0 means no match.
292 */
293static inline int
294_scsih_srch_boot_device_name(u64 device_name,
295 Mpi2BootDeviceDeviceName_t *boot_device)
296{
297 return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
298}
299
300/**
301 * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
302 * @enclosure_logical_id: enclosure logical id
303 * @slot_number: slot number
304 * @boot_device: boot device object from bios page 2
305 *
306 * Returns 1 when there's a match, 0 means no match.
307 */
308static inline int
309_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
310 Mpi2BootDeviceEnclosureSlot_t *boot_device)
311{
312 return (enclosure_logical_id == le64_to_cpu(boot_device->
313 EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
314 SlotNumber)) ? 1 : 0;
315}
316
317/**
318 * _scsih_is_boot_device - search for matching boot device.
319 * @sas_address: sas address
320 * @device_name: device name specified in INDENTIFY fram
321 * @enclosure_logical_id: enclosure logical id
322 * @slot_number: slot number
323 * @form: specifies boot device form
324 * @boot_device: boot device object from bios page 2
325 *
326 * Returns 1 when there's a match, 0 means no match.
327 */
328static int
329_scsih_is_boot_device(u64 sas_address, u64 device_name,
330 u64 enclosure_logical_id, u16 slot, u8 form,
331 Mpi2BiosPage2BootDevice_t *boot_device)
332{
333 int rc = 0;
334
335 switch (form) {
336 case MPI2_BIOSPAGE2_FORM_SAS_WWID:
337 if (!sas_address)
338 break;
339 rc = _scsih_srch_boot_sas_address(
340 sas_address, &boot_device->SasWwid);
341 break;
342 case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
343 if (!enclosure_logical_id)
344 break;
345 rc = _scsih_srch_boot_encl_slot(
346 enclosure_logical_id,
347 slot, &boot_device->EnclosureSlot);
348 break;
349 case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
350 if (!device_name)
351 break;
352 rc = _scsih_srch_boot_device_name(
353 device_name, &boot_device->DeviceName);
354 break;
355 case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
356 break;
357 }
358
359 return rc;
360}
361
362/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530363 * _scsih_get_sas_address - set the sas_address for given device handle
364 * @handle: device handle
365 * @sas_address: sas address
366 *
367 * Returns 0 success, non-zero when failure
368 */
369static int
370_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
371 u64 *sas_address)
372{
373 Mpi2SasDevicePage0_t sas_device_pg0;
374 Mpi2ConfigReply_t mpi_reply;
375 u32 ioc_status;
376
377 if (handle <= ioc->sas_hba.num_phys) {
378 *sas_address = ioc->sas_hba.sas_address;
379 return 0;
380 } else
381 *sas_address = 0;
382
383 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
384 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
385 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
386 ioc->name, __FILE__, __LINE__, __func__);
387 return -ENXIO;
388 }
389
390 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
391 MPI2_IOCSTATUS_MASK;
392 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
393 printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
394 "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
395 __FILE__, __LINE__, __func__);
396 return -EIO;
397 }
398
399 *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
400 return 0;
401}
402
403/**
Eric Moore635374e2009-03-09 01:21:12 -0600404 * _scsih_determine_boot_device - determine boot device.
405 * @ioc: per adapter object
406 * @device: either sas_device or raid_device object
407 * @is_raid: [flag] 1 = raid object, 0 = sas object
408 *
409 * Determines whether this device should be first reported device to
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300410 * to scsi-ml or sas transport, this purpose is for persistent boot device.
Eric Moore635374e2009-03-09 01:21:12 -0600411 * There are primary, alternate, and current entries in bios page 2. The order
412 * priority is primary, alternate, then current. This routine saves
413 * the corresponding device object and is_raid flag in the ioc object.
414 * The saved data to be used later in _scsih_probe_boot_devices().
415 */
416static void
417_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
418 void *device, u8 is_raid)
419{
420 struct _sas_device *sas_device;
421 struct _raid_device *raid_device;
422 u64 sas_address;
423 u64 device_name;
424 u64 enclosure_logical_id;
425 u16 slot;
426
427 /* only process this function when driver loads */
428 if (!ioc->wait_for_port_enable_to_complete)
429 return;
430
431 if (!is_raid) {
432 sas_device = device;
433 sas_address = sas_device->sas_address;
434 device_name = sas_device->device_name;
435 enclosure_logical_id = sas_device->enclosure_logical_id;
436 slot = sas_device->slot;
437 } else {
438 raid_device = device;
439 sas_address = raid_device->wwid;
440 device_name = 0;
441 enclosure_logical_id = 0;
442 slot = 0;
443 }
444
445 if (!ioc->req_boot_device.device) {
446 if (_scsih_is_boot_device(sas_address, device_name,
447 enclosure_logical_id, slot,
448 (ioc->bios_pg2.ReqBootDeviceForm &
449 MPI2_BIOSPAGE2_FORM_MASK),
450 &ioc->bios_pg2.RequestedBootDevice)) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530451 dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -0600452 "%s: req_boot_device(0x%016llx)\n",
453 ioc->name, __func__,
454 (unsigned long long)sas_address));
455 ioc->req_boot_device.device = device;
456 ioc->req_boot_device.is_raid = is_raid;
457 }
458 }
459
460 if (!ioc->req_alt_boot_device.device) {
461 if (_scsih_is_boot_device(sas_address, device_name,
462 enclosure_logical_id, slot,
463 (ioc->bios_pg2.ReqAltBootDeviceForm &
464 MPI2_BIOSPAGE2_FORM_MASK),
465 &ioc->bios_pg2.RequestedAltBootDevice)) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530466 dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -0600467 "%s: req_alt_boot_device(0x%016llx)\n",
468 ioc->name, __func__,
469 (unsigned long long)sas_address));
470 ioc->req_alt_boot_device.device = device;
471 ioc->req_alt_boot_device.is_raid = is_raid;
472 }
473 }
474
475 if (!ioc->current_boot_device.device) {
476 if (_scsih_is_boot_device(sas_address, device_name,
477 enclosure_logical_id, slot,
478 (ioc->bios_pg2.CurrentBootDeviceForm &
479 MPI2_BIOSPAGE2_FORM_MASK),
480 &ioc->bios_pg2.CurrentBootDevice)) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530481 dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -0600482 "%s: current_boot_device(0x%016llx)\n",
483 ioc->name, __func__,
484 (unsigned long long)sas_address));
485 ioc->current_boot_device.device = device;
486 ioc->current_boot_device.is_raid = is_raid;
487 }
488 }
489}
490
491/**
492 * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
493 * @ioc: per adapter object
494 * @sas_address: sas address
495 * Context: Calling function should acquire ioc->sas_device_lock
496 *
497 * This searches for sas_device based on sas_address, then return sas_device
498 * object.
499 */
500struct _sas_device *
501mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
502 u64 sas_address)
503{
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530504 struct _sas_device *sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600505
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530506 list_for_each_entry(sas_device, &ioc->sas_device_list, list)
507 if (sas_device->sas_address == sas_address)
508 return sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600509
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530510 list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
511 if (sas_device->sas_address == sas_address)
512 return sas_device;
513
514 return NULL;
Eric Moore635374e2009-03-09 01:21:12 -0600515}
516
517/**
518 * _scsih_sas_device_find_by_handle - sas device search
519 * @ioc: per adapter object
520 * @handle: sas device handle (assigned by firmware)
521 * Context: Calling function should acquire ioc->sas_device_lock
522 *
523 * This searches for sas_device based on sas_address, then return sas_device
524 * object.
525 */
526static struct _sas_device *
527_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
528{
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530529 struct _sas_device *sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600530
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530531 list_for_each_entry(sas_device, &ioc->sas_device_list, list)
532 if (sas_device->handle == handle)
533 return sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600534
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530535 list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
536 if (sas_device->handle == handle)
537 return sas_device;
538
539 return NULL;
Eric Moore635374e2009-03-09 01:21:12 -0600540}
541
542/**
543 * _scsih_sas_device_remove - remove sas_device from list.
544 * @ioc: per adapter object
545 * @sas_device: the sas_device object
546 * Context: This function will acquire ioc->sas_device_lock.
547 *
548 * Removing object and freeing associated memory from the ioc->sas_device_list.
549 */
550static void
551_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
552 struct _sas_device *sas_device)
553{
554 unsigned long flags;
555
Kashyap, Desai980ead32010-04-08 17:55:22 +0530556 if (!sas_device)
557 return;
558
Eric Moore635374e2009-03-09 01:21:12 -0600559 spin_lock_irqsave(&ioc->sas_device_lock, flags);
Kashyap, Desai980ead32010-04-08 17:55:22 +0530560 if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
561 sas_device->sas_address)) {
562 list_del(&sas_device->list);
563 kfree(sas_device);
564 }
Eric Moore635374e2009-03-09 01:21:12 -0600565 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
566}
567
568/**
569 * _scsih_sas_device_add - insert sas_device to the list.
570 * @ioc: per adapter object
571 * @sas_device: the sas_device object
572 * Context: This function will acquire ioc->sas_device_lock.
573 *
574 * Adding new object to the ioc->sas_device_list.
575 */
576static void
577_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
578 struct _sas_device *sas_device)
579{
580 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -0600581
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530582 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
Eric Moore635374e2009-03-09 01:21:12 -0600583 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
584 sas_device->handle, (unsigned long long)sas_device->sas_address));
585
586 spin_lock_irqsave(&ioc->sas_device_lock, flags);
587 list_add_tail(&sas_device->list, &ioc->sas_device_list);
588 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
589
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530590 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
591 sas_device->sas_address_parent))
Eric Moore635374e2009-03-09 01:21:12 -0600592 _scsih_sas_device_remove(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -0600593}
594
595/**
596 * _scsih_sas_device_init_add - insert sas_device to the list.
597 * @ioc: per adapter object
598 * @sas_device: the sas_device object
599 * Context: This function will acquire ioc->sas_device_lock.
600 *
601 * Adding new object at driver load time to the ioc->sas_device_init_list.
602 */
603static void
604_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
605 struct _sas_device *sas_device)
606{
607 unsigned long flags;
608
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530609 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
Eric Moore635374e2009-03-09 01:21:12 -0600610 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
611 sas_device->handle, (unsigned long long)sas_device->sas_address));
612
613 spin_lock_irqsave(&ioc->sas_device_lock, flags);
614 list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
615 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
616 _scsih_determine_boot_device(ioc, sas_device, 0);
617}
618
619/**
Eric Moore635374e2009-03-09 01:21:12 -0600620 * _scsih_raid_device_find_by_id - raid device search
621 * @ioc: per adapter object
622 * @id: sas device target id
623 * @channel: sas device channel
624 * Context: Calling function should acquire ioc->raid_device_lock
625 *
626 * This searches for raid_device based on target id, then return raid_device
627 * object.
628 */
629static struct _raid_device *
630_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
631{
632 struct _raid_device *raid_device, *r;
633
634 r = NULL;
635 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
636 if (raid_device->id == id && raid_device->channel == channel) {
637 r = raid_device;
638 goto out;
639 }
640 }
641
642 out:
643 return r;
644}
645
646/**
647 * _scsih_raid_device_find_by_handle - raid device search
648 * @ioc: per adapter object
649 * @handle: sas device handle (assigned by firmware)
650 * Context: Calling function should acquire ioc->raid_device_lock
651 *
652 * This searches for raid_device based on handle, then return raid_device
653 * object.
654 */
655static struct _raid_device *
656_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
657{
658 struct _raid_device *raid_device, *r;
659
660 r = NULL;
661 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
662 if (raid_device->handle != handle)
663 continue;
664 r = raid_device;
665 goto out;
666 }
667
668 out:
669 return r;
670}
671
672/**
673 * _scsih_raid_device_find_by_wwid - raid device search
674 * @ioc: per adapter object
675 * @handle: sas device handle (assigned by firmware)
676 * Context: Calling function should acquire ioc->raid_device_lock
677 *
678 * This searches for raid_device based on wwid, then return raid_device
679 * object.
680 */
681static struct _raid_device *
682_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
683{
684 struct _raid_device *raid_device, *r;
685
686 r = NULL;
687 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
688 if (raid_device->wwid != wwid)
689 continue;
690 r = raid_device;
691 goto out;
692 }
693
694 out:
695 return r;
696}
697
698/**
699 * _scsih_raid_device_add - add raid_device object
700 * @ioc: per adapter object
701 * @raid_device: raid_device object
702 *
703 * This is added to the raid_device_list link list.
704 */
705static void
706_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
707 struct _raid_device *raid_device)
708{
709 unsigned long flags;
710
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530711 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
Eric Moore635374e2009-03-09 01:21:12 -0600712 "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
713 raid_device->handle, (unsigned long long)raid_device->wwid));
714
715 spin_lock_irqsave(&ioc->raid_device_lock, flags);
716 list_add_tail(&raid_device->list, &ioc->raid_device_list);
717 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
718}
719
720/**
721 * _scsih_raid_device_remove - delete raid_device object
722 * @ioc: per adapter object
723 * @raid_device: raid_device object
724 *
725 * This is removed from the raid_device_list link list.
726 */
727static void
728_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
729 struct _raid_device *raid_device)
730{
731 unsigned long flags;
732
733 spin_lock_irqsave(&ioc->raid_device_lock, flags);
734 list_del(&raid_device->list);
735 memset(raid_device, 0, sizeof(struct _raid_device));
736 kfree(raid_device);
737 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
738}
739
740/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530741 * mpt2sas_scsih_expander_find_by_handle - expander device search
742 * @ioc: per adapter object
743 * @handle: expander handle (assigned by firmware)
744 * Context: Calling function should acquire ioc->sas_device_lock
745 *
746 * This searches for expander device based on handle, then returns the
747 * sas_node object.
748 */
749struct _sas_node *
750mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
751{
752 struct _sas_node *sas_expander, *r;
753
754 r = NULL;
755 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
756 if (sas_expander->handle != handle)
757 continue;
758 r = sas_expander;
759 goto out;
760 }
761 out:
762 return r;
763}
764
765/**
Eric Moore635374e2009-03-09 01:21:12 -0600766 * mpt2sas_scsih_expander_find_by_sas_address - expander device search
767 * @ioc: per adapter object
768 * @sas_address: sas address
769 * Context: Calling function should acquire ioc->sas_node_lock.
770 *
771 * This searches for expander device based on sas_address, then returns the
772 * sas_node object.
773 */
774struct _sas_node *
775mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
776 u64 sas_address)
777{
778 struct _sas_node *sas_expander, *r;
779
780 r = NULL;
781 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
782 if (sas_expander->sas_address != sas_address)
783 continue;
784 r = sas_expander;
785 goto out;
786 }
787 out:
788 return r;
789}
790
791/**
792 * _scsih_expander_node_add - insert expander device to the list.
793 * @ioc: per adapter object
794 * @sas_expander: the sas_device object
795 * Context: This function will acquire ioc->sas_node_lock.
796 *
797 * Adding new object to the ioc->sas_expander_list.
798 *
799 * Return nothing.
800 */
801static void
802_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
803 struct _sas_node *sas_expander)
804{
805 unsigned long flags;
806
807 spin_lock_irqsave(&ioc->sas_node_lock, flags);
808 list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
809 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
810}
811
812/**
813 * _scsih_is_end_device - determines if device is an end device
814 * @device_info: bitfield providing information about the device.
815 * Context: none
816 *
817 * Returns 1 if end device.
818 */
819static int
820_scsih_is_end_device(u32 device_info)
821{
822 if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
823 ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
824 (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
825 (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
826 return 1;
827 else
828 return 0;
829}
830
831/**
Kashyap, Desaiec07a052011-01-05 17:54:32 +0530832 * _scsih_scsi_lookup_get - returns scmd entry
Eric Moore635374e2009-03-09 01:21:12 -0600833 * @ioc: per adapter object
834 * @smid: system request message index
Eric Moore635374e2009-03-09 01:21:12 -0600835 *
836 * Returns the smid stored scmd pointer.
837 */
838static struct scsi_cmnd *
839_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
840{
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530841 return ioc->scsi_lookup[smid - 1].scmd;
Eric Moore635374e2009-03-09 01:21:12 -0600842}
843
844/**
Kashyap, Desaiec07a052011-01-05 17:54:32 +0530845 * _scsih_scsi_lookup_get_clear - returns scmd entry
846 * @ioc: per adapter object
847 * @smid: system request message index
848 *
849 * Returns the smid stored scmd pointer.
850 * Then will derefrence the stored scmd pointer.
851 */
852static inline struct scsi_cmnd *
853_scsih_scsi_lookup_get_clear(struct MPT2SAS_ADAPTER *ioc, u16 smid)
854{
855 unsigned long flags;
856 struct scsi_cmnd *scmd;
857
858 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
859 scmd = ioc->scsi_lookup[smid - 1].scmd;
860 ioc->scsi_lookup[smid - 1].scmd = NULL;
861 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
862
863 return scmd;
864}
865
866/**
Eric Moore635374e2009-03-09 01:21:12 -0600867 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
868 * @ioc: per adapter object
869 * @smid: system request message index
870 * @scmd: pointer to scsi command object
871 * Context: This function will acquire ioc->scsi_lookup_lock.
872 *
873 * This will search for a scmd pointer in the scsi_lookup array,
874 * returning the revelent smid. A returned value of zero means invalid.
875 */
876static u16
877_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
878 *scmd)
879{
880 u16 smid;
881 unsigned long flags;
882 int i;
883
884 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
885 smid = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530886 for (i = 0; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600887 if (ioc->scsi_lookup[i].scmd == scmd) {
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530888 smid = ioc->scsi_lookup[i].smid;
Eric Moore635374e2009-03-09 01:21:12 -0600889 goto out;
890 }
891 }
892 out:
893 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
894 return smid;
895}
896
897/**
898 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
899 * @ioc: per adapter object
900 * @id: target id
901 * @channel: channel
902 * Context: This function will acquire ioc->scsi_lookup_lock.
903 *
904 * This will search for a matching channel:id in the scsi_lookup array,
905 * returning 1 if found.
906 */
907static u8
908_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
909 int channel)
910{
911 u8 found;
912 unsigned long flags;
913 int i;
914
915 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
916 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530917 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600918 if (ioc->scsi_lookup[i].scmd &&
919 (ioc->scsi_lookup[i].scmd->device->id == id &&
920 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
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 Moore993e0da2009-05-18 13:00:45 -0600931 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
932 * @ioc: per adapter object
933 * @id: target id
934 * @lun: lun number
935 * @channel: channel
936 * Context: This function will acquire ioc->scsi_lookup_lock.
937 *
938 * This will search for a matching channel:id:lun in the scsi_lookup array,
939 * returning 1 if found.
940 */
941static u8
942_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
943 unsigned int lun, int channel)
944{
945 u8 found;
946 unsigned long flags;
947 int i;
948
949 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
950 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530951 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore993e0da2009-05-18 13:00:45 -0600952 if (ioc->scsi_lookup[i].scmd &&
953 (ioc->scsi_lookup[i].scmd->device->id == id &&
954 ioc->scsi_lookup[i].scmd->device->channel == channel &&
955 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
956 found = 1;
957 goto out;
958 }
959 }
960 out:
961 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
962 return found;
963}
964
965/**
Kashyap, Desai35f805b2010-11-13 04:34:06 +0530966 * _scsih_get_chain_buffer_tracker - obtain chain tracker
Eric Moore635374e2009-03-09 01:21:12 -0600967 * @ioc: per adapter object
Kashyap, Desai35f805b2010-11-13 04:34:06 +0530968 * @smid: smid associated to an IO request
Eric Moore635374e2009-03-09 01:21:12 -0600969 *
Kashyap, Desai35f805b2010-11-13 04:34:06 +0530970 * Returns chain tracker(from ioc->free_chain_list)
Eric Moore635374e2009-03-09 01:21:12 -0600971 */
Kashyap, Desai35f805b2010-11-13 04:34:06 +0530972static struct chain_tracker *
973_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid)
Eric Moore635374e2009-03-09 01:21:12 -0600974{
Kashyap, Desai35f805b2010-11-13 04:34:06 +0530975 struct chain_tracker *chain_req;
976 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -0600977
Kashyap, Desai35f805b2010-11-13 04:34:06 +0530978 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
979 if (list_empty(&ioc->free_chain_list)) {
980 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
981 printk(MPT2SAS_WARN_FMT "chain buffers not available\n",
982 ioc->name);
983 return NULL;
984 }
985 chain_req = list_entry(ioc->free_chain_list.next,
986 struct chain_tracker, tracker_list);
987 list_del_init(&chain_req->tracker_list);
988 list_add_tail(&chain_req->tracker_list,
989 &ioc->scsi_lookup[smid - 1].chain_list);
990 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
991 return chain_req;
Eric Moore635374e2009-03-09 01:21:12 -0600992}
993
994/**
995 * _scsih_build_scatter_gather - main sg creation routine
996 * @ioc: per adapter object
997 * @scmd: scsi command
998 * @smid: system request message index
999 * Context: none.
1000 *
1001 * The main routine that builds scatter gather table from a given
1002 * scsi request sent via the .queuecommand main handler.
1003 *
1004 * Returns 0 success, anything else error
1005 */
1006static int
1007_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
1008 struct scsi_cmnd *scmd, u16 smid)
1009{
1010 Mpi2SCSIIORequest_t *mpi_request;
1011 dma_addr_t chain_dma;
1012 struct scatterlist *sg_scmd;
1013 void *sg_local, *chain;
1014 u32 chain_offset;
1015 u32 chain_length;
1016 u32 chain_flags;
FUJITA Tomonoribb789d02010-03-09 11:09:50 +09001017 int sges_left;
Eric Moore635374e2009-03-09 01:21:12 -06001018 u32 sges_in_segment;
1019 u32 sgl_flags;
1020 u32 sgl_flags_last_element;
1021 u32 sgl_flags_end_buffer;
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301022 struct chain_tracker *chain_req;
Eric Moore635374e2009-03-09 01:21:12 -06001023
1024 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1025
1026 /* init scatter gather flags */
1027 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
1028 if (scmd->sc_data_direction == DMA_TO_DEVICE)
1029 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
1030 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
1031 << MPI2_SGE_FLAGS_SHIFT;
1032 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
1033 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
1034 << MPI2_SGE_FLAGS_SHIFT;
1035 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1036
1037 sg_scmd = scsi_sglist(scmd);
1038 sges_left = scsi_dma_map(scmd);
FUJITA Tomonoribb789d02010-03-09 11:09:50 +09001039 if (sges_left < 0) {
Eric Moore635374e2009-03-09 01:21:12 -06001040 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
1041 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
1042 return -ENOMEM;
1043 }
1044
1045 sg_local = &mpi_request->SGL;
1046 sges_in_segment = ioc->max_sges_in_main_message;
1047 if (sges_left <= sges_in_segment)
1048 goto fill_in_last_segment;
1049
1050 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
1051 (sges_in_segment * ioc->sge_size))/4;
1052
1053 /* fill in main message segment when there is a chain following */
1054 while (sges_in_segment) {
1055 if (sges_in_segment == 1)
1056 ioc->base_add_sg_single(sg_local,
1057 sgl_flags_last_element | sg_dma_len(sg_scmd),
1058 sg_dma_address(sg_scmd));
1059 else
1060 ioc->base_add_sg_single(sg_local, sgl_flags |
1061 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1062 sg_scmd = sg_next(sg_scmd);
1063 sg_local += ioc->sge_size;
1064 sges_left--;
1065 sges_in_segment--;
1066 }
1067
1068 /* initializing the chain flags and pointers */
1069 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301070 chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
1071 if (!chain_req)
1072 return -1;
1073 chain = chain_req->chain_buffer;
1074 chain_dma = chain_req->chain_buffer_dma;
Eric Moore635374e2009-03-09 01:21:12 -06001075 do {
1076 sges_in_segment = (sges_left <=
1077 ioc->max_sges_in_chain_message) ? sges_left :
1078 ioc->max_sges_in_chain_message;
1079 chain_offset = (sges_left == sges_in_segment) ?
1080 0 : (sges_in_segment * ioc->sge_size)/4;
1081 chain_length = sges_in_segment * ioc->sge_size;
1082 if (chain_offset) {
1083 chain_offset = chain_offset <<
1084 MPI2_SGE_CHAIN_OFFSET_SHIFT;
1085 chain_length += ioc->sge_size;
1086 }
1087 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
1088 chain_length, chain_dma);
1089 sg_local = chain;
1090 if (!chain_offset)
1091 goto fill_in_last_segment;
1092
1093 /* fill in chain segments */
1094 while (sges_in_segment) {
1095 if (sges_in_segment == 1)
1096 ioc->base_add_sg_single(sg_local,
1097 sgl_flags_last_element |
1098 sg_dma_len(sg_scmd),
1099 sg_dma_address(sg_scmd));
1100 else
1101 ioc->base_add_sg_single(sg_local, sgl_flags |
1102 sg_dma_len(sg_scmd),
1103 sg_dma_address(sg_scmd));
1104 sg_scmd = sg_next(sg_scmd);
1105 sg_local += ioc->sge_size;
1106 sges_left--;
1107 sges_in_segment--;
1108 }
1109
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301110 chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
1111 if (!chain_req)
1112 return -1;
1113 chain = chain_req->chain_buffer;
1114 chain_dma = chain_req->chain_buffer_dma;
Eric Moore635374e2009-03-09 01:21:12 -06001115 } while (1);
1116
1117
1118 fill_in_last_segment:
1119
1120 /* fill the last segment */
1121 while (sges_left) {
1122 if (sges_left == 1)
1123 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1124 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1125 else
1126 ioc->base_add_sg_single(sg_local, sgl_flags |
1127 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1128 sg_scmd = sg_next(sg_scmd);
1129 sg_local += ioc->sge_size;
1130 sges_left--;
1131 }
1132
1133 return 0;
1134}
1135
1136/**
Kashyap, Desaia93c6b42010-11-13 04:39:11 +05301137 * _scsih_adjust_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001138 * @sdev: scsi device struct
1139 * @qdepth: requested queue depth
1140 *
Kashyap, Desaia93c6b42010-11-13 04:39:11 +05301141 *
1142 * Returns nothing
Eric Moore635374e2009-03-09 01:21:12 -06001143 */
Kashyap, Desaia93c6b42010-11-13 04:39:11 +05301144static void
1145_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
Eric Moore635374e2009-03-09 01:21:12 -06001146{
1147 struct Scsi_Host *shost = sdev->host;
1148 int max_depth;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301149 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1150 struct MPT2SAS_DEVICE *sas_device_priv_data;
1151 struct MPT2SAS_TARGET *sas_target_priv_data;
1152 struct _sas_device *sas_device;
1153 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06001154
1155 max_depth = shost->can_queue;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301156
1157 /* limit max device queue for SATA to 32 */
1158 sas_device_priv_data = sdev->hostdata;
1159 if (!sas_device_priv_data)
1160 goto not_sata;
1161 sas_target_priv_data = sas_device_priv_data->sas_target;
1162 if (!sas_target_priv_data)
1163 goto not_sata;
1164 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
1165 goto not_sata;
1166 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1167 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1168 sas_device_priv_data->sas_target->sas_address);
1169 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1170 if (sas_device && sas_device->device_info &
1171 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1172 max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
1173
1174 not_sata:
1175
Eric Moore635374e2009-03-09 01:21:12 -06001176 if (!sdev->tagged_supported)
1177 max_depth = 1;
1178 if (qdepth > max_depth)
1179 qdepth = max_depth;
Kashyap, Desaia93c6b42010-11-13 04:39:11 +05301180 scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
1181}
1182
1183/**
1184 * _scsih_change_queue_depth - setting device queue depth
1185 * @sdev: scsi device struct
1186 * @qdepth: requested queue depth
1187 * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP
1188 * (see include/scsi/scsi_host.h for definition)
1189 *
1190 * Returns queue depth.
1191 */
1192static int
1193_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
1194{
1195 if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP)
1196 _scsih_adjust_queue_depth(sdev, qdepth);
1197 else if (reason == SCSI_QDEPTH_QFULL)
1198 scsi_track_queue_full(sdev, qdepth);
1199 else
1200 return -EOPNOTSUPP;
Eric Moore635374e2009-03-09 01:21:12 -06001201
1202 if (sdev->inquiry_len > 7)
1203 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1204 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1205 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1206 sdev->ordered_tags, sdev->scsi_level,
1207 (sdev->inquiry[7] & 2) >> 1);
1208
1209 return sdev->queue_depth;
1210}
1211
1212/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301213 * _scsih_change_queue_type - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001214 * @sdev: scsi device struct
1215 * @tag_type: requested tag type
1216 *
1217 * Returns queue tag type.
1218 */
1219static int
Eric Moored5d135b2009-05-18 13:02:08 -06001220_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001221{
1222 if (sdev->tagged_supported) {
1223 scsi_set_tag_type(sdev, tag_type);
1224 if (tag_type)
1225 scsi_activate_tcq(sdev, sdev->queue_depth);
1226 else
1227 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1228 } else
1229 tag_type = 0;
1230
1231 return tag_type;
1232}
1233
1234/**
Eric Moored5d135b2009-05-18 13:02:08 -06001235 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001236 * @starget: scsi target struct
1237 *
1238 * Returns 0 if ok. Any other return is assumed to be an error and
1239 * the device is ignored.
1240 */
1241static int
Eric Moored5d135b2009-05-18 13:02:08 -06001242_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001243{
1244 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1245 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1246 struct MPT2SAS_TARGET *sas_target_priv_data;
1247 struct _sas_device *sas_device;
1248 struct _raid_device *raid_device;
1249 unsigned long flags;
1250 struct sas_rphy *rphy;
1251
1252 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1253 if (!sas_target_priv_data)
1254 return -ENOMEM;
1255
1256 starget->hostdata = sas_target_priv_data;
1257 sas_target_priv_data->starget = starget;
1258 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1259
1260 /* RAID volumes */
1261 if (starget->channel == RAID_CHANNEL) {
1262 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1263 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1264 starget->channel);
1265 if (raid_device) {
1266 sas_target_priv_data->handle = raid_device->handle;
1267 sas_target_priv_data->sas_address = raid_device->wwid;
1268 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301269 sas_target_priv_data->raid_device = raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06001270 raid_device->starget = starget;
1271 }
1272 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1273 return 0;
1274 }
1275
1276 /* sas/sata devices */
1277 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1278 rphy = dev_to_rphy(starget->dev.parent);
1279 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1280 rphy->identify.sas_address);
1281
1282 if (sas_device) {
1283 sas_target_priv_data->handle = sas_device->handle;
1284 sas_target_priv_data->sas_address = sas_device->sas_address;
1285 sas_device->starget = starget;
1286 sas_device->id = starget->id;
1287 sas_device->channel = starget->channel;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05301288 if (test_bit(sas_device->handle, ioc->pd_handles))
Eric Moore635374e2009-03-09 01:21:12 -06001289 sas_target_priv_data->flags |=
1290 MPT_TARGET_FLAGS_RAID_COMPONENT;
1291 }
1292 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1293
1294 return 0;
1295}
1296
1297/**
Eric Moored5d135b2009-05-18 13:02:08 -06001298 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001299 * @starget: scsi target struct
1300 *
1301 * Returns nothing.
1302 */
1303static void
Eric Moored5d135b2009-05-18 13:02:08 -06001304_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001305{
1306 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1307 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1308 struct MPT2SAS_TARGET *sas_target_priv_data;
1309 struct _sas_device *sas_device;
1310 struct _raid_device *raid_device;
1311 unsigned long flags;
1312 struct sas_rphy *rphy;
1313
1314 sas_target_priv_data = starget->hostdata;
1315 if (!sas_target_priv_data)
1316 return;
1317
1318 if (starget->channel == RAID_CHANNEL) {
1319 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1320 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1321 starget->channel);
1322 if (raid_device) {
1323 raid_device->starget = NULL;
1324 raid_device->sdev = NULL;
1325 }
1326 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1327 goto out;
1328 }
1329
1330 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1331 rphy = dev_to_rphy(starget->dev.parent);
1332 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1333 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001334 if (sas_device && (sas_device->starget == starget) &&
1335 (sas_device->id == starget->id) &&
1336 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001337 sas_device->starget = NULL;
1338
1339 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1340
1341 out:
1342 kfree(sas_target_priv_data);
1343 starget->hostdata = NULL;
1344}
1345
1346/**
Eric Moored5d135b2009-05-18 13:02:08 -06001347 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001348 * @sdev: scsi device struct
1349 *
1350 * Returns 0 if ok. Any other return is assumed to be an error and
1351 * the device is ignored.
1352 */
1353static int
Eric Moored5d135b2009-05-18 13:02:08 -06001354_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001355{
1356 struct Scsi_Host *shost;
1357 struct MPT2SAS_ADAPTER *ioc;
1358 struct MPT2SAS_TARGET *sas_target_priv_data;
1359 struct MPT2SAS_DEVICE *sas_device_priv_data;
1360 struct scsi_target *starget;
1361 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06001362 unsigned long flags;
1363
1364 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1365 if (!sas_device_priv_data)
1366 return -ENOMEM;
1367
1368 sas_device_priv_data->lun = sdev->lun;
1369 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1370
1371 starget = scsi_target(sdev);
1372 sas_target_priv_data = starget->hostdata;
1373 sas_target_priv_data->num_luns++;
1374 sas_device_priv_data->sas_target = sas_target_priv_data;
1375 sdev->hostdata = sas_device_priv_data;
1376 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1377 sdev->no_uld_attach = 1;
1378
1379 shost = dev_to_shost(&starget->dev);
1380 ioc = shost_priv(shost);
1381 if (starget->channel == RAID_CHANNEL) {
1382 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1383 raid_device = _scsih_raid_device_find_by_id(ioc,
1384 starget->id, starget->channel);
1385 if (raid_device)
1386 raid_device->sdev = sdev; /* raid is single lun */
1387 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06001388 }
1389
Eric Moore635374e2009-03-09 01:21:12 -06001390 return 0;
1391}
1392
1393/**
Eric Moored5d135b2009-05-18 13:02:08 -06001394 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001395 * @sdev: scsi device struct
1396 *
1397 * Returns nothing.
1398 */
1399static void
Eric Moored5d135b2009-05-18 13:02:08 -06001400_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001401{
1402 struct MPT2SAS_TARGET *sas_target_priv_data;
1403 struct scsi_target *starget;
1404
1405 if (!sdev->hostdata)
1406 return;
1407
1408 starget = scsi_target(sdev);
1409 sas_target_priv_data = starget->hostdata;
1410 sas_target_priv_data->num_luns--;
1411 kfree(sdev->hostdata);
1412 sdev->hostdata = NULL;
1413}
1414
1415/**
Eric Moored5d135b2009-05-18 13:02:08 -06001416 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001417 * @ioc: per adapter object
1418 * @sas_device: the sas_device object
1419 * @sdev: scsi device struct
1420 */
1421static void
Eric Moored5d135b2009-05-18 13:02:08 -06001422_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06001423 struct _sas_device *sas_device, struct scsi_device *sdev)
1424{
1425 Mpi2ConfigReply_t mpi_reply;
1426 Mpi2SasDevicePage0_t sas_device_pg0;
1427 u32 ioc_status;
1428 u16 flags;
1429 u32 device_info;
1430
1431 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
1432 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
1433 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1434 ioc->name, __FILE__, __LINE__, __func__);
1435 return;
1436 }
1437
1438 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1439 MPI2_IOCSTATUS_MASK;
1440 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1441 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1442 ioc->name, __FILE__, __LINE__, __func__);
1443 return;
1444 }
1445
1446 flags = le16_to_cpu(sas_device_pg0.Flags);
Kashyap, Desaie94f6742010-03-17 16:24:52 +05301447 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
Eric Moore635374e2009-03-09 01:21:12 -06001448
1449 sdev_printk(KERN_INFO, sdev,
1450 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1451 "sw_preserve(%s)\n",
1452 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1453 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1454 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1455 "n",
1456 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1457 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1458 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1459}
1460
1461/**
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301462 * _scsih_is_raid - return boolean indicating device is raid volume
1463 * @dev the device struct object
1464 */
1465static int
1466_scsih_is_raid(struct device *dev)
1467{
1468 struct scsi_device *sdev = to_scsi_device(dev);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301469 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301470
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301471 if (ioc->is_warpdrive)
1472 return 0;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301473 return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
1474}
1475
1476/**
1477 * _scsih_get_resync - get raid volume resync percent complete
1478 * @dev the device struct object
1479 */
1480static void
1481_scsih_get_resync(struct device *dev)
1482{
1483 struct scsi_device *sdev = to_scsi_device(dev);
1484 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1485 static struct _raid_device *raid_device;
1486 unsigned long flags;
1487 Mpi2RaidVolPage0_t vol_pg0;
1488 Mpi2ConfigReply_t mpi_reply;
1489 u32 volume_status_flags;
1490 u8 percent_complete = 0;
1491
1492 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1493 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1494 sdev->channel);
1495 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1496
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301497 if (!raid_device || ioc->is_warpdrive)
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301498 goto out;
1499
1500 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1501 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1502 sizeof(Mpi2RaidVolPage0_t))) {
1503 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1504 ioc->name, __FILE__, __LINE__, __func__);
1505 goto out;
1506 }
1507
1508 volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1509 if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
1510 percent_complete = raid_device->percent_complete;
1511 out:
1512 raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
1513}
1514
1515/**
1516 * _scsih_get_state - get raid volume level
1517 * @dev the device struct object
1518 */
1519static void
1520_scsih_get_state(struct device *dev)
1521{
1522 struct scsi_device *sdev = to_scsi_device(dev);
1523 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1524 static struct _raid_device *raid_device;
1525 unsigned long flags;
1526 Mpi2RaidVolPage0_t vol_pg0;
1527 Mpi2ConfigReply_t mpi_reply;
1528 u32 volstate;
1529 enum raid_state state = RAID_STATE_UNKNOWN;
1530
1531 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1532 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1533 sdev->channel);
1534 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1535
1536 if (!raid_device)
1537 goto out;
1538
1539 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1540 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1541 sizeof(Mpi2RaidVolPage0_t))) {
1542 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1543 ioc->name, __FILE__, __LINE__, __func__);
1544 goto out;
1545 }
1546
1547 volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1548 if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
1549 state = RAID_STATE_RESYNCING;
1550 goto out;
1551 }
1552
1553 switch (vol_pg0.VolumeState) {
1554 case MPI2_RAID_VOL_STATE_OPTIMAL:
1555 case MPI2_RAID_VOL_STATE_ONLINE:
1556 state = RAID_STATE_ACTIVE;
1557 break;
1558 case MPI2_RAID_VOL_STATE_DEGRADED:
1559 state = RAID_STATE_DEGRADED;
1560 break;
1561 case MPI2_RAID_VOL_STATE_FAILED:
1562 case MPI2_RAID_VOL_STATE_MISSING:
1563 state = RAID_STATE_OFFLINE;
1564 break;
1565 }
1566 out:
1567 raid_set_state(mpt2sas_raid_template, dev, state);
1568}
1569
1570/**
1571 * _scsih_set_level - set raid level
1572 * @sdev: scsi device struct
1573 * @raid_device: raid_device object
1574 */
1575static void
1576_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
1577{
1578 enum raid_level level = RAID_LEVEL_UNKNOWN;
1579
1580 switch (raid_device->volume_type) {
1581 case MPI2_RAID_VOL_TYPE_RAID0:
1582 level = RAID_LEVEL_0;
1583 break;
1584 case MPI2_RAID_VOL_TYPE_RAID10:
1585 level = RAID_LEVEL_10;
1586 break;
1587 case MPI2_RAID_VOL_TYPE_RAID1E:
1588 level = RAID_LEVEL_1E;
1589 break;
1590 case MPI2_RAID_VOL_TYPE_RAID1:
1591 level = RAID_LEVEL_1;
1592 break;
1593 }
1594
1595 raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
1596}
1597
1598/**
Eric Moore635374e2009-03-09 01:21:12 -06001599 * _scsih_get_volume_capabilities - volume capabilities
1600 * @ioc: per adapter object
1601 * @sas_device: the raid_device object
1602 */
1603static void
1604_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1605 struct _raid_device *raid_device)
1606{
1607 Mpi2RaidVolPage0_t *vol_pg0;
1608 Mpi2RaidPhysDiskPage0_t pd_pg0;
1609 Mpi2SasDevicePage0_t sas_device_pg0;
1610 Mpi2ConfigReply_t mpi_reply;
1611 u16 sz;
1612 u8 num_pds;
1613
1614 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1615 &num_pds)) || !num_pds) {
1616 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1617 ioc->name, __FILE__, __LINE__, __func__);
1618 return;
1619 }
1620
1621 raid_device->num_pds = num_pds;
1622 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1623 sizeof(Mpi2RaidVol0PhysDisk_t));
1624 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1625 if (!vol_pg0) {
1626 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1627 ioc->name, __FILE__, __LINE__, __func__);
1628 return;
1629 }
1630
1631 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1632 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1633 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1634 ioc->name, __FILE__, __LINE__, __func__);
1635 kfree(vol_pg0);
1636 return;
1637 }
1638
1639 raid_device->volume_type = vol_pg0->VolumeType;
1640
1641 /* figure out what the underlying devices are by
1642 * obtaining the device_info bits for the 1st device
1643 */
1644 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1645 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1646 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1647 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1648 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1649 le16_to_cpu(pd_pg0.DevHandle)))) {
1650 raid_device->device_info =
1651 le32_to_cpu(sas_device_pg0.DeviceInfo);
1652 }
1653 }
1654
1655 kfree(vol_pg0);
1656}
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301657/**
1658 * _scsih_disable_ddio - Disable direct I/O for all the volumes
1659 * @ioc: per adapter object
1660 */
1661static void
1662_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
1663{
1664 Mpi2RaidVolPage1_t vol_pg1;
1665 Mpi2ConfigReply_t mpi_reply;
1666 struct _raid_device *raid_device;
1667 u16 handle;
1668 u16 ioc_status;
1669
1670 handle = 0xFFFF;
1671 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
1672 &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
1673 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1674 MPI2_IOCSTATUS_MASK;
1675 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
1676 break;
1677 handle = le16_to_cpu(vol_pg1.DevHandle);
1678 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
1679 if (raid_device)
1680 raid_device->direct_io_enabled = 0;
1681 }
1682 return;
1683}
1684
1685
1686/**
1687 * _scsih_get_num_volumes - Get number of volumes in the ioc
1688 * @ioc: per adapter object
1689 */
1690static u8
1691_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc)
1692{
1693 Mpi2RaidVolPage1_t vol_pg1;
1694 Mpi2ConfigReply_t mpi_reply;
1695 u16 handle;
1696 u8 vol_cnt = 0;
1697 u16 ioc_status;
1698
1699 handle = 0xFFFF;
1700 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
1701 &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
1702 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1703 MPI2_IOCSTATUS_MASK;
1704 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
1705 break;
1706 vol_cnt++;
1707 handle = le16_to_cpu(vol_pg1.DevHandle);
1708 }
1709 return vol_cnt;
1710}
1711
1712
1713/**
1714 * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O.
1715 * @ioc: per adapter object
1716 * @raid_device: the raid_device object
1717 */
1718static void
1719_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc,
1720 struct _raid_device *raid_device)
1721{
1722 Mpi2RaidVolPage0_t *vol_pg0;
1723 Mpi2RaidPhysDiskPage0_t pd_pg0;
1724 Mpi2ConfigReply_t mpi_reply;
1725 u16 sz;
1726 u8 num_pds, count;
1727 u64 mb = 1024 * 1024;
1728 u64 tb_2 = 2 * mb * mb;
1729 u64 capacity;
1730 u32 stripe_sz;
1731 u8 i, stripe_exp;
1732
1733 if (!ioc->is_warpdrive)
1734 return;
1735
1736 if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) {
1737 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1738 "globally as drives are exposed\n", ioc->name);
1739 return;
1740 }
1741 if (_scsih_get_num_volumes(ioc) > 1) {
1742 _scsih_disable_ddio(ioc);
1743 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1744 "globally as number of drives > 1\n", ioc->name);
1745 return;
1746 }
1747 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1748 &num_pds)) || !num_pds) {
1749 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1750 "Failure in computing number of drives\n", ioc->name);
1751 return;
1752 }
1753
1754 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1755 sizeof(Mpi2RaidVol0PhysDisk_t));
1756 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1757 if (!vol_pg0) {
1758 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1759 "Memory allocation failure for RVPG0\n", ioc->name);
1760 return;
1761 }
1762
1763 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1764 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1765 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1766 "Failure in retrieving RVPG0\n", ioc->name);
1767 kfree(vol_pg0);
1768 return;
1769 }
1770
1771 /*
1772 * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
1773 * assumed for WARPDRIVE, disable direct I/O
1774 */
1775 if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
1776 printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled "
1777 "for the drive with handle(0x%04x): num_mem=%d, "
1778 "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
1779 num_pds, MPT_MAX_WARPDRIVE_PDS);
1780 kfree(vol_pg0);
1781 return;
1782 }
1783 for (count = 0; count < num_pds; count++) {
1784 if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1785 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1786 vol_pg0->PhysDisk[count].PhysDiskNum) ||
1787 pd_pg0.DevHandle == MPT2SAS_INVALID_DEVICE_HANDLE) {
1788 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
1789 "disabled for the drive with handle(0x%04x) member"
1790 "handle retrieval failed for member number=%d\n",
1791 ioc->name, raid_device->handle,
1792 vol_pg0->PhysDisk[count].PhysDiskNum);
1793 goto out_error;
1794 }
1795 raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
1796 }
1797
1798 /*
1799 * Assumption for WD: Direct I/O is not supported if the volume is
1800 * not RAID0, if the stripe size is not 64KB, if the block size is
1801 * not 512 and if the volume size is >2TB
1802 */
1803 if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0 ||
1804 le16_to_cpu(vol_pg0->BlockSize) != 512) {
1805 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1806 "for the drive with handle(0x%04x): type=%d, "
1807 "s_sz=%uK, blk_size=%u\n", ioc->name,
1808 raid_device->handle, raid_device->volume_type,
1809 le32_to_cpu(vol_pg0->StripeSize)/2,
1810 le16_to_cpu(vol_pg0->BlockSize));
1811 goto out_error;
1812 }
1813
1814 capacity = (u64) le16_to_cpu(vol_pg0->BlockSize) *
1815 (le64_to_cpu(vol_pg0->MaxLBA) + 1);
1816
1817 if (capacity > tb_2) {
1818 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1819 "for the drive with handle(0x%04x) since drive sz > 2TB\n",
1820 ioc->name, raid_device->handle);
1821 goto out_error;
1822 }
1823
1824 stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
1825 stripe_exp = 0;
1826 for (i = 0; i < 32; i++) {
1827 if (stripe_sz & 1)
1828 break;
1829 stripe_exp++;
1830 stripe_sz >>= 1;
1831 }
1832 if (i == 32) {
1833 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1834 "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
1835 ioc->name, raid_device->handle,
1836 le32_to_cpu(vol_pg0->StripeSize)/2);
1837 goto out_error;
1838 }
1839 raid_device->stripe_exponent = stripe_exp;
1840 raid_device->direct_io_enabled = 1;
1841
1842 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive"
1843 " with handle(0x%04x)\n", ioc->name, raid_device->handle);
1844 /*
1845 * WARPDRIVE: Though the following fields are not used for direct IO,
1846 * stored for future purpose:
1847 */
1848 raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
1849 raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
1850 raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
1851
1852
1853 kfree(vol_pg0);
1854 return;
1855
1856out_error:
1857 raid_device->direct_io_enabled = 0;
1858 for (count = 0; count < num_pds; count++)
1859 raid_device->pd_handle[count] = 0;
1860 kfree(vol_pg0);
1861 return;
1862}
Eric Moore635374e2009-03-09 01:21:12 -06001863
1864/**
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301865 * _scsih_enable_tlr - setting TLR flags
1866 * @ioc: per adapter object
1867 * @sdev: scsi device struct
1868 *
1869 * Enabling Transaction Layer Retries for tape devices when
1870 * vpd page 0x90 is present
1871 *
1872 */
1873static void
1874_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev)
1875{
1876 /* only for TAPE */
1877 if (sdev->type != TYPE_TAPE)
1878 return;
1879
1880 if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR))
1881 return;
1882
1883 sas_enable_tlr(sdev);
1884 sdev_printk(KERN_INFO, sdev, "TLR %s\n",
1885 sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled");
1886 return;
1887
1888}
1889
1890/**
Eric Moored5d135b2009-05-18 13:02:08 -06001891 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001892 * @sdev: scsi device struct
1893 *
1894 * Returns 0 if ok. Any other return is assumed to be an error and
1895 * the device is ignored.
1896 */
1897static int
Eric Moored5d135b2009-05-18 13:02:08 -06001898_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001899{
1900 struct Scsi_Host *shost = sdev->host;
1901 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1902 struct MPT2SAS_DEVICE *sas_device_priv_data;
1903 struct MPT2SAS_TARGET *sas_target_priv_data;
1904 struct _sas_device *sas_device;
1905 struct _raid_device *raid_device;
1906 unsigned long flags;
1907 int qdepth;
1908 u8 ssp_target = 0;
1909 char *ds = "";
1910 char *r_level = "";
1911
1912 qdepth = 1;
1913 sas_device_priv_data = sdev->hostdata;
1914 sas_device_priv_data->configured_lun = 1;
1915 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1916 sas_target_priv_data = sas_device_priv_data->sas_target;
1917
1918 /* raid volume handling */
1919 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1920
1921 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1922 raid_device = _scsih_raid_device_find_by_handle(ioc,
1923 sas_target_priv_data->handle);
1924 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1925 if (!raid_device) {
1926 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1927 ioc->name, __FILE__, __LINE__, __func__);
1928 return 0;
1929 }
1930
1931 _scsih_get_volume_capabilities(ioc, raid_device);
1932
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301933 /*
1934 * WARPDRIVE: Initialize the required data for Direct IO
1935 */
1936 _scsih_init_warpdrive_properties(ioc, raid_device);
1937
Eric Moore635374e2009-03-09 01:21:12 -06001938 /* RAID Queue Depth Support
1939 * IS volume = underlying qdepth of drive type, either
1940 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
1941 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
1942 */
1943 if (raid_device->device_info &
1944 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1945 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1946 ds = "SSP";
1947 } else {
1948 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1949 if (raid_device->device_info &
1950 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1951 ds = "SATA";
1952 else
1953 ds = "STP";
1954 }
1955
1956 switch (raid_device->volume_type) {
1957 case MPI2_RAID_VOL_TYPE_RAID0:
1958 r_level = "RAID0";
1959 break;
1960 case MPI2_RAID_VOL_TYPE_RAID1E:
1961 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05301962 if (ioc->manu_pg10.OEMIdentifier &&
Kashyap, Desaic97951e2011-06-14 10:54:56 +05301963 (le32_to_cpu(ioc->manu_pg10.GenericFlags0) &
Kashyap, Desaied79f122009-08-20 13:23:49 +05301964 MFG10_GF0_R10_DISPLAY) &&
1965 !(raid_device->num_pds % 2))
1966 r_level = "RAID10";
1967 else
1968 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06001969 break;
1970 case MPI2_RAID_VOL_TYPE_RAID1:
1971 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1972 r_level = "RAID1";
1973 break;
1974 case MPI2_RAID_VOL_TYPE_RAID10:
1975 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1976 r_level = "RAID10";
1977 break;
1978 case MPI2_RAID_VOL_TYPE_UNKNOWN:
1979 default:
1980 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1981 r_level = "RAIDX";
1982 break;
1983 }
1984
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301985 if (!ioc->hide_ir_msg)
1986 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
1987 "wwid(0x%016llx), pd_count(%d), type(%s)\n",
1988 r_level, raid_device->handle,
1989 (unsigned long long)raid_device->wwid,
1990 raid_device->num_pds, ds);
Mike Christiee881a172009-10-15 17:46:39 -07001991 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301992 /* raid transport support */
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301993 if (!ioc->is_warpdrive)
1994 _scsih_set_level(sdev, raid_device);
Eric Moore635374e2009-03-09 01:21:12 -06001995 return 0;
1996 }
1997
1998 /* non-raid handling */
1999 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2000 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2001 sas_device_priv_data->sas_target->sas_address);
2002 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2003 if (sas_device) {
2004 if (sas_target_priv_data->flags &
2005 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2006 mpt2sas_config_get_volume_handle(ioc,
2007 sas_device->handle, &sas_device->volume_handle);
2008 mpt2sas_config_get_volume_wwid(ioc,
2009 sas_device->volume_handle,
2010 &sas_device->volume_wwid);
2011 }
2012 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
2013 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
2014 ssp_target = 1;
2015 ds = "SSP";
2016 } else {
2017 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
2018 if (sas_device->device_info &
2019 MPI2_SAS_DEVICE_INFO_STP_TARGET)
2020 ds = "STP";
2021 else if (sas_device->device_info &
2022 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
2023 ds = "SATA";
2024 }
2025
2026 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
Kashyap, Desai7fbae672010-06-17 13:45:17 +05302027 "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
Eric Moore635374e2009-03-09 01:21:12 -06002028 ds, sas_device->handle,
2029 (unsigned long long)sas_device->sas_address,
Kashyap, Desai7fbae672010-06-17 13:45:17 +05302030 sas_device->phy,
Eric Moore635374e2009-03-09 01:21:12 -06002031 (unsigned long long)sas_device->device_name);
2032 sdev_printk(KERN_INFO, sdev, "%s: "
2033 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
2034 (unsigned long long) sas_device->enclosure_logical_id,
2035 sas_device->slot);
2036
2037 if (!ssp_target)
Eric Moored5d135b2009-05-18 13:02:08 -06002038 _scsih_display_sata_capabilities(ioc, sas_device, sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002039 }
2040
Mike Christiee881a172009-10-15 17:46:39 -07002041 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Eric Moore635374e2009-03-09 01:21:12 -06002042
Kashyap, Desai84f0b042009-12-16 18:56:28 +05302043 if (ssp_target) {
Eric Moore635374e2009-03-09 01:21:12 -06002044 sas_read_port_mode_page(sdev);
Kashyap, Desai84f0b042009-12-16 18:56:28 +05302045 _scsih_enable_tlr(ioc, sdev);
2046 }
Eric Moore635374e2009-03-09 01:21:12 -06002047 return 0;
2048}
2049
2050/**
Eric Moored5d135b2009-05-18 13:02:08 -06002051 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06002052 * @sdev: scsi device struct
2053 * @bdev: pointer to block device context
2054 * @capacity: device size (in 512 byte sectors)
2055 * @params: three element array to place output:
2056 * params[0] number of heads (max 255)
2057 * params[1] number of sectors (max 63)
2058 * params[2] number of cylinders
2059 *
2060 * Return nothing.
2061 */
2062static int
Eric Moored5d135b2009-05-18 13:02:08 -06002063_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06002064 sector_t capacity, int params[])
2065{
2066 int heads;
2067 int sectors;
2068 sector_t cylinders;
2069 ulong dummy;
2070
2071 heads = 64;
2072 sectors = 32;
2073
2074 dummy = heads * sectors;
2075 cylinders = capacity;
2076 sector_div(cylinders, dummy);
2077
2078 /*
2079 * Handle extended translation size for logical drives
2080 * > 1Gb
2081 */
2082 if ((ulong)capacity >= 0x200000) {
2083 heads = 255;
2084 sectors = 63;
2085 dummy = heads * sectors;
2086 cylinders = capacity;
2087 sector_div(cylinders, dummy);
2088 }
2089
2090 /* return result */
2091 params[0] = heads;
2092 params[1] = sectors;
2093 params[2] = cylinders;
2094
2095 return 0;
2096}
2097
2098/**
2099 * _scsih_response_code - translation of device response code
2100 * @ioc: per adapter object
2101 * @response_code: response code returned by the device
2102 *
2103 * Return nothing.
2104 */
2105static void
2106_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
2107{
2108 char *desc;
2109
2110 switch (response_code) {
2111 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
2112 desc = "task management request completed";
2113 break;
2114 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
2115 desc = "invalid frame";
2116 break;
2117 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2118 desc = "task management request not supported";
2119 break;
2120 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
2121 desc = "task management request failed";
2122 break;
2123 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2124 desc = "task management request succeeded";
2125 break;
2126 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2127 desc = "invalid lun";
2128 break;
2129 case 0xA:
2130 desc = "overlapped tag attempted";
2131 break;
2132 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2133 desc = "task queued, however not sent to target";
2134 break;
2135 default:
2136 desc = "unknown";
2137 break;
2138 }
2139 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
2140 ioc->name, response_code, desc);
2141}
2142
2143/**
Eric Moored5d135b2009-05-18 13:02:08 -06002144 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06002145 * @ioc: per adapter object
2146 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302147 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06002148 * @reply: reply message frame(lower 32bit addr)
2149 * Context: none.
2150 *
2151 * The callback handler when using scsih_issue_tm.
2152 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302153 * Return 1 meaning mf should be freed from _base_interrupt
2154 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06002155 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302156static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302157_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06002158{
2159 MPI2DefaultReply_t *mpi_reply;
2160
2161 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302162 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06002163 if (ioc->tm_cmds.smid != smid)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302164 return 1;
nagalakshmi.nandigama@lsi.com911ae942011-09-08 06:18:50 +05302165 mpt2sas_base_flush_reply_queues(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06002166 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
2167 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
2168 if (mpi_reply) {
2169 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
2170 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
2171 }
2172 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
2173 complete(&ioc->tm_cmds.done);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302174 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06002175}
2176
2177/**
2178 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
2179 * @ioc: per adapter object
2180 * @handle: device handle
2181 *
2182 * During taskmangement request, we need to freeze the device queue.
2183 */
2184void
2185mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2186{
2187 struct MPT2SAS_DEVICE *sas_device_priv_data;
2188 struct scsi_device *sdev;
2189 u8 skip = 0;
2190
2191 shost_for_each_device(sdev, ioc->shost) {
2192 if (skip)
2193 continue;
2194 sas_device_priv_data = sdev->hostdata;
2195 if (!sas_device_priv_data)
2196 continue;
2197 if (sas_device_priv_data->sas_target->handle == handle) {
2198 sas_device_priv_data->sas_target->tm_busy = 1;
2199 skip = 1;
2200 ioc->ignore_loginfos = 1;
2201 }
2202 }
2203}
2204
2205/**
2206 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
2207 * @ioc: per adapter object
2208 * @handle: device handle
2209 *
2210 * During taskmangement request, we need to freeze the device queue.
2211 */
2212void
2213mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2214{
2215 struct MPT2SAS_DEVICE *sas_device_priv_data;
2216 struct scsi_device *sdev;
2217 u8 skip = 0;
2218
2219 shost_for_each_device(sdev, ioc->shost) {
2220 if (skip)
2221 continue;
2222 sas_device_priv_data = sdev->hostdata;
2223 if (!sas_device_priv_data)
2224 continue;
2225 if (sas_device_priv_data->sas_target->handle == handle) {
2226 sas_device_priv_data->sas_target->tm_busy = 0;
2227 skip = 1;
2228 ioc->ignore_loginfos = 0;
2229 }
2230 }
2231}
2232
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302233
Eric Moore635374e2009-03-09 01:21:12 -06002234/**
2235 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
2236 * @ioc: per adapter struct
2237 * @device_handle: device handle
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302238 * @channel: the channel assigned by the OS
2239 * @id: the id assigned by the OS
Eric Moore635374e2009-03-09 01:21:12 -06002240 * @lun: lun number
2241 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
2242 * @smid_task: smid assigned to the task
2243 * @timeout: timeout in seconds
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302244 * @serial_number: the serial_number from scmd
2245 * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302246 * Context: user
Eric Moore635374e2009-03-09 01:21:12 -06002247 *
2248 * A generic API for sending task management requests to firmware.
2249 *
Eric Moore635374e2009-03-09 01:21:12 -06002250 * The callback index is set inside `ioc->tm_cb_idx`.
2251 *
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302252 * Return SUCCESS or FAILED.
Eric Moore635374e2009-03-09 01:21:12 -06002253 */
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302254int
2255mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
2256 uint id, uint lun, u8 type, u16 smid_task, ulong timeout,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302257 unsigned long serial_number, enum mutex_type m_type)
Eric Moore635374e2009-03-09 01:21:12 -06002258{
2259 Mpi2SCSITaskManagementRequest_t *mpi_request;
2260 Mpi2SCSITaskManagementReply_t *mpi_reply;
2261 u16 smid = 0;
2262 u32 ioc_state;
2263 unsigned long timeleft;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302264 struct scsiio_tracker *scsi_lookup = NULL;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302265 int rc;
Eric Moore635374e2009-03-09 01:21:12 -06002266
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302267 if (m_type == TM_MUTEX_ON)
2268 mutex_lock(&ioc->tm_cmds.mutex);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302269 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
2270 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
2271 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302272 rc = FAILED;
2273 goto err_out;
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302274 }
2275
Eric Moore3cb54692010-07-08 14:44:34 -06002276 if (ioc->shost_recovery || ioc->remove_host ||
2277 ioc->pci_error_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06002278 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2279 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302280 rc = FAILED;
2281 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002282 }
Eric Moore635374e2009-03-09 01:21:12 -06002283
2284 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
2285 if (ioc_state & MPI2_DOORBELL_USED) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05302286 dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
Eric Moore635374e2009-03-09 01:21:12 -06002287 "active!\n", ioc->name));
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302288 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302289 FORCE_BIG_HAMMER);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302290 rc = (!rc) ? SUCCESS : FAILED;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302291 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002292 }
2293
2294 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
2295 mpt2sas_base_fault_info(ioc, ioc_state &
2296 MPI2_DOORBELL_DATA_MASK);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302297 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302298 FORCE_BIG_HAMMER);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302299 rc = (!rc) ? SUCCESS : FAILED;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302300 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002301 }
2302
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302303 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06002304 if (!smid) {
2305 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2306 ioc->name, __func__);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302307 rc = FAILED;
2308 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002309 }
2310
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302311 if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2312 scsi_lookup = &ioc->scsi_lookup[smid_task - 1];
2313
Eric Moore635374e2009-03-09 01:21:12 -06002314 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302315 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
2316 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06002317 ioc->tm_cmds.status = MPT2_CMD_PENDING;
2318 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2319 ioc->tm_cmds.smid = smid;
2320 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302321 memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t));
Eric Moore635374e2009-03-09 01:21:12 -06002322 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2323 mpi_request->DevHandle = cpu_to_le16(handle);
2324 mpi_request->TaskType = type;
2325 mpi_request->TaskMID = cpu_to_le16(smid_task);
2326 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
2327 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05302328 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302329 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002330 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
Eric Moore635374e2009-03-09 01:21:12 -06002331 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
2332 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
2333 ioc->name, __func__);
2334 _debug_dump_mf(mpi_request,
2335 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302336 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) {
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302337 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302338 FORCE_BIG_HAMMER);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302339 rc = (!rc) ? SUCCESS : FAILED;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302340 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2341 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2342 goto err_out;
2343 }
Eric Moore635374e2009-03-09 01:21:12 -06002344 }
2345
2346 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
2347 mpi_reply = ioc->tm_cmds.reply;
2348 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
2349 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
2350 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
2351 le32_to_cpu(mpi_reply->IOCLogInfo),
2352 le32_to_cpu(mpi_reply->TerminationCount)));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302353 if (ioc->logging_level & MPT_DEBUG_TM) {
Eric Moore635374e2009-03-09 01:21:12 -06002354 _scsih_response_code(ioc, mpi_reply->ResponseCode);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302355 if (mpi_reply->IOCStatus)
2356 _debug_dump_mf(mpi_request,
2357 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
2358 }
Eric Moore635374e2009-03-09 01:21:12 -06002359 }
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302360
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302361 switch (type) {
2362 case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302363 rc = SUCCESS;
2364 if (scsi_lookup->scmd == NULL)
2365 break;
2366 rc = FAILED;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302367 break;
2368
2369 case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2370 if (_scsih_scsi_lookup_find_by_target(ioc, id, channel))
2371 rc = FAILED;
2372 else
2373 rc = SUCCESS;
2374 break;
2375
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302376 case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302377 case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
2378 if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel))
2379 rc = FAILED;
2380 else
2381 rc = SUCCESS;
2382 break;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302383 case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
2384 rc = SUCCESS;
2385 break;
2386 default:
2387 rc = FAILED;
2388 break;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302389 }
2390
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302391 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2392 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302393 if (m_type == TM_MUTEX_ON)
2394 mutex_unlock(&ioc->tm_cmds.mutex);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302395
2396 return rc;
2397
2398 err_out:
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302399 if (m_type == TM_MUTEX_ON)
2400 mutex_unlock(&ioc->tm_cmds.mutex);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302401 return rc;
Eric Moore635374e2009-03-09 01:21:12 -06002402}
2403
2404/**
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302405 * _scsih_tm_display_info - displays info about the device
2406 * @ioc: per adapter struct
2407 * @scmd: pointer to scsi command object
2408 *
2409 * Called by task management callback handlers.
2410 */
2411static void
2412_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
2413{
2414 struct scsi_target *starget = scmd->device->sdev_target;
2415 struct MPT2SAS_TARGET *priv_target = starget->hostdata;
2416 struct _sas_device *sas_device = NULL;
2417 unsigned long flags;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302418 char *device_str = NULL;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302419
2420 if (!priv_target)
2421 return;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302422 if (ioc->hide_ir_msg)
2423 device_str = "WarpDrive";
2424 else
2425 device_str = "volume";
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302426
2427 scsi_print_command(scmd);
2428 if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302429 starget_printk(KERN_INFO, starget, "%s handle(0x%04x), "
2430 "%s wwid(0x%016llx)\n", device_str, priv_target->handle,
2431 device_str, (unsigned long long)priv_target->sas_address);
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302432 } else {
2433 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2434 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2435 priv_target->sas_address);
2436 if (sas_device) {
2437 if (priv_target->flags &
2438 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2439 starget_printk(KERN_INFO, starget,
2440 "volume handle(0x%04x), "
2441 "volume wwid(0x%016llx)\n",
2442 sas_device->volume_handle,
2443 (unsigned long long)sas_device->volume_wwid);
2444 }
2445 starget_printk(KERN_INFO, starget,
2446 "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
2447 sas_device->handle,
2448 (unsigned long long)sas_device->sas_address,
2449 sas_device->phy);
2450 starget_printk(KERN_INFO, starget,
2451 "enclosure_logical_id(0x%016llx), slot(%d)\n",
2452 (unsigned long long)sas_device->enclosure_logical_id,
2453 sas_device->slot);
2454 }
2455 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2456 }
2457}
2458
2459/**
Eric Moored5d135b2009-05-18 13:02:08 -06002460 * _scsih_abort - eh threads main abort routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302461 * @scmd: pointer to scsi command object
Eric Moore635374e2009-03-09 01:21:12 -06002462 *
2463 * Returns SUCCESS if command aborted else FAILED
2464 */
2465static int
Eric Moored5d135b2009-05-18 13:02:08 -06002466_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002467{
2468 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2469 struct MPT2SAS_DEVICE *sas_device_priv_data;
2470 u16 smid;
2471 u16 handle;
2472 int r;
Eric Moore635374e2009-03-09 01:21:12 -06002473
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302474 sdev_printk(KERN_INFO, scmd->device, "attempting task abort! "
2475 "scmd(%p)\n", scmd);
2476 _scsih_tm_display_info(ioc, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002477
2478 sas_device_priv_data = scmd->device->hostdata;
2479 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302480 sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
2481 "scmd(%p)\n", scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002482 scmd->result = DID_NO_CONNECT << 16;
2483 scmd->scsi_done(scmd);
2484 r = SUCCESS;
2485 goto out;
2486 }
2487
2488 /* search for the command */
2489 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
2490 if (!smid) {
2491 scmd->result = DID_RESET << 16;
2492 r = SUCCESS;
2493 goto out;
2494 }
2495
2496 /* for hidden raid components and volumes this is not supported */
2497 if (sas_device_priv_data->sas_target->flags &
2498 MPT_TARGET_FLAGS_RAID_COMPONENT ||
2499 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
2500 scmd->result = DID_RESET << 16;
2501 r = FAILED;
2502 goto out;
2503 }
2504
Kashyap, Desaifa7f3162009-09-23 17:26:58 +05302505 mpt2sas_halt_firmware(ioc);
2506
Eric Moore635374e2009-03-09 01:21:12 -06002507 handle = sas_device_priv_data->sas_target->handle;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302508 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2509 scmd->device->id, scmd->device->lun,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302510 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
2511 scmd->serial_number, TM_MUTEX_ON);
Eric Moore635374e2009-03-09 01:21:12 -06002512
2513 out:
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302514 sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
2515 ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002516 return r;
2517}
2518
Eric Moore635374e2009-03-09 01:21:12 -06002519/**
Eric Moored5d135b2009-05-18 13:02:08 -06002520 * _scsih_dev_reset - eh threads main device reset routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302521 * @scmd: pointer to scsi command object
Eric Moore635374e2009-03-09 01:21:12 -06002522 *
2523 * Returns SUCCESS if command aborted else FAILED
2524 */
2525static int
Eric Moored5d135b2009-05-18 13:02:08 -06002526_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002527{
2528 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2529 struct MPT2SAS_DEVICE *sas_device_priv_data;
2530 struct _sas_device *sas_device;
2531 unsigned long flags;
2532 u16 handle;
2533 int r;
2534
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302535 struct scsi_target *starget = scmd->device->sdev_target;
2536
Kashyap, Desai37aaa782010-11-13 04:41:32 +05302537 starget_printk(KERN_INFO, starget, "attempting device reset! "
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302538 "scmd(%p)\n", scmd);
2539 _scsih_tm_display_info(ioc, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002540
2541 sas_device_priv_data = scmd->device->hostdata;
2542 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Kashyap, Desai37aaa782010-11-13 04:41:32 +05302543 starget_printk(KERN_INFO, starget, "device been deleted! "
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302544 "scmd(%p)\n", scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002545 scmd->result = DID_NO_CONNECT << 16;
2546 scmd->scsi_done(scmd);
2547 r = SUCCESS;
2548 goto out;
2549 }
2550
2551 /* for hidden raid components obtain the volume_handle */
2552 handle = 0;
2553 if (sas_device_priv_data->sas_target->flags &
2554 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2555 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2556 sas_device = _scsih_sas_device_find_by_handle(ioc,
2557 sas_device_priv_data->sas_target->handle);
2558 if (sas_device)
2559 handle = sas_device->volume_handle;
2560 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2561 } else
2562 handle = sas_device_priv_data->sas_target->handle;
2563
2564 if (!handle) {
2565 scmd->result = DID_RESET << 16;
2566 r = FAILED;
2567 goto out;
2568 }
2569
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302570 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2571 scmd->device->id, scmd->device->lun,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302572 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, 0,
2573 TM_MUTEX_ON);
Eric Moore993e0da2009-05-18 13:00:45 -06002574
2575 out:
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302576 sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
2577 ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002578 return r;
2579}
2580
2581/**
Eric Moored5d135b2009-05-18 13:02:08 -06002582 * _scsih_target_reset - eh threads main target reset routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302583 * @scmd: pointer to scsi command object
Eric Moore993e0da2009-05-18 13:00:45 -06002584 *
2585 * Returns SUCCESS if command aborted else FAILED
2586 */
2587static int
Eric Moored5d135b2009-05-18 13:02:08 -06002588_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06002589{
2590 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2591 struct MPT2SAS_DEVICE *sas_device_priv_data;
2592 struct _sas_device *sas_device;
2593 unsigned long flags;
2594 u16 handle;
2595 int r;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302596 struct scsi_target *starget = scmd->device->sdev_target;
Eric Moore993e0da2009-05-18 13:00:45 -06002597
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302598 starget_printk(KERN_INFO, starget, "attempting target reset! "
2599 "scmd(%p)\n", scmd);
2600 _scsih_tm_display_info(ioc, scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002601
2602 sas_device_priv_data = scmd->device->hostdata;
2603 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302604 starget_printk(KERN_INFO, starget, "target been deleted! "
2605 "scmd(%p)\n", scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002606 scmd->result = DID_NO_CONNECT << 16;
2607 scmd->scsi_done(scmd);
2608 r = SUCCESS;
2609 goto out;
2610 }
2611
2612 /* for hidden raid components obtain the volume_handle */
2613 handle = 0;
2614 if (sas_device_priv_data->sas_target->flags &
2615 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2616 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2617 sas_device = _scsih_sas_device_find_by_handle(ioc,
2618 sas_device_priv_data->sas_target->handle);
2619 if (sas_device)
2620 handle = sas_device->volume_handle;
2621 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2622 } else
2623 handle = sas_device_priv_data->sas_target->handle;
2624
2625 if (!handle) {
2626 scmd->result = DID_RESET << 16;
2627 r = FAILED;
2628 goto out;
2629 }
2630
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302631 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2632 scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302633 30, 0, TM_MUTEX_ON);
Eric Moore635374e2009-03-09 01:21:12 -06002634
2635 out:
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302636 starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
2637 ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002638 return r;
2639}
2640
2641/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302642 * _scsih_host_reset - eh threads main host reset routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302643 * @scmd: pointer to scsi command object
Eric Moore635374e2009-03-09 01:21:12 -06002644 *
2645 * Returns SUCCESS if command aborted else FAILED
2646 */
2647static int
Eric Moored5d135b2009-05-18 13:02:08 -06002648_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002649{
2650 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2651 int r, retval;
2652
2653 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2654 ioc->name, scmd);
2655 scsi_print_command(scmd);
2656
2657 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2658 FORCE_BIG_HAMMER);
2659 r = (retval < 0) ? FAILED : SUCCESS;
2660 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2661 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2662
2663 return r;
2664}
2665
2666/**
2667 * _scsih_fw_event_add - insert and queue up fw_event
2668 * @ioc: per adapter object
2669 * @fw_event: object describing the event
2670 * Context: This function will acquire ioc->fw_event_lock.
2671 *
2672 * This adds the firmware event object into link list, then queues it up to
2673 * be processed from user context.
2674 *
2675 * Return nothing.
2676 */
2677static void
2678_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2679{
2680 unsigned long flags;
2681
2682 if (ioc->firmware_event_thread == NULL)
2683 return;
2684
2685 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2686 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302687 INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work);
2688 queue_delayed_work(ioc->firmware_event_thread,
2689 &fw_event->delayed_work, 0);
Eric Moore635374e2009-03-09 01:21:12 -06002690 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2691}
2692
2693/**
2694 * _scsih_fw_event_free - delete fw_event
2695 * @ioc: per adapter object
2696 * @fw_event: object describing the event
2697 * Context: This function will acquire ioc->fw_event_lock.
2698 *
2699 * This removes firmware event object from link list, frees associated memory.
2700 *
2701 * Return nothing.
2702 */
2703static void
2704_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2705 *fw_event)
2706{
2707 unsigned long flags;
2708
2709 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2710 list_del(&fw_event->list);
2711 kfree(fw_event->event_data);
2712 kfree(fw_event);
2713 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2714}
2715
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302716
Eric Moore635374e2009-03-09 01:21:12 -06002717/**
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302718 * _scsih_queue_rescan - queue a topology rescan from user context
Eric Moore635374e2009-03-09 01:21:12 -06002719 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06002720 *
2721 * Return nothing.
2722 */
2723static void
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302724_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06002725{
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302726 struct fw_event_work *fw_event;
2727
2728 if (ioc->wait_for_port_enable_to_complete)
2729 return;
2730 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
2731 if (!fw_event)
2732 return;
2733 fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET;
2734 fw_event->ioc = ioc;
2735 _scsih_fw_event_add(ioc, fw_event);
2736}
2737
2738/**
2739 * _scsih_fw_event_cleanup_queue - cleanup event queue
2740 * @ioc: per adapter object
2741 *
2742 * Walk the firmware event queue, either killing timers, or waiting
2743 * for outstanding events to complete
2744 *
2745 * Return nothing.
2746 */
2747static void
2748_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)
2749{
2750 struct fw_event_work *fw_event, *next;
2751
2752 if (list_empty(&ioc->fw_event_list) ||
2753 !ioc->firmware_event_thread || in_interrupt())
Eric Moore635374e2009-03-09 01:21:12 -06002754 return;
2755
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302756 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
2757 if (cancel_delayed_work(&fw_event->delayed_work)) {
2758 _scsih_fw_event_free(ioc, fw_event);
2759 continue;
2760 }
2761 fw_event->cancel_pending_work = 1;
2762 }
Eric Moore635374e2009-03-09 01:21:12 -06002763}
2764
Eric Moore635374e2009-03-09 01:21:12 -06002765/**
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302766 * _scsih_ublock_io_all_device - unblock every device
2767 * @ioc: per adapter object
2768 *
2769 * change the device state from block to running
2770 */
2771static void
2772_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc)
2773{
2774 struct MPT2SAS_DEVICE *sas_device_priv_data;
2775 struct scsi_device *sdev;
2776
2777 shost_for_each_device(sdev, ioc->shost) {
2778 sas_device_priv_data = sdev->hostdata;
2779 if (!sas_device_priv_data)
2780 continue;
2781 if (!sas_device_priv_data->block)
2782 continue;
2783 sas_device_priv_data->block = 0;
2784 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, "
2785 "handle(0x%04x)\n",
2786 sas_device_priv_data->sas_target->handle));
2787 scsi_internal_device_unblock(sdev);
2788 }
2789}
2790/**
Eric Moore635374e2009-03-09 01:21:12 -06002791 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2792 * @ioc: per adapter object
2793 * @handle: device handle
2794 *
2795 * During device pull we need to appropiately set the sdev state.
2796 */
2797static void
2798_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2799{
2800 struct MPT2SAS_DEVICE *sas_device_priv_data;
2801 struct scsi_device *sdev;
2802
2803 shost_for_each_device(sdev, ioc->shost) {
2804 sas_device_priv_data = sdev->hostdata;
2805 if (!sas_device_priv_data)
2806 continue;
2807 if (!sas_device_priv_data->block)
2808 continue;
2809 if (sas_device_priv_data->sas_target->handle == handle) {
2810 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2811 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2812 "handle(0x%04x)\n", ioc->name, handle));
2813 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302814 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002815 }
2816 }
2817}
2818
2819/**
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302820 * _scsih_block_io_all_device - set the device state to SDEV_BLOCK
2821 * @ioc: per adapter object
2822 * @handle: device handle
2823 *
2824 * During device pull we need to appropiately set the sdev state.
2825 */
2826static void
2827_scsih_block_io_all_device(struct MPT2SAS_ADAPTER *ioc)
2828{
2829 struct MPT2SAS_DEVICE *sas_device_priv_data;
2830 struct scsi_device *sdev;
2831
2832 shost_for_each_device(sdev, ioc->shost) {
2833 sas_device_priv_data = sdev->hostdata;
2834 if (!sas_device_priv_data)
2835 continue;
2836 if (sas_device_priv_data->block)
2837 continue;
2838 sas_device_priv_data->block = 1;
2839 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, "
2840 "handle(0x%04x)\n",
2841 sas_device_priv_data->sas_target->handle));
2842 scsi_internal_device_block(sdev);
2843 }
2844}
2845
2846
2847/**
Eric Moore635374e2009-03-09 01:21:12 -06002848 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2849 * @ioc: per adapter object
2850 * @handle: device handle
2851 *
2852 * During device pull we need to appropiately set the sdev state.
2853 */
2854static void
2855_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2856{
2857 struct MPT2SAS_DEVICE *sas_device_priv_data;
2858 struct scsi_device *sdev;
2859
2860 shost_for_each_device(sdev, ioc->shost) {
2861 sas_device_priv_data = sdev->hostdata;
2862 if (!sas_device_priv_data)
2863 continue;
2864 if (sas_device_priv_data->block)
2865 continue;
2866 if (sas_device_priv_data->sas_target->handle == handle) {
2867 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2868 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2869 "handle(0x%04x)\n", ioc->name, handle));
2870 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302871 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002872 }
2873 }
2874}
2875
2876/**
2877 * _scsih_block_io_to_children_attached_to_ex
2878 * @ioc: per adapter object
2879 * @sas_expander: the sas_device object
2880 *
2881 * This routine set sdev state to SDEV_BLOCK for all devices
2882 * attached to this expander. This function called when expander is
2883 * pulled.
2884 */
2885static void
2886_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2887 struct _sas_node *sas_expander)
2888{
2889 struct _sas_port *mpt2sas_port;
2890 struct _sas_device *sas_device;
2891 struct _sas_node *expander_sibling;
2892 unsigned long flags;
2893
2894 if (!sas_expander)
2895 return;
2896
2897 list_for_each_entry(mpt2sas_port,
2898 &sas_expander->sas_port_list, port_list) {
2899 if (mpt2sas_port->remote_identify.device_type ==
2900 SAS_END_DEVICE) {
2901 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2902 sas_device =
2903 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2904 mpt2sas_port->remote_identify.sas_address);
2905 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2906 if (!sas_device)
2907 continue;
2908 _scsih_block_io_device(ioc, sas_device->handle);
2909 }
2910 }
2911
2912 list_for_each_entry(mpt2sas_port,
2913 &sas_expander->sas_port_list, port_list) {
2914
2915 if (mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05302916 SAS_EDGE_EXPANDER_DEVICE ||
Eric Moore635374e2009-03-09 01:21:12 -06002917 mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05302918 SAS_FANOUT_EXPANDER_DEVICE) {
Eric Moore635374e2009-03-09 01:21:12 -06002919
2920 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2921 expander_sibling =
2922 mpt2sas_scsih_expander_find_by_sas_address(
2923 ioc, mpt2sas_port->remote_identify.sas_address);
2924 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2925 _scsih_block_io_to_children_attached_to_ex(ioc,
2926 expander_sibling);
2927 }
2928 }
2929}
2930
2931/**
2932 * _scsih_block_io_to_children_attached_directly
2933 * @ioc: per adapter object
2934 * @event_data: topology change event data
2935 *
2936 * This routine set sdev state to SDEV_BLOCK for all devices
2937 * direct attached during device pull.
2938 */
2939static void
2940_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2941 Mpi2EventDataSasTopologyChangeList_t *event_data)
2942{
2943 int i;
2944 u16 handle;
2945 u16 reason_code;
2946 u8 phy_number;
2947
2948 for (i = 0; i < event_data->NumEntries; i++) {
2949 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2950 if (!handle)
2951 continue;
2952 phy_number = event_data->StartPhyNum + i;
2953 reason_code = event_data->PHY[i].PhyStatus &
2954 MPI2_EVENT_SAS_TOPO_RC_MASK;
2955 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2956 _scsih_block_io_device(ioc, handle);
2957 }
2958}
2959
2960/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302961 * _scsih_tm_tr_send - send task management request
2962 * @ioc: per adapter object
2963 * @handle: device handle
2964 * Context: interrupt time.
2965 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002966 * This code is to initiate the device removal handshake protocol
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302967 * with controller firmware. This function will issue target reset
2968 * using high priority request queue. It will send a sas iounit
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002969 * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302970 *
2971 * This is designed to send muliple task management request at the same
2972 * time to the fifo. If the fifo is full, we will append the request,
2973 * and process it in a future completion.
2974 */
2975static void
2976_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2977{
2978 Mpi2SCSITaskManagementRequest_t *mpi_request;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302979 u16 smid;
2980 struct _sas_device *sas_device;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05302981 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302982 unsigned long flags;
2983 struct _tr_list *delayed_tr;
2984
Eric Moore3cb54692010-07-08 14:44:34 -06002985 if (ioc->shost_recovery || ioc->remove_host ||
2986 ioc->pci_error_recovery) {
Kashyap, Desai1278b112010-03-09 17:34:13 +05302987 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
2988 "progress!\n", __func__, ioc->name));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302989 return;
2990 }
2991
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05302992 /* if PD, then return */
2993 if (test_bit(handle, ioc->pd_handles))
2994 return;
2995
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302996 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2997 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05302998 if (sas_device && sas_device->starget &&
2999 sas_device->starget->hostdata) {
3000 sas_target_priv_data = sas_device->starget->hostdata;
3001 sas_target_priv_data->deleted = 1;
3002 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3003 "setting delete flag: handle(0x%04x), "
3004 "sas_addr(0x%016llx)\n", ioc->name, handle,
3005 (unsigned long long) sas_device->sas_address));
Kashyap, Desai1278b112010-03-09 17:34:13 +05303006 }
3007 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303008
3009 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
3010 if (!smid) {
3011 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
3012 if (!delayed_tr)
3013 return;
3014 INIT_LIST_HEAD(&delayed_tr->list);
3015 delayed_tr->handle = handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303016 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
3017 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3018 "DELAYED:tr:handle(0x%04x), (open)\n",
3019 ioc->name, handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303020 return;
3021 }
3022
Kashyap, Desai1278b112010-03-09 17:34:13 +05303023 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
3024 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
3025 ioc->tm_tr_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303026 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3027 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
3028 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
3029 mpi_request->DevHandle = cpu_to_le16(handle);
3030 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303031 mpt2sas_base_put_smid_hi_priority(ioc, smid);
3032}
3033
3034
3035
3036/**
3037 * _scsih_sas_control_complete - completion routine
3038 * @ioc: per adapter object
3039 * @smid: system request message index
3040 * @msix_index: MSIX table index supplied by the OS
3041 * @reply: reply message frame(lower 32bit addr)
3042 * Context: interrupt time.
3043 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003044 * This is the sas iounit control completion routine.
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303045 * This code is part of the code to initiate the device removal
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003046 * handshake protocol with controller firmware.
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303047 *
3048 * Return 1 meaning mf should be freed from _base_interrupt
3049 * 0 means the mf is freed from this function.
3050 */
3051static u8
3052_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
3053 u8 msix_index, u32 reply)
3054{
Kashyap, Desai363fa502010-11-13 04:29:20 +05303055#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303056 Mpi2SasIoUnitControlReply_t *mpi_reply =
3057 mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai363fa502010-11-13 04:29:20 +05303058#endif
Kashyap, Desai1278b112010-03-09 17:34:13 +05303059 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3060 "sc_complete:handle(0x%04x), (open) "
3061 "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
3062 ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
3063 le16_to_cpu(mpi_reply->IOCStatus),
3064 le32_to_cpu(mpi_reply->IOCLogInfo)));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303065 return 1;
3066}
3067
3068/**
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303069 * _scsih_tm_tr_volume_send - send target reset request for volumes
3070 * @ioc: per adapter object
3071 * @handle: device handle
3072 * Context: interrupt time.
3073 *
3074 * This is designed to send muliple task management request at the same
3075 * time to the fifo. If the fifo is full, we will append the request,
3076 * and process it in a future completion.
3077 */
3078static void
3079_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3080{
3081 Mpi2SCSITaskManagementRequest_t *mpi_request;
3082 u16 smid;
3083 struct _tr_list *delayed_tr;
3084
Eric Moore3cb54692010-07-08 14:44:34 -06003085 if (ioc->shost_recovery || ioc->remove_host ||
3086 ioc->pci_error_recovery) {
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303087 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
3088 "progress!\n", __func__, ioc->name));
3089 return;
3090 }
3091
3092 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx);
3093 if (!smid) {
3094 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
3095 if (!delayed_tr)
3096 return;
3097 INIT_LIST_HEAD(&delayed_tr->list);
3098 delayed_tr->handle = handle;
3099 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list);
3100 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3101 "DELAYED:tr:handle(0x%04x), (open)\n",
3102 ioc->name, handle));
3103 return;
3104 }
3105
3106 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
3107 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
3108 ioc->tm_tr_volume_cb_idx));
3109 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3110 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
3111 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
3112 mpi_request->DevHandle = cpu_to_le16(handle);
3113 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
3114 mpt2sas_base_put_smid_hi_priority(ioc, smid);
3115}
3116
3117/**
3118 * _scsih_tm_volume_tr_complete - target reset completion
3119 * @ioc: per adapter object
3120 * @smid: system request message index
3121 * @msix_index: MSIX table index supplied by the OS
3122 * @reply: reply message frame(lower 32bit addr)
3123 * Context: interrupt time.
3124 *
3125 * Return 1 meaning mf should be freed from _base_interrupt
3126 * 0 means the mf is freed from this function.
3127 */
3128static u8
3129_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
3130 u8 msix_index, u32 reply)
3131{
3132 u16 handle;
3133 Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
3134 Mpi2SCSITaskManagementReply_t *mpi_reply =
3135 mpt2sas_base_get_reply_virt_addr(ioc, reply);
3136
Eric Moore3cb54692010-07-08 14:44:34 -06003137 if (ioc->shost_recovery || ioc->remove_host ||
3138 ioc->pci_error_recovery) {
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303139 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
3140 "progress!\n", __func__, ioc->name));
3141 return 1;
3142 }
3143
3144 mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
3145 handle = le16_to_cpu(mpi_request_tm->DevHandle);
3146 if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
3147 dewtprintk(ioc, printk("spurious interrupt: "
3148 "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle,
3149 le16_to_cpu(mpi_reply->DevHandle), smid));
3150 return 0;
3151 }
3152
3153 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3154 "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
3155 "loginfo(0x%08x), completed(%d)\n", ioc->name,
3156 handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
3157 le32_to_cpu(mpi_reply->IOCLogInfo),
3158 le32_to_cpu(mpi_reply->TerminationCount)));
3159
3160 return _scsih_check_for_pending_tm(ioc, smid);
3161}
3162
3163/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303164 * _scsih_tm_tr_complete -
3165 * @ioc: per adapter object
3166 * @smid: system request message index
3167 * @msix_index: MSIX table index supplied by the OS
3168 * @reply: reply message frame(lower 32bit addr)
3169 * Context: interrupt time.
3170 *
3171 * This is the target reset completion routine.
3172 * This code is part of the code to initiate the device removal
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003173 * handshake protocol with controller firmware.
3174 * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303175 *
3176 * Return 1 meaning mf should be freed from _base_interrupt
3177 * 0 means the mf is freed from this function.
3178 */
3179static u8
3180_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
3181 u32 reply)
3182{
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303183 u16 handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303184 Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303185 Mpi2SCSITaskManagementReply_t *mpi_reply =
3186 mpt2sas_base_get_reply_virt_addr(ioc, reply);
3187 Mpi2SasIoUnitControlRequest_t *mpi_request;
3188 u16 smid_sas_ctrl;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303189
Eric Moore3cb54692010-07-08 14:44:34 -06003190 if (ioc->shost_recovery || ioc->remove_host ||
3191 ioc->pci_error_recovery) {
Kashyap, Desai1278b112010-03-09 17:34:13 +05303192 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
3193 "progress!\n", __func__, ioc->name));
3194 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303195 }
3196
Kashyap, Desai1278b112010-03-09 17:34:13 +05303197 mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
3198 handle = le16_to_cpu(mpi_request_tm->DevHandle);
3199 if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
3200 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: "
3201 "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle,
3202 le16_to_cpu(mpi_reply->DevHandle), smid));
3203 return 0;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303204 }
3205
Kashyap, Desai1278b112010-03-09 17:34:13 +05303206 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3207 "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
3208 "loginfo(0x%08x), completed(%d)\n", ioc->name,
3209 handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
3210 le32_to_cpu(mpi_reply->IOCLogInfo),
3211 le32_to_cpu(mpi_reply->TerminationCount)));
3212
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303213 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
3214 if (!smid_sas_ctrl) {
3215 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
3216 ioc->name, __func__);
Kashyap, Desai1278b112010-03-09 17:34:13 +05303217 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303218 }
3219
Kashyap, Desai1278b112010-03-09 17:34:13 +05303220 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), "
3221 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl,
3222 ioc->tm_sas_control_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303223 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
3224 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
3225 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
3226 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303227 mpi_request->DevHandle = mpi_request_tm->DevHandle;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303228 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
Kashyap, Desai1278b112010-03-09 17:34:13 +05303229
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303230 return _scsih_check_for_pending_tm(ioc, smid);
3231}
3232
3233/**
3234 * _scsih_check_for_pending_tm - check for pending task management
3235 * @ioc: per adapter object
3236 * @smid: system request message index
3237 *
3238 * This will check delayed target reset list, and feed the
3239 * next reqeust.
3240 *
3241 * Return 1 meaning mf should be freed from _base_interrupt
3242 * 0 means the mf is freed from this function.
3243 */
3244static u8
3245_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid)
3246{
3247 struct _tr_list *delayed_tr;
3248
3249 if (!list_empty(&ioc->delayed_tr_volume_list)) {
3250 delayed_tr = list_entry(ioc->delayed_tr_volume_list.next,
3251 struct _tr_list, list);
3252 mpt2sas_base_free_smid(ioc, smid);
3253 _scsih_tm_tr_volume_send(ioc, delayed_tr->handle);
3254 list_del(&delayed_tr->list);
3255 kfree(delayed_tr);
3256 return 0;
3257 }
3258
Kashyap, Desai1278b112010-03-09 17:34:13 +05303259 if (!list_empty(&ioc->delayed_tr_list)) {
3260 delayed_tr = list_entry(ioc->delayed_tr_list.next,
3261 struct _tr_list, list);
3262 mpt2sas_base_free_smid(ioc, smid);
3263 _scsih_tm_tr_send(ioc, delayed_tr->handle);
3264 list_del(&delayed_tr->list);
3265 kfree(delayed_tr);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303266 return 0;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303267 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303268
Kashyap, Desai1278b112010-03-09 17:34:13 +05303269 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303270}
3271
3272/**
Eric Moore635374e2009-03-09 01:21:12 -06003273 * _scsih_check_topo_delete_events - sanity check on topo events
3274 * @ioc: per adapter object
3275 * @event_data: the event data payload
3276 *
3277 * This routine added to better handle cable breaker.
3278 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003279 * This handles the case where driver receives multiple expander
Eric Moore635374e2009-03-09 01:21:12 -06003280 * add and delete events in a single shot. When there is a delete event
3281 * the routine will void any pending add events waiting in the event queue.
3282 *
3283 * Return nothing.
3284 */
3285static void
3286_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
3287 Mpi2EventDataSasTopologyChangeList_t *event_data)
3288{
3289 struct fw_event_work *fw_event;
3290 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
3291 u16 expander_handle;
3292 struct _sas_node *sas_expander;
3293 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303294 int i, reason_code;
3295 u16 handle;
3296
3297 for (i = 0 ; i < event_data->NumEntries; i++) {
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303298 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
3299 if (!handle)
3300 continue;
3301 reason_code = event_data->PHY[i].PhyStatus &
3302 MPI2_EVENT_SAS_TOPO_RC_MASK;
3303 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
3304 _scsih_tm_tr_send(ioc, handle);
3305 }
Eric Moore635374e2009-03-09 01:21:12 -06003306
3307 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
3308 if (expander_handle < ioc->sas_hba.num_phys) {
3309 _scsih_block_io_to_children_attached_directly(ioc, event_data);
3310 return;
3311 }
3312
3313 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
3314 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
3315 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3316 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
3317 expander_handle);
3318 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3319 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
3320 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
3321 _scsih_block_io_to_children_attached_directly(ioc, event_data);
3322
3323 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
3324 return;
3325
3326 /* mark ignore flag for pending events */
3327 spin_lock_irqsave(&ioc->fw_event_lock, flags);
3328 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
3329 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
3330 fw_event->ignore)
3331 continue;
3332 local_event_data = fw_event->event_data;
3333 if (local_event_data->ExpStatus ==
3334 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
3335 local_event_data->ExpStatus ==
3336 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
3337 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
3338 expander_handle) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05303339 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -06003340 "setting ignoring flag\n", ioc->name));
3341 fw_event->ignore = 1;
3342 }
3343 }
3344 }
3345 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
3346}
3347
3348/**
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303349 * _scsih_set_volume_delete_flag - setting volume delete flag
3350 * @ioc: per adapter object
3351 * @handle: device handle
3352 *
3353 * This
3354 * Return nothing.
3355 */
3356static void
3357_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3358{
3359 struct _raid_device *raid_device;
3360 struct MPT2SAS_TARGET *sas_target_priv_data;
3361 unsigned long flags;
3362
3363 spin_lock_irqsave(&ioc->raid_device_lock, flags);
3364 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
3365 if (raid_device && raid_device->starget &&
3366 raid_device->starget->hostdata) {
3367 sas_target_priv_data =
3368 raid_device->starget->hostdata;
3369 sas_target_priv_data->deleted = 1;
3370 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3371 "setting delete flag: handle(0x%04x), "
3372 "wwid(0x%016llx)\n", ioc->name, handle,
3373 (unsigned long long) raid_device->wwid));
3374 }
3375 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
3376}
3377
3378/**
3379 * _scsih_set_volume_handle_for_tr - set handle for target reset to volume
3380 * @handle: input handle
3381 * @a: handle for volume a
3382 * @b: handle for volume b
3383 *
3384 * IR firmware only supports two raid volumes. The purpose of this
3385 * routine is to set the volume handle in either a or b. When the given
3386 * input handle is non-zero, or when a and b have not been set before.
3387 */
3388static void
3389_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b)
3390{
3391 if (!handle || handle == *a || handle == *b)
3392 return;
3393 if (!*a)
3394 *a = handle;
3395 else if (!*b)
3396 *b = handle;
3397}
3398
3399/**
3400 * _scsih_check_ir_config_unhide_events - check for UNHIDE events
3401 * @ioc: per adapter object
3402 * @event_data: the event data payload
3403 * Context: interrupt time.
3404 *
3405 * This routine will send target reset to volume, followed by target
3406 * resets to the PDs. This is called when a PD has been removed, or
3407 * volume has been deleted or removed. When the target reset is sent
3408 * to volume, the PD target resets need to be queued to start upon
3409 * completion of the volume target reset.
3410 *
3411 * Return nothing.
3412 */
3413static void
3414_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc,
3415 Mpi2EventDataIrConfigChangeList_t *event_data)
3416{
3417 Mpi2EventIrConfigElement_t *element;
3418 int i;
3419 u16 handle, volume_handle, a, b;
3420 struct _tr_list *delayed_tr;
3421
3422 a = 0;
3423 b = 0;
3424
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303425 if (ioc->is_warpdrive)
3426 return;
3427
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303428 /* Volume Resets for Deleted or Removed */
3429 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3430 for (i = 0; i < event_data->NumElements; i++, element++) {
3431 if (element->ReasonCode ==
3432 MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED ||
3433 element->ReasonCode ==
3434 MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
3435 volume_handle = le16_to_cpu(element->VolDevHandle);
3436 _scsih_set_volume_delete_flag(ioc, volume_handle);
3437 _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
3438 }
3439 }
3440
3441 /* Volume Resets for UNHIDE events */
3442 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3443 for (i = 0; i < event_data->NumElements; i++, element++) {
3444 if (le32_to_cpu(event_data->Flags) &
3445 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
3446 continue;
3447 if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) {
3448 volume_handle = le16_to_cpu(element->VolDevHandle);
3449 _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
3450 }
3451 }
3452
3453 if (a)
3454 _scsih_tm_tr_volume_send(ioc, a);
3455 if (b)
3456 _scsih_tm_tr_volume_send(ioc, b);
3457
3458 /* PD target resets */
3459 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3460 for (i = 0; i < event_data->NumElements; i++, element++) {
3461 if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE)
3462 continue;
3463 handle = le16_to_cpu(element->PhysDiskDevHandle);
3464 volume_handle = le16_to_cpu(element->VolDevHandle);
3465 clear_bit(handle, ioc->pd_handles);
3466 if (!volume_handle)
3467 _scsih_tm_tr_send(ioc, handle);
3468 else if (volume_handle == a || volume_handle == b) {
3469 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
3470 BUG_ON(!delayed_tr);
3471 INIT_LIST_HEAD(&delayed_tr->list);
3472 delayed_tr->handle = handle;
3473 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
3474 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3475 "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name,
3476 handle));
3477 } else
3478 _scsih_tm_tr_send(ioc, handle);
3479 }
3480}
3481
3482
3483/**
3484 * _scsih_check_volume_delete_events - set delete flag for volumes
3485 * @ioc: per adapter object
3486 * @event_data: the event data payload
3487 * Context: interrupt time.
3488 *
3489 * This will handle the case when the cable connected to entire volume is
3490 * pulled. We will take care of setting the deleted flag so normal IO will
3491 * not be sent.
3492 *
3493 * Return nothing.
3494 */
3495static void
3496_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc,
3497 Mpi2EventDataIrVolume_t *event_data)
3498{
3499 u32 state;
3500
3501 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
3502 return;
3503 state = le32_to_cpu(event_data->NewValue);
3504 if (state == MPI2_RAID_VOL_STATE_MISSING || state ==
3505 MPI2_RAID_VOL_STATE_FAILED)
3506 _scsih_set_volume_delete_flag(ioc,
3507 le16_to_cpu(event_data->VolDevHandle));
3508}
3509
3510/**
Eric Moore635374e2009-03-09 01:21:12 -06003511 * _scsih_flush_running_cmds - completing outstanding commands.
3512 * @ioc: per adapter object
3513 *
3514 * The flushing out of all pending scmd commands following host reset,
3515 * where all IO is dropped to the floor.
3516 *
3517 * Return nothing.
3518 */
3519static void
3520_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
3521{
3522 struct scsi_cmnd *scmd;
3523 u16 smid;
3524 u16 count = 0;
3525
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303526 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Kashyap, Desaiec07a052011-01-05 17:54:32 +05303527 scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003528 if (!scmd)
3529 continue;
3530 count++;
3531 mpt2sas_base_free_smid(ioc, smid);
3532 scsi_dma_unmap(scmd);
Eric Moore3cb54692010-07-08 14:44:34 -06003533 if (ioc->pci_error_recovery)
3534 scmd->result = DID_NO_CONNECT << 16;
3535 else
3536 scmd->result = DID_RESET << 16;
Eric Moore635374e2009-03-09 01:21:12 -06003537 scmd->scsi_done(scmd);
3538 }
3539 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
3540 ioc->name, count));
3541}
3542
3543/**
Eric Moore3c621b32009-05-18 12:59:41 -06003544 * _scsih_setup_eedp - setup MPI request for EEDP transfer
3545 * @scmd: pointer to scsi command object
3546 * @mpi_request: pointer to the SCSI_IO reqest message frame
3547 *
3548 * Supporting protection 1 and 3.
3549 *
3550 * Returns nothing
3551 */
3552static void
3553_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
3554{
3555 u16 eedp_flags;
3556 unsigned char prot_op = scsi_get_prot_op(scmd);
3557 unsigned char prot_type = scsi_get_prot_type(scmd);
3558
Eric Moored334aa72010-04-22 10:47:40 -06003559 if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL)
Eric Moore3c621b32009-05-18 12:59:41 -06003560 return;
3561
3562 if (prot_op == SCSI_PROT_READ_STRIP)
3563 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
3564 else if (prot_op == SCSI_PROT_WRITE_INSERT)
3565 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
3566 else
3567 return;
3568
Eric Moore3c621b32009-05-18 12:59:41 -06003569 switch (prot_type) {
3570 case SCSI_PROT_DIF_TYPE1:
Martin K. Petersen756aca72011-05-18 00:45:22 -04003571 case SCSI_PROT_DIF_TYPE2:
Eric Moore3c621b32009-05-18 12:59:41 -06003572
3573 /*
3574 * enable ref/guard checking
3575 * auto increment ref tag
3576 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05303577 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
Eric Moore3c621b32009-05-18 12:59:41 -06003578 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
3579 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
3580 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
3581 cpu_to_be32(scsi_get_lba(scmd));
Eric Moored334aa72010-04-22 10:47:40 -06003582 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003583
Eric Moore3c621b32009-05-18 12:59:41 -06003584 case SCSI_PROT_DIF_TYPE3:
3585
3586 /*
3587 * enable guard checking
3588 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05303589 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
Eric Moore3c621b32009-05-18 12:59:41 -06003590 break;
3591 }
Kashyap, Desai463217b2009-10-05 15:53:06 +05303592 mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
3593 mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
Eric Moore3c621b32009-05-18 12:59:41 -06003594}
3595
3596/**
3597 * _scsih_eedp_error_handling - return sense code for EEDP errors
3598 * @scmd: pointer to scsi command object
3599 * @ioc_status: ioc status
3600 *
3601 * Returns nothing
3602 */
3603static void
3604_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
3605{
3606 u8 ascq;
3607 u8 sk;
3608 u8 host_byte;
3609
3610 switch (ioc_status) {
3611 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3612 ascq = 0x01;
3613 break;
3614 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3615 ascq = 0x02;
3616 break;
3617 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3618 ascq = 0x03;
3619 break;
3620 default:
3621 ascq = 0x00;
3622 break;
3623 }
3624
3625 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
3626 sk = ILLEGAL_REQUEST;
3627 host_byte = DID_ABORT;
3628 } else {
3629 sk = ABORTED_COMMAND;
3630 host_byte = DID_OK;
3631 }
3632
3633 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
3634 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
3635 SAM_STAT_CHECK_CONDITION;
3636}
3637
3638/**
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303639 * _scsih_scsi_direct_io_get - returns direct io flag
3640 * @ioc: per adapter object
3641 * @smid: system request message index
3642 *
3643 * Returns the smid stored scmd pointer.
3644 */
3645static inline u8
3646_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
3647{
3648 return ioc->scsi_lookup[smid - 1].direct_io;
3649}
3650
3651/**
3652 * _scsih_scsi_direct_io_set - sets direct io flag
3653 * @ioc: per adapter object
3654 * @smid: system request message index
3655 * @direct_io: Zero or non-zero value to set in the direct_io flag
3656 *
3657 * Returns Nothing.
3658 */
3659static inline void
3660_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
3661{
3662 ioc->scsi_lookup[smid - 1].direct_io = direct_io;
3663}
3664
3665
3666/**
3667 * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
3668 * @ioc: per adapter object
3669 * @scmd: pointer to scsi command object
3670 * @raid_device: pointer to raid device data structure
3671 * @mpi_request: pointer to the SCSI_IO reqest message frame
3672 * @smid: system request message index
3673 *
3674 * Returns nothing
3675 */
3676static void
3677_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
3678 struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
3679 u16 smid)
3680{
3681 u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size;
3682 u32 stripe_sz, stripe_exp;
3683 u8 num_pds, *cdb_ptr, *tmp_ptr, *lba_ptr1, *lba_ptr2;
3684 u8 cdb0 = scmd->cmnd[0];
3685
3686 /*
3687 * Try Direct I/O to RAID memeber disks
3688 */
3689 if (cdb0 == READ_16 || cdb0 == READ_10 ||
3690 cdb0 == WRITE_16 || cdb0 == WRITE_10) {
3691 cdb_ptr = mpi_request->CDB.CDB32;
3692
3693 if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4]
3694 | cdb_ptr[5])) {
3695 io_size = scsi_bufflen(scmd) >> 9;
3696 /* get virtual lba */
3697 lba_ptr1 = lba_ptr2 = (cdb0 < READ_16) ? &cdb_ptr[2] :
3698 &cdb_ptr[6];
3699 tmp_ptr = (u8 *)&v_lba + 3;
3700 *tmp_ptr-- = *lba_ptr1++;
3701 *tmp_ptr-- = *lba_ptr1++;
3702 *tmp_ptr-- = *lba_ptr1++;
3703 *tmp_ptr = *lba_ptr1;
3704
3705 if (((u64)v_lba + (u64)io_size - 1) <=
3706 (u32)raid_device->max_lba) {
3707 stripe_sz = raid_device->stripe_sz;
3708 stripe_exp = raid_device->stripe_exponent;
3709 stripe_off = v_lba & (stripe_sz - 1);
3710
3711 /* Check whether IO falls within a stripe */
3712 if ((stripe_off + io_size) <= stripe_sz) {
3713 num_pds = raid_device->num_pds;
3714 p_lba = v_lba >> stripe_exp;
3715 stripe_unit = p_lba / num_pds;
3716 column = p_lba % num_pds;
3717 p_lba = (stripe_unit << stripe_exp) +
3718 stripe_off;
3719 mpi_request->DevHandle =
3720 cpu_to_le16(raid_device->
3721 pd_handle[column]);
3722 tmp_ptr = (u8 *)&p_lba + 3;
3723 *lba_ptr2++ = *tmp_ptr--;
3724 *lba_ptr2++ = *tmp_ptr--;
3725 *lba_ptr2++ = *tmp_ptr--;
3726 *lba_ptr2 = *tmp_ptr;
3727 /*
3728 * WD: To indicate this I/O is directI/O
3729 */
3730 _scsih_scsi_direct_io_set(ioc, smid, 1);
3731 }
3732 }
3733 }
3734 }
3735}
3736
3737/**
Eric Moored5d135b2009-05-18 13:02:08 -06003738 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06003739 * @scmd: pointer to scsi command object
3740 * @done: function pointer to be invoked on completion
3741 *
3742 * The callback index is set inside `ioc->scsi_io_cb_idx`.
3743 *
3744 * Returns 0 on success. If there's a failure, return either:
3745 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
3746 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
3747 */
3748static int
Jeff Garzikf2812332010-11-16 02:10:29 -05003749_scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06003750{
3751 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
3752 struct MPT2SAS_DEVICE *sas_device_priv_data;
3753 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303754 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06003755 Mpi2SCSIIORequest_t *mpi_request;
3756 u32 mpi_control;
3757 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06003758
3759 scmd->scsi_done = done;
3760 sas_device_priv_data = scmd->device->hostdata;
Kashyap, Desai130b9582010-04-08 17:54:32 +05303761 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Eric Moore635374e2009-03-09 01:21:12 -06003762 scmd->result = DID_NO_CONNECT << 16;
3763 scmd->scsi_done(scmd);
3764 return 0;
3765 }
3766
Kashyap, Desai78215782011-06-14 10:57:08 +05303767 if (ioc->pci_error_recovery || ioc->remove_host) {
Eric Moore3cb54692010-07-08 14:44:34 -06003768 scmd->result = DID_NO_CONNECT << 16;
3769 scmd->scsi_done(scmd);
3770 return 0;
3771 }
3772
Eric Moore635374e2009-03-09 01:21:12 -06003773 sas_target_priv_data = sas_device_priv_data->sas_target;
Kashyap, Desai130b9582010-04-08 17:54:32 +05303774 /* invalid device handle */
3775 if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
Eric Moore635374e2009-03-09 01:21:12 -06003776 scmd->result = DID_NO_CONNECT << 16;
3777 scmd->scsi_done(scmd);
3778 return 0;
3779 }
3780
Kashyap, Desai130b9582010-04-08 17:54:32 +05303781 /* host recovery or link resets sent via IOCTLs */
3782 if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06003783 return SCSI_MLQUEUE_HOST_BUSY;
Uwe Kleine-König65155b32010-06-11 12:17:01 +02003784 /* device busy with task management */
Kashyap, Desai130b9582010-04-08 17:54:32 +05303785 else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
3786 return SCSI_MLQUEUE_DEVICE_BUSY;
3787 /* device has been deleted */
3788 else if (sas_target_priv_data->deleted) {
3789 scmd->result = DID_NO_CONNECT << 16;
3790 scmd->scsi_done(scmd);
3791 return 0;
3792 }
Eric Moore635374e2009-03-09 01:21:12 -06003793
3794 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
3795 mpi_control = MPI2_SCSIIO_CONTROL_READ;
3796 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
3797 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
3798 else
3799 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
3800
3801 /* set tags */
3802 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
3803 if (scmd->device->tagged_supported) {
3804 if (scmd->device->ordered_tags)
3805 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
3806 else
3807 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
3808 } else
3809/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
3810/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
3811 */
3812 mpi_control |= (0x500);
3813
3814 } else
3815 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303816 /* Make sure Device is not raid volume.
3817 * We do not expose raid functionality to upper layer for warpdrive.
3818 */
3819 if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
Eric Moored334aa72010-04-22 10:47:40 -06003820 sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
Eric Moore635374e2009-03-09 01:21:12 -06003821 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
3822
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303823 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06003824 if (!smid) {
3825 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
3826 ioc->name, __func__);
3827 goto out;
3828 }
3829 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3830 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06003831 _scsih_setup_eedp(scmd, mpi_request);
Eric Moored334aa72010-04-22 10:47:40 -06003832 if (scmd->cmd_len == 32)
3833 mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
Eric Moore635374e2009-03-09 01:21:12 -06003834 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3835 if (sas_device_priv_data->sas_target->flags &
3836 MPT_TARGET_FLAGS_RAID_COMPONENT)
3837 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3838 else
3839 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3840 mpi_request->DevHandle =
3841 cpu_to_le16(sas_device_priv_data->sas_target->handle);
3842 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
3843 mpi_request->Control = cpu_to_le32(mpi_control);
3844 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
3845 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
3846 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
3847 mpi_request->SenseBufferLowAddress =
Kashyap, Desaiec9472c2009-09-23 17:34:13 +05303848 mpt2sas_base_get_sense_buffer_dma(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003849 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
3850 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
3851 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303852 mpi_request->VF_ID = 0; /* TODO */
3853 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003854 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
3855 mpi_request->LUN);
3856 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
3857
3858 if (!mpi_request->DataLength) {
3859 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
3860 } else {
3861 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
3862 mpt2sas_base_free_smid(ioc, smid);
3863 goto out;
3864 }
3865 }
3866
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303867 raid_device = sas_target_priv_data->raid_device;
3868 if (raid_device && raid_device->direct_io_enabled)
3869 _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request,
3870 smid);
3871
Kashyap, Desai58287fd2010-03-17 16:27:25 +05303872 if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST))
3873 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303874 le16_to_cpu(mpi_request->DevHandle));
Kashyap, Desai58287fd2010-03-17 16:27:25 +05303875 else
3876 mpt2sas_base_put_smid_default(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003877 return 0;
3878
3879 out:
3880 return SCSI_MLQUEUE_HOST_BUSY;
3881}
3882
Jeff Garzikf2812332010-11-16 02:10:29 -05003883static DEF_SCSI_QCMD(_scsih_qcmd)
3884
Eric Moore635374e2009-03-09 01:21:12 -06003885/**
3886 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
3887 * @sense_buffer: sense data returned by target
3888 * @data: normalized skey/asc/ascq
3889 *
3890 * Return nothing.
3891 */
3892static void
3893_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
3894{
3895 if ((sense_buffer[0] & 0x7F) >= 0x72) {
3896 /* descriptor format */
3897 data->skey = sense_buffer[1] & 0x0F;
3898 data->asc = sense_buffer[2];
3899 data->ascq = sense_buffer[3];
3900 } else {
3901 /* fixed format */
3902 data->skey = sense_buffer[2] & 0x0F;
3903 data->asc = sense_buffer[12];
3904 data->ascq = sense_buffer[13];
3905 }
3906}
3907
3908#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3909/**
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003910 * _scsih_scsi_ioc_info - translated non-successful SCSI_IO request
Eric Moore635374e2009-03-09 01:21:12 -06003911 * @ioc: per adapter object
3912 * @scmd: pointer to scsi command object
3913 * @mpi_reply: reply mf payload returned from firmware
3914 *
3915 * scsi_status - SCSI Status code returned from target device
3916 * scsi_state - state info associated with SCSI_IO determined by ioc
3917 * ioc_status - ioc supplied status info
3918 *
3919 * Return nothing.
3920 */
3921static void
3922_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
3923 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
3924{
3925 u32 response_info;
3926 u8 *response_bytes;
3927 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
3928 MPI2_IOCSTATUS_MASK;
3929 u8 scsi_state = mpi_reply->SCSIState;
3930 u8 scsi_status = mpi_reply->SCSIStatus;
3931 char *desc_ioc_state = NULL;
3932 char *desc_scsi_status = NULL;
3933 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303934 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
Kashyap, Desai7fbae672010-06-17 13:45:17 +05303935 struct _sas_device *sas_device = NULL;
3936 unsigned long flags;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05303937 struct scsi_target *starget = scmd->device->sdev_target;
3938 struct MPT2SAS_TARGET *priv_target = starget->hostdata;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303939 char *device_str = NULL;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05303940
3941 if (!priv_target)
3942 return;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303943
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303944 if (ioc->hide_ir_msg)
3945 device_str = "WarpDrive";
3946 else
3947 device_str = "volume";
3948
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303949 if (log_info == 0x31170000)
3950 return;
Eric Moore635374e2009-03-09 01:21:12 -06003951
3952 switch (ioc_status) {
3953 case MPI2_IOCSTATUS_SUCCESS:
3954 desc_ioc_state = "success";
3955 break;
3956 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3957 desc_ioc_state = "invalid function";
3958 break;
3959 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3960 desc_ioc_state = "scsi recovered error";
3961 break;
3962 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
3963 desc_ioc_state = "scsi invalid dev handle";
3964 break;
3965 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3966 desc_ioc_state = "scsi device not there";
3967 break;
3968 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3969 desc_ioc_state = "scsi data overrun";
3970 break;
3971 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3972 desc_ioc_state = "scsi data underrun";
3973 break;
3974 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3975 desc_ioc_state = "scsi io data error";
3976 break;
3977 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3978 desc_ioc_state = "scsi protocol error";
3979 break;
3980 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3981 desc_ioc_state = "scsi task terminated";
3982 break;
3983 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3984 desc_ioc_state = "scsi residual mismatch";
3985 break;
3986 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3987 desc_ioc_state = "scsi task mgmt failed";
3988 break;
3989 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3990 desc_ioc_state = "scsi ioc terminated";
3991 break;
3992 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3993 desc_ioc_state = "scsi ext terminated";
3994 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003995 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3996 desc_ioc_state = "eedp guard error";
3997 break;
3998 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3999 desc_ioc_state = "eedp ref tag error";
4000 break;
4001 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
4002 desc_ioc_state = "eedp app tag error";
4003 break;
Eric Moore635374e2009-03-09 01:21:12 -06004004 default:
4005 desc_ioc_state = "unknown";
4006 break;
4007 }
4008
4009 switch (scsi_status) {
4010 case MPI2_SCSI_STATUS_GOOD:
4011 desc_scsi_status = "good";
4012 break;
4013 case MPI2_SCSI_STATUS_CHECK_CONDITION:
4014 desc_scsi_status = "check condition";
4015 break;
4016 case MPI2_SCSI_STATUS_CONDITION_MET:
4017 desc_scsi_status = "condition met";
4018 break;
4019 case MPI2_SCSI_STATUS_BUSY:
4020 desc_scsi_status = "busy";
4021 break;
4022 case MPI2_SCSI_STATUS_INTERMEDIATE:
4023 desc_scsi_status = "intermediate";
4024 break;
4025 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
4026 desc_scsi_status = "intermediate condmet";
4027 break;
4028 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
4029 desc_scsi_status = "reservation conflict";
4030 break;
4031 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
4032 desc_scsi_status = "command terminated";
4033 break;
4034 case MPI2_SCSI_STATUS_TASK_SET_FULL:
4035 desc_scsi_status = "task set full";
4036 break;
4037 case MPI2_SCSI_STATUS_ACA_ACTIVE:
4038 desc_scsi_status = "aca active";
4039 break;
4040 case MPI2_SCSI_STATUS_TASK_ABORTED:
4041 desc_scsi_status = "task aborted";
4042 break;
4043 default:
4044 desc_scsi_status = "unknown";
4045 break;
4046 }
4047
4048 desc_scsi_state[0] = '\0';
4049 if (!scsi_state)
4050 desc_scsi_state = " ";
4051 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
4052 strcat(desc_scsi_state, "response info ");
4053 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
4054 strcat(desc_scsi_state, "state terminated ");
4055 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
4056 strcat(desc_scsi_state, "no status ");
4057 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
4058 strcat(desc_scsi_state, "autosense failed ");
4059 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
4060 strcat(desc_scsi_state, "autosense valid ");
4061
4062 scsi_print_command(scmd);
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304063
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304064 if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304065 printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
4066 device_str, (unsigned long long)priv_target->sas_address);
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304067 } else {
4068 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4069 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4070 priv_target->sas_address);
4071 if (sas_device) {
4072 printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
4073 "phy(%d)\n", ioc->name, sas_device->sas_address,
4074 sas_device->phy);
4075 printk(MPT2SAS_WARN_FMT
4076 "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
4077 ioc->name, sas_device->enclosure_logical_id,
4078 sas_device->slot);
4079 }
4080 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304081 }
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304082
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304083 printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), "
4084 "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle),
4085 desc_ioc_state, ioc_status, smid);
Eric Moore635374e2009-03-09 01:21:12 -06004086 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
4087 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
4088 scsi_get_resid(scmd));
4089 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
4090 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
4091 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
4092 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
4093 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
4094 scsi_status, desc_scsi_state, scsi_state);
4095
4096 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
4097 struct sense_info data;
4098 _scsih_normalize_sense(scmd->sense_buffer, &data);
4099 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
Kashyap, Desaie94f6742010-03-17 16:24:52 +05304100 "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey,
4101 data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));
Eric Moore635374e2009-03-09 01:21:12 -06004102 }
4103
4104 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
4105 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
4106 response_bytes = (u8 *)&response_info;
Kashyap, Desai9982f592009-09-23 17:23:07 +05304107 _scsih_response_code(ioc, response_bytes[0]);
Eric Moore635374e2009-03-09 01:21:12 -06004108 }
4109}
4110#endif
4111
4112/**
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05304113 * _scsih_turn_on_fault_led - illuminate Fault LED
Eric Moore635374e2009-03-09 01:21:12 -06004114 * @ioc: per adapter object
4115 * @handle: device handle
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05304116 * Context: process
4117 *
4118 * Return nothing.
4119 */
4120static void
4121_scsih_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4122{
4123 Mpi2SepReply_t mpi_reply;
4124 Mpi2SepRequest_t mpi_request;
4125
4126 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
4127 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
4128 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
4129 mpi_request.SlotStatus =
4130 cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
4131 mpi_request.DevHandle = cpu_to_le16(handle);
4132 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
4133 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
4134 &mpi_request)) != 0) {
4135 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
4136 __FILE__, __LINE__, __func__);
4137 return;
4138 }
4139
4140 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
4141 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: "
4142 "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name,
4143 le16_to_cpu(mpi_reply.IOCStatus),
4144 le32_to_cpu(mpi_reply.IOCLogInfo)));
4145 return;
4146 }
4147}
4148
4149/**
4150 * _scsih_send_event_to_turn_on_fault_led - fire delayed event
4151 * @ioc: per adapter object
4152 * @handle: device handle
4153 * Context: interrupt.
4154 *
4155 * Return nothing.
4156 */
4157static void
4158_scsih_send_event_to_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4159{
4160 struct fw_event_work *fw_event;
4161
4162 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
4163 if (!fw_event)
4164 return;
4165 fw_event->event = MPT2SAS_TURN_ON_FAULT_LED;
4166 fw_event->device_handle = handle;
4167 fw_event->ioc = ioc;
4168 _scsih_fw_event_add(ioc, fw_event);
4169}
4170
4171/**
4172 * _scsih_smart_predicted_fault - process smart errors
4173 * @ioc: per adapter object
4174 * @handle: device handle
4175 * Context: interrupt.
Eric Moore635374e2009-03-09 01:21:12 -06004176 *
4177 * Return nothing.
4178 */
4179static void
4180_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4181{
Eric Moore635374e2009-03-09 01:21:12 -06004182 struct scsi_target *starget;
4183 struct MPT2SAS_TARGET *sas_target_priv_data;
4184 Mpi2EventNotificationReply_t *event_reply;
4185 Mpi2EventDataSasDeviceStatusChange_t *event_data;
4186 struct _sas_device *sas_device;
4187 ssize_t sz;
4188 unsigned long flags;
4189
4190 /* only handle non-raid devices */
4191 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4192 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4193 if (!sas_device) {
4194 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4195 return;
4196 }
4197 starget = sas_device->starget;
4198 sas_target_priv_data = starget->hostdata;
4199
4200 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
4201 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
4202 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4203 return;
4204 }
4205 starget_printk(KERN_WARNING, starget, "predicted fault\n");
4206 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4207
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05304208 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
4209 _scsih_send_event_to_turn_on_fault_led(ioc, handle);
Eric Moore635374e2009-03-09 01:21:12 -06004210
4211 /* insert into event log */
4212 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
4213 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
4214 event_reply = kzalloc(sz, GFP_KERNEL);
4215 if (!event_reply) {
4216 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4217 ioc->name, __FILE__, __LINE__, __func__);
4218 return;
4219 }
4220
4221 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
4222 event_reply->Event =
4223 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
4224 event_reply->MsgLength = sz/4;
4225 event_reply->EventDataLength =
4226 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
4227 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
4228 event_reply->EventData;
4229 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
4230 event_data->ASC = 0x5D;
4231 event_data->DevHandle = cpu_to_le16(handle);
4232 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
4233 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
4234 kfree(event_reply);
4235}
4236
4237/**
Eric Moored5d135b2009-05-18 13:02:08 -06004238 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06004239 * @ioc: per adapter object
4240 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304241 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06004242 * @reply: reply message frame(lower 32bit addr)
4243 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304244 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06004245 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304246 * Return 1 meaning mf should be freed from _base_interrupt
4247 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06004248 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304249static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304250_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06004251{
4252 Mpi2SCSIIORequest_t *mpi_request;
4253 Mpi2SCSIIOReply_t *mpi_reply;
4254 struct scsi_cmnd *scmd;
4255 u16 ioc_status;
4256 u32 xfer_cnt;
4257 u8 scsi_state;
4258 u8 scsi_status;
4259 u32 log_info;
4260 struct MPT2SAS_DEVICE *sas_device_priv_data;
Kashyap, Desai9982f592009-09-23 17:23:07 +05304261 u32 response_code = 0;
Kashyap, Desai82a45252011-07-05 12:40:23 +05304262 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06004263
4264 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desaiec07a052011-01-05 17:54:32 +05304265 scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06004266 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304267 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06004268
4269 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
4270
4271 if (mpi_reply == NULL) {
4272 scmd->result = DID_OK << 16;
4273 goto out;
4274 }
4275
4276 sas_device_priv_data = scmd->device->hostdata;
4277 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
4278 sas_device_priv_data->sas_target->deleted) {
4279 scmd->result = DID_NO_CONNECT << 16;
4280 goto out;
4281 }
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304282 /*
4283 * WARPDRIVE: If direct_io is set then it is directIO,
4284 * the failed direct I/O should be redirected to volume
4285 */
4286 if (_scsih_scsi_direct_io_get(ioc, smid)) {
Kashyap, Desai82a45252011-07-05 12:40:23 +05304287 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
4288 ioc->scsi_lookup[smid - 1].scmd = scmd;
4289 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304290 _scsih_scsi_direct_io_set(ioc, smid, 0);
4291 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
4292 mpi_request->DevHandle =
4293 cpu_to_le16(sas_device_priv_data->sas_target->handle);
4294 mpt2sas_base_put_smid_scsi_io(ioc, smid,
4295 sas_device_priv_data->sas_target->handle);
4296 return 0;
4297 }
4298
Eric Moore635374e2009-03-09 01:21:12 -06004299
4300 /* turning off TLR */
Kashyap, Desai9982f592009-09-23 17:23:07 +05304301 scsi_state = mpi_reply->SCSIState;
4302 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
4303 response_code =
4304 le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
Eric Moore635374e2009-03-09 01:21:12 -06004305 if (!sas_device_priv_data->tlr_snoop_check) {
4306 sas_device_priv_data->tlr_snoop_check++;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304307 /* Make sure Device is not raid volume.
4308 * We do not expose raid functionality to upper layer for warpdrive.
4309 */
4310 if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
Kashyap, Desai3ed21522010-02-17 16:08:36 +05304311 sas_is_tlr_enabled(scmd->device) &&
Kashyap, Desai84f0b042009-12-16 18:56:28 +05304312 response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
4313 sas_disable_tlr(scmd->device);
4314 sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
4315 }
Eric Moore635374e2009-03-09 01:21:12 -06004316 }
4317
4318 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
4319 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
4320 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
4321 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
4322 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
4323 else
4324 log_info = 0;
4325 ioc_status &= MPI2_IOCSTATUS_MASK;
Eric Moore635374e2009-03-09 01:21:12 -06004326 scsi_status = mpi_reply->SCSIStatus;
4327
4328 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
4329 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
4330 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
4331 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
4332 ioc_status = MPI2_IOCSTATUS_SUCCESS;
4333 }
4334
4335 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
4336 struct sense_info data;
4337 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
4338 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06004339 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06004340 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06004341 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06004342 _scsih_normalize_sense(scmd->sense_buffer, &data);
4343 /* failure prediction threshold exceeded */
4344 if (data.asc == 0x5D)
4345 _scsih_smart_predicted_fault(ioc,
4346 le16_to_cpu(mpi_reply->DevHandle));
4347 }
4348
4349 switch (ioc_status) {
4350 case MPI2_IOCSTATUS_BUSY:
4351 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
4352 scmd->result = SAM_STAT_BUSY;
4353 break;
4354
4355 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
4356 scmd->result = DID_NO_CONNECT << 16;
4357 break;
4358
4359 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
4360 if (sas_device_priv_data->block) {
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05304361 scmd->result = DID_TRANSPORT_DISRUPTED << 16;
4362 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06004363 }
Eric Moore635374e2009-03-09 01:21:12 -06004364 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
4365 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
4366 scmd->result = DID_RESET << 16;
4367 break;
4368
4369 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
4370 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
4371 scmd->result = DID_SOFT_ERROR << 16;
4372 else
4373 scmd->result = (DID_OK << 16) | scsi_status;
4374 break;
4375
4376 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
4377 scmd->result = (DID_OK << 16) | scsi_status;
4378
4379 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
4380 break;
4381
4382 if (xfer_cnt < scmd->underflow) {
4383 if (scsi_status == SAM_STAT_BUSY)
4384 scmd->result = SAM_STAT_BUSY;
4385 else
4386 scmd->result = DID_SOFT_ERROR << 16;
4387 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
4388 MPI2_SCSI_STATE_NO_SCSI_STATUS))
4389 scmd->result = DID_SOFT_ERROR << 16;
4390 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
4391 scmd->result = DID_RESET << 16;
4392 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
4393 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
4394 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
4395 scmd->result = (DRIVER_SENSE << 24) |
4396 SAM_STAT_CHECK_CONDITION;
4397 scmd->sense_buffer[0] = 0x70;
4398 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
4399 scmd->sense_buffer[12] = 0x20;
4400 scmd->sense_buffer[13] = 0;
4401 }
4402 break;
4403
4404 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
4405 scsi_set_resid(scmd, 0);
4406 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
4407 case MPI2_IOCSTATUS_SUCCESS:
4408 scmd->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9982f592009-09-23 17:23:07 +05304409 if (response_code ==
4410 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
4411 (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
4412 MPI2_SCSI_STATE_NO_SCSI_STATUS)))
Eric Moore635374e2009-03-09 01:21:12 -06004413 scmd->result = DID_SOFT_ERROR << 16;
4414 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
4415 scmd->result = DID_RESET << 16;
4416 break;
4417
Eric Moore3c621b32009-05-18 12:59:41 -06004418 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
4419 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
4420 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
4421 _scsih_eedp_error_handling(scmd, ioc_status);
4422 break;
Eric Moore635374e2009-03-09 01:21:12 -06004423 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
4424 case MPI2_IOCSTATUS_INVALID_FUNCTION:
4425 case MPI2_IOCSTATUS_INVALID_SGL:
4426 case MPI2_IOCSTATUS_INTERNAL_ERROR:
4427 case MPI2_IOCSTATUS_INVALID_FIELD:
4428 case MPI2_IOCSTATUS_INVALID_STATE:
4429 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
4430 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
4431 default:
4432 scmd->result = DID_SOFT_ERROR << 16;
4433 break;
4434
4435 }
4436
4437#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4438 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
4439 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
4440#endif
4441
4442 out:
4443 scsi_dma_unmap(scmd);
4444 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304445 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06004446}
4447
4448/**
Eric Moore635374e2009-03-09 01:21:12 -06004449 * _scsih_sas_host_refresh - refreshing sas host object contents
4450 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06004451 * Context: user
4452 *
4453 * During port enable, fw will send topology events for every device. Its
4454 * possible that the handles may change from the previous setting, so this
4455 * code keeping handles updating if changed.
4456 *
4457 * Return nothing.
4458 */
4459static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304460_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06004461{
4462 u16 sz;
4463 u16 ioc_status;
4464 int i;
4465 Mpi2ConfigReply_t mpi_reply;
4466 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304467 u16 attached_handle;
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304468 u8 link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06004469
4470 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
4471 "updating handles for sas_host(0x%016llx)\n",
4472 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
4473
4474 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
4475 * sizeof(Mpi2SasIOUnit0PhyData_t));
4476 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
4477 if (!sas_iounit_pg0) {
4478 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4479 ioc->name, __FILE__, __LINE__, __func__);
4480 return;
4481 }
Eric Moore635374e2009-03-09 01:21:12 -06004482
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304483 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
4484 sas_iounit_pg0, sz)) != 0)
4485 goto out;
4486 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
4487 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
4488 goto out;
4489 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304490 link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304491 if (i == 0)
4492 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
4493 PhyData[0].ControllerDevHandle);
4494 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
4495 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
4496 AttachedDevHandle);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304497 if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
4498 link_rate = MPI2_SAS_NEG_LINK_RATE_1_5;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304499 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304500 attached_handle, i, link_rate);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304501 }
Eric Moore635374e2009-03-09 01:21:12 -06004502 out:
4503 kfree(sas_iounit_pg0);
4504}
4505
4506/**
4507 * _scsih_sas_host_add - create sas host object
4508 * @ioc: per adapter object
4509 *
4510 * Creating host side data object, stored in ioc->sas_hba
4511 *
4512 * Return nothing.
4513 */
4514static void
4515_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
4516{
4517 int i;
4518 Mpi2ConfigReply_t mpi_reply;
4519 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
4520 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
4521 Mpi2SasPhyPage0_t phy_pg0;
4522 Mpi2SasDevicePage0_t sas_device_pg0;
4523 Mpi2SasEnclosurePage0_t enclosure_pg0;
4524 u16 ioc_status;
4525 u16 sz;
4526 u16 device_missing_delay;
4527
4528 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
4529 if (!ioc->sas_hba.num_phys) {
4530 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4531 ioc->name, __FILE__, __LINE__, __func__);
4532 return;
4533 }
4534
4535 /* sas_iounit page 0 */
4536 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
4537 sizeof(Mpi2SasIOUnit0PhyData_t));
4538 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
4539 if (!sas_iounit_pg0) {
4540 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4541 ioc->name, __FILE__, __LINE__, __func__);
4542 return;
4543 }
4544 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
4545 sas_iounit_pg0, sz))) {
4546 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4547 ioc->name, __FILE__, __LINE__, __func__);
4548 goto out;
4549 }
4550 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4551 MPI2_IOCSTATUS_MASK;
4552 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4553 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4554 ioc->name, __FILE__, __LINE__, __func__);
4555 goto out;
4556 }
4557
4558 /* sas_iounit page 1 */
4559 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
4560 sizeof(Mpi2SasIOUnit1PhyData_t));
4561 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
4562 if (!sas_iounit_pg1) {
4563 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4564 ioc->name, __FILE__, __LINE__, __func__);
4565 goto out;
4566 }
4567 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
4568 sas_iounit_pg1, sz))) {
4569 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4570 ioc->name, __FILE__, __LINE__, __func__);
4571 goto out;
4572 }
4573 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4574 MPI2_IOCSTATUS_MASK;
4575 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4576 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4577 ioc->name, __FILE__, __LINE__, __func__);
4578 goto out;
4579 }
4580
4581 ioc->io_missing_delay =
4582 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
4583 device_missing_delay =
4584 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
4585 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
4586 ioc->device_missing_delay = (device_missing_delay &
4587 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
4588 else
4589 ioc->device_missing_delay = device_missing_delay &
4590 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
4591
4592 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
4593 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
4594 sizeof(struct _sas_phy), GFP_KERNEL);
4595 if (!ioc->sas_hba.phy) {
4596 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4597 ioc->name, __FILE__, __LINE__, __func__);
4598 goto out;
4599 }
4600 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
4601 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
4602 i))) {
4603 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4604 ioc->name, __FILE__, __LINE__, __func__);
4605 goto out;
4606 }
4607 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4608 MPI2_IOCSTATUS_MASK;
4609 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4610 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4611 ioc->name, __FILE__, __LINE__, __func__);
4612 goto out;
4613 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304614
4615 if (i == 0)
4616 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
4617 PhyData[0].ControllerDevHandle);
4618 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06004619 ioc->sas_hba.phy[i].phy_id = i;
4620 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
4621 phy_pg0, ioc->sas_hba.parent_dev);
4622 }
4623 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304624 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06004625 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4626 ioc->name, __FILE__, __LINE__, __func__);
4627 goto out;
4628 }
Eric Moore635374e2009-03-09 01:21:12 -06004629 ioc->sas_hba.enclosure_handle =
4630 le16_to_cpu(sas_device_pg0.EnclosureHandle);
4631 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4632 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
4633 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
4634 (unsigned long long) ioc->sas_hba.sas_address,
4635 ioc->sas_hba.num_phys) ;
4636
4637 if (ioc->sas_hba.enclosure_handle) {
4638 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
4639 &enclosure_pg0,
4640 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4641 ioc->sas_hba.enclosure_handle))) {
4642 ioc->sas_hba.enclosure_logical_id =
4643 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
4644 }
4645 }
4646
4647 out:
4648 kfree(sas_iounit_pg1);
4649 kfree(sas_iounit_pg0);
4650}
4651
4652/**
4653 * _scsih_expander_add - creating expander object
4654 * @ioc: per adapter object
4655 * @handle: expander handle
4656 *
4657 * Creating expander object, stored in ioc->sas_expander_list.
4658 *
4659 * Return 0 for success, else error.
4660 */
4661static int
4662_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4663{
4664 struct _sas_node *sas_expander;
4665 Mpi2ConfigReply_t mpi_reply;
4666 Mpi2ExpanderPage0_t expander_pg0;
4667 Mpi2ExpanderPage1_t expander_pg1;
4668 Mpi2SasEnclosurePage0_t enclosure_pg0;
4669 u32 ioc_status;
4670 u16 parent_handle;
Kashyap, Desaic97951e2011-06-14 10:54:56 +05304671 u64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004672 int i;
4673 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05304674 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06004675 int rc = 0;
4676
4677 if (!handle)
4678 return -1;
4679
Eric Moore3cb54692010-07-08 14:44:34 -06004680 if (ioc->shost_recovery || ioc->pci_error_recovery)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304681 return -1;
4682
Eric Moore635374e2009-03-09 01:21:12 -06004683 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
4684 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
4685 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4686 ioc->name, __FILE__, __LINE__, __func__);
4687 return -1;
4688 }
4689
4690 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4691 MPI2_IOCSTATUS_MASK;
4692 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4693 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4694 ioc->name, __FILE__, __LINE__, __func__);
4695 return -1;
4696 }
4697
4698 /* handle out of order topology events */
4699 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304700 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
4701 != 0) {
4702 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4703 ioc->name, __FILE__, __LINE__, __func__);
4704 return -1;
4705 }
4706 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06004707 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304708 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
4709 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004710 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4711 if (!sas_expander) {
4712 rc = _scsih_expander_add(ioc, parent_handle);
4713 if (rc != 0)
4714 return rc;
4715 }
4716 }
4717
Eric Moore635374e2009-03-09 01:21:12 -06004718 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304719 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06004720 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
4721 sas_address);
4722 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4723
4724 if (sas_expander)
4725 return 0;
4726
4727 sas_expander = kzalloc(sizeof(struct _sas_node),
4728 GFP_KERNEL);
4729 if (!sas_expander) {
4730 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4731 ioc->name, __FILE__, __LINE__, __func__);
4732 return -1;
4733 }
4734
4735 sas_expander->handle = handle;
4736 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304737 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06004738 sas_expander->sas_address = sas_address;
4739
4740 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
4741 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304742 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06004743 sas_expander->sas_address, sas_expander->num_phys);
4744
4745 if (!sas_expander->num_phys)
4746 goto out_fail;
4747 sas_expander->phy = kcalloc(sas_expander->num_phys,
4748 sizeof(struct _sas_phy), GFP_KERNEL);
4749 if (!sas_expander->phy) {
4750 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4751 ioc->name, __FILE__, __LINE__, __func__);
4752 rc = -1;
4753 goto out_fail;
4754 }
4755
4756 INIT_LIST_HEAD(&sas_expander->sas_port_list);
4757 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304758 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004759 if (!mpt2sas_port) {
4760 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4761 ioc->name, __FILE__, __LINE__, __func__);
4762 rc = -1;
4763 goto out_fail;
4764 }
4765 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
4766
4767 for (i = 0 ; i < sas_expander->num_phys ; i++) {
4768 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
4769 &expander_pg1, i, handle))) {
4770 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4771 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05304772 rc = -1;
4773 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06004774 }
4775 sas_expander->phy[i].handle = handle;
4776 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05304777
4778 if ((mpt2sas_transport_add_expander_phy(ioc,
4779 &sas_expander->phy[i], expander_pg1,
4780 sas_expander->parent_dev))) {
4781 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4782 ioc->name, __FILE__, __LINE__, __func__);
4783 rc = -1;
4784 goto out_fail;
4785 }
Eric Moore635374e2009-03-09 01:21:12 -06004786 }
4787
4788 if (sas_expander->enclosure_handle) {
4789 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
4790 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4791 sas_expander->enclosure_handle))) {
4792 sas_expander->enclosure_logical_id =
4793 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
4794 }
4795 }
4796
4797 _scsih_expander_node_add(ioc, sas_expander);
4798 return 0;
4799
4800 out_fail:
4801
Kashyap, Desai20f58952009-08-07 19:34:26 +05304802 if (mpt2sas_port)
4803 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304804 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004805 kfree(sas_expander);
4806 return rc;
4807}
4808
4809/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05304810 * _scsih_done - scsih callback handler.
4811 * @ioc: per adapter object
4812 * @smid: system request message index
4813 * @msix_index: MSIX table index supplied by the OS
4814 * @reply: reply message frame(lower 32bit addr)
4815 *
4816 * Callback handler when sending internal generated message frames.
4817 * The callback index passed is `ioc->scsih_cb_idx`
4818 *
4819 * Return 1 meaning mf should be freed from _base_interrupt
4820 * 0 means the mf is freed from this function.
4821 */
4822static u8
4823_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
4824{
4825 MPI2DefaultReply_t *mpi_reply;
4826
4827 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
4828 if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
4829 return 1;
4830 if (ioc->scsih_cmds.smid != smid)
4831 return 1;
4832 ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
4833 if (mpi_reply) {
4834 memcpy(ioc->scsih_cmds.reply, mpi_reply,
4835 mpi_reply->MsgLength*4);
4836 ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
4837 }
4838 ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
4839 complete(&ioc->scsih_cmds.done);
4840 return 1;
4841}
4842
4843/**
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304844 * mpt2sas_expander_remove - removing expander object
Eric Moore635374e2009-03-09 01:21:12 -06004845 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304846 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06004847 *
4848 * Return nothing.
4849 */
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304850void
4851mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06004852{
4853 struct _sas_node *sas_expander;
4854 unsigned long flags;
4855
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304856 if (ioc->shost_recovery)
4857 return;
4858
Eric Moore635374e2009-03-09 01:21:12 -06004859 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304860 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
4861 sas_address);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304862 if (!sas_expander) {
4863 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4864 return;
4865 }
4866 list_del(&sas_expander->list);
Eric Moore635374e2009-03-09 01:21:12 -06004867 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4868 _scsih_expander_node_remove(ioc, sas_expander);
4869}
4870
4871/**
Kashyap, Desaib4344272010-03-17 16:24:14 +05304872 * _scsih_check_access_status - check access flags
4873 * @ioc: per adapter object
4874 * @sas_address: sas address
4875 * @handle: sas device handle
4876 * @access_flags: errors returned during discovery of the device
4877 *
4878 * Return 0 for success, else failure
4879 */
4880static u8
4881_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
4882 u16 handle, u8 access_status)
4883{
4884 u8 rc = 1;
4885 char *desc = NULL;
4886
4887 switch (access_status) {
4888 case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS:
4889 case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION:
4890 rc = 0;
4891 break;
4892 case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED:
4893 desc = "sata capability failed";
4894 break;
4895 case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT:
4896 desc = "sata affiliation conflict";
4897 break;
4898 case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE:
4899 desc = "route not addressable";
4900 break;
4901 case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE:
4902 desc = "smp error not addressable";
4903 break;
4904 case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED:
4905 desc = "device blocked";
4906 break;
4907 case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED:
4908 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN:
4909 case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT:
4910 case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG:
4911 case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION:
4912 case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER:
4913 case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN:
4914 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN:
4915 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN:
4916 case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION:
4917 case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE:
4918 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX:
4919 desc = "sata initialization failed";
4920 break;
4921 default:
4922 desc = "unknown";
4923 break;
4924 }
4925
4926 if (!rc)
4927 return 0;
4928
4929 printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), "
4930 "handle(0x%04x)\n", ioc->name, desc,
4931 (unsigned long long)sas_address, handle);
4932 return rc;
4933}
4934
4935static void
4936_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4937{
4938 Mpi2ConfigReply_t mpi_reply;
4939 Mpi2SasDevicePage0_t sas_device_pg0;
4940 struct _sas_device *sas_device;
4941 u32 ioc_status;
4942 unsigned long flags;
4943 u64 sas_address;
4944 struct scsi_target *starget;
4945 struct MPT2SAS_TARGET *sas_target_priv_data;
4946 u32 device_info;
4947
4948 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4949 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
4950 return;
4951
4952 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
4953 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
4954 return;
4955
4956 /* check if this is end device */
4957 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4958 if (!(_scsih_is_end_device(device_info)))
4959 return;
4960
4961 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4962 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4963 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4964 sas_address);
4965
4966 if (!sas_device) {
4967 printk(MPT2SAS_ERR_FMT "device is not present "
4968 "handle(0x%04x), no sas_device!!!\n", ioc->name, handle);
4969 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4970 return;
4971 }
4972
4973 if (unlikely(sas_device->handle != handle)) {
4974 starget = sas_device->starget;
4975 sas_target_priv_data = starget->hostdata;
4976 starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)"
4977 " to (0x%04x)!!!\n", sas_device->handle, handle);
4978 sas_target_priv_data->handle = handle;
4979 sas_device->handle = handle;
4980 }
4981 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4982
4983 /* check if device is present */
4984 if (!(le16_to_cpu(sas_device_pg0.Flags) &
4985 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
4986 printk(MPT2SAS_ERR_FMT "device is not present "
4987 "handle(0x%04x), flags!!!\n", ioc->name, handle);
4988 return;
4989 }
4990
4991 /* check if there were any issues with discovery */
4992 if (_scsih_check_access_status(ioc, sas_address, handle,
4993 sas_device_pg0.AccessStatus))
4994 return;
4995 _scsih_ublock_io_device(ioc, handle);
4996
4997}
4998
4999/**
Eric Moore635374e2009-03-09 01:21:12 -06005000 * _scsih_add_device - creating sas device object
5001 * @ioc: per adapter object
5002 * @handle: sas device handle
5003 * @phy_num: phy number end device attached to
5004 * @is_pd: is this hidden raid component
5005 *
5006 * Creating end device object, stored in ioc->sas_device_list.
5007 *
5008 * Returns 0 for success, non-zero for failure.
5009 */
5010static int
5011_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
5012{
5013 Mpi2ConfigReply_t mpi_reply;
5014 Mpi2SasDevicePage0_t sas_device_pg0;
5015 Mpi2SasEnclosurePage0_t enclosure_pg0;
5016 struct _sas_device *sas_device;
5017 u32 ioc_status;
5018 __le64 sas_address;
5019 u32 device_info;
5020 unsigned long flags;
5021
5022 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
5023 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
5024 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5025 ioc->name, __FILE__, __LINE__, __func__);
5026 return -1;
5027 }
5028
5029 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5030 MPI2_IOCSTATUS_MASK;
5031 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5032 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5033 ioc->name, __FILE__, __LINE__, __func__);
5034 return -1;
5035 }
5036
Kashyap, Desaib4344272010-03-17 16:24:14 +05305037 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5038
Eric Moore635374e2009-03-09 01:21:12 -06005039 /* check if device is present */
5040 if (!(le16_to_cpu(sas_device_pg0.Flags) &
5041 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
5042 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5043 ioc->name, __FILE__, __LINE__, __func__);
5044 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
5045 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
5046 return -1;
5047 }
5048
Kashyap, Desaib4344272010-03-17 16:24:14 +05305049 /* check if there were any issues with discovery */
5050 if (_scsih_check_access_status(ioc, sas_address, handle,
5051 sas_device_pg0.AccessStatus))
Eric Moore635374e2009-03-09 01:21:12 -06005052 return -1;
Eric Moore635374e2009-03-09 01:21:12 -06005053
5054 /* check if this is end device */
5055 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5056 if (!(_scsih_is_end_device(device_info))) {
5057 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5058 ioc->name, __FILE__, __LINE__, __func__);
5059 return -1;
5060 }
5061
Eric Moore635374e2009-03-09 01:21:12 -06005062
5063 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5064 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5065 sas_address);
5066 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5067
Kashyap, Desaib4344272010-03-17 16:24:14 +05305068 if (sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06005069 return 0;
Eric Moore635374e2009-03-09 01:21:12 -06005070
5071 sas_device = kzalloc(sizeof(struct _sas_device),
5072 GFP_KERNEL);
5073 if (!sas_device) {
5074 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5075 ioc->name, __FILE__, __LINE__, __func__);
5076 return -1;
5077 }
5078
5079 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305080 if (_scsih_get_sas_address(ioc, le16_to_cpu
5081 (sas_device_pg0.ParentDevHandle),
5082 &sas_device->sas_address_parent) != 0)
5083 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5084 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06005085 sas_device->enclosure_handle =
5086 le16_to_cpu(sas_device_pg0.EnclosureHandle);
5087 sas_device->slot =
5088 le16_to_cpu(sas_device_pg0.Slot);
5089 sas_device->device_info = device_info;
5090 sas_device->sas_address = sas_address;
Kashyap, Desai7fbae672010-06-17 13:45:17 +05305091 sas_device->phy = sas_device_pg0.PhyNum;
Eric Moore635374e2009-03-09 01:21:12 -06005092
5093 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05305094 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
5095 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
5096 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06005097 sas_device->enclosure_logical_id =
5098 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06005099
5100 /* get device name */
5101 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
5102
5103 if (ioc->wait_for_port_enable_to_complete)
5104 _scsih_sas_device_init_add(ioc, sas_device);
5105 else
5106 _scsih_sas_device_add(ioc, sas_device);
5107
5108 return 0;
5109}
5110
5111/**
Kashyap, Desai1278b112010-03-09 17:34:13 +05305112 * _scsih_remove_device - removing sas device object
5113 * @ioc: per adapter object
5114 * @sas_device_delete: the sas_device object
5115 *
5116 * Return nothing.
5117 */
5118static void
5119_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
5120 struct _sas_device *sas_device)
5121{
5122 struct _sas_device sas_device_backup;
5123 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05305124
Kashyap, Desai1278b112010-03-09 17:34:13 +05305125 if (!sas_device)
5126 return;
Eric Moore635374e2009-03-09 01:21:12 -06005127
Kashyap, Desai1278b112010-03-09 17:34:13 +05305128 memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));
Eric Moore635374e2009-03-09 01:21:12 -06005129 _scsih_sas_device_remove(ioc, sas_device);
5130
Kashyap, Desai1278b112010-03-09 17:34:13 +05305131 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
5132 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
5133 sas_device_backup.handle, (unsigned long long)
5134 sas_device_backup.sas_address));
5135
5136 if (sas_device_backup.starget && sas_device_backup.starget->hostdata) {
5137 sas_target_priv_data = sas_device_backup.starget->hostdata;
5138 sas_target_priv_data->deleted = 1;
5139 }
5140
Kashyap, Desai1278b112010-03-09 17:34:13 +05305141 _scsih_ublock_io_device(ioc, sas_device_backup.handle);
5142
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05305143 if (!ioc->hide_drives)
5144 mpt2sas_transport_port_remove(ioc,
5145 sas_device_backup.sas_address,
5146 sas_device_backup.sas_address_parent);
Kashyap, Desai1278b112010-03-09 17:34:13 +05305147
5148 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
5149 "(0x%016llx)\n", ioc->name, sas_device_backup.handle,
5150 (unsigned long long) sas_device_backup.sas_address);
5151
5152 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
5153 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
5154 sas_device_backup.handle, (unsigned long long)
5155 sas_device_backup.sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06005156}
5157
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305158/**
5159 * mpt2sas_device_remove - removing device object
5160 * @ioc: per adapter object
5161 * @sas_address: expander sas_address
5162 *
5163 * Return nothing.
5164 */
5165void
5166mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
5167{
5168 struct _sas_device *sas_device;
5169 unsigned long flags;
5170
5171 if (ioc->shost_recovery)
5172 return;
5173
5174 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5175 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5176 sas_address);
5177 if (!sas_device) {
5178 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5179 return;
5180 }
5181 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5182 _scsih_remove_device(ioc, sas_device);
5183}
5184
Eric Moore635374e2009-03-09 01:21:12 -06005185#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5186/**
5187 * _scsih_sas_topology_change_event_debug - debug for topology event
5188 * @ioc: per adapter object
5189 * @event_data: event data payload
5190 * Context: user.
5191 */
5192static void
5193_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5194 Mpi2EventDataSasTopologyChangeList_t *event_data)
5195{
5196 int i;
5197 u16 handle;
5198 u16 reason_code;
5199 u8 phy_number;
5200 char *status_str = NULL;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305201 u8 link_rate, prev_link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06005202
5203 switch (event_data->ExpStatus) {
5204 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
5205 status_str = "add";
5206 break;
5207 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
5208 status_str = "remove";
5209 break;
5210 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305211 case 0:
Eric Moore635374e2009-03-09 01:21:12 -06005212 status_str = "responding";
5213 break;
5214 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
5215 status_str = "remove delay";
5216 break;
5217 default:
5218 status_str = "unknown status";
5219 break;
5220 }
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305221 printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n",
Eric Moore635374e2009-03-09 01:21:12 -06005222 ioc->name, status_str);
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305223 printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) "
Eric Moore635374e2009-03-09 01:21:12 -06005224 "start_phy(%02d), count(%d)\n",
5225 le16_to_cpu(event_data->ExpanderDevHandle),
5226 le16_to_cpu(event_data->EnclosureHandle),
5227 event_data->StartPhyNum, event_data->NumEntries);
5228 for (i = 0; i < event_data->NumEntries; i++) {
5229 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
5230 if (!handle)
5231 continue;
5232 phy_number = event_data->StartPhyNum + i;
5233 reason_code = event_data->PHY[i].PhyStatus &
5234 MPI2_EVENT_SAS_TOPO_RC_MASK;
5235 switch (reason_code) {
5236 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305237 status_str = "target add";
Eric Moore635374e2009-03-09 01:21:12 -06005238 break;
5239 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305240 status_str = "target remove";
Eric Moore635374e2009-03-09 01:21:12 -06005241 break;
5242 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305243 status_str = "delay target remove";
Eric Moore635374e2009-03-09 01:21:12 -06005244 break;
5245 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305246 status_str = "link rate change";
Eric Moore635374e2009-03-09 01:21:12 -06005247 break;
5248 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305249 status_str = "target responding";
Eric Moore635374e2009-03-09 01:21:12 -06005250 break;
5251 default:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305252 status_str = "unknown";
Eric Moore635374e2009-03-09 01:21:12 -06005253 break;
5254 }
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305255 link_rate = event_data->PHY[i].LinkRate >> 4;
5256 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305257 printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:"
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305258 " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
5259 handle, status_str, link_rate, prev_link_rate);
5260
Eric Moore635374e2009-03-09 01:21:12 -06005261 }
5262}
5263#endif
5264
5265/**
5266 * _scsih_sas_topology_change_event - handle topology changes
5267 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305268 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005269 * Context: user.
5270 *
5271 */
5272static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305273_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06005274 struct fw_event_work *fw_event)
5275{
5276 int i;
5277 u16 parent_handle, handle;
5278 u16 reason_code;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305279 u8 phy_number, max_phys;
Eric Moore635374e2009-03-09 01:21:12 -06005280 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305281 struct _sas_device *sas_device;
5282 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06005283 unsigned long flags;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305284 u8 link_rate, prev_link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305285 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005286
5287#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5288 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5289 _scsih_sas_topology_change_event_debug(ioc, event_data);
5290#endif
5291
Eric Moore3cb54692010-07-08 14:44:34 -06005292 if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery)
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305293 return;
5294
Eric Moore635374e2009-03-09 01:21:12 -06005295 if (!ioc->sas_hba.num_phys)
5296 _scsih_sas_host_add(ioc);
5297 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305298 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005299
5300 if (fw_event->ignore) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305301 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander "
Eric Moore635374e2009-03-09 01:21:12 -06005302 "event\n", ioc->name));
5303 return;
5304 }
5305
5306 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
5307
5308 /* handle expander add */
5309 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
5310 if (_scsih_expander_add(ioc, parent_handle) != 0)
5311 return;
5312
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305313 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5314 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
5315 parent_handle);
5316 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305317 if (sas_expander) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305318 sas_address = sas_expander->sas_address;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305319 max_phys = sas_expander->num_phys;
5320 } else if (parent_handle < ioc->sas_hba.num_phys) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305321 sas_address = ioc->sas_hba.sas_address;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305322 max_phys = ioc->sas_hba.num_phys;
5323 } else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305324 return;
5325
Eric Moore635374e2009-03-09 01:21:12 -06005326 /* handle siblings events */
5327 for (i = 0; i < event_data->NumEntries; i++) {
5328 if (fw_event->ignore) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305329 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring "
Eric Moore635374e2009-03-09 01:21:12 -06005330 "expander event\n", ioc->name));
5331 return;
5332 }
Eric Moore3cb54692010-07-08 14:44:34 -06005333 if (ioc->shost_recovery || ioc->remove_host ||
5334 ioc->pci_error_recovery)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305335 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05305336 phy_number = event_data->StartPhyNum + i;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305337 if (phy_number >= max_phys)
5338 continue;
Kashyap, Desai308609c2009-09-14 11:07:23 +05305339 reason_code = event_data->PHY[i].PhyStatus &
5340 MPI2_EVENT_SAS_TOPO_RC_MASK;
5341 if ((event_data->PHY[i].PhyStatus &
5342 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
5343 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06005344 continue;
5345 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
5346 if (!handle)
5347 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305348 link_rate = event_data->PHY[i].LinkRate >> 4;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305349 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Eric Moore635374e2009-03-09 01:21:12 -06005350 switch (reason_code) {
5351 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305352
5353 if (link_rate == prev_link_rate)
5354 break;
5355
5356 mpt2sas_transport_update_links(ioc, sas_address,
5357 handle, phy_number, link_rate);
5358
Kashyap, Desaib4344272010-03-17 16:24:14 +05305359 if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
5360 break;
5361
5362 _scsih_check_device(ioc, handle);
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305363 break;
Eric Moore635374e2009-03-09 01:21:12 -06005364 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305365
5366 mpt2sas_transport_update_links(ioc, sas_address,
5367 handle, phy_number, link_rate);
5368
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305369 _scsih_add_device(ioc, handle, phy_number, 0);
Eric Moore635374e2009-03-09 01:21:12 -06005370 break;
5371 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305372
5373 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5374 sas_device = _scsih_sas_device_find_by_handle(ioc,
5375 handle);
5376 if (!sas_device) {
5377 spin_unlock_irqrestore(&ioc->sas_device_lock,
5378 flags);
5379 break;
5380 }
5381 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5382 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005383 break;
5384 }
5385 }
5386
5387 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305388 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
5389 sas_expander)
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305390 mpt2sas_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06005391
5392}
5393
5394#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5395/**
5396 * _scsih_sas_device_status_change_event_debug - debug for device event
5397 * @event_data: event data payload
5398 * Context: user.
5399 *
5400 * Return nothing.
5401 */
5402static void
5403_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5404 Mpi2EventDataSasDeviceStatusChange_t *event_data)
5405{
5406 char *reason_str = NULL;
5407
5408 switch (event_data->ReasonCode) {
5409 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
5410 reason_str = "smart data";
5411 break;
5412 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
5413 reason_str = "unsupported device discovered";
5414 break;
5415 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
5416 reason_str = "internal device reset";
5417 break;
5418 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
5419 reason_str = "internal task abort";
5420 break;
5421 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
5422 reason_str = "internal task abort set";
5423 break;
5424 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
5425 reason_str = "internal clear task set";
5426 break;
5427 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
5428 reason_str = "internal query task";
5429 break;
5430 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
5431 reason_str = "sata init failure";
5432 break;
5433 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
5434 reason_str = "internal device reset complete";
5435 break;
5436 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
5437 reason_str = "internal task abort complete";
5438 break;
5439 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
5440 reason_str = "internal async notification";
5441 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305442 case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
5443 reason_str = "expander reduced functionality";
5444 break;
5445 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
5446 reason_str = "expander reduced functionality complete";
5447 break;
Eric Moore635374e2009-03-09 01:21:12 -06005448 default:
5449 reason_str = "unknown reason";
5450 break;
5451 }
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305452 printk(MPT2SAS_INFO_FMT "device status change: (%s)\n"
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305453 "\thandle(0x%04x), sas address(0x%016llx), tag(%d)",
5454 ioc->name, reason_str, le16_to_cpu(event_data->DevHandle),
5455 (unsigned long long)le64_to_cpu(event_data->SASAddress),
5456 le16_to_cpu(event_data->TaskTag));
Eric Moore635374e2009-03-09 01:21:12 -06005457 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305458 printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
Eric Moore635374e2009-03-09 01:21:12 -06005459 event_data->ASC, event_data->ASCQ);
5460 printk(KERN_INFO "\n");
5461}
5462#endif
5463
5464/**
5465 * _scsih_sas_device_status_change_event - handle device status change
5466 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305467 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005468 * Context: user.
5469 *
5470 * Return nothing.
5471 */
5472static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305473_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
5474 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005475{
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305476 struct MPT2SAS_TARGET *target_priv_data;
5477 struct _sas_device *sas_device;
Kashyap, Desaic97951e2011-06-14 10:54:56 +05305478 u64 sas_address;
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305479 unsigned long flags;
5480 Mpi2EventDataSasDeviceStatusChange_t *event_data =
5481 fw_event->event_data;
5482
Eric Moore635374e2009-03-09 01:21:12 -06005483#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5484 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305485 _scsih_sas_device_status_change_event_debug(ioc,
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305486 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005487#endif
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305488
Kashyap, Desaiefe82a12011-01-04 11:34:17 +05305489 /* In MPI Revision K (0xC), the internal device reset complete was
5490 * implemented, so avoid setting tm_busy flag for older firmware.
5491 */
5492 if ((ioc->facts.HeaderVersion >> 8) < 0xC)
5493 return;
5494
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05305495 if (event_data->ReasonCode !=
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305496 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05305497 event_data->ReasonCode !=
5498 MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305499 return;
5500
5501 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5502 sas_address = le64_to_cpu(event_data->SASAddress);
5503 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5504 sas_address);
5505 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5506
5507 if (!sas_device || !sas_device->starget)
5508 return;
5509
5510 target_priv_data = sas_device->starget->hostdata;
5511 if (!target_priv_data)
5512 return;
5513
5514 if (event_data->ReasonCode ==
5515 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
5516 target_priv_data->tm_busy = 1;
5517 else
5518 target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06005519}
5520
5521#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5522/**
5523 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
5524 * @ioc: per adapter object
5525 * @event_data: event data payload
5526 * Context: user.
5527 *
5528 * Return nothing.
5529 */
5530static void
5531_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5532 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
5533{
5534 char *reason_str = NULL;
5535
5536 switch (event_data->ReasonCode) {
5537 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
5538 reason_str = "enclosure add";
5539 break;
5540 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
5541 reason_str = "enclosure remove";
5542 break;
5543 default:
5544 reason_str = "unknown reason";
5545 break;
5546 }
5547
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305548 printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n"
Eric Moore635374e2009-03-09 01:21:12 -06005549 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
5550 " number slots(%d)\n", ioc->name, reason_str,
5551 le16_to_cpu(event_data->EnclosureHandle),
5552 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
5553 le16_to_cpu(event_data->StartSlot));
5554}
5555#endif
5556
5557/**
5558 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
5559 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305560 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005561 * Context: user.
5562 *
5563 * Return nothing.
5564 */
5565static void
5566_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305567 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005568{
5569#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5570 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5571 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305572 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005573#endif
5574}
5575
5576/**
5577 * _scsih_sas_broadcast_primative_event - handle broadcast events
5578 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305579 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005580 * Context: user.
5581 *
5582 * Return nothing.
5583 */
5584static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305585_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
5586 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005587{
5588 struct scsi_cmnd *scmd;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305589 struct scsi_device *sdev;
Eric Moore635374e2009-03-09 01:21:12 -06005590 u16 smid, handle;
5591 u32 lun;
5592 struct MPT2SAS_DEVICE *sas_device_priv_data;
5593 u32 termination_count;
5594 u32 query_count;
5595 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305596 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
Kashyap, Desai463217b2009-10-05 15:53:06 +05305597 u16 ioc_status;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305598 unsigned long flags;
5599 int r;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305600 u8 max_retries = 0;
5601 u8 task_abort_retries;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305602
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305603 mutex_lock(&ioc->tm_cmds.mutex);
5604 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: phy number(%d), "
5605 "width(%d)\n", ioc->name, __func__, event_data->PhyNum,
5606 event_data->PortWidth));
5607
5608 _scsih_block_io_all_device(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005609
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305610 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305611 mpi_reply = ioc->tm_cmds.reply;
5612broadcast_aen_retry:
5613
5614 /* sanity checks for retrying this loop */
5615 if (max_retries++ == 5) {
5616 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n",
5617 ioc->name, __func__));
5618 goto out;
5619 } else if (max_retries > 1)
5620 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n",
5621 ioc->name, __func__, max_retries - 1));
5622
Eric Moore635374e2009-03-09 01:21:12 -06005623 termination_count = 0;
5624 query_count = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05305625 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305626 if (ioc->ioc_reset_in_progress_status)
5627 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06005628 scmd = _scsih_scsi_lookup_get(ioc, smid);
5629 if (!scmd)
5630 continue;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305631 sdev = scmd->device;
5632 sas_device_priv_data = sdev->hostdata;
Eric Moore635374e2009-03-09 01:21:12 -06005633 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
5634 continue;
5635 /* skip hidden raid components */
5636 if (sas_device_priv_data->sas_target->flags &
5637 MPT_TARGET_FLAGS_RAID_COMPONENT)
5638 continue;
5639 /* skip volumes */
5640 if (sas_device_priv_data->sas_target->flags &
5641 MPT_TARGET_FLAGS_VOLUME)
5642 continue;
5643
5644 handle = sas_device_priv_data->sas_target->handle;
5645 lun = sas_device_priv_data->lun;
5646 query_count++;
5647
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305648 if (ioc->ioc_reset_in_progress_status)
5649 goto out;
5650
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305651 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305652 r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
5653 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, 0,
5654 TM_MUTEX_OFF);
5655 if (r == FAILED) {
5656 sdev_printk(KERN_WARNING, sdev,
5657 "mpt2sas_scsih_issue_tm: FAILED when sending "
5658 "QUERY_TASK: scmd(%p)\n", scmd);
5659 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
5660 goto broadcast_aen_retry;
5661 }
Kashyap, Desai463217b2009-10-05 15:53:06 +05305662 ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
5663 & MPI2_IOCSTATUS_MASK;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305664 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5665 sdev_printk(KERN_WARNING, sdev, "query task: FAILED "
5666 "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status,
5667 scmd);
5668 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
5669 goto broadcast_aen_retry;
5670 }
5671
5672 /* see if IO is still owned by IOC and target */
5673 if (mpi_reply->ResponseCode ==
Eric Moore635374e2009-03-09 01:21:12 -06005674 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
5675 mpi_reply->ResponseCode ==
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305676 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) {
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305677 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06005678 continue;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305679 }
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305680 task_abort_retries = 0;
5681 tm_retry:
5682 if (task_abort_retries++ == 60) {
5683 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
5684 "%s: ABORT_TASK: giving up\n", ioc->name,
5685 __func__));
5686 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
5687 goto broadcast_aen_retry;
5688 }
5689
5690 if (ioc->ioc_reset_in_progress_status)
5691 goto out_no_lock;
5692
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305693 r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id,
5694 sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305695 scmd->serial_number, TM_MUTEX_OFF);
5696 if (r == FAILED) {
5697 sdev_printk(KERN_WARNING, sdev,
5698 "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : "
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305699 "scmd(%p)\n", scmd);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305700 goto tm_retry;
5701 }
5702
5703 if (task_abort_retries > 1)
5704 sdev_printk(KERN_WARNING, sdev,
5705 "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):"
5706 " scmd(%p)\n",
5707 task_abort_retries - 1, scmd);
5708
Eric Moore635374e2009-03-09 01:21:12 -06005709 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305710 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06005711 }
Eric Moore635374e2009-03-09 01:21:12 -06005712
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305713 if (ioc->broadcast_aen_pending) {
5714 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to"
5715 " pending AEN\n", ioc->name, __func__));
5716 ioc->broadcast_aen_pending = 0;
5717 goto broadcast_aen_retry;
5718 }
5719
5720 out:
5721 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
5722 out_no_lock:
5723
5724 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -06005725 "%s - exit, query_count = %d termination_count = %d\n",
5726 ioc->name, __func__, query_count, termination_count));
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305727
5728 ioc->broadcast_aen_busy = 0;
5729 if (!ioc->ioc_reset_in_progress_status)
5730 _scsih_ublock_io_all_device(ioc);
5731 mutex_unlock(&ioc->tm_cmds.mutex);
Eric Moore635374e2009-03-09 01:21:12 -06005732}
5733
5734/**
5735 * _scsih_sas_discovery_event - handle discovery events
5736 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305737 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005738 * Context: user.
5739 *
5740 * Return nothing.
5741 */
5742static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305743_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
5744 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005745{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305746 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
5747
Eric Moore635374e2009-03-09 01:21:12 -06005748#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5749 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305750 printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name,
Eric Moore635374e2009-03-09 01:21:12 -06005751 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
5752 "start" : "stop");
5753 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05305754 printk("discovery_status(0x%08x)",
5755 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06005756 printk("\n");
5757 }
5758#endif
5759
5760 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
5761 !ioc->sas_hba.num_phys)
5762 _scsih_sas_host_add(ioc);
5763}
5764
5765/**
5766 * _scsih_reprobe_lun - reprobing lun
5767 * @sdev: scsi device struct
5768 * @no_uld_attach: sdev->no_uld_attach flag setting
5769 *
5770 **/
5771static void
5772_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
5773{
5774 int rc;
5775
5776 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
5777 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
5778 sdev->no_uld_attach ? "hidding" : "exposing");
5779 rc = scsi_device_reprobe(sdev);
5780}
5781
5782/**
5783 * _scsih_reprobe_target - reprobing target
5784 * @starget: scsi target struct
5785 * @no_uld_attach: sdev->no_uld_attach flag setting
5786 *
5787 * Note: no_uld_attach flag determines whether the disk device is attached
5788 * to block layer. A value of `1` means to not attach.
5789 **/
5790static void
5791_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
5792{
5793 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
5794
5795 if (no_uld_attach)
5796 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
5797 else
5798 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
5799
5800 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
5801 _scsih_reprobe_lun);
5802}
5803/**
5804 * _scsih_sas_volume_add - add new volume
5805 * @ioc: per adapter object
5806 * @element: IR config element data
5807 * Context: user.
5808 *
5809 * Return nothing.
5810 */
5811static void
5812_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
5813 Mpi2EventIrConfigElement_t *element)
5814{
5815 struct _raid_device *raid_device;
5816 unsigned long flags;
5817 u64 wwid;
5818 u16 handle = le16_to_cpu(element->VolDevHandle);
5819 int rc;
5820
Eric Moore635374e2009-03-09 01:21:12 -06005821 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
5822 if (!wwid) {
5823 printk(MPT2SAS_ERR_FMT
5824 "failure at %s:%d/%s()!\n", ioc->name,
5825 __FILE__, __LINE__, __func__);
5826 return;
5827 }
5828
5829 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5830 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
5831 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5832
5833 if (raid_device)
5834 return;
5835
5836 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
5837 if (!raid_device) {
5838 printk(MPT2SAS_ERR_FMT
5839 "failure at %s:%d/%s()!\n", ioc->name,
5840 __FILE__, __LINE__, __func__);
5841 return;
5842 }
5843
5844 raid_device->id = ioc->sas_id++;
5845 raid_device->channel = RAID_CHANNEL;
5846 raid_device->handle = handle;
5847 raid_device->wwid = wwid;
5848 _scsih_raid_device_add(ioc, raid_device);
5849 if (!ioc->wait_for_port_enable_to_complete) {
5850 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5851 raid_device->id, 0);
5852 if (rc)
5853 _scsih_raid_device_remove(ioc, raid_device);
5854 } else
5855 _scsih_determine_boot_device(ioc, raid_device, 1);
5856}
5857
5858/**
5859 * _scsih_sas_volume_delete - delete volume
5860 * @ioc: per adapter object
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305861 * @handle: volume device handle
Eric Moore635374e2009-03-09 01:21:12 -06005862 * Context: user.
5863 *
5864 * Return nothing.
5865 */
5866static void
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305867_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
Eric Moore635374e2009-03-09 01:21:12 -06005868{
5869 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06005870 unsigned long flags;
5871 struct MPT2SAS_TARGET *sas_target_priv_data;
5872
Eric Moore635374e2009-03-09 01:21:12 -06005873 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5874 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5875 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5876 if (!raid_device)
5877 return;
5878 if (raid_device->starget) {
5879 sas_target_priv_data = raid_device->starget->hostdata;
5880 sas_target_priv_data->deleted = 1;
5881 scsi_remove_target(&raid_device->starget->dev);
5882 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305883 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
5884 "(0x%016llx)\n", ioc->name, raid_device->handle,
5885 (unsigned long long) raid_device->wwid);
Eric Moore635374e2009-03-09 01:21:12 -06005886 _scsih_raid_device_remove(ioc, raid_device);
5887}
5888
5889/**
5890 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
5891 * @ioc: per adapter object
5892 * @element: IR config element data
5893 * Context: user.
5894 *
5895 * Return nothing.
5896 */
5897static void
5898_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
5899 Mpi2EventIrConfigElement_t *element)
5900{
5901 struct _sas_device *sas_device;
5902 unsigned long flags;
5903 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
5904
5905 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5906 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5907 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5908 if (!sas_device)
5909 return;
5910
5911 /* exposing raid component */
5912 sas_device->volume_handle = 0;
5913 sas_device->volume_wwid = 0;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305914 clear_bit(handle, ioc->pd_handles);
Eric Moore635374e2009-03-09 01:21:12 -06005915 _scsih_reprobe_target(sas_device->starget, 0);
5916}
5917
5918/**
5919 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
5920 * @ioc: per adapter object
5921 * @element: IR config element data
5922 * Context: user.
5923 *
5924 * Return nothing.
5925 */
5926static void
5927_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
5928 Mpi2EventIrConfigElement_t *element)
5929{
5930 struct _sas_device *sas_device;
5931 unsigned long flags;
5932 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
5933
5934 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5935 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5936 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5937 if (!sas_device)
5938 return;
5939
5940 /* hiding raid component */
5941 mpt2sas_config_get_volume_handle(ioc, handle,
5942 &sas_device->volume_handle);
5943 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
5944 &sas_device->volume_wwid);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305945 set_bit(handle, ioc->pd_handles);
Eric Moore635374e2009-03-09 01:21:12 -06005946 _scsih_reprobe_target(sas_device->starget, 1);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05305947
Eric Moore635374e2009-03-09 01:21:12 -06005948}
5949
5950/**
5951 * _scsih_sas_pd_delete - delete pd component
5952 * @ioc: per adapter object
5953 * @element: IR config element data
5954 * Context: user.
5955 *
5956 * Return nothing.
5957 */
5958static void
5959_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
5960 Mpi2EventIrConfigElement_t *element)
5961{
5962 struct _sas_device *sas_device;
5963 unsigned long flags;
5964 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
5965
5966 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5967 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5968 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5969 if (!sas_device)
5970 return;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305971 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005972}
5973
5974/**
5975 * _scsih_sas_pd_add - remove pd component
5976 * @ioc: per adapter object
5977 * @element: IR config element data
5978 * Context: user.
5979 *
5980 * Return nothing.
5981 */
5982static void
5983_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
5984 Mpi2EventIrConfigElement_t *element)
5985{
5986 struct _sas_device *sas_device;
5987 unsigned long flags;
5988 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305989 Mpi2ConfigReply_t mpi_reply;
5990 Mpi2SasDevicePage0_t sas_device_pg0;
5991 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305992 u64 sas_address;
5993 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06005994
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305995 set_bit(handle, ioc->pd_handles);
5996
Eric Moore635374e2009-03-09 01:21:12 -06005997 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5998 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5999 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306000 if (sas_device)
Kashyap, Desai62727a72009-08-07 19:35:18 +05306001 return;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306002
6003 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
6004 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
6005 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6006 ioc->name, __FILE__, __LINE__, __func__);
6007 return;
6008 }
6009
6010 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6011 MPI2_IOCSTATUS_MASK;
6012 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
6013 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6014 ioc->name, __FILE__, __LINE__, __func__);
6015 return;
6016 }
6017
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306018 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
6019 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
6020 mpt2sas_transport_update_links(ioc, sas_address, handle,
6021 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05306022
6023 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06006024}
6025
6026#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
6027/**
6028 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
6029 * @ioc: per adapter object
6030 * @event_data: event data payload
6031 * Context: user.
6032 *
6033 * Return nothing.
6034 */
6035static void
6036_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
6037 Mpi2EventDataIrConfigChangeList_t *event_data)
6038{
6039 Mpi2EventIrConfigElement_t *element;
6040 u8 element_type;
6041 int i;
6042 char *reason_str = NULL, *element_str = NULL;
6043
6044 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
6045
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306046 printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n",
Eric Moore635374e2009-03-09 01:21:12 -06006047 ioc->name, (le32_to_cpu(event_data->Flags) &
6048 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
6049 "foreign" : "native", event_data->NumElements);
6050 for (i = 0; i < event_data->NumElements; i++, element++) {
6051 switch (element->ReasonCode) {
6052 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
6053 reason_str = "add";
6054 break;
6055 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
6056 reason_str = "remove";
6057 break;
6058 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
6059 reason_str = "no change";
6060 break;
6061 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
6062 reason_str = "hide";
6063 break;
6064 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
6065 reason_str = "unhide";
6066 break;
6067 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
6068 reason_str = "volume_created";
6069 break;
6070 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
6071 reason_str = "volume_deleted";
6072 break;
6073 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
6074 reason_str = "pd_created";
6075 break;
6076 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
6077 reason_str = "pd_deleted";
6078 break;
6079 default:
6080 reason_str = "unknown reason";
6081 break;
6082 }
6083 element_type = le16_to_cpu(element->ElementFlags) &
6084 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
6085 switch (element_type) {
6086 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
6087 element_str = "volume";
6088 break;
6089 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
6090 element_str = "phys disk";
6091 break;
6092 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
6093 element_str = "hot spare";
6094 break;
6095 default:
6096 element_str = "unknown element";
6097 break;
6098 }
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306099 printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), "
Eric Moore635374e2009-03-09 01:21:12 -06006100 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
6101 reason_str, le16_to_cpu(element->VolDevHandle),
6102 le16_to_cpu(element->PhysDiskDevHandle),
6103 element->PhysDiskNum);
6104 }
6105}
6106#endif
6107
6108/**
6109 * _scsih_sas_ir_config_change_event - handle ir configuration change events
6110 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306111 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006112 * Context: user.
6113 *
6114 * Return nothing.
6115 */
6116static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306117_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
6118 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006119{
6120 Mpi2EventIrConfigElement_t *element;
6121 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306122 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306123 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06006124
6125#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306126 if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
6127 && !ioc->hide_ir_msg)
Eric Moore635374e2009-03-09 01:21:12 -06006128 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
6129
6130#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05306131 foreign_config = (le32_to_cpu(event_data->Flags) &
6132 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06006133
6134 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
6135 for (i = 0; i < event_data->NumElements; i++, element++) {
6136
6137 switch (element->ReasonCode) {
6138 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
6139 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05306140 if (!foreign_config)
6141 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006142 break;
6143 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
6144 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05306145 if (!foreign_config)
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306146 _scsih_sas_volume_delete(ioc,
6147 le16_to_cpu(element->VolDevHandle));
Eric Moore635374e2009-03-09 01:21:12 -06006148 break;
6149 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306150 if (!ioc->is_warpdrive)
6151 _scsih_sas_pd_hide(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006152 break;
6153 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306154 if (!ioc->is_warpdrive)
6155 _scsih_sas_pd_expose(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006156 break;
6157 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306158 if (!ioc->is_warpdrive)
6159 _scsih_sas_pd_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006160 break;
6161 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306162 if (!ioc->is_warpdrive)
6163 _scsih_sas_pd_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006164 break;
6165 }
6166 }
6167}
6168
6169/**
6170 * _scsih_sas_ir_volume_event - IR volume event
6171 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306172 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006173 * Context: user.
6174 *
6175 * Return nothing.
6176 */
6177static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306178_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
6179 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006180{
6181 u64 wwid;
6182 unsigned long flags;
6183 struct _raid_device *raid_device;
6184 u16 handle;
6185 u32 state;
6186 int rc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306187 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06006188
6189 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
6190 return;
6191
6192 handle = le16_to_cpu(event_data->VolDevHandle);
6193 state = le32_to_cpu(event_data->NewValue);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306194 if (!ioc->hide_ir_msg)
6195 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
6196 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
6197 le32_to_cpu(event_data->PreviousValue), state));
Eric Moore635374e2009-03-09 01:21:12 -06006198
Eric Moore635374e2009-03-09 01:21:12 -06006199 switch (state) {
6200 case MPI2_RAID_VOL_STATE_MISSING:
6201 case MPI2_RAID_VOL_STATE_FAILED:
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306202 _scsih_sas_volume_delete(ioc, handle);
Eric Moore635374e2009-03-09 01:21:12 -06006203 break;
6204
6205 case MPI2_RAID_VOL_STATE_ONLINE:
6206 case MPI2_RAID_VOL_STATE_DEGRADED:
6207 case MPI2_RAID_VOL_STATE_OPTIMAL:
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306208
6209 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6210 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
6211 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6212
Eric Moore635374e2009-03-09 01:21:12 -06006213 if (raid_device)
6214 break;
6215
6216 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
6217 if (!wwid) {
6218 printk(MPT2SAS_ERR_FMT
6219 "failure at %s:%d/%s()!\n", ioc->name,
6220 __FILE__, __LINE__, __func__);
6221 break;
6222 }
6223
6224 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
6225 if (!raid_device) {
6226 printk(MPT2SAS_ERR_FMT
6227 "failure at %s:%d/%s()!\n", ioc->name,
6228 __FILE__, __LINE__, __func__);
6229 break;
6230 }
6231
6232 raid_device->id = ioc->sas_id++;
6233 raid_device->channel = RAID_CHANNEL;
6234 raid_device->handle = handle;
6235 raid_device->wwid = wwid;
6236 _scsih_raid_device_add(ioc, raid_device);
6237 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6238 raid_device->id, 0);
6239 if (rc)
6240 _scsih_raid_device_remove(ioc, raid_device);
6241 break;
6242
6243 case MPI2_RAID_VOL_STATE_INITIALIZING:
6244 default:
6245 break;
6246 }
6247}
6248
6249/**
6250 * _scsih_sas_ir_physical_disk_event - PD event
6251 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306252 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006253 * Context: user.
6254 *
6255 * Return nothing.
6256 */
6257static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306258_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
6259 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006260{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306261 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06006262 u32 state;
6263 struct _sas_device *sas_device;
6264 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306265 Mpi2ConfigReply_t mpi_reply;
6266 Mpi2SasDevicePage0_t sas_device_pg0;
6267 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306268 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306269 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06006270
6271 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
6272 return;
6273
6274 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
6275 state = le32_to_cpu(event_data->NewValue);
6276
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306277 if (!ioc->hide_ir_msg)
6278 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
6279 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
6280 le32_to_cpu(event_data->PreviousValue), state));
Eric Moore635374e2009-03-09 01:21:12 -06006281
Eric Moore635374e2009-03-09 01:21:12 -06006282 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06006283 case MPI2_RAID_PD_STATE_ONLINE:
6284 case MPI2_RAID_PD_STATE_DEGRADED:
6285 case MPI2_RAID_PD_STATE_REBUILDING:
6286 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306287 case MPI2_RAID_PD_STATE_HOT_SPARE:
6288
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306289 if (!ioc->is_warpdrive)
6290 set_bit(handle, ioc->pd_handles);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306291
6292 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6293 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
6294 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6295
6296 if (sas_device)
Kashyap, Desai62727a72009-08-07 19:35:18 +05306297 return;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306298
6299 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
6300 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
6301 handle))) {
6302 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6303 ioc->name, __FILE__, __LINE__, __func__);
6304 return;
6305 }
6306
6307 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6308 MPI2_IOCSTATUS_MASK;
6309 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
6310 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6311 ioc->name, __FILE__, __LINE__, __func__);
6312 return;
6313 }
6314
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306315 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
6316 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
6317 mpt2sas_transport_update_links(ioc, sas_address, handle,
6318 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05306319
6320 _scsih_add_device(ioc, handle, 0, 1);
6321
Eric Moore635374e2009-03-09 01:21:12 -06006322 break;
6323
Kashyap, Desai62727a72009-08-07 19:35:18 +05306324 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06006325 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
6326 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
Eric Moore635374e2009-03-09 01:21:12 -06006327 default:
6328 break;
6329 }
6330}
6331
6332#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
6333/**
6334 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
6335 * @ioc: per adapter object
6336 * @event_data: event data payload
6337 * Context: user.
6338 *
6339 * Return nothing.
6340 */
6341static void
6342_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
6343 Mpi2EventDataIrOperationStatus_t *event_data)
6344{
6345 char *reason_str = NULL;
6346
6347 switch (event_data->RAIDOperation) {
6348 case MPI2_EVENT_IR_RAIDOP_RESYNC:
6349 reason_str = "resync";
6350 break;
6351 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
6352 reason_str = "online capacity expansion";
6353 break;
6354 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
6355 reason_str = "consistency check";
6356 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05306357 case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
6358 reason_str = "background init";
6359 break;
6360 case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
6361 reason_str = "make data consistent";
Eric Moore635374e2009-03-09 01:21:12 -06006362 break;
6363 }
6364
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05306365 if (!reason_str)
6366 return;
6367
Eric Moore635374e2009-03-09 01:21:12 -06006368 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
6369 "\thandle(0x%04x), percent complete(%d)\n",
6370 ioc->name, reason_str,
6371 le16_to_cpu(event_data->VolDevHandle),
6372 event_data->PercentComplete);
6373}
6374#endif
6375
6376/**
6377 * _scsih_sas_ir_operation_status_event - handle RAID operation events
6378 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306379 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006380 * Context: user.
6381 *
6382 * Return nothing.
6383 */
6384static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306385_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
6386 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006387{
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306388 Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data;
6389 static struct _raid_device *raid_device;
6390 unsigned long flags;
6391 u16 handle;
6392
Eric Moore635374e2009-03-09 01:21:12 -06006393#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306394 if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
6395 && !ioc->hide_ir_msg)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306396 _scsih_sas_ir_operation_status_event_debug(ioc,
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306397 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06006398#endif
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306399
6400 /* code added for raid transport support */
6401 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
6402
6403 handle = le16_to_cpu(event_data->VolDevHandle);
6404
6405 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6406 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
6407 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6408
6409 if (!raid_device)
6410 return;
6411
6412 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
6413 raid_device->percent_complete =
6414 event_data->PercentComplete;
6415 }
Eric Moore635374e2009-03-09 01:21:12 -06006416}
6417
6418/**
Kashyap, Desai14695852010-03-30 10:52:44 +05306419 * _scsih_prep_device_scan - initialize parameters prior to device scan
6420 * @ioc: per adapter object
6421 *
6422 * Set the deleted flag prior to device scan. If the device is found during
6423 * the scan, then we clear the deleted flag.
6424 */
6425static void
6426_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc)
6427{
6428 struct MPT2SAS_DEVICE *sas_device_priv_data;
6429 struct scsi_device *sdev;
6430
6431 shost_for_each_device(sdev, ioc->shost) {
6432 sas_device_priv_data = sdev->hostdata;
6433 if (sas_device_priv_data && sas_device_priv_data->sas_target)
6434 sas_device_priv_data->sas_target->deleted = 1;
6435 }
6436}
6437
6438/**
Eric Moore635374e2009-03-09 01:21:12 -06006439 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
6440 * @ioc: per adapter object
6441 * @sas_address: sas address
6442 * @slot: enclosure slot id
6443 * @handle: device handle
6444 *
6445 * After host reset, find out whether devices are still responding.
6446 * Used in _scsi_remove_unresponsive_sas_devices.
6447 *
6448 * Return nothing.
6449 */
6450static void
6451_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
6452 u16 slot, u16 handle)
6453{
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306454 struct MPT2SAS_TARGET *sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06006455 struct scsi_target *starget;
6456 struct _sas_device *sas_device;
6457 unsigned long flags;
6458
6459 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6460 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
6461 if (sas_device->sas_address == sas_address &&
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306462 sas_device->slot == slot) {
Eric Moore635374e2009-03-09 01:21:12 -06006463 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306464 starget = sas_device->starget;
Kashyap, Desai14695852010-03-30 10:52:44 +05306465 if (starget && starget->hostdata) {
6466 sas_target_priv_data = starget->hostdata;
6467 sas_target_priv_data->tm_busy = 0;
6468 sas_target_priv_data->deleted = 0;
6469 } else
6470 sas_target_priv_data = NULL;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306471 if (starget)
6472 starget_printk(KERN_INFO, starget,
6473 "handle(0x%04x), sas_addr(0x%016llx), "
6474 "enclosure logical id(0x%016llx), "
6475 "slot(%d)\n", handle,
6476 (unsigned long long)sas_device->sas_address,
6477 (unsigned long long)
6478 sas_device->enclosure_logical_id,
6479 sas_device->slot);
Eric Moore635374e2009-03-09 01:21:12 -06006480 if (sas_device->handle == handle)
6481 goto out;
6482 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
6483 sas_device->handle);
6484 sas_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05306485 if (sas_target_priv_data)
6486 sas_target_priv_data->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06006487 goto out;
6488 }
6489 }
6490 out:
6491 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6492}
6493
6494/**
6495 * _scsih_search_responding_sas_devices -
6496 * @ioc: per adapter object
6497 *
6498 * After host reset, find out whether devices are still responding.
6499 * If not remove.
6500 *
6501 * Return nothing.
6502 */
6503static void
6504_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
6505{
6506 Mpi2SasDevicePage0_t sas_device_pg0;
6507 Mpi2ConfigReply_t mpi_reply;
6508 u16 ioc_status;
6509 __le64 sas_address;
6510 u16 handle;
6511 u32 device_info;
6512 u16 slot;
6513
6514 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
6515
6516 if (list_empty(&ioc->sas_device_list))
6517 return;
6518
6519 handle = 0xFFFF;
6520 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
6521 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
6522 handle))) {
6523 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6524 MPI2_IOCSTATUS_MASK;
6525 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6526 break;
6527 handle = le16_to_cpu(sas_device_pg0.DevHandle);
6528 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
6529 if (!(_scsih_is_end_device(device_info)))
6530 continue;
6531 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
6532 slot = le16_to_cpu(sas_device_pg0.Slot);
6533 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
6534 handle);
6535 }
6536}
6537
6538/**
6539 * _scsih_mark_responding_raid_device - mark a raid_device as responding
6540 * @ioc: per adapter object
6541 * @wwid: world wide identifier for raid volume
6542 * @handle: device handle
6543 *
6544 * After host reset, find out whether devices are still responding.
6545 * Used in _scsi_remove_unresponsive_raid_devices.
6546 *
6547 * Return nothing.
6548 */
6549static void
6550_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
6551 u16 handle)
6552{
6553 struct MPT2SAS_TARGET *sas_target_priv_data;
6554 struct scsi_target *starget;
6555 struct _raid_device *raid_device;
6556 unsigned long flags;
6557
6558 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6559 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
6560 if (raid_device->wwid == wwid && raid_device->starget) {
Kashyap, Desai14695852010-03-30 10:52:44 +05306561 starget = raid_device->starget;
6562 if (starget && starget->hostdata) {
6563 sas_target_priv_data = starget->hostdata;
6564 sas_target_priv_data->deleted = 0;
6565 } else
6566 sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06006567 raid_device->responding = 1;
6568 starget_printk(KERN_INFO, raid_device->starget,
6569 "handle(0x%04x), wwid(0x%016llx)\n", handle,
6570 (unsigned long long)raid_device->wwid);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306571 /*
6572 * WARPDRIVE: The handles of the PDs might have changed
6573 * across the host reset so re-initialize the
6574 * required data for Direct IO
6575 */
6576 _scsih_init_warpdrive_properties(ioc, raid_device);
Eric Moore635374e2009-03-09 01:21:12 -06006577 if (raid_device->handle == handle)
6578 goto out;
6579 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
6580 raid_device->handle);
6581 raid_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05306582 if (sas_target_priv_data)
6583 sas_target_priv_data->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06006584 goto out;
6585 }
6586 }
6587 out:
6588 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6589}
6590
6591/**
6592 * _scsih_search_responding_raid_devices -
6593 * @ioc: per adapter object
6594 *
6595 * After host reset, find out whether devices are still responding.
6596 * If not remove.
6597 *
6598 * Return nothing.
6599 */
6600static void
6601_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
6602{
6603 Mpi2RaidVolPage1_t volume_pg1;
Kashyap, Desaid417d1c2010-06-17 13:48:10 +05306604 Mpi2RaidVolPage0_t volume_pg0;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306605 Mpi2RaidPhysDiskPage0_t pd_pg0;
Eric Moore635374e2009-03-09 01:21:12 -06006606 Mpi2ConfigReply_t mpi_reply;
6607 u16 ioc_status;
6608 u16 handle;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306609 u8 phys_disk_num;
Eric Moore635374e2009-03-09 01:21:12 -06006610
6611 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
6612
6613 if (list_empty(&ioc->raid_device_list))
6614 return;
6615
6616 handle = 0xFFFF;
6617 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
6618 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
6619 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6620 MPI2_IOCSTATUS_MASK;
6621 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6622 break;
6623 handle = le16_to_cpu(volume_pg1.DevHandle);
Kashyap, Desaid417d1c2010-06-17 13:48:10 +05306624
6625 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
6626 &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
6627 sizeof(Mpi2RaidVolPage0_t)))
6628 continue;
6629
6630 if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
6631 volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
6632 volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED)
6633 _scsih_mark_responding_raid_device(ioc,
6634 le64_to_cpu(volume_pg1.WWID), handle);
Eric Moore635374e2009-03-09 01:21:12 -06006635 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306636
6637 /* refresh the pd_handles */
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306638 if (!ioc->is_warpdrive) {
6639 phys_disk_num = 0xFF;
6640 memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
6641 while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
6642 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
6643 phys_disk_num))) {
6644 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6645 MPI2_IOCSTATUS_MASK;
6646 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6647 break;
6648 phys_disk_num = pd_pg0.PhysDiskNum;
6649 handle = le16_to_cpu(pd_pg0.DevHandle);
6650 set_bit(handle, ioc->pd_handles);
6651 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306652 }
Eric Moore635374e2009-03-09 01:21:12 -06006653}
6654
6655/**
6656 * _scsih_mark_responding_expander - mark a expander as responding
6657 * @ioc: per adapter object
6658 * @sas_address: sas address
6659 * @handle:
6660 *
6661 * After host reset, find out whether devices are still responding.
6662 * Used in _scsi_remove_unresponsive_expanders.
6663 *
6664 * Return nothing.
6665 */
6666static void
6667_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
6668 u16 handle)
6669{
6670 struct _sas_node *sas_expander;
6671 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306672 int i;
Eric Moore635374e2009-03-09 01:21:12 -06006673
6674 spin_lock_irqsave(&ioc->sas_node_lock, flags);
6675 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306676 if (sas_expander->sas_address != sas_address)
6677 continue;
6678 sas_expander->responding = 1;
6679 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06006680 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306681 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
6682 " from(0x%04x) to (0x%04x)!!!\n",
6683 (unsigned long long)sas_expander->sas_address,
6684 sas_expander->handle, handle);
6685 sas_expander->handle = handle;
6686 for (i = 0 ; i < sas_expander->num_phys ; i++)
6687 sas_expander->phy[i].handle = handle;
6688 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06006689 }
6690 out:
6691 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
6692}
6693
6694/**
6695 * _scsih_search_responding_expanders -
6696 * @ioc: per adapter object
6697 *
6698 * After host reset, find out whether devices are still responding.
6699 * If not remove.
6700 *
6701 * Return nothing.
6702 */
6703static void
6704_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
6705{
6706 Mpi2ExpanderPage0_t expander_pg0;
6707 Mpi2ConfigReply_t mpi_reply;
6708 u16 ioc_status;
Kashyap, Desaic97951e2011-06-14 10:54:56 +05306709 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06006710 u16 handle;
6711
6712 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
6713
6714 if (list_empty(&ioc->sas_expander_list))
6715 return;
6716
6717 handle = 0xFFFF;
6718 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
6719 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
6720
6721 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6722 MPI2_IOCSTATUS_MASK;
6723 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6724 break;
6725
6726 handle = le16_to_cpu(expander_pg0.DevHandle);
6727 sas_address = le64_to_cpu(expander_pg0.SASAddress);
6728 printk(KERN_INFO "\texpander present: handle(0x%04x), "
6729 "sas_addr(0x%016llx)\n", handle,
6730 (unsigned long long)sas_address);
6731 _scsih_mark_responding_expander(ioc, sas_address, handle);
6732 }
6733
6734}
6735
6736/**
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306737 * _scsih_remove_unresponding_sas_devices - removing unresponding devices
Eric Moore635374e2009-03-09 01:21:12 -06006738 * @ioc: per adapter object
6739 *
6740 * Return nothing.
6741 */
6742static void
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306743_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06006744{
6745 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306746 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06006747 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06006748
Eric Moore635374e2009-03-09 01:21:12 -06006749
6750 list_for_each_entry_safe(sas_device, sas_device_next,
6751 &ioc->sas_device_list, list) {
6752 if (sas_device->responding) {
6753 sas_device->responding = 0;
6754 continue;
6755 }
6756 if (sas_device->starget)
6757 starget_printk(KERN_INFO, sas_device->starget,
6758 "removing: handle(0x%04x), sas_addr(0x%016llx), "
6759 "enclosure logical id(0x%016llx), slot(%d)\n",
6760 sas_device->handle,
6761 (unsigned long long)sas_device->sas_address,
6762 (unsigned long long)
6763 sas_device->enclosure_logical_id,
6764 sas_device->slot);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306765 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06006766 }
6767
6768 list_for_each_entry_safe(raid_device, raid_device_next,
6769 &ioc->raid_device_list, list) {
6770 if (raid_device->responding) {
6771 raid_device->responding = 0;
6772 continue;
6773 }
6774 if (raid_device->starget) {
6775 starget_printk(KERN_INFO, raid_device->starget,
6776 "removing: handle(0x%04x), wwid(0x%016llx)\n",
6777 raid_device->handle,
6778 (unsigned long long)raid_device->wwid);
6779 scsi_remove_target(&raid_device->starget->dev);
6780 }
6781 _scsih_raid_device_remove(ioc, raid_device);
6782 }
6783
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306784 retry_expander_search:
6785 sas_expander = NULL;
6786 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06006787 if (sas_expander->responding) {
6788 sas_expander->responding = 0;
6789 continue;
6790 }
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05306791 mpt2sas_expander_remove(ioc, sas_expander->sas_address);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306792 goto retry_expander_search;
6793 }
6794}
6795
6796/**
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306797 * _scsih_hide_unhide_sas_devices - add/remove device to/from OS
6798 * @ioc: per adapter object
6799 *
6800 * Return nothing.
6801 */
6802static void
6803_scsih_hide_unhide_sas_devices(struct MPT2SAS_ADAPTER *ioc)
6804{
6805 struct _sas_device *sas_device, *sas_device_next;
6806
6807 if (!ioc->is_warpdrive || ioc->mfg_pg10_hide_flag !=
6808 MFG_PAGE10_HIDE_IF_VOL_PRESENT)
6809 return;
6810
6811 if (ioc->hide_drives) {
6812 if (_scsih_get_num_volumes(ioc))
6813 return;
6814 ioc->hide_drives = 0;
6815 list_for_each_entry_safe(sas_device, sas_device_next,
6816 &ioc->sas_device_list, list) {
6817 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
6818 sas_device->sas_address_parent)) {
6819 _scsih_sas_device_remove(ioc, sas_device);
6820 } else if (!sas_device->starget) {
6821 mpt2sas_transport_port_remove(ioc,
6822 sas_device->sas_address,
6823 sas_device->sas_address_parent);
6824 _scsih_sas_device_remove(ioc, sas_device);
6825 }
6826 }
6827 } else {
6828 if (!_scsih_get_num_volumes(ioc))
6829 return;
6830 ioc->hide_drives = 1;
6831 list_for_each_entry_safe(sas_device, sas_device_next,
6832 &ioc->sas_device_list, list) {
6833 mpt2sas_transport_port_remove(ioc,
6834 sas_device->sas_address,
6835 sas_device->sas_address_parent);
6836 }
6837 }
6838}
6839
6840/**
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306841 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
6842 * @ioc: per adapter object
6843 * @reset_phase: phase
6844 *
6845 * The handler for doing any required cleanup or initialization.
6846 *
6847 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
6848 * MPT2_IOC_DONE_RESET
6849 *
6850 * Return nothing.
6851 */
6852void
6853mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
6854{
6855 switch (reset_phase) {
6856 case MPT2_IOC_PRE_RESET:
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306857 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306858 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306859 break;
6860 case MPT2_IOC_AFTER_RESET:
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306861 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306862 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306863 if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
6864 ioc->scsih_cmds.status |= MPT2_CMD_RESET;
6865 mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
6866 complete(&ioc->scsih_cmds.done);
6867 }
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306868 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
6869 ioc->tm_cmds.status |= MPT2_CMD_RESET;
6870 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
6871 complete(&ioc->tm_cmds.done);
6872 }
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306873 _scsih_fw_event_cleanup_queue(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306874 _scsih_flush_running_cmds(ioc);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306875 _scsih_queue_rescan(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306876 break;
6877 case MPT2_IOC_DONE_RESET:
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306878 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306879 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306880 _scsih_sas_host_refresh(ioc);
Kashyap, Desai14695852010-03-30 10:52:44 +05306881 _scsih_prep_device_scan(ioc);
6882 _scsih_search_responding_sas_devices(ioc);
6883 _scsih_search_responding_raid_devices(ioc);
6884 _scsih_search_responding_expanders(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306885 break;
Eric Moore635374e2009-03-09 01:21:12 -06006886 }
6887}
6888
6889/**
6890 * _firmware_event_work - delayed task for processing firmware events
6891 * @ioc: per adapter object
6892 * @work: equal to the fw_event_work object
6893 * Context: user.
6894 *
6895 * Return nothing.
6896 */
6897static void
6898_firmware_event_work(struct work_struct *work)
6899{
6900 struct fw_event_work *fw_event = container_of(work,
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306901 struct fw_event_work, delayed_work.work);
Eric Moore635374e2009-03-09 01:21:12 -06006902 unsigned long flags;
6903 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
6904
Eric Moore635374e2009-03-09 01:21:12 -06006905 /* the queue is being flushed so ignore this event */
Eric Moore3cb54692010-07-08 14:44:34 -06006906 if (ioc->remove_host || fw_event->cancel_pending_work ||
6907 ioc->pci_error_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06006908 _scsih_fw_event_free(ioc, fw_event);
6909 return;
6910 }
Eric Moore635374e2009-03-09 01:21:12 -06006911
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306912 if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) {
6913 _scsih_fw_event_free(ioc, fw_event);
6914 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
6915 if (ioc->shost_recovery) {
6916 init_completion(&ioc->shost_recovery_done);
6917 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
6918 flags);
6919 wait_for_completion(&ioc->shost_recovery_done);
6920 } else
6921 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
6922 flags);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306923 _scsih_remove_unresponding_sas_devices(ioc);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306924 _scsih_hide_unhide_sas_devices(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006925 return;
6926 }
Eric Moore635374e2009-03-09 01:21:12 -06006927
6928 switch (fw_event->event) {
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05306929 case MPT2SAS_TURN_ON_FAULT_LED:
6930 _scsih_turn_on_fault_led(ioc, fw_event->device_handle);
6931 break;
Eric Moore635374e2009-03-09 01:21:12 -06006932 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306933 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006934 break;
6935 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306936 _scsih_sas_device_status_change_event(ioc,
6937 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006938 break;
6939 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306940 _scsih_sas_discovery_event(ioc,
6941 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006942 break;
6943 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306944 _scsih_sas_broadcast_primative_event(ioc,
6945 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006946 break;
6947 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
6948 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306949 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006950 break;
6951 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306952 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006953 break;
6954 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306955 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006956 break;
6957 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306958 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006959 break;
6960 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306961 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006962 break;
Eric Moore635374e2009-03-09 01:21:12 -06006963 }
6964 _scsih_fw_event_free(ioc, fw_event);
6965}
6966
6967/**
6968 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
6969 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306970 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06006971 * @reply: reply message frame(lower 32bit addr)
6972 * Context: interrupt.
6973 *
6974 * This function merely adds a new work task into ioc->firmware_event_thread.
6975 * The tasks are worked from _firmware_event_work in user context.
6976 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306977 * Return 1 meaning mf should be freed from _base_interrupt
6978 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06006979 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306980u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306981mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
6982 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06006983{
6984 struct fw_event_work *fw_event;
6985 Mpi2EventNotificationReply_t *mpi_reply;
Eric Moore635374e2009-03-09 01:21:12 -06006986 u16 event;
Kashyap, Desaie94f6742010-03-17 16:24:52 +05306987 u16 sz;
Eric Moore635374e2009-03-09 01:21:12 -06006988
6989 /* events turned off due to host reset or driver unloading */
Eric Moore3cb54692010-07-08 14:44:34 -06006990 if (ioc->remove_host || ioc->pci_error_recovery)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306991 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006992
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306993 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06006994 event = le16_to_cpu(mpi_reply->Event);
6995
6996 switch (event) {
6997 /* handle these */
6998 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
6999 {
7000 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
7001 (Mpi2EventDataSasBroadcastPrimitive_t *)
7002 mpi_reply->EventData;
7003
7004 if (baen_data->Primitive !=
Kashyap, Desaif93213d2011-06-14 10:56:43 +05307005 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307006 return 1;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05307007
7008 if (ioc->broadcast_aen_busy) {
7009 ioc->broadcast_aen_pending++;
7010 return 1;
7011 } else
7012 ioc->broadcast_aen_busy = 1;
Eric Moore635374e2009-03-09 01:21:12 -06007013 break;
7014 }
7015
7016 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
7017 _scsih_check_topo_delete_events(ioc,
7018 (Mpi2EventDataSasTopologyChangeList_t *)
7019 mpi_reply->EventData);
7020 break;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307021 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
7022 _scsih_check_ir_config_unhide_events(ioc,
7023 (Mpi2EventDataIrConfigChangeList_t *)
7024 mpi_reply->EventData);
7025 break;
7026 case MPI2_EVENT_IR_VOLUME:
7027 _scsih_check_volume_delete_events(ioc,
7028 (Mpi2EventDataIrVolume_t *)
7029 mpi_reply->EventData);
7030 break;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307031 case MPI2_EVENT_LOG_ENTRY_ADDED:
7032 {
7033 Mpi2EventDataLogEntryAdded_t *log_entry;
7034 u32 *log_code;
7035
7036 if (!ioc->is_warpdrive)
7037 break;
7038
7039 log_entry = (Mpi2EventDataLogEntryAdded_t *)
7040 mpi_reply->EventData;
7041 log_code = (u32 *)log_entry->LogData;
7042
7043 if (le16_to_cpu(log_entry->LogEntryQualifier)
7044 != MPT2_WARPDRIVE_LOGENTRY)
7045 break;
7046
7047 switch (le32_to_cpu(*log_code)) {
7048 case MPT2_WARPDRIVE_LC_SSDT:
7049 printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
7050 "IO Throttling has occurred in the WarpDrive "
7051 "subsystem. Check WarpDrive documentation for "
7052 "additional details.\n", ioc->name);
7053 break;
7054 case MPT2_WARPDRIVE_LC_SSDLW:
7055 printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
7056 "Program/Erase Cycles for the WarpDrive subsystem "
7057 "in degraded range. Check WarpDrive documentation "
7058 "for additional details.\n", ioc->name);
7059 break;
7060 case MPT2_WARPDRIVE_LC_SSDLF:
7061 printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
7062 "There are no Program/Erase Cycles for the "
7063 "WarpDrive subsystem. The storage device will be "
7064 "in read-only mode. Check WarpDrive documentation "
7065 "for additional details.\n", ioc->name);
7066 break;
7067 case MPT2_WARPDRIVE_LC_BRMF:
7068 printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
7069 "The Backup Rail Monitor has failed on the "
7070 "WarpDrive subsystem. Check WarpDrive "
7071 "documentation for additional details.\n",
7072 ioc->name);
7073 break;
7074 }
7075
7076 break;
7077 }
Eric Moore635374e2009-03-09 01:21:12 -06007078 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
7079 case MPI2_EVENT_IR_OPERATION_STATUS:
7080 case MPI2_EVENT_SAS_DISCOVERY:
7081 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
Eric Moore635374e2009-03-09 01:21:12 -06007082 case MPI2_EVENT_IR_PHYSICAL_DISK:
Eric Moore635374e2009-03-09 01:21:12 -06007083 break;
7084
7085 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307086 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06007087 }
7088
7089 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
7090 if (!fw_event) {
7091 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7092 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307093 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06007094 }
Kashyap, Desaie94f6742010-03-17 16:24:52 +05307095 sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
7096 fw_event->event_data = kzalloc(sz, GFP_ATOMIC);
Eric Moore635374e2009-03-09 01:21:12 -06007097 if (!fw_event->event_data) {
7098 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7099 ioc->name, __FILE__, __LINE__, __func__);
7100 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307101 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06007102 }
7103
7104 memcpy(fw_event->event_data, mpi_reply->EventData,
Kashyap, Desaie94f6742010-03-17 16:24:52 +05307105 sz);
Eric Moore635374e2009-03-09 01:21:12 -06007106 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307107 fw_event->VF_ID = mpi_reply->VF_ID;
7108 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06007109 fw_event->event = event;
7110 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307111 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06007112}
7113
7114/* shost template */
7115static struct scsi_host_template scsih_driver_template = {
7116 .module = THIS_MODULE,
7117 .name = "Fusion MPT SAS Host",
7118 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06007119 .queuecommand = _scsih_qcmd,
7120 .target_alloc = _scsih_target_alloc,
7121 .slave_alloc = _scsih_slave_alloc,
7122 .slave_configure = _scsih_slave_configure,
7123 .target_destroy = _scsih_target_destroy,
7124 .slave_destroy = _scsih_slave_destroy,
7125 .change_queue_depth = _scsih_change_queue_depth,
7126 .change_queue_type = _scsih_change_queue_type,
7127 .eh_abort_handler = _scsih_abort,
7128 .eh_device_reset_handler = _scsih_dev_reset,
7129 .eh_target_reset_handler = _scsih_target_reset,
7130 .eh_host_reset_handler = _scsih_host_reset,
7131 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06007132 .can_queue = 1,
7133 .this_id = -1,
7134 .sg_tablesize = MPT2SAS_SG_DEPTH,
7135 .max_sectors = 8192,
7136 .cmd_per_lun = 7,
7137 .use_clustering = ENABLE_CLUSTERING,
7138 .shost_attrs = mpt2sas_host_attrs,
7139 .sdev_attrs = mpt2sas_dev_attrs,
7140};
7141
7142/**
7143 * _scsih_expander_node_remove - removing expander device from list.
7144 * @ioc: per adapter object
7145 * @sas_expander: the sas_device object
7146 * Context: Calling function should acquire ioc->sas_node_lock.
7147 *
7148 * Removing object and freeing associated memory from the
7149 * ioc->sas_expander_list.
7150 *
7151 * Return nothing.
7152 */
7153static void
7154_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
7155 struct _sas_node *sas_expander)
7156{
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307157 struct _sas_port *mpt2sas_port, *next;
Eric Moore635374e2009-03-09 01:21:12 -06007158
7159 /* remove sibling ports attached to this expander */
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307160 list_for_each_entry_safe(mpt2sas_port, next,
Eric Moore635374e2009-03-09 01:21:12 -06007161 &sas_expander->sas_port_list, port_list) {
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307162 if (ioc->shost_recovery)
7163 return;
Eric Moore635374e2009-03-09 01:21:12 -06007164 if (mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307165 SAS_END_DEVICE)
7166 mpt2sas_device_remove(ioc,
7167 mpt2sas_port->remote_identify.sas_address);
7168 else if (mpt2sas_port->remote_identify.device_type ==
7169 SAS_EDGE_EXPANDER_DEVICE ||
Eric Moore635374e2009-03-09 01:21:12 -06007170 mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307171 SAS_FANOUT_EXPANDER_DEVICE)
7172 mpt2sas_expander_remove(ioc,
7173 mpt2sas_port->remote_identify.sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06007174 }
7175
7176 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307177 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06007178
7179 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
7180 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
7181 sas_expander->handle, (unsigned long long)
7182 sas_expander->sas_address);
7183
Eric Moore635374e2009-03-09 01:21:12 -06007184 kfree(sas_expander->phy);
7185 kfree(sas_expander);
7186}
7187
7188/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05307189 * _scsih_ir_shutdown - IR shutdown notification
7190 * @ioc: per adapter object
7191 *
7192 * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
7193 * the host system is shutting down.
7194 *
7195 * Return nothing.
7196 */
7197static void
7198_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
7199{
7200 Mpi2RaidActionRequest_t *mpi_request;
7201 Mpi2RaidActionReply_t *mpi_reply;
7202 u16 smid;
7203
7204 /* is IR firmware build loaded ? */
7205 if (!ioc->ir_firmware)
7206 return;
7207
7208 /* are there any volumes ? */
7209 if (list_empty(&ioc->raid_device_list))
7210 return;
7211
7212 mutex_lock(&ioc->scsih_cmds.mutex);
7213
7214 if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
7215 printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
7216 ioc->name, __func__);
7217 goto out;
7218 }
7219 ioc->scsih_cmds.status = MPT2_CMD_PENDING;
7220
7221 smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
7222 if (!smid) {
7223 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
7224 ioc->name, __func__);
7225 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
7226 goto out;
7227 }
7228
7229 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
7230 ioc->scsih_cmds.smid = smid;
7231 memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
7232
7233 mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
7234 mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
7235
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307236 if (!ioc->hide_ir_msg)
7237 printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
Kashyap, Desai744090d2009-10-05 15:56:56 +05307238 init_completion(&ioc->scsih_cmds.done);
7239 mpt2sas_base_put_smid_default(ioc, smid);
7240 wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
7241
7242 if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
7243 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
7244 ioc->name, __func__);
7245 goto out;
7246 }
7247
7248 if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
7249 mpi_reply = ioc->scsih_cmds.reply;
7250
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307251 if (!ioc->hide_ir_msg)
7252 printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
7253 "ioc_status(0x%04x), loginfo(0x%08x)\n",
7254 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
7255 le32_to_cpu(mpi_reply->IOCLogInfo));
Kashyap, Desai744090d2009-10-05 15:56:56 +05307256 }
7257
7258 out:
7259 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
7260 mutex_unlock(&ioc->scsih_cmds.mutex);
7261}
7262
7263/**
7264 * _scsih_shutdown - routine call during system shutdown
7265 * @pdev: PCI device struct
7266 *
7267 * Return nothing.
7268 */
7269static void
7270_scsih_shutdown(struct pci_dev *pdev)
7271{
7272 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7273 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05307274 struct workqueue_struct *wq;
7275 unsigned long flags;
7276
7277 ioc->remove_host = 1;
7278 _scsih_fw_event_cleanup_queue(ioc);
7279
7280 spin_lock_irqsave(&ioc->fw_event_lock, flags);
7281 wq = ioc->firmware_event_thread;
7282 ioc->firmware_event_thread = NULL;
7283 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
7284 if (wq)
7285 destroy_workqueue(wq);
Kashyap, Desai744090d2009-10-05 15:56:56 +05307286
7287 _scsih_ir_shutdown(ioc);
7288 mpt2sas_base_detach(ioc);
7289}
7290
7291/**
Eric Moored5d135b2009-05-18 13:02:08 -06007292 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06007293 * @pdev: PCI device struct
7294 *
Kashyap, Desai744090d2009-10-05 15:56:56 +05307295 * Routine called when unloading the driver.
Eric Moore635374e2009-03-09 01:21:12 -06007296 * Return nothing.
7297 */
7298static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06007299_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06007300{
7301 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7302 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307303 struct _sas_port *mpt2sas_port, *next_port;
Kashyap, Desaid7384b22009-12-16 18:50:06 +05307304 struct _raid_device *raid_device, *next;
7305 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06007306 struct workqueue_struct *wq;
7307 unsigned long flags;
7308
7309 ioc->remove_host = 1;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05307310 _scsih_fw_event_cleanup_queue(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007311
7312 spin_lock_irqsave(&ioc->fw_event_lock, flags);
7313 wq = ioc->firmware_event_thread;
7314 ioc->firmware_event_thread = NULL;
7315 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
7316 if (wq)
7317 destroy_workqueue(wq);
7318
Kashyap, Desaid7384b22009-12-16 18:50:06 +05307319 /* release all the volumes */
Kashyap, Desai3a9c9132011-01-04 11:40:23 +05307320 _scsih_ir_shutdown(ioc);
Kashyap, Desaid7384b22009-12-16 18:50:06 +05307321 list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
7322 list) {
7323 if (raid_device->starget) {
7324 sas_target_priv_data =
7325 raid_device->starget->hostdata;
7326 sas_target_priv_data->deleted = 1;
7327 scsi_remove_target(&raid_device->starget->dev);
7328 }
7329 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
7330 "(0x%016llx)\n", ioc->name, raid_device->handle,
7331 (unsigned long long) raid_device->wwid);
7332 _scsih_raid_device_remove(ioc, raid_device);
7333 }
7334
Eric Moore635374e2009-03-09 01:21:12 -06007335 /* free ports attached to the sas_host */
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307336 list_for_each_entry_safe(mpt2sas_port, next_port,
Eric Moore635374e2009-03-09 01:21:12 -06007337 &ioc->sas_hba.sas_port_list, port_list) {
7338 if (mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307339 SAS_END_DEVICE)
7340 mpt2sas_device_remove(ioc,
Eric Moore635374e2009-03-09 01:21:12 -06007341 mpt2sas_port->remote_identify.sas_address);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307342 else if (mpt2sas_port->remote_identify.device_type ==
7343 SAS_EDGE_EXPANDER_DEVICE ||
7344 mpt2sas_port->remote_identify.device_type ==
7345 SAS_FANOUT_EXPANDER_DEVICE)
7346 mpt2sas_expander_remove(ioc,
7347 mpt2sas_port->remote_identify.sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06007348 }
7349
7350 /* free phys attached to the sas_host */
7351 if (ioc->sas_hba.num_phys) {
7352 kfree(ioc->sas_hba.phy);
7353 ioc->sas_hba.phy = NULL;
7354 ioc->sas_hba.num_phys = 0;
7355 }
7356
7357 sas_remove_host(shost);
kashyap.desai@lsi.com9ae89b02011-08-04 16:47:50 +05307358 mpt2sas_base_detach(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007359 list_del(&ioc->list);
7360 scsi_remove_host(shost);
7361 scsi_host_put(shost);
7362}
7363
7364/**
7365 * _scsih_probe_boot_devices - reports 1st device
7366 * @ioc: per adapter object
7367 *
7368 * If specified in bios page 2, this routine reports the 1st
7369 * device scsi-ml or sas transport for persistent boot device
7370 * purposes. Please refer to function _scsih_determine_boot_device()
7371 */
7372static void
7373_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
7374{
7375 u8 is_raid;
7376 void *device;
7377 struct _sas_device *sas_device;
7378 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307379 u16 handle;
7380 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06007381 u64 sas_address;
7382 unsigned long flags;
7383 int rc;
7384
7385 device = NULL;
7386 if (ioc->req_boot_device.device) {
7387 device = ioc->req_boot_device.device;
7388 is_raid = ioc->req_boot_device.is_raid;
7389 } else if (ioc->req_alt_boot_device.device) {
7390 device = ioc->req_alt_boot_device.device;
7391 is_raid = ioc->req_alt_boot_device.is_raid;
7392 } else if (ioc->current_boot_device.device) {
7393 device = ioc->current_boot_device.device;
7394 is_raid = ioc->current_boot_device.is_raid;
7395 }
7396
7397 if (!device)
7398 return;
7399
7400 if (is_raid) {
7401 raid_device = device;
7402 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
7403 raid_device->id, 0);
7404 if (rc)
7405 _scsih_raid_device_remove(ioc, raid_device);
7406 } else {
7407 sas_device = device;
7408 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307409 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06007410 sas_address = sas_device->sas_address;
7411 spin_lock_irqsave(&ioc->sas_device_lock, flags);
7412 list_move_tail(&sas_device->list, &ioc->sas_device_list);
7413 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307414
7415 if (ioc->hide_drives)
7416 return;
Eric Moore635374e2009-03-09 01:21:12 -06007417 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307418 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06007419 _scsih_sas_device_remove(ioc, sas_device);
7420 } else if (!sas_device->starget) {
7421 mpt2sas_transport_port_remove(ioc, sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307422 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06007423 _scsih_sas_device_remove(ioc, sas_device);
7424 }
7425 }
7426}
7427
7428/**
7429 * _scsih_probe_raid - reporting raid volumes to scsi-ml
7430 * @ioc: per adapter object
7431 *
7432 * Called during initial loading of the driver.
7433 */
7434static void
7435_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
7436{
7437 struct _raid_device *raid_device, *raid_next;
7438 int rc;
7439
7440 list_for_each_entry_safe(raid_device, raid_next,
7441 &ioc->raid_device_list, list) {
7442 if (raid_device->starget)
7443 continue;
7444 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
7445 raid_device->id, 0);
7446 if (rc)
7447 _scsih_raid_device_remove(ioc, raid_device);
7448 }
7449}
7450
7451/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307452 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06007453 * @ioc: per adapter object
7454 *
7455 * Called during initial loading of the driver.
7456 */
7457static void
7458_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
7459{
7460 struct _sas_device *sas_device, *next;
7461 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06007462
7463 /* SAS Device List */
7464 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
7465 list) {
7466 spin_lock_irqsave(&ioc->sas_device_lock, flags);
7467 list_move_tail(&sas_device->list, &ioc->sas_device_list);
7468 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
7469
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307470 if (ioc->hide_drives)
7471 continue;
7472
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307473 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
7474 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06007475 _scsih_sas_device_remove(ioc, sas_device);
7476 } else if (!sas_device->starget) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307477 mpt2sas_transport_port_remove(ioc,
7478 sas_device->sas_address,
7479 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06007480 _scsih_sas_device_remove(ioc, sas_device);
7481 }
7482 }
7483}
7484
7485/**
7486 * _scsih_probe_devices - probing for devices
7487 * @ioc: per adapter object
7488 *
7489 * Called during initial loading of the driver.
7490 */
7491static void
7492_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
7493{
7494 u16 volume_mapping_flags =
7495 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
7496 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
7497
7498 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
7499 return; /* return when IOC doesn't support initiator mode */
7500
7501 _scsih_probe_boot_devices(ioc);
7502
7503 if (ioc->ir_firmware) {
7504 if ((volume_mapping_flags &
7505 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
7506 _scsih_probe_sas(ioc);
7507 _scsih_probe_raid(ioc);
7508 } else {
7509 _scsih_probe_raid(ioc);
7510 _scsih_probe_sas(ioc);
7511 }
7512 } else
7513 _scsih_probe_sas(ioc);
7514}
7515
7516/**
Eric Moored5d135b2009-05-18 13:02:08 -06007517 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06007518 * @pdev: PCI device struct
7519 * @id: pci device id
7520 *
7521 * Returns 0 success, anything else error.
7522 */
7523static int
Eric Moored5d135b2009-05-18 13:02:08 -06007524_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06007525{
7526 struct MPT2SAS_ADAPTER *ioc;
7527 struct Scsi_Host *shost;
7528
7529 shost = scsi_host_alloc(&scsih_driver_template,
7530 sizeof(struct MPT2SAS_ADAPTER));
7531 if (!shost)
7532 return -ENODEV;
7533
7534 /* init local params */
7535 ioc = shost_priv(shost);
7536 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
7537 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06007538 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06007539 ioc->shost = shost;
7540 ioc->id = mpt_ids++;
7541 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
7542 ioc->pdev = pdev;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307543 if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) {
7544 ioc->is_warpdrive = 1;
7545 ioc->hide_ir_msg = 1;
7546 } else
7547 ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
Eric Moore635374e2009-03-09 01:21:12 -06007548 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
7549 ioc->tm_cb_idx = tm_cb_idx;
7550 ioc->ctl_cb_idx = ctl_cb_idx;
7551 ioc->base_cb_idx = base_cb_idx;
7552 ioc->transport_cb_idx = transport_cb_idx;
Kashyap, Desai744090d2009-10-05 15:56:56 +05307553 ioc->scsih_cb_idx = scsih_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06007554 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307555 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307556 ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307557 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06007558 ioc->logging_level = logging_level;
7559 /* misc semaphores and spin locks */
Kashyap, Desaid2742132010-06-17 13:28:55 +05307560 mutex_init(&ioc->reset_in_progress_mutex);
Eric Moore635374e2009-03-09 01:21:12 -06007561 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
7562 spin_lock_init(&ioc->scsi_lookup_lock);
7563 spin_lock_init(&ioc->sas_device_lock);
7564 spin_lock_init(&ioc->sas_node_lock);
7565 spin_lock_init(&ioc->fw_event_lock);
7566 spin_lock_init(&ioc->raid_device_lock);
7567
7568 INIT_LIST_HEAD(&ioc->sas_device_list);
7569 INIT_LIST_HEAD(&ioc->sas_device_init_list);
7570 INIT_LIST_HEAD(&ioc->sas_expander_list);
7571 INIT_LIST_HEAD(&ioc->fw_event_list);
7572 INIT_LIST_HEAD(&ioc->raid_device_list);
7573 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307574 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307575 INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
Eric Moore635374e2009-03-09 01:21:12 -06007576
7577 /* init shost parameters */
Eric Moored334aa72010-04-22 10:47:40 -06007578 shost->max_cmd_len = 32;
Eric Moore635374e2009-03-09 01:21:12 -06007579 shost->max_lun = max_lun;
7580 shost->transportt = mpt2sas_transport_template;
7581 shost->unique_id = ioc->id;
7582
Kashyap, Desaia3e1e552011-06-14 10:56:12 +05307583 if (max_sectors != 0xFFFF) {
7584 if (max_sectors < 64) {
7585 shost->max_sectors = 64;
7586 printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
7587 "for max_sectors, range is 64 to 8192. Assigning "
7588 "value of 64.\n", ioc->name, max_sectors);
7589 } else if (max_sectors > 8192) {
7590 shost->max_sectors = 8192;
7591 printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
7592 "for max_sectors, range is 64 to 8192. Assigning "
7593 "default value of 8192.\n", ioc->name,
7594 max_sectors);
7595 } else {
7596 shost->max_sectors = max_sectors & 0xFFFE;
7597 printk(MPT2SAS_INFO_FMT "The max_sectors value is "
7598 "set to %d\n", ioc->name, shost->max_sectors);
7599 }
7600 }
7601
Eric Moore635374e2009-03-09 01:21:12 -06007602 if ((scsi_add_host(shost, &pdev->dev))) {
7603 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7604 ioc->name, __FILE__, __LINE__, __func__);
7605 list_del(&ioc->list);
7606 goto out_add_shost_fail;
7607 }
7608
Eric Moore3c621b32009-05-18 12:59:41 -06007609 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
Eric Moored334aa72010-04-22 10:47:40 -06007610 | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307611 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06007612
Eric Moore635374e2009-03-09 01:21:12 -06007613 /* event thread */
7614 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
7615 "fw_event%d", ioc->id);
7616 ioc->firmware_event_thread = create_singlethread_workqueue(
7617 ioc->firmware_event_name);
7618 if (!ioc->firmware_event_thread) {
7619 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7620 ioc->name, __FILE__, __LINE__, __func__);
7621 goto out_thread_fail;
7622 }
7623
7624 ioc->wait_for_port_enable_to_complete = 1;
7625 if ((mpt2sas_base_attach(ioc))) {
7626 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7627 ioc->name, __FILE__, __LINE__, __func__);
7628 goto out_attach_fail;
7629 }
7630
7631 ioc->wait_for_port_enable_to_complete = 0;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307632 if (ioc->is_warpdrive) {
7633 if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS)
7634 ioc->hide_drives = 0;
7635 else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS)
7636 ioc->hide_drives = 1;
7637 else {
7638 if (_scsih_get_num_volumes(ioc))
7639 ioc->hide_drives = 1;
7640 else
7641 ioc->hide_drives = 0;
7642 }
7643 } else
7644 ioc->hide_drives = 0;
7645
Eric Moore635374e2009-03-09 01:21:12 -06007646 _scsih_probe_devices(ioc);
7647 return 0;
7648
7649 out_attach_fail:
7650 destroy_workqueue(ioc->firmware_event_thread);
7651 out_thread_fail:
7652 list_del(&ioc->list);
7653 scsi_remove_host(shost);
7654 out_add_shost_fail:
7655 return -ENODEV;
7656}
7657
7658#ifdef CONFIG_PM
7659/**
Eric Moored5d135b2009-05-18 13:02:08 -06007660 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06007661 * @pdev: PCI device struct
7662 * @state: PM state change to (usually PCI_D3)
7663 *
7664 * Returns 0 success, anything else error.
7665 */
7666static int
Eric Moored5d135b2009-05-18 13:02:08 -06007667_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06007668{
7669 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7670 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaic97951e2011-06-14 10:54:56 +05307671 pci_power_t device_state;
Eric Moore635374e2009-03-09 01:21:12 -06007672
Kashyap, Desaie4750c92009-08-07 19:37:59 +05307673 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007674 scsi_block_requests(shost);
7675 device_state = pci_choose_state(pdev, state);
7676 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
7677 "operating state [D%d]\n", ioc->name, pdev,
7678 pci_name(pdev), device_state);
7679
7680 mpt2sas_base_free_resources(ioc);
7681 pci_save_state(pdev);
7682 pci_disable_device(pdev);
7683 pci_set_power_state(pdev, device_state);
7684 return 0;
7685}
7686
7687/**
Eric Moored5d135b2009-05-18 13:02:08 -06007688 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06007689 * @pdev: PCI device struct
7690 *
7691 * Returns 0 success, anything else error.
7692 */
7693static int
Eric Moored5d135b2009-05-18 13:02:08 -06007694_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06007695{
7696 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7697 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaic97951e2011-06-14 10:54:56 +05307698 pci_power_t device_state = pdev->current_state;
Eric Moore635374e2009-03-09 01:21:12 -06007699 int r;
7700
7701 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
7702 "operating state [D%d]\n", ioc->name, pdev,
7703 pci_name(pdev), device_state);
7704
7705 pci_set_power_state(pdev, PCI_D0);
7706 pci_enable_wake(pdev, PCI_D0, 0);
7707 pci_restore_state(pdev);
7708 ioc->pdev = pdev;
7709 r = mpt2sas_base_map_resources(ioc);
7710 if (r)
7711 return r;
7712
7713 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
7714 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05307715 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007716 return 0;
7717}
7718#endif /* CONFIG_PM */
7719
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307720/**
7721 * _scsih_pci_error_detected - Called when a PCI error is detected.
7722 * @pdev: PCI device struct
7723 * @state: PCI channel state
7724 *
7725 * Description: Called when a PCI error is detected.
7726 *
7727 * Return value:
7728 * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
7729 */
7730static pci_ers_result_t
7731_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
7732{
7733 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7734 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7735
7736 printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n",
7737 ioc->name, state);
7738
7739 switch (state) {
7740 case pci_channel_io_normal:
7741 return PCI_ERS_RESULT_CAN_RECOVER;
7742 case pci_channel_io_frozen:
Eric Moore3cb54692010-07-08 14:44:34 -06007743 /* Fatal error, prepare for slot reset */
7744 ioc->pci_error_recovery = 1;
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307745 scsi_block_requests(ioc->shost);
7746 mpt2sas_base_stop_watchdog(ioc);
7747 mpt2sas_base_free_resources(ioc);
7748 return PCI_ERS_RESULT_NEED_RESET;
7749 case pci_channel_io_perm_failure:
Eric Moore3cb54692010-07-08 14:44:34 -06007750 /* Permanent error, prepare for device removal */
7751 ioc->pci_error_recovery = 1;
7752 mpt2sas_base_stop_watchdog(ioc);
7753 _scsih_flush_running_cmds(ioc);
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307754 return PCI_ERS_RESULT_DISCONNECT;
7755 }
7756 return PCI_ERS_RESULT_NEED_RESET;
7757}
7758
7759/**
7760 * _scsih_pci_slot_reset - Called when PCI slot has been reset.
7761 * @pdev: PCI device struct
7762 *
7763 * Description: This routine is called by the pci error recovery
7764 * code after the PCI slot has been reset, just before we
7765 * should resume normal operations.
7766 */
7767static pci_ers_result_t
7768_scsih_pci_slot_reset(struct pci_dev *pdev)
7769{
7770 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7771 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7772 int rc;
7773
7774 printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
7775 ioc->name);
7776
Eric Moore3cb54692010-07-08 14:44:34 -06007777 ioc->pci_error_recovery = 0;
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307778 ioc->pdev = pdev;
Eric Moore3cb54692010-07-08 14:44:34 -06007779 pci_restore_state(pdev);
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307780 rc = mpt2sas_base_map_resources(ioc);
7781 if (rc)
7782 return PCI_ERS_RESULT_DISCONNECT;
7783
7784
7785 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
7786 FORCE_BIG_HAMMER);
7787
7788 printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name,
7789 (rc == 0) ? "success" : "failed");
7790
7791 if (!rc)
7792 return PCI_ERS_RESULT_RECOVERED;
7793 else
7794 return PCI_ERS_RESULT_DISCONNECT;
7795}
7796
7797/**
7798 * _scsih_pci_resume() - resume normal ops after PCI reset
7799 * @pdev: pointer to PCI device
7800 *
7801 * Called when the error recovery driver tells us that its
7802 * OK to resume normal operation. Use completion to allow
7803 * halted scsi ops to resume.
7804 */
7805static void
7806_scsih_pci_resume(struct pci_dev *pdev)
7807{
7808 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7809 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7810
7811 printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name);
7812
7813 pci_cleanup_aer_uncorrect_error_status(pdev);
7814 mpt2sas_base_start_watchdog(ioc);
7815 scsi_unblock_requests(ioc->shost);
7816}
7817
7818/**
7819 * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
7820 * @pdev: pointer to PCI device
7821 */
7822static pci_ers_result_t
7823_scsih_pci_mmio_enabled(struct pci_dev *pdev)
7824{
7825 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7826 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7827
7828 printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n",
7829 ioc->name);
7830
7831 /* TODO - dump whatever for debugging purposes */
7832
7833 /* Request a slot reset. */
7834 return PCI_ERS_RESULT_NEED_RESET;
7835}
7836
7837static struct pci_error_handlers _scsih_err_handler = {
7838 .error_detected = _scsih_pci_error_detected,
7839 .mmio_enabled = _scsih_pci_mmio_enabled,
7840 .slot_reset = _scsih_pci_slot_reset,
7841 .resume = _scsih_pci_resume,
7842};
Eric Moore635374e2009-03-09 01:21:12 -06007843
7844static struct pci_driver scsih_driver = {
7845 .name = MPT2SAS_DRIVER_NAME,
7846 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06007847 .probe = _scsih_probe,
7848 .remove = __devexit_p(_scsih_remove),
Kashyap, Desai744090d2009-10-05 15:56:56 +05307849 .shutdown = _scsih_shutdown,
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307850 .err_handler = &_scsih_err_handler,
Eric Moore635374e2009-03-09 01:21:12 -06007851#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06007852 .suspend = _scsih_suspend,
7853 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06007854#endif
7855};
7856
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307857/* raid transport support */
7858static struct raid_function_template mpt2sas_raid_functions = {
7859 .cookie = &scsih_driver_template,
7860 .is_raid = _scsih_is_raid,
7861 .get_resync = _scsih_get_resync,
7862 .get_state = _scsih_get_state,
7863};
Eric Moore635374e2009-03-09 01:21:12 -06007864
7865/**
Eric Moored5d135b2009-05-18 13:02:08 -06007866 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06007867 *
7868 * Returns 0 success, anything else error.
7869 */
7870static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06007871_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06007872{
7873 int error;
7874
7875 mpt_ids = 0;
7876 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
7877 MPT2SAS_DRIVER_VERSION);
7878
7879 mpt2sas_transport_template =
7880 sas_attach_transport(&mpt2sas_transport_functions);
7881 if (!mpt2sas_transport_template)
7882 return -ENODEV;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307883 /* raid transport support */
7884 mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
7885 if (!mpt2sas_raid_template) {
7886 sas_release_transport(mpt2sas_transport_template);
7887 return -ENODEV;
7888 }
Eric Moore635374e2009-03-09 01:21:12 -06007889
7890 mpt2sas_base_initialize_callback_handler();
7891
7892 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06007893 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06007894
Uwe Kleine-König65155b32010-06-11 12:17:01 +02007895 /* task management callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06007896 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06007897
7898 /* base internal commands callback handler */
7899 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
7900
7901 /* transport internal commands callback handler */
7902 transport_cb_idx = mpt2sas_base_register_callback_handler(
7903 mpt2sas_transport_done);
7904
Kashyap, Desai744090d2009-10-05 15:56:56 +05307905 /* scsih internal commands callback handler */
7906 scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
7907
Eric Moore635374e2009-03-09 01:21:12 -06007908 /* configuration page API internal commands callback handler */
7909 config_cb_idx = mpt2sas_base_register_callback_handler(
7910 mpt2sas_config_done);
7911
7912 /* ctl module callback handler */
7913 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
7914
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307915 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
7916 _scsih_tm_tr_complete);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307917
7918 tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler(
7919 _scsih_tm_volume_tr_complete);
7920
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307921 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
7922 _scsih_sas_control_complete);
7923
Eric Moore635374e2009-03-09 01:21:12 -06007924 mpt2sas_ctl_init();
7925
7926 error = pci_register_driver(&scsih_driver);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307927 if (error) {
7928 /* raid transport support */
7929 raid_class_release(mpt2sas_raid_template);
Eric Moore635374e2009-03-09 01:21:12 -06007930 sas_release_transport(mpt2sas_transport_template);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307931 }
Eric Moore635374e2009-03-09 01:21:12 -06007932
7933 return error;
7934}
7935
7936/**
Eric Moored5d135b2009-05-18 13:02:08 -06007937 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06007938 *
7939 * Returns 0 success, anything else error.
7940 */
7941static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06007942_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06007943{
7944 printk(KERN_INFO "mpt2sas version %s unloading\n",
7945 MPT2SAS_DRIVER_VERSION);
7946
7947 pci_unregister_driver(&scsih_driver);
7948
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307949 mpt2sas_ctl_exit();
7950
Eric Moore635374e2009-03-09 01:21:12 -06007951 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
7952 mpt2sas_base_release_callback_handler(tm_cb_idx);
7953 mpt2sas_base_release_callback_handler(base_cb_idx);
7954 mpt2sas_base_release_callback_handler(transport_cb_idx);
Kashyap, Desai744090d2009-10-05 15:56:56 +05307955 mpt2sas_base_release_callback_handler(scsih_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06007956 mpt2sas_base_release_callback_handler(config_cb_idx);
7957 mpt2sas_base_release_callback_handler(ctl_cb_idx);
7958
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307959 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307960 mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307961 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
7962
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307963 /* raid transport support */
7964 raid_class_release(mpt2sas_raid_template);
7965 sas_release_transport(mpt2sas_transport_template);
7966
Eric Moore635374e2009-03-09 01:21:12 -06007967}
7968
Eric Moored5d135b2009-05-18 13:02:08 -06007969module_init(_scsih_init);
7970module_exit(_scsih_exit);