blob: f86f2b1418e759389b03bf1ba6a68062c7a225f7 [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;
Eric Moore635374e2009-03-09 01:21:12 -06002165 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
2166 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
2167 if (mpi_reply) {
2168 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
2169 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
2170 }
2171 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
2172 complete(&ioc->tm_cmds.done);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302173 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06002174}
2175
2176/**
2177 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
2178 * @ioc: per adapter object
2179 * @handle: device handle
2180 *
2181 * During taskmangement request, we need to freeze the device queue.
2182 */
2183void
2184mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2185{
2186 struct MPT2SAS_DEVICE *sas_device_priv_data;
2187 struct scsi_device *sdev;
2188 u8 skip = 0;
2189
2190 shost_for_each_device(sdev, ioc->shost) {
2191 if (skip)
2192 continue;
2193 sas_device_priv_data = sdev->hostdata;
2194 if (!sas_device_priv_data)
2195 continue;
2196 if (sas_device_priv_data->sas_target->handle == handle) {
2197 sas_device_priv_data->sas_target->tm_busy = 1;
2198 skip = 1;
2199 ioc->ignore_loginfos = 1;
2200 }
2201 }
2202}
2203
2204/**
2205 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
2206 * @ioc: per adapter object
2207 * @handle: device handle
2208 *
2209 * During taskmangement request, we need to freeze the device queue.
2210 */
2211void
2212mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2213{
2214 struct MPT2SAS_DEVICE *sas_device_priv_data;
2215 struct scsi_device *sdev;
2216 u8 skip = 0;
2217
2218 shost_for_each_device(sdev, ioc->shost) {
2219 if (skip)
2220 continue;
2221 sas_device_priv_data = sdev->hostdata;
2222 if (!sas_device_priv_data)
2223 continue;
2224 if (sas_device_priv_data->sas_target->handle == handle) {
2225 sas_device_priv_data->sas_target->tm_busy = 0;
2226 skip = 1;
2227 ioc->ignore_loginfos = 0;
2228 }
2229 }
2230}
2231
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302232
Eric Moore635374e2009-03-09 01:21:12 -06002233/**
2234 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
2235 * @ioc: per adapter struct
2236 * @device_handle: device handle
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302237 * @channel: the channel assigned by the OS
2238 * @id: the id assigned by the OS
Eric Moore635374e2009-03-09 01:21:12 -06002239 * @lun: lun number
2240 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
2241 * @smid_task: smid assigned to the task
2242 * @timeout: timeout in seconds
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302243 * Context: user
Eric Moore635374e2009-03-09 01:21:12 -06002244 *
2245 * A generic API for sending task management requests to firmware.
2246 *
Eric Moore635374e2009-03-09 01:21:12 -06002247 * The callback index is set inside `ioc->tm_cb_idx`.
2248 *
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302249 * Return SUCCESS or FAILED.
Eric Moore635374e2009-03-09 01:21:12 -06002250 */
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302251int
2252mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
2253 uint id, uint lun, u8 type, u16 smid_task, ulong timeout,
2254 struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002255{
2256 Mpi2SCSITaskManagementRequest_t *mpi_request;
2257 Mpi2SCSITaskManagementReply_t *mpi_reply;
2258 u16 smid = 0;
2259 u32 ioc_state;
2260 unsigned long timeleft;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302261 struct scsi_cmnd *scmd_lookup;
2262 int rc;
Eric Moore635374e2009-03-09 01:21:12 -06002263
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302264 mutex_lock(&ioc->tm_cmds.mutex);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302265 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
2266 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
2267 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302268 rc = FAILED;
2269 goto err_out;
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302270 }
2271
Eric Moore3cb54692010-07-08 14:44:34 -06002272 if (ioc->shost_recovery || ioc->remove_host ||
2273 ioc->pci_error_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06002274 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2275 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302276 rc = FAILED;
2277 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002278 }
Eric Moore635374e2009-03-09 01:21:12 -06002279
2280 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
2281 if (ioc_state & MPI2_DOORBELL_USED) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05302282 dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
Eric Moore635374e2009-03-09 01:21:12 -06002283 "active!\n", ioc->name));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302284 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2285 FORCE_BIG_HAMMER);
2286 rc = SUCCESS;
2287 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002288 }
2289
2290 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
2291 mpt2sas_base_fault_info(ioc, ioc_state &
2292 MPI2_DOORBELL_DATA_MASK);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302293 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2294 FORCE_BIG_HAMMER);
2295 rc = SUCCESS;
2296 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002297 }
2298
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302299 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06002300 if (!smid) {
2301 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2302 ioc->name, __func__);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302303 rc = FAILED;
2304 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002305 }
2306
2307 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302308 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
2309 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06002310 ioc->tm_cmds.status = MPT2_CMD_PENDING;
2311 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2312 ioc->tm_cmds.smid = smid;
2313 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2314 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2315 mpi_request->DevHandle = cpu_to_le16(handle);
2316 mpi_request->TaskType = type;
2317 mpi_request->TaskMID = cpu_to_le16(smid_task);
2318 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
2319 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05302320 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302321 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002322 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
Eric Moore635374e2009-03-09 01:21:12 -06002323 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
2324 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
2325 ioc->name, __func__);
2326 _debug_dump_mf(mpi_request,
2327 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302328 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) {
2329 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2330 FORCE_BIG_HAMMER);
2331 rc = SUCCESS;
2332 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2333 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2334 goto err_out;
2335 }
Eric Moore635374e2009-03-09 01:21:12 -06002336 }
2337
2338 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
2339 mpi_reply = ioc->tm_cmds.reply;
2340 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
2341 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
2342 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
2343 le32_to_cpu(mpi_reply->IOCLogInfo),
2344 le32_to_cpu(mpi_reply->TerminationCount)));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302345 if (ioc->logging_level & MPT_DEBUG_TM) {
Eric Moore635374e2009-03-09 01:21:12 -06002346 _scsih_response_code(ioc, mpi_reply->ResponseCode);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302347 if (mpi_reply->IOCStatus)
2348 _debug_dump_mf(mpi_request,
2349 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
2350 }
Eric Moore635374e2009-03-09 01:21:12 -06002351 }
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302352
2353 /* sanity check:
2354 * Check to see the commands were terminated.
2355 * This is only needed for eh callbacks, hence the scmd check.
2356 */
2357 rc = FAILED;
2358 if (scmd == NULL)
2359 goto bypass_sanity_checks;
2360 switch (type) {
2361 case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2362 scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task);
Christoph Hellwiga7c44d42011-04-04 09:42:30 -04002363 if (scmd_lookup)
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302364 rc = FAILED;
2365 else
2366 rc = SUCCESS;
2367 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
2376 case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
2377 if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel))
2378 rc = FAILED;
2379 else
2380 rc = SUCCESS;
2381 break;
2382 }
2383
2384 bypass_sanity_checks:
2385
2386 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2387 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2388 mutex_unlock(&ioc->tm_cmds.mutex);
2389
2390 return rc;
2391
2392 err_out:
2393 mutex_unlock(&ioc->tm_cmds.mutex);
2394 return rc;
Eric Moore635374e2009-03-09 01:21:12 -06002395}
2396
2397/**
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302398 * _scsih_tm_display_info - displays info about the device
2399 * @ioc: per adapter struct
2400 * @scmd: pointer to scsi command object
2401 *
2402 * Called by task management callback handlers.
2403 */
2404static void
2405_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
2406{
2407 struct scsi_target *starget = scmd->device->sdev_target;
2408 struct MPT2SAS_TARGET *priv_target = starget->hostdata;
2409 struct _sas_device *sas_device = NULL;
2410 unsigned long flags;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302411 char *device_str = NULL;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302412
2413 if (!priv_target)
2414 return;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302415 if (ioc->hide_ir_msg)
2416 device_str = "WarpDrive";
2417 else
2418 device_str = "volume";
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302419
2420 scsi_print_command(scmd);
2421 if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302422 starget_printk(KERN_INFO, starget, "%s handle(0x%04x), "
2423 "%s wwid(0x%016llx)\n", device_str, priv_target->handle,
2424 device_str, (unsigned long long)priv_target->sas_address);
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302425 } else {
2426 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2427 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2428 priv_target->sas_address);
2429 if (sas_device) {
2430 if (priv_target->flags &
2431 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2432 starget_printk(KERN_INFO, starget,
2433 "volume handle(0x%04x), "
2434 "volume wwid(0x%016llx)\n",
2435 sas_device->volume_handle,
2436 (unsigned long long)sas_device->volume_wwid);
2437 }
2438 starget_printk(KERN_INFO, starget,
2439 "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
2440 sas_device->handle,
2441 (unsigned long long)sas_device->sas_address,
2442 sas_device->phy);
2443 starget_printk(KERN_INFO, starget,
2444 "enclosure_logical_id(0x%016llx), slot(%d)\n",
2445 (unsigned long long)sas_device->enclosure_logical_id,
2446 sas_device->slot);
2447 }
2448 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2449 }
2450}
2451
2452/**
Eric Moored5d135b2009-05-18 13:02:08 -06002453 * _scsih_abort - eh threads main abort routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302454 * @scmd: pointer to scsi command object
Eric Moore635374e2009-03-09 01:21:12 -06002455 *
2456 * Returns SUCCESS if command aborted else FAILED
2457 */
2458static int
Eric Moored5d135b2009-05-18 13:02:08 -06002459_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002460{
2461 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2462 struct MPT2SAS_DEVICE *sas_device_priv_data;
2463 u16 smid;
2464 u16 handle;
2465 int r;
Eric Moore635374e2009-03-09 01:21:12 -06002466
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302467 sdev_printk(KERN_INFO, scmd->device, "attempting task abort! "
2468 "scmd(%p)\n", scmd);
2469 _scsih_tm_display_info(ioc, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002470
2471 sas_device_priv_data = scmd->device->hostdata;
2472 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302473 sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
2474 "scmd(%p)\n", scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002475 scmd->result = DID_NO_CONNECT << 16;
2476 scmd->scsi_done(scmd);
2477 r = SUCCESS;
2478 goto out;
2479 }
2480
2481 /* search for the command */
2482 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
2483 if (!smid) {
2484 scmd->result = DID_RESET << 16;
2485 r = SUCCESS;
2486 goto out;
2487 }
2488
2489 /* for hidden raid components and volumes this is not supported */
2490 if (sas_device_priv_data->sas_target->flags &
2491 MPT_TARGET_FLAGS_RAID_COMPONENT ||
2492 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
2493 scmd->result = DID_RESET << 16;
2494 r = FAILED;
2495 goto out;
2496 }
2497
Kashyap, Desaifa7f3162009-09-23 17:26:58 +05302498 mpt2sas_halt_firmware(ioc);
2499
Eric Moore635374e2009-03-09 01:21:12 -06002500 handle = sas_device_priv_data->sas_target->handle;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302501 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2502 scmd->device->id, scmd->device->lun,
2503 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002504
2505 out:
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302506 sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
2507 ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002508 return r;
2509}
2510
Eric Moore635374e2009-03-09 01:21:12 -06002511/**
Eric Moored5d135b2009-05-18 13:02:08 -06002512 * _scsih_dev_reset - eh threads main device reset routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302513 * @scmd: pointer to scsi command object
Eric Moore635374e2009-03-09 01:21:12 -06002514 *
2515 * Returns SUCCESS if command aborted else FAILED
2516 */
2517static int
Eric Moored5d135b2009-05-18 13:02:08 -06002518_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002519{
2520 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2521 struct MPT2SAS_DEVICE *sas_device_priv_data;
2522 struct _sas_device *sas_device;
2523 unsigned long flags;
2524 u16 handle;
2525 int r;
2526
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302527 struct scsi_target *starget = scmd->device->sdev_target;
2528
Kashyap, Desai37aaa782010-11-13 04:41:32 +05302529 starget_printk(KERN_INFO, starget, "attempting device reset! "
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302530 "scmd(%p)\n", scmd);
2531 _scsih_tm_display_info(ioc, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002532
2533 sas_device_priv_data = scmd->device->hostdata;
2534 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Kashyap, Desai37aaa782010-11-13 04:41:32 +05302535 starget_printk(KERN_INFO, starget, "device been deleted! "
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302536 "scmd(%p)\n", scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002537 scmd->result = DID_NO_CONNECT << 16;
2538 scmd->scsi_done(scmd);
2539 r = SUCCESS;
2540 goto out;
2541 }
2542
2543 /* for hidden raid components obtain the volume_handle */
2544 handle = 0;
2545 if (sas_device_priv_data->sas_target->flags &
2546 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2547 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2548 sas_device = _scsih_sas_device_find_by_handle(ioc,
2549 sas_device_priv_data->sas_target->handle);
2550 if (sas_device)
2551 handle = sas_device->volume_handle;
2552 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2553 } else
2554 handle = sas_device_priv_data->sas_target->handle;
2555
2556 if (!handle) {
2557 scmd->result = DID_RESET << 16;
2558 r = FAILED;
2559 goto out;
2560 }
2561
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302562 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2563 scmd->device->id, scmd->device->lun,
2564 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002565
2566 out:
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302567 sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
2568 ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002569 return r;
2570}
2571
2572/**
Eric Moored5d135b2009-05-18 13:02:08 -06002573 * _scsih_target_reset - eh threads main target reset routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302574 * @scmd: pointer to scsi command object
Eric Moore993e0da2009-05-18 13:00:45 -06002575 *
2576 * Returns SUCCESS if command aborted else FAILED
2577 */
2578static int
Eric Moored5d135b2009-05-18 13:02:08 -06002579_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06002580{
2581 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2582 struct MPT2SAS_DEVICE *sas_device_priv_data;
2583 struct _sas_device *sas_device;
2584 unsigned long flags;
2585 u16 handle;
2586 int r;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302587 struct scsi_target *starget = scmd->device->sdev_target;
Eric Moore993e0da2009-05-18 13:00:45 -06002588
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302589 starget_printk(KERN_INFO, starget, "attempting target reset! "
2590 "scmd(%p)\n", scmd);
2591 _scsih_tm_display_info(ioc, scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002592
2593 sas_device_priv_data = scmd->device->hostdata;
2594 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302595 starget_printk(KERN_INFO, starget, "target been deleted! "
2596 "scmd(%p)\n", scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002597 scmd->result = DID_NO_CONNECT << 16;
2598 scmd->scsi_done(scmd);
2599 r = SUCCESS;
2600 goto out;
2601 }
2602
2603 /* for hidden raid components obtain the volume_handle */
2604 handle = 0;
2605 if (sas_device_priv_data->sas_target->flags &
2606 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2607 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2608 sas_device = _scsih_sas_device_find_by_handle(ioc,
2609 sas_device_priv_data->sas_target->handle);
2610 if (sas_device)
2611 handle = sas_device->volume_handle;
2612 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2613 } else
2614 handle = sas_device_priv_data->sas_target->handle;
2615
2616 if (!handle) {
2617 scmd->result = DID_RESET << 16;
2618 r = FAILED;
2619 goto out;
2620 }
2621
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302622 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2623 scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
2624 30, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002625
2626 out:
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302627 starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
2628 ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002629 return r;
2630}
2631
2632/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302633 * _scsih_host_reset - eh threads main host reset routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302634 * @scmd: pointer to scsi command object
Eric Moore635374e2009-03-09 01:21:12 -06002635 *
2636 * Returns SUCCESS if command aborted else FAILED
2637 */
2638static int
Eric Moored5d135b2009-05-18 13:02:08 -06002639_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002640{
2641 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2642 int r, retval;
2643
2644 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2645 ioc->name, scmd);
2646 scsi_print_command(scmd);
2647
2648 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2649 FORCE_BIG_HAMMER);
2650 r = (retval < 0) ? FAILED : SUCCESS;
2651 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2652 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2653
2654 return r;
2655}
2656
2657/**
2658 * _scsih_fw_event_add - insert and queue up fw_event
2659 * @ioc: per adapter object
2660 * @fw_event: object describing the event
2661 * Context: This function will acquire ioc->fw_event_lock.
2662 *
2663 * This adds the firmware event object into link list, then queues it up to
2664 * be processed from user context.
2665 *
2666 * Return nothing.
2667 */
2668static void
2669_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2670{
2671 unsigned long flags;
2672
2673 if (ioc->firmware_event_thread == NULL)
2674 return;
2675
2676 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2677 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302678 INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work);
2679 queue_delayed_work(ioc->firmware_event_thread,
2680 &fw_event->delayed_work, 0);
Eric Moore635374e2009-03-09 01:21:12 -06002681 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2682}
2683
2684/**
2685 * _scsih_fw_event_free - delete fw_event
2686 * @ioc: per adapter object
2687 * @fw_event: object describing the event
2688 * Context: This function will acquire ioc->fw_event_lock.
2689 *
2690 * This removes firmware event object from link list, frees associated memory.
2691 *
2692 * Return nothing.
2693 */
2694static void
2695_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2696 *fw_event)
2697{
2698 unsigned long flags;
2699
2700 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2701 list_del(&fw_event->list);
2702 kfree(fw_event->event_data);
2703 kfree(fw_event);
2704 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2705}
2706
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302707
Eric Moore635374e2009-03-09 01:21:12 -06002708/**
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302709 * _scsih_queue_rescan - queue a topology rescan from user context
Eric Moore635374e2009-03-09 01:21:12 -06002710 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06002711 *
2712 * Return nothing.
2713 */
2714static void
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302715_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06002716{
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302717 struct fw_event_work *fw_event;
2718
2719 if (ioc->wait_for_port_enable_to_complete)
2720 return;
2721 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
2722 if (!fw_event)
2723 return;
2724 fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET;
2725 fw_event->ioc = ioc;
2726 _scsih_fw_event_add(ioc, fw_event);
2727}
2728
2729/**
2730 * _scsih_fw_event_cleanup_queue - cleanup event queue
2731 * @ioc: per adapter object
2732 *
2733 * Walk the firmware event queue, either killing timers, or waiting
2734 * for outstanding events to complete
2735 *
2736 * Return nothing.
2737 */
2738static void
2739_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)
2740{
2741 struct fw_event_work *fw_event, *next;
2742
2743 if (list_empty(&ioc->fw_event_list) ||
2744 !ioc->firmware_event_thread || in_interrupt())
Eric Moore635374e2009-03-09 01:21:12 -06002745 return;
2746
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302747 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
2748 if (cancel_delayed_work(&fw_event->delayed_work)) {
2749 _scsih_fw_event_free(ioc, fw_event);
2750 continue;
2751 }
2752 fw_event->cancel_pending_work = 1;
2753 }
Eric Moore635374e2009-03-09 01:21:12 -06002754}
2755
Eric Moore635374e2009-03-09 01:21:12 -06002756/**
2757 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2758 * @ioc: per adapter object
2759 * @handle: device handle
2760 *
2761 * During device pull we need to appropiately set the sdev state.
2762 */
2763static void
2764_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2765{
2766 struct MPT2SAS_DEVICE *sas_device_priv_data;
2767 struct scsi_device *sdev;
2768
2769 shost_for_each_device(sdev, ioc->shost) {
2770 sas_device_priv_data = sdev->hostdata;
2771 if (!sas_device_priv_data)
2772 continue;
2773 if (!sas_device_priv_data->block)
2774 continue;
2775 if (sas_device_priv_data->sas_target->handle == handle) {
2776 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2777 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2778 "handle(0x%04x)\n", ioc->name, handle));
2779 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302780 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002781 }
2782 }
2783}
2784
2785/**
2786 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2787 * @ioc: per adapter object
2788 * @handle: device handle
2789 *
2790 * During device pull we need to appropiately set the sdev state.
2791 */
2792static void
2793_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2794{
2795 struct MPT2SAS_DEVICE *sas_device_priv_data;
2796 struct scsi_device *sdev;
2797
2798 shost_for_each_device(sdev, ioc->shost) {
2799 sas_device_priv_data = sdev->hostdata;
2800 if (!sas_device_priv_data)
2801 continue;
2802 if (sas_device_priv_data->block)
2803 continue;
2804 if (sas_device_priv_data->sas_target->handle == handle) {
2805 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2806 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2807 "handle(0x%04x)\n", ioc->name, handle));
2808 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302809 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002810 }
2811 }
2812}
2813
2814/**
2815 * _scsih_block_io_to_children_attached_to_ex
2816 * @ioc: per adapter object
2817 * @sas_expander: the sas_device object
2818 *
2819 * This routine set sdev state to SDEV_BLOCK for all devices
2820 * attached to this expander. This function called when expander is
2821 * pulled.
2822 */
2823static void
2824_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2825 struct _sas_node *sas_expander)
2826{
2827 struct _sas_port *mpt2sas_port;
2828 struct _sas_device *sas_device;
2829 struct _sas_node *expander_sibling;
2830 unsigned long flags;
2831
2832 if (!sas_expander)
2833 return;
2834
2835 list_for_each_entry(mpt2sas_port,
2836 &sas_expander->sas_port_list, port_list) {
2837 if (mpt2sas_port->remote_identify.device_type ==
2838 SAS_END_DEVICE) {
2839 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2840 sas_device =
2841 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2842 mpt2sas_port->remote_identify.sas_address);
2843 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2844 if (!sas_device)
2845 continue;
2846 _scsih_block_io_device(ioc, sas_device->handle);
2847 }
2848 }
2849
2850 list_for_each_entry(mpt2sas_port,
2851 &sas_expander->sas_port_list, port_list) {
2852
2853 if (mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05302854 SAS_EDGE_EXPANDER_DEVICE ||
Eric Moore635374e2009-03-09 01:21:12 -06002855 mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05302856 SAS_FANOUT_EXPANDER_DEVICE) {
Eric Moore635374e2009-03-09 01:21:12 -06002857
2858 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2859 expander_sibling =
2860 mpt2sas_scsih_expander_find_by_sas_address(
2861 ioc, mpt2sas_port->remote_identify.sas_address);
2862 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2863 _scsih_block_io_to_children_attached_to_ex(ioc,
2864 expander_sibling);
2865 }
2866 }
2867}
2868
2869/**
2870 * _scsih_block_io_to_children_attached_directly
2871 * @ioc: per adapter object
2872 * @event_data: topology change event data
2873 *
2874 * This routine set sdev state to SDEV_BLOCK for all devices
2875 * direct attached during device pull.
2876 */
2877static void
2878_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2879 Mpi2EventDataSasTopologyChangeList_t *event_data)
2880{
2881 int i;
2882 u16 handle;
2883 u16 reason_code;
2884 u8 phy_number;
2885
2886 for (i = 0; i < event_data->NumEntries; i++) {
2887 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2888 if (!handle)
2889 continue;
2890 phy_number = event_data->StartPhyNum + i;
2891 reason_code = event_data->PHY[i].PhyStatus &
2892 MPI2_EVENT_SAS_TOPO_RC_MASK;
2893 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2894 _scsih_block_io_device(ioc, handle);
2895 }
2896}
2897
2898/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302899 * _scsih_tm_tr_send - send task management request
2900 * @ioc: per adapter object
2901 * @handle: device handle
2902 * Context: interrupt time.
2903 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002904 * This code is to initiate the device removal handshake protocol
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302905 * with controller firmware. This function will issue target reset
2906 * using high priority request queue. It will send a sas iounit
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002907 * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302908 *
2909 * This is designed to send muliple task management request at the same
2910 * time to the fifo. If the fifo is full, we will append the request,
2911 * and process it in a future completion.
2912 */
2913static void
2914_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2915{
2916 Mpi2SCSITaskManagementRequest_t *mpi_request;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302917 u16 smid;
2918 struct _sas_device *sas_device;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05302919 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302920 unsigned long flags;
2921 struct _tr_list *delayed_tr;
2922
Eric Moore3cb54692010-07-08 14:44:34 -06002923 if (ioc->shost_recovery || ioc->remove_host ||
2924 ioc->pci_error_recovery) {
Kashyap, Desai1278b112010-03-09 17:34:13 +05302925 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
2926 "progress!\n", __func__, ioc->name));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302927 return;
2928 }
2929
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05302930 /* if PD, then return */
2931 if (test_bit(handle, ioc->pd_handles))
2932 return;
2933
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302934 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2935 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05302936 if (sas_device && sas_device->starget &&
2937 sas_device->starget->hostdata) {
2938 sas_target_priv_data = sas_device->starget->hostdata;
2939 sas_target_priv_data->deleted = 1;
2940 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2941 "setting delete flag: handle(0x%04x), "
2942 "sas_addr(0x%016llx)\n", ioc->name, handle,
2943 (unsigned long long) sas_device->sas_address));
Kashyap, Desai1278b112010-03-09 17:34:13 +05302944 }
2945 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302946
2947 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
2948 if (!smid) {
2949 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
2950 if (!delayed_tr)
2951 return;
2952 INIT_LIST_HEAD(&delayed_tr->list);
2953 delayed_tr->handle = handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05302954 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
2955 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2956 "DELAYED:tr:handle(0x%04x), (open)\n",
2957 ioc->name, handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302958 return;
2959 }
2960
Kashyap, Desai1278b112010-03-09 17:34:13 +05302961 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
2962 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
2963 ioc->tm_tr_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302964 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2965 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2966 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2967 mpi_request->DevHandle = cpu_to_le16(handle);
2968 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302969 mpt2sas_base_put_smid_hi_priority(ioc, smid);
2970}
2971
2972
2973
2974/**
2975 * _scsih_sas_control_complete - completion routine
2976 * @ioc: per adapter object
2977 * @smid: system request message index
2978 * @msix_index: MSIX table index supplied by the OS
2979 * @reply: reply message frame(lower 32bit addr)
2980 * Context: interrupt time.
2981 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002982 * This is the sas iounit control completion routine.
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302983 * This code is part of the code to initiate the device removal
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002984 * handshake protocol with controller firmware.
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302985 *
2986 * Return 1 meaning mf should be freed from _base_interrupt
2987 * 0 means the mf is freed from this function.
2988 */
2989static u8
2990_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
2991 u8 msix_index, u32 reply)
2992{
Kashyap, Desai363fa50f2010-11-13 04:29:20 +05302993#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302994 Mpi2SasIoUnitControlReply_t *mpi_reply =
2995 mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai363fa50f2010-11-13 04:29:20 +05302996#endif
Kashyap, Desai1278b112010-03-09 17:34:13 +05302997 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2998 "sc_complete:handle(0x%04x), (open) "
2999 "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
3000 ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
3001 le16_to_cpu(mpi_reply->IOCStatus),
3002 le32_to_cpu(mpi_reply->IOCLogInfo)));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303003 return 1;
3004}
3005
3006/**
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303007 * _scsih_tm_tr_volume_send - send target reset request for volumes
3008 * @ioc: per adapter object
3009 * @handle: device handle
3010 * Context: interrupt time.
3011 *
3012 * This is designed to send muliple task management request at the same
3013 * time to the fifo. If the fifo is full, we will append the request,
3014 * and process it in a future completion.
3015 */
3016static void
3017_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3018{
3019 Mpi2SCSITaskManagementRequest_t *mpi_request;
3020 u16 smid;
3021 struct _tr_list *delayed_tr;
3022
Eric Moore3cb54692010-07-08 14:44:34 -06003023 if (ioc->shost_recovery || ioc->remove_host ||
3024 ioc->pci_error_recovery) {
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303025 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
3026 "progress!\n", __func__, ioc->name));
3027 return;
3028 }
3029
3030 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx);
3031 if (!smid) {
3032 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
3033 if (!delayed_tr)
3034 return;
3035 INIT_LIST_HEAD(&delayed_tr->list);
3036 delayed_tr->handle = handle;
3037 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list);
3038 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3039 "DELAYED:tr:handle(0x%04x), (open)\n",
3040 ioc->name, handle));
3041 return;
3042 }
3043
3044 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
3045 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
3046 ioc->tm_tr_volume_cb_idx));
3047 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3048 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
3049 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
3050 mpi_request->DevHandle = cpu_to_le16(handle);
3051 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
3052 mpt2sas_base_put_smid_hi_priority(ioc, smid);
3053}
3054
3055/**
3056 * _scsih_tm_volume_tr_complete - target reset completion
3057 * @ioc: per adapter object
3058 * @smid: system request message index
3059 * @msix_index: MSIX table index supplied by the OS
3060 * @reply: reply message frame(lower 32bit addr)
3061 * Context: interrupt time.
3062 *
3063 * Return 1 meaning mf should be freed from _base_interrupt
3064 * 0 means the mf is freed from this function.
3065 */
3066static u8
3067_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
3068 u8 msix_index, u32 reply)
3069{
3070 u16 handle;
3071 Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
3072 Mpi2SCSITaskManagementReply_t *mpi_reply =
3073 mpt2sas_base_get_reply_virt_addr(ioc, reply);
3074
Eric Moore3cb54692010-07-08 14:44:34 -06003075 if (ioc->shost_recovery || ioc->remove_host ||
3076 ioc->pci_error_recovery) {
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303077 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
3078 "progress!\n", __func__, ioc->name));
3079 return 1;
3080 }
3081
3082 mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
3083 handle = le16_to_cpu(mpi_request_tm->DevHandle);
3084 if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
3085 dewtprintk(ioc, printk("spurious interrupt: "
3086 "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle,
3087 le16_to_cpu(mpi_reply->DevHandle), smid));
3088 return 0;
3089 }
3090
3091 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3092 "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
3093 "loginfo(0x%08x), completed(%d)\n", ioc->name,
3094 handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
3095 le32_to_cpu(mpi_reply->IOCLogInfo),
3096 le32_to_cpu(mpi_reply->TerminationCount)));
3097
3098 return _scsih_check_for_pending_tm(ioc, smid);
3099}
3100
3101/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303102 * _scsih_tm_tr_complete -
3103 * @ioc: per adapter object
3104 * @smid: system request message index
3105 * @msix_index: MSIX table index supplied by the OS
3106 * @reply: reply message frame(lower 32bit addr)
3107 * Context: interrupt time.
3108 *
3109 * This is the target reset completion routine.
3110 * This code is part of the code to initiate the device removal
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003111 * handshake protocol with controller firmware.
3112 * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303113 *
3114 * Return 1 meaning mf should be freed from _base_interrupt
3115 * 0 means the mf is freed from this function.
3116 */
3117static u8
3118_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
3119 u32 reply)
3120{
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303121 u16 handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303122 Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303123 Mpi2SCSITaskManagementReply_t *mpi_reply =
3124 mpt2sas_base_get_reply_virt_addr(ioc, reply);
3125 Mpi2SasIoUnitControlRequest_t *mpi_request;
3126 u16 smid_sas_ctrl;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303127
Eric Moore3cb54692010-07-08 14:44:34 -06003128 if (ioc->shost_recovery || ioc->remove_host ||
3129 ioc->pci_error_recovery) {
Kashyap, Desai1278b112010-03-09 17:34:13 +05303130 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
3131 "progress!\n", __func__, ioc->name));
3132 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303133 }
3134
Kashyap, Desai1278b112010-03-09 17:34:13 +05303135 mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
3136 handle = le16_to_cpu(mpi_request_tm->DevHandle);
3137 if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
3138 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: "
3139 "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle,
3140 le16_to_cpu(mpi_reply->DevHandle), smid));
3141 return 0;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303142 }
3143
Kashyap, Desai1278b112010-03-09 17:34:13 +05303144 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3145 "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
3146 "loginfo(0x%08x), completed(%d)\n", ioc->name,
3147 handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
3148 le32_to_cpu(mpi_reply->IOCLogInfo),
3149 le32_to_cpu(mpi_reply->TerminationCount)));
3150
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303151 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
3152 if (!smid_sas_ctrl) {
3153 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
3154 ioc->name, __func__);
Kashyap, Desai1278b112010-03-09 17:34:13 +05303155 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303156 }
3157
Kashyap, Desai1278b112010-03-09 17:34:13 +05303158 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), "
3159 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl,
3160 ioc->tm_sas_control_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303161 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
3162 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
3163 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
3164 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303165 mpi_request->DevHandle = mpi_request_tm->DevHandle;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303166 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
Kashyap, Desai1278b112010-03-09 17:34:13 +05303167
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303168 return _scsih_check_for_pending_tm(ioc, smid);
3169}
3170
3171/**
3172 * _scsih_check_for_pending_tm - check for pending task management
3173 * @ioc: per adapter object
3174 * @smid: system request message index
3175 *
3176 * This will check delayed target reset list, and feed the
3177 * next reqeust.
3178 *
3179 * Return 1 meaning mf should be freed from _base_interrupt
3180 * 0 means the mf is freed from this function.
3181 */
3182static u8
3183_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid)
3184{
3185 struct _tr_list *delayed_tr;
3186
3187 if (!list_empty(&ioc->delayed_tr_volume_list)) {
3188 delayed_tr = list_entry(ioc->delayed_tr_volume_list.next,
3189 struct _tr_list, list);
3190 mpt2sas_base_free_smid(ioc, smid);
3191 _scsih_tm_tr_volume_send(ioc, delayed_tr->handle);
3192 list_del(&delayed_tr->list);
3193 kfree(delayed_tr);
3194 return 0;
3195 }
3196
Kashyap, Desai1278b112010-03-09 17:34:13 +05303197 if (!list_empty(&ioc->delayed_tr_list)) {
3198 delayed_tr = list_entry(ioc->delayed_tr_list.next,
3199 struct _tr_list, list);
3200 mpt2sas_base_free_smid(ioc, smid);
3201 _scsih_tm_tr_send(ioc, delayed_tr->handle);
3202 list_del(&delayed_tr->list);
3203 kfree(delayed_tr);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303204 return 0;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303205 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303206
Kashyap, Desai1278b112010-03-09 17:34:13 +05303207 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303208}
3209
3210/**
Eric Moore635374e2009-03-09 01:21:12 -06003211 * _scsih_check_topo_delete_events - sanity check on topo events
3212 * @ioc: per adapter object
3213 * @event_data: the event data payload
3214 *
3215 * This routine added to better handle cable breaker.
3216 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003217 * This handles the case where driver receives multiple expander
Eric Moore635374e2009-03-09 01:21:12 -06003218 * add and delete events in a single shot. When there is a delete event
3219 * the routine will void any pending add events waiting in the event queue.
3220 *
3221 * Return nothing.
3222 */
3223static void
3224_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
3225 Mpi2EventDataSasTopologyChangeList_t *event_data)
3226{
3227 struct fw_event_work *fw_event;
3228 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
3229 u16 expander_handle;
3230 struct _sas_node *sas_expander;
3231 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303232 int i, reason_code;
3233 u16 handle;
3234
3235 for (i = 0 ; i < event_data->NumEntries; i++) {
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303236 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
3237 if (!handle)
3238 continue;
3239 reason_code = event_data->PHY[i].PhyStatus &
3240 MPI2_EVENT_SAS_TOPO_RC_MASK;
3241 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
3242 _scsih_tm_tr_send(ioc, handle);
3243 }
Eric Moore635374e2009-03-09 01:21:12 -06003244
3245 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
3246 if (expander_handle < ioc->sas_hba.num_phys) {
3247 _scsih_block_io_to_children_attached_directly(ioc, event_data);
3248 return;
3249 }
3250
3251 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
3252 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
3253 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3254 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
3255 expander_handle);
3256 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3257 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
3258 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
3259 _scsih_block_io_to_children_attached_directly(ioc, event_data);
3260
3261 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
3262 return;
3263
3264 /* mark ignore flag for pending events */
3265 spin_lock_irqsave(&ioc->fw_event_lock, flags);
3266 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
3267 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
3268 fw_event->ignore)
3269 continue;
3270 local_event_data = fw_event->event_data;
3271 if (local_event_data->ExpStatus ==
3272 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
3273 local_event_data->ExpStatus ==
3274 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
3275 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
3276 expander_handle) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05303277 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -06003278 "setting ignoring flag\n", ioc->name));
3279 fw_event->ignore = 1;
3280 }
3281 }
3282 }
3283 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
3284}
3285
3286/**
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303287 * _scsih_set_volume_delete_flag - setting volume delete flag
3288 * @ioc: per adapter object
3289 * @handle: device handle
3290 *
3291 * This
3292 * Return nothing.
3293 */
3294static void
3295_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3296{
3297 struct _raid_device *raid_device;
3298 struct MPT2SAS_TARGET *sas_target_priv_data;
3299 unsigned long flags;
3300
3301 spin_lock_irqsave(&ioc->raid_device_lock, flags);
3302 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
3303 if (raid_device && raid_device->starget &&
3304 raid_device->starget->hostdata) {
3305 sas_target_priv_data =
3306 raid_device->starget->hostdata;
3307 sas_target_priv_data->deleted = 1;
3308 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3309 "setting delete flag: handle(0x%04x), "
3310 "wwid(0x%016llx)\n", ioc->name, handle,
3311 (unsigned long long) raid_device->wwid));
3312 }
3313 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
3314}
3315
3316/**
3317 * _scsih_set_volume_handle_for_tr - set handle for target reset to volume
3318 * @handle: input handle
3319 * @a: handle for volume a
3320 * @b: handle for volume b
3321 *
3322 * IR firmware only supports two raid volumes. The purpose of this
3323 * routine is to set the volume handle in either a or b. When the given
3324 * input handle is non-zero, or when a and b have not been set before.
3325 */
3326static void
3327_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b)
3328{
3329 if (!handle || handle == *a || handle == *b)
3330 return;
3331 if (!*a)
3332 *a = handle;
3333 else if (!*b)
3334 *b = handle;
3335}
3336
3337/**
3338 * _scsih_check_ir_config_unhide_events - check for UNHIDE events
3339 * @ioc: per adapter object
3340 * @event_data: the event data payload
3341 * Context: interrupt time.
3342 *
3343 * This routine will send target reset to volume, followed by target
3344 * resets to the PDs. This is called when a PD has been removed, or
3345 * volume has been deleted or removed. When the target reset is sent
3346 * to volume, the PD target resets need to be queued to start upon
3347 * completion of the volume target reset.
3348 *
3349 * Return nothing.
3350 */
3351static void
3352_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc,
3353 Mpi2EventDataIrConfigChangeList_t *event_data)
3354{
3355 Mpi2EventIrConfigElement_t *element;
3356 int i;
3357 u16 handle, volume_handle, a, b;
3358 struct _tr_list *delayed_tr;
3359
3360 a = 0;
3361 b = 0;
3362
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303363 if (ioc->is_warpdrive)
3364 return;
3365
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303366 /* Volume Resets for Deleted or Removed */
3367 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3368 for (i = 0; i < event_data->NumElements; i++, element++) {
3369 if (element->ReasonCode ==
3370 MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED ||
3371 element->ReasonCode ==
3372 MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
3373 volume_handle = le16_to_cpu(element->VolDevHandle);
3374 _scsih_set_volume_delete_flag(ioc, volume_handle);
3375 _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
3376 }
3377 }
3378
3379 /* Volume Resets for UNHIDE events */
3380 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3381 for (i = 0; i < event_data->NumElements; i++, element++) {
3382 if (le32_to_cpu(event_data->Flags) &
3383 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
3384 continue;
3385 if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) {
3386 volume_handle = le16_to_cpu(element->VolDevHandle);
3387 _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
3388 }
3389 }
3390
3391 if (a)
3392 _scsih_tm_tr_volume_send(ioc, a);
3393 if (b)
3394 _scsih_tm_tr_volume_send(ioc, b);
3395
3396 /* PD target resets */
3397 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3398 for (i = 0; i < event_data->NumElements; i++, element++) {
3399 if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE)
3400 continue;
3401 handle = le16_to_cpu(element->PhysDiskDevHandle);
3402 volume_handle = le16_to_cpu(element->VolDevHandle);
3403 clear_bit(handle, ioc->pd_handles);
3404 if (!volume_handle)
3405 _scsih_tm_tr_send(ioc, handle);
3406 else if (volume_handle == a || volume_handle == b) {
3407 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
3408 BUG_ON(!delayed_tr);
3409 INIT_LIST_HEAD(&delayed_tr->list);
3410 delayed_tr->handle = handle;
3411 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
3412 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3413 "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name,
3414 handle));
3415 } else
3416 _scsih_tm_tr_send(ioc, handle);
3417 }
3418}
3419
3420
3421/**
3422 * _scsih_check_volume_delete_events - set delete flag for volumes
3423 * @ioc: per adapter object
3424 * @event_data: the event data payload
3425 * Context: interrupt time.
3426 *
3427 * This will handle the case when the cable connected to entire volume is
3428 * pulled. We will take care of setting the deleted flag so normal IO will
3429 * not be sent.
3430 *
3431 * Return nothing.
3432 */
3433static void
3434_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc,
3435 Mpi2EventDataIrVolume_t *event_data)
3436{
3437 u32 state;
3438
3439 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
3440 return;
3441 state = le32_to_cpu(event_data->NewValue);
3442 if (state == MPI2_RAID_VOL_STATE_MISSING || state ==
3443 MPI2_RAID_VOL_STATE_FAILED)
3444 _scsih_set_volume_delete_flag(ioc,
3445 le16_to_cpu(event_data->VolDevHandle));
3446}
3447
3448/**
Eric Moore635374e2009-03-09 01:21:12 -06003449 * _scsih_flush_running_cmds - completing outstanding commands.
3450 * @ioc: per adapter object
3451 *
3452 * The flushing out of all pending scmd commands following host reset,
3453 * where all IO is dropped to the floor.
3454 *
3455 * Return nothing.
3456 */
3457static void
3458_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
3459{
3460 struct scsi_cmnd *scmd;
3461 u16 smid;
3462 u16 count = 0;
3463
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303464 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Kashyap, Desaiec07a052011-01-05 17:54:32 +05303465 scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003466 if (!scmd)
3467 continue;
3468 count++;
3469 mpt2sas_base_free_smid(ioc, smid);
3470 scsi_dma_unmap(scmd);
Eric Moore3cb54692010-07-08 14:44:34 -06003471 if (ioc->pci_error_recovery)
3472 scmd->result = DID_NO_CONNECT << 16;
3473 else
3474 scmd->result = DID_RESET << 16;
Eric Moore635374e2009-03-09 01:21:12 -06003475 scmd->scsi_done(scmd);
3476 }
3477 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
3478 ioc->name, count));
3479}
3480
3481/**
Eric Moore3c621b32009-05-18 12:59:41 -06003482 * _scsih_setup_eedp - setup MPI request for EEDP transfer
3483 * @scmd: pointer to scsi command object
3484 * @mpi_request: pointer to the SCSI_IO reqest message frame
3485 *
3486 * Supporting protection 1 and 3.
3487 *
3488 * Returns nothing
3489 */
3490static void
3491_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
3492{
3493 u16 eedp_flags;
3494 unsigned char prot_op = scsi_get_prot_op(scmd);
3495 unsigned char prot_type = scsi_get_prot_type(scmd);
3496
Eric Moored334aa72010-04-22 10:47:40 -06003497 if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL)
Eric Moore3c621b32009-05-18 12:59:41 -06003498 return;
3499
3500 if (prot_op == SCSI_PROT_READ_STRIP)
3501 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
3502 else if (prot_op == SCSI_PROT_WRITE_INSERT)
3503 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
3504 else
3505 return;
3506
Eric Moore3c621b32009-05-18 12:59:41 -06003507 switch (prot_type) {
3508 case SCSI_PROT_DIF_TYPE1:
Martin K. Petersen756aca72011-05-18 00:45:22 -04003509 case SCSI_PROT_DIF_TYPE2:
Eric Moore3c621b32009-05-18 12:59:41 -06003510
3511 /*
3512 * enable ref/guard checking
3513 * auto increment ref tag
3514 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05303515 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
Eric Moore3c621b32009-05-18 12:59:41 -06003516 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
3517 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
3518 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
3519 cpu_to_be32(scsi_get_lba(scmd));
Eric Moored334aa72010-04-22 10:47:40 -06003520 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003521
Eric Moore3c621b32009-05-18 12:59:41 -06003522 case SCSI_PROT_DIF_TYPE3:
3523
3524 /*
3525 * enable guard checking
3526 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05303527 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
Eric Moore3c621b32009-05-18 12:59:41 -06003528 break;
3529 }
Kashyap, Desai463217b2009-10-05 15:53:06 +05303530 mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
3531 mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
Eric Moore3c621b32009-05-18 12:59:41 -06003532}
3533
3534/**
3535 * _scsih_eedp_error_handling - return sense code for EEDP errors
3536 * @scmd: pointer to scsi command object
3537 * @ioc_status: ioc status
3538 *
3539 * Returns nothing
3540 */
3541static void
3542_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
3543{
3544 u8 ascq;
3545 u8 sk;
3546 u8 host_byte;
3547
3548 switch (ioc_status) {
3549 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3550 ascq = 0x01;
3551 break;
3552 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3553 ascq = 0x02;
3554 break;
3555 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3556 ascq = 0x03;
3557 break;
3558 default:
3559 ascq = 0x00;
3560 break;
3561 }
3562
3563 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
3564 sk = ILLEGAL_REQUEST;
3565 host_byte = DID_ABORT;
3566 } else {
3567 sk = ABORTED_COMMAND;
3568 host_byte = DID_OK;
3569 }
3570
3571 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
3572 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
3573 SAM_STAT_CHECK_CONDITION;
3574}
3575
3576/**
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303577 * _scsih_scsi_direct_io_get - returns direct io flag
3578 * @ioc: per adapter object
3579 * @smid: system request message index
3580 *
3581 * Returns the smid stored scmd pointer.
3582 */
3583static inline u8
3584_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
3585{
3586 return ioc->scsi_lookup[smid - 1].direct_io;
3587}
3588
3589/**
3590 * _scsih_scsi_direct_io_set - sets direct io flag
3591 * @ioc: per adapter object
3592 * @smid: system request message index
3593 * @direct_io: Zero or non-zero value to set in the direct_io flag
3594 *
3595 * Returns Nothing.
3596 */
3597static inline void
3598_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
3599{
3600 ioc->scsi_lookup[smid - 1].direct_io = direct_io;
3601}
3602
3603
3604/**
3605 * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
3606 * @ioc: per adapter object
3607 * @scmd: pointer to scsi command object
3608 * @raid_device: pointer to raid device data structure
3609 * @mpi_request: pointer to the SCSI_IO reqest message frame
3610 * @smid: system request message index
3611 *
3612 * Returns nothing
3613 */
3614static void
3615_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
3616 struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
3617 u16 smid)
3618{
3619 u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size;
3620 u32 stripe_sz, stripe_exp;
3621 u8 num_pds, *cdb_ptr, *tmp_ptr, *lba_ptr1, *lba_ptr2;
3622 u8 cdb0 = scmd->cmnd[0];
3623
3624 /*
3625 * Try Direct I/O to RAID memeber disks
3626 */
3627 if (cdb0 == READ_16 || cdb0 == READ_10 ||
3628 cdb0 == WRITE_16 || cdb0 == WRITE_10) {
3629 cdb_ptr = mpi_request->CDB.CDB32;
3630
3631 if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4]
3632 | cdb_ptr[5])) {
3633 io_size = scsi_bufflen(scmd) >> 9;
3634 /* get virtual lba */
3635 lba_ptr1 = lba_ptr2 = (cdb0 < READ_16) ? &cdb_ptr[2] :
3636 &cdb_ptr[6];
3637 tmp_ptr = (u8 *)&v_lba + 3;
3638 *tmp_ptr-- = *lba_ptr1++;
3639 *tmp_ptr-- = *lba_ptr1++;
3640 *tmp_ptr-- = *lba_ptr1++;
3641 *tmp_ptr = *lba_ptr1;
3642
3643 if (((u64)v_lba + (u64)io_size - 1) <=
3644 (u32)raid_device->max_lba) {
3645 stripe_sz = raid_device->stripe_sz;
3646 stripe_exp = raid_device->stripe_exponent;
3647 stripe_off = v_lba & (stripe_sz - 1);
3648
3649 /* Check whether IO falls within a stripe */
3650 if ((stripe_off + io_size) <= stripe_sz) {
3651 num_pds = raid_device->num_pds;
3652 p_lba = v_lba >> stripe_exp;
3653 stripe_unit = p_lba / num_pds;
3654 column = p_lba % num_pds;
3655 p_lba = (stripe_unit << stripe_exp) +
3656 stripe_off;
3657 mpi_request->DevHandle =
3658 cpu_to_le16(raid_device->
3659 pd_handle[column]);
3660 tmp_ptr = (u8 *)&p_lba + 3;
3661 *lba_ptr2++ = *tmp_ptr--;
3662 *lba_ptr2++ = *tmp_ptr--;
3663 *lba_ptr2++ = *tmp_ptr--;
3664 *lba_ptr2 = *tmp_ptr;
3665 /*
3666 * WD: To indicate this I/O is directI/O
3667 */
3668 _scsih_scsi_direct_io_set(ioc, smid, 1);
3669 }
3670 }
3671 }
3672 }
3673}
3674
3675/**
Eric Moored5d135b2009-05-18 13:02:08 -06003676 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06003677 * @scmd: pointer to scsi command object
3678 * @done: function pointer to be invoked on completion
3679 *
3680 * The callback index is set inside `ioc->scsi_io_cb_idx`.
3681 *
3682 * Returns 0 on success. If there's a failure, return either:
3683 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
3684 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
3685 */
3686static int
Jeff Garzikf2812332010-11-16 02:10:29 -05003687_scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06003688{
3689 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
3690 struct MPT2SAS_DEVICE *sas_device_priv_data;
3691 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303692 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06003693 Mpi2SCSIIORequest_t *mpi_request;
3694 u32 mpi_control;
3695 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06003696
3697 scmd->scsi_done = done;
3698 sas_device_priv_data = scmd->device->hostdata;
Kashyap, Desai130b9582010-04-08 17:54:32 +05303699 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Eric Moore635374e2009-03-09 01:21:12 -06003700 scmd->result = DID_NO_CONNECT << 16;
3701 scmd->scsi_done(scmd);
3702 return 0;
3703 }
3704
Eric Moore3cb54692010-07-08 14:44:34 -06003705 if (ioc->pci_error_recovery) {
3706 scmd->result = DID_NO_CONNECT << 16;
3707 scmd->scsi_done(scmd);
3708 return 0;
3709 }
3710
Eric Moore635374e2009-03-09 01:21:12 -06003711 sas_target_priv_data = sas_device_priv_data->sas_target;
Kashyap, Desai130b9582010-04-08 17:54:32 +05303712 /* invalid device handle */
3713 if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
Eric Moore635374e2009-03-09 01:21:12 -06003714 scmd->result = DID_NO_CONNECT << 16;
3715 scmd->scsi_done(scmd);
3716 return 0;
3717 }
3718
Kashyap, Desai130b9582010-04-08 17:54:32 +05303719 /* host recovery or link resets sent via IOCTLs */
3720 if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06003721 return SCSI_MLQUEUE_HOST_BUSY;
Uwe Kleine-König65155b32010-06-11 12:17:01 +02003722 /* device busy with task management */
Kashyap, Desai130b9582010-04-08 17:54:32 +05303723 else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
3724 return SCSI_MLQUEUE_DEVICE_BUSY;
3725 /* device has been deleted */
3726 else if (sas_target_priv_data->deleted) {
3727 scmd->result = DID_NO_CONNECT << 16;
3728 scmd->scsi_done(scmd);
3729 return 0;
3730 }
Eric Moore635374e2009-03-09 01:21:12 -06003731
3732 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
3733 mpi_control = MPI2_SCSIIO_CONTROL_READ;
3734 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
3735 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
3736 else
3737 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
3738
3739 /* set tags */
3740 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
3741 if (scmd->device->tagged_supported) {
3742 if (scmd->device->ordered_tags)
3743 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
3744 else
3745 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
3746 } else
3747/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
3748/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
3749 */
3750 mpi_control |= (0x500);
3751
3752 } else
3753 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303754 /* Make sure Device is not raid volume.
3755 * We do not expose raid functionality to upper layer for warpdrive.
3756 */
3757 if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
Eric Moored334aa72010-04-22 10:47:40 -06003758 sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
Eric Moore635374e2009-03-09 01:21:12 -06003759 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
3760
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303761 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06003762 if (!smid) {
3763 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
3764 ioc->name, __func__);
3765 goto out;
3766 }
3767 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3768 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06003769 _scsih_setup_eedp(scmd, mpi_request);
Eric Moored334aa72010-04-22 10:47:40 -06003770 if (scmd->cmd_len == 32)
3771 mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
Eric Moore635374e2009-03-09 01:21:12 -06003772 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3773 if (sas_device_priv_data->sas_target->flags &
3774 MPT_TARGET_FLAGS_RAID_COMPONENT)
3775 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3776 else
3777 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3778 mpi_request->DevHandle =
3779 cpu_to_le16(sas_device_priv_data->sas_target->handle);
3780 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
3781 mpi_request->Control = cpu_to_le32(mpi_control);
3782 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
3783 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
3784 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
3785 mpi_request->SenseBufferLowAddress =
Kashyap, Desaiec9472c2009-09-23 17:34:13 +05303786 mpt2sas_base_get_sense_buffer_dma(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003787 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
3788 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
3789 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303790 mpi_request->VF_ID = 0; /* TODO */
3791 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003792 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
3793 mpi_request->LUN);
3794 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
3795
3796 if (!mpi_request->DataLength) {
3797 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
3798 } else {
3799 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
3800 mpt2sas_base_free_smid(ioc, smid);
3801 goto out;
3802 }
3803 }
3804
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303805 raid_device = sas_target_priv_data->raid_device;
3806 if (raid_device && raid_device->direct_io_enabled)
3807 _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request,
3808 smid);
3809
Kashyap, Desai58287fd2010-03-17 16:27:25 +05303810 if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST))
3811 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303812 le16_to_cpu(mpi_request->DevHandle));
Kashyap, Desai58287fd2010-03-17 16:27:25 +05303813 else
3814 mpt2sas_base_put_smid_default(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003815 return 0;
3816
3817 out:
3818 return SCSI_MLQUEUE_HOST_BUSY;
3819}
3820
Jeff Garzikf2812332010-11-16 02:10:29 -05003821static DEF_SCSI_QCMD(_scsih_qcmd)
3822
Eric Moore635374e2009-03-09 01:21:12 -06003823/**
3824 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
3825 * @sense_buffer: sense data returned by target
3826 * @data: normalized skey/asc/ascq
3827 *
3828 * Return nothing.
3829 */
3830static void
3831_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
3832{
3833 if ((sense_buffer[0] & 0x7F) >= 0x72) {
3834 /* descriptor format */
3835 data->skey = sense_buffer[1] & 0x0F;
3836 data->asc = sense_buffer[2];
3837 data->ascq = sense_buffer[3];
3838 } else {
3839 /* fixed format */
3840 data->skey = sense_buffer[2] & 0x0F;
3841 data->asc = sense_buffer[12];
3842 data->ascq = sense_buffer[13];
3843 }
3844}
3845
3846#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3847/**
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003848 * _scsih_scsi_ioc_info - translated non-successful SCSI_IO request
Eric Moore635374e2009-03-09 01:21:12 -06003849 * @ioc: per adapter object
3850 * @scmd: pointer to scsi command object
3851 * @mpi_reply: reply mf payload returned from firmware
3852 *
3853 * scsi_status - SCSI Status code returned from target device
3854 * scsi_state - state info associated with SCSI_IO determined by ioc
3855 * ioc_status - ioc supplied status info
3856 *
3857 * Return nothing.
3858 */
3859static void
3860_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
3861 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
3862{
3863 u32 response_info;
3864 u8 *response_bytes;
3865 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
3866 MPI2_IOCSTATUS_MASK;
3867 u8 scsi_state = mpi_reply->SCSIState;
3868 u8 scsi_status = mpi_reply->SCSIStatus;
3869 char *desc_ioc_state = NULL;
3870 char *desc_scsi_status = NULL;
3871 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303872 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
Kashyap, Desai7fbae672010-06-17 13:45:17 +05303873 struct _sas_device *sas_device = NULL;
3874 unsigned long flags;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05303875 struct scsi_target *starget = scmd->device->sdev_target;
3876 struct MPT2SAS_TARGET *priv_target = starget->hostdata;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303877 char *device_str = NULL;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05303878
3879 if (!priv_target)
3880 return;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303881
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303882 if (ioc->hide_ir_msg)
3883 device_str = "WarpDrive";
3884 else
3885 device_str = "volume";
3886
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303887 if (log_info == 0x31170000)
3888 return;
Eric Moore635374e2009-03-09 01:21:12 -06003889
3890 switch (ioc_status) {
3891 case MPI2_IOCSTATUS_SUCCESS:
3892 desc_ioc_state = "success";
3893 break;
3894 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3895 desc_ioc_state = "invalid function";
3896 break;
3897 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3898 desc_ioc_state = "scsi recovered error";
3899 break;
3900 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
3901 desc_ioc_state = "scsi invalid dev handle";
3902 break;
3903 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3904 desc_ioc_state = "scsi device not there";
3905 break;
3906 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3907 desc_ioc_state = "scsi data overrun";
3908 break;
3909 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3910 desc_ioc_state = "scsi data underrun";
3911 break;
3912 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3913 desc_ioc_state = "scsi io data error";
3914 break;
3915 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3916 desc_ioc_state = "scsi protocol error";
3917 break;
3918 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3919 desc_ioc_state = "scsi task terminated";
3920 break;
3921 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3922 desc_ioc_state = "scsi residual mismatch";
3923 break;
3924 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3925 desc_ioc_state = "scsi task mgmt failed";
3926 break;
3927 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3928 desc_ioc_state = "scsi ioc terminated";
3929 break;
3930 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3931 desc_ioc_state = "scsi ext terminated";
3932 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003933 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3934 desc_ioc_state = "eedp guard error";
3935 break;
3936 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3937 desc_ioc_state = "eedp ref tag error";
3938 break;
3939 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3940 desc_ioc_state = "eedp app tag error";
3941 break;
Eric Moore635374e2009-03-09 01:21:12 -06003942 default:
3943 desc_ioc_state = "unknown";
3944 break;
3945 }
3946
3947 switch (scsi_status) {
3948 case MPI2_SCSI_STATUS_GOOD:
3949 desc_scsi_status = "good";
3950 break;
3951 case MPI2_SCSI_STATUS_CHECK_CONDITION:
3952 desc_scsi_status = "check condition";
3953 break;
3954 case MPI2_SCSI_STATUS_CONDITION_MET:
3955 desc_scsi_status = "condition met";
3956 break;
3957 case MPI2_SCSI_STATUS_BUSY:
3958 desc_scsi_status = "busy";
3959 break;
3960 case MPI2_SCSI_STATUS_INTERMEDIATE:
3961 desc_scsi_status = "intermediate";
3962 break;
3963 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
3964 desc_scsi_status = "intermediate condmet";
3965 break;
3966 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
3967 desc_scsi_status = "reservation conflict";
3968 break;
3969 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
3970 desc_scsi_status = "command terminated";
3971 break;
3972 case MPI2_SCSI_STATUS_TASK_SET_FULL:
3973 desc_scsi_status = "task set full";
3974 break;
3975 case MPI2_SCSI_STATUS_ACA_ACTIVE:
3976 desc_scsi_status = "aca active";
3977 break;
3978 case MPI2_SCSI_STATUS_TASK_ABORTED:
3979 desc_scsi_status = "task aborted";
3980 break;
3981 default:
3982 desc_scsi_status = "unknown";
3983 break;
3984 }
3985
3986 desc_scsi_state[0] = '\0';
3987 if (!scsi_state)
3988 desc_scsi_state = " ";
3989 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3990 strcat(desc_scsi_state, "response info ");
3991 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3992 strcat(desc_scsi_state, "state terminated ");
3993 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
3994 strcat(desc_scsi_state, "no status ");
3995 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
3996 strcat(desc_scsi_state, "autosense failed ");
3997 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
3998 strcat(desc_scsi_state, "autosense valid ");
3999
4000 scsi_print_command(scmd);
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304001
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304002 if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304003 printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
4004 device_str, (unsigned long long)priv_target->sas_address);
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304005 } else {
4006 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4007 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4008 priv_target->sas_address);
4009 if (sas_device) {
4010 printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
4011 "phy(%d)\n", ioc->name, sas_device->sas_address,
4012 sas_device->phy);
4013 printk(MPT2SAS_WARN_FMT
4014 "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
4015 ioc->name, sas_device->enclosure_logical_id,
4016 sas_device->slot);
4017 }
4018 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304019 }
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304020
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304021 printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), "
4022 "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle),
4023 desc_ioc_state, ioc_status, smid);
Eric Moore635374e2009-03-09 01:21:12 -06004024 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
4025 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
4026 scsi_get_resid(scmd));
4027 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
4028 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
4029 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
4030 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
4031 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
4032 scsi_status, desc_scsi_state, scsi_state);
4033
4034 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
4035 struct sense_info data;
4036 _scsih_normalize_sense(scmd->sense_buffer, &data);
4037 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
Kashyap, Desaie94f6742010-03-17 16:24:52 +05304038 "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey,
4039 data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));
Eric Moore635374e2009-03-09 01:21:12 -06004040 }
4041
4042 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
4043 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
4044 response_bytes = (u8 *)&response_info;
Kashyap, Desai9982f592009-09-23 17:23:07 +05304045 _scsih_response_code(ioc, response_bytes[0]);
Eric Moore635374e2009-03-09 01:21:12 -06004046 }
4047}
4048#endif
4049
4050/**
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05304051 * _scsih_turn_on_fault_led - illuminate Fault LED
Eric Moore635374e2009-03-09 01:21:12 -06004052 * @ioc: per adapter object
4053 * @handle: device handle
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05304054 * Context: process
4055 *
4056 * Return nothing.
4057 */
4058static void
4059_scsih_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4060{
4061 Mpi2SepReply_t mpi_reply;
4062 Mpi2SepRequest_t mpi_request;
4063
4064 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
4065 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
4066 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
4067 mpi_request.SlotStatus =
4068 cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
4069 mpi_request.DevHandle = cpu_to_le16(handle);
4070 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
4071 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
4072 &mpi_request)) != 0) {
4073 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
4074 __FILE__, __LINE__, __func__);
4075 return;
4076 }
4077
4078 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
4079 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: "
4080 "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name,
4081 le16_to_cpu(mpi_reply.IOCStatus),
4082 le32_to_cpu(mpi_reply.IOCLogInfo)));
4083 return;
4084 }
4085}
4086
4087/**
4088 * _scsih_send_event_to_turn_on_fault_led - fire delayed event
4089 * @ioc: per adapter object
4090 * @handle: device handle
4091 * Context: interrupt.
4092 *
4093 * Return nothing.
4094 */
4095static void
4096_scsih_send_event_to_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4097{
4098 struct fw_event_work *fw_event;
4099
4100 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
4101 if (!fw_event)
4102 return;
4103 fw_event->event = MPT2SAS_TURN_ON_FAULT_LED;
4104 fw_event->device_handle = handle;
4105 fw_event->ioc = ioc;
4106 _scsih_fw_event_add(ioc, fw_event);
4107}
4108
4109/**
4110 * _scsih_smart_predicted_fault - process smart errors
4111 * @ioc: per adapter object
4112 * @handle: device handle
4113 * Context: interrupt.
Eric Moore635374e2009-03-09 01:21:12 -06004114 *
4115 * Return nothing.
4116 */
4117static void
4118_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4119{
Eric Moore635374e2009-03-09 01:21:12 -06004120 struct scsi_target *starget;
4121 struct MPT2SAS_TARGET *sas_target_priv_data;
4122 Mpi2EventNotificationReply_t *event_reply;
4123 Mpi2EventDataSasDeviceStatusChange_t *event_data;
4124 struct _sas_device *sas_device;
4125 ssize_t sz;
4126 unsigned long flags;
4127
4128 /* only handle non-raid devices */
4129 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4130 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4131 if (!sas_device) {
4132 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4133 return;
4134 }
4135 starget = sas_device->starget;
4136 sas_target_priv_data = starget->hostdata;
4137
4138 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
4139 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
4140 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4141 return;
4142 }
4143 starget_printk(KERN_WARNING, starget, "predicted fault\n");
4144 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4145
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05304146 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
4147 _scsih_send_event_to_turn_on_fault_led(ioc, handle);
Eric Moore635374e2009-03-09 01:21:12 -06004148
4149 /* insert into event log */
4150 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
4151 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
4152 event_reply = kzalloc(sz, GFP_KERNEL);
4153 if (!event_reply) {
4154 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4155 ioc->name, __FILE__, __LINE__, __func__);
4156 return;
4157 }
4158
4159 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
4160 event_reply->Event =
4161 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
4162 event_reply->MsgLength = sz/4;
4163 event_reply->EventDataLength =
4164 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
4165 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
4166 event_reply->EventData;
4167 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
4168 event_data->ASC = 0x5D;
4169 event_data->DevHandle = cpu_to_le16(handle);
4170 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
4171 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
4172 kfree(event_reply);
4173}
4174
4175/**
Eric Moored5d135b2009-05-18 13:02:08 -06004176 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06004177 * @ioc: per adapter object
4178 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304179 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06004180 * @reply: reply message frame(lower 32bit addr)
4181 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304182 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06004183 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304184 * Return 1 meaning mf should be freed from _base_interrupt
4185 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06004186 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304187static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304188_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06004189{
4190 Mpi2SCSIIORequest_t *mpi_request;
4191 Mpi2SCSIIOReply_t *mpi_reply;
4192 struct scsi_cmnd *scmd;
4193 u16 ioc_status;
4194 u32 xfer_cnt;
4195 u8 scsi_state;
4196 u8 scsi_status;
4197 u32 log_info;
4198 struct MPT2SAS_DEVICE *sas_device_priv_data;
Kashyap, Desai9982f592009-09-23 17:23:07 +05304199 u32 response_code = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004200
4201 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desaiec07a052011-01-05 17:54:32 +05304202 scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06004203 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304204 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06004205
4206 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
4207
4208 if (mpi_reply == NULL) {
4209 scmd->result = DID_OK << 16;
4210 goto out;
4211 }
4212
4213 sas_device_priv_data = scmd->device->hostdata;
4214 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
4215 sas_device_priv_data->sas_target->deleted) {
4216 scmd->result = DID_NO_CONNECT << 16;
4217 goto out;
4218 }
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304219 /*
4220 * WARPDRIVE: If direct_io is set then it is directIO,
4221 * the failed direct I/O should be redirected to volume
4222 */
4223 if (_scsih_scsi_direct_io_get(ioc, smid)) {
4224 _scsih_scsi_direct_io_set(ioc, smid, 0);
4225 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
4226 mpi_request->DevHandle =
4227 cpu_to_le16(sas_device_priv_data->sas_target->handle);
4228 mpt2sas_base_put_smid_scsi_io(ioc, smid,
4229 sas_device_priv_data->sas_target->handle);
4230 return 0;
4231 }
4232
Eric Moore635374e2009-03-09 01:21:12 -06004233
4234 /* turning off TLR */
Kashyap, Desai9982f592009-09-23 17:23:07 +05304235 scsi_state = mpi_reply->SCSIState;
4236 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
4237 response_code =
4238 le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
Eric Moore635374e2009-03-09 01:21:12 -06004239 if (!sas_device_priv_data->tlr_snoop_check) {
4240 sas_device_priv_data->tlr_snoop_check++;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304241 /* Make sure Device is not raid volume.
4242 * We do not expose raid functionality to upper layer for warpdrive.
4243 */
4244 if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
Kashyap, Desai3ed21522010-02-17 16:08:36 +05304245 sas_is_tlr_enabled(scmd->device) &&
Kashyap, Desai84f0b042009-12-16 18:56:28 +05304246 response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
4247 sas_disable_tlr(scmd->device);
4248 sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
4249 }
Eric Moore635374e2009-03-09 01:21:12 -06004250 }
4251
4252 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
4253 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
4254 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
4255 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
4256 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
4257 else
4258 log_info = 0;
4259 ioc_status &= MPI2_IOCSTATUS_MASK;
Eric Moore635374e2009-03-09 01:21:12 -06004260 scsi_status = mpi_reply->SCSIStatus;
4261
4262 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
4263 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
4264 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
4265 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
4266 ioc_status = MPI2_IOCSTATUS_SUCCESS;
4267 }
4268
4269 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
4270 struct sense_info data;
4271 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
4272 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06004273 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06004274 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06004275 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06004276 _scsih_normalize_sense(scmd->sense_buffer, &data);
4277 /* failure prediction threshold exceeded */
4278 if (data.asc == 0x5D)
4279 _scsih_smart_predicted_fault(ioc,
4280 le16_to_cpu(mpi_reply->DevHandle));
4281 }
4282
4283 switch (ioc_status) {
4284 case MPI2_IOCSTATUS_BUSY:
4285 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
4286 scmd->result = SAM_STAT_BUSY;
4287 break;
4288
4289 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
4290 scmd->result = DID_NO_CONNECT << 16;
4291 break;
4292
4293 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
4294 if (sas_device_priv_data->block) {
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05304295 scmd->result = DID_TRANSPORT_DISRUPTED << 16;
4296 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06004297 }
Eric Moore635374e2009-03-09 01:21:12 -06004298 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
4299 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
4300 scmd->result = DID_RESET << 16;
4301 break;
4302
4303 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
4304 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
4305 scmd->result = DID_SOFT_ERROR << 16;
4306 else
4307 scmd->result = (DID_OK << 16) | scsi_status;
4308 break;
4309
4310 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
4311 scmd->result = (DID_OK << 16) | scsi_status;
4312
4313 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
4314 break;
4315
4316 if (xfer_cnt < scmd->underflow) {
4317 if (scsi_status == SAM_STAT_BUSY)
4318 scmd->result = SAM_STAT_BUSY;
4319 else
4320 scmd->result = DID_SOFT_ERROR << 16;
4321 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
4322 MPI2_SCSI_STATE_NO_SCSI_STATUS))
4323 scmd->result = DID_SOFT_ERROR << 16;
4324 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
4325 scmd->result = DID_RESET << 16;
4326 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
4327 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
4328 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
4329 scmd->result = (DRIVER_SENSE << 24) |
4330 SAM_STAT_CHECK_CONDITION;
4331 scmd->sense_buffer[0] = 0x70;
4332 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
4333 scmd->sense_buffer[12] = 0x20;
4334 scmd->sense_buffer[13] = 0;
4335 }
4336 break;
4337
4338 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
4339 scsi_set_resid(scmd, 0);
4340 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
4341 case MPI2_IOCSTATUS_SUCCESS:
4342 scmd->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9982f592009-09-23 17:23:07 +05304343 if (response_code ==
4344 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
4345 (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
4346 MPI2_SCSI_STATE_NO_SCSI_STATUS)))
Eric Moore635374e2009-03-09 01:21:12 -06004347 scmd->result = DID_SOFT_ERROR << 16;
4348 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
4349 scmd->result = DID_RESET << 16;
4350 break;
4351
Eric Moore3c621b32009-05-18 12:59:41 -06004352 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
4353 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
4354 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
4355 _scsih_eedp_error_handling(scmd, ioc_status);
4356 break;
Eric Moore635374e2009-03-09 01:21:12 -06004357 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
4358 case MPI2_IOCSTATUS_INVALID_FUNCTION:
4359 case MPI2_IOCSTATUS_INVALID_SGL:
4360 case MPI2_IOCSTATUS_INTERNAL_ERROR:
4361 case MPI2_IOCSTATUS_INVALID_FIELD:
4362 case MPI2_IOCSTATUS_INVALID_STATE:
4363 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
4364 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
4365 default:
4366 scmd->result = DID_SOFT_ERROR << 16;
4367 break;
4368
4369 }
4370
4371#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4372 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
4373 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
4374#endif
4375
4376 out:
4377 scsi_dma_unmap(scmd);
4378 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304379 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06004380}
4381
4382/**
Eric Moore635374e2009-03-09 01:21:12 -06004383 * _scsih_sas_host_refresh - refreshing sas host object contents
4384 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06004385 * Context: user
4386 *
4387 * During port enable, fw will send topology events for every device. Its
4388 * possible that the handles may change from the previous setting, so this
4389 * code keeping handles updating if changed.
4390 *
4391 * Return nothing.
4392 */
4393static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304394_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06004395{
4396 u16 sz;
4397 u16 ioc_status;
4398 int i;
4399 Mpi2ConfigReply_t mpi_reply;
4400 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304401 u16 attached_handle;
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304402 u8 link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06004403
4404 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
4405 "updating handles for sas_host(0x%016llx)\n",
4406 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
4407
4408 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
4409 * sizeof(Mpi2SasIOUnit0PhyData_t));
4410 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
4411 if (!sas_iounit_pg0) {
4412 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4413 ioc->name, __FILE__, __LINE__, __func__);
4414 return;
4415 }
Eric Moore635374e2009-03-09 01:21:12 -06004416
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304417 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
4418 sas_iounit_pg0, sz)) != 0)
4419 goto out;
4420 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
4421 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
4422 goto out;
4423 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304424 link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304425 if (i == 0)
4426 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
4427 PhyData[0].ControllerDevHandle);
4428 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
4429 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
4430 AttachedDevHandle);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304431 if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
4432 link_rate = MPI2_SAS_NEG_LINK_RATE_1_5;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304433 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304434 attached_handle, i, link_rate);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304435 }
Eric Moore635374e2009-03-09 01:21:12 -06004436 out:
4437 kfree(sas_iounit_pg0);
4438}
4439
4440/**
4441 * _scsih_sas_host_add - create sas host object
4442 * @ioc: per adapter object
4443 *
4444 * Creating host side data object, stored in ioc->sas_hba
4445 *
4446 * Return nothing.
4447 */
4448static void
4449_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
4450{
4451 int i;
4452 Mpi2ConfigReply_t mpi_reply;
4453 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
4454 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
4455 Mpi2SasPhyPage0_t phy_pg0;
4456 Mpi2SasDevicePage0_t sas_device_pg0;
4457 Mpi2SasEnclosurePage0_t enclosure_pg0;
4458 u16 ioc_status;
4459 u16 sz;
4460 u16 device_missing_delay;
4461
4462 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
4463 if (!ioc->sas_hba.num_phys) {
4464 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4465 ioc->name, __FILE__, __LINE__, __func__);
4466 return;
4467 }
4468
4469 /* sas_iounit page 0 */
4470 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
4471 sizeof(Mpi2SasIOUnit0PhyData_t));
4472 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
4473 if (!sas_iounit_pg0) {
4474 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4475 ioc->name, __FILE__, __LINE__, __func__);
4476 return;
4477 }
4478 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
4479 sas_iounit_pg0, sz))) {
4480 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4481 ioc->name, __FILE__, __LINE__, __func__);
4482 goto out;
4483 }
4484 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4485 MPI2_IOCSTATUS_MASK;
4486 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4487 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4488 ioc->name, __FILE__, __LINE__, __func__);
4489 goto out;
4490 }
4491
4492 /* sas_iounit page 1 */
4493 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
4494 sizeof(Mpi2SasIOUnit1PhyData_t));
4495 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
4496 if (!sas_iounit_pg1) {
4497 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4498 ioc->name, __FILE__, __LINE__, __func__);
4499 goto out;
4500 }
4501 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
4502 sas_iounit_pg1, sz))) {
4503 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4504 ioc->name, __FILE__, __LINE__, __func__);
4505 goto out;
4506 }
4507 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4508 MPI2_IOCSTATUS_MASK;
4509 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4510 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4511 ioc->name, __FILE__, __LINE__, __func__);
4512 goto out;
4513 }
4514
4515 ioc->io_missing_delay =
4516 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
4517 device_missing_delay =
4518 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
4519 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
4520 ioc->device_missing_delay = (device_missing_delay &
4521 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
4522 else
4523 ioc->device_missing_delay = device_missing_delay &
4524 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
4525
4526 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
4527 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
4528 sizeof(struct _sas_phy), GFP_KERNEL);
4529 if (!ioc->sas_hba.phy) {
4530 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4531 ioc->name, __FILE__, __LINE__, __func__);
4532 goto out;
4533 }
4534 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
4535 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
4536 i))) {
4537 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4538 ioc->name, __FILE__, __LINE__, __func__);
4539 goto out;
4540 }
4541 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4542 MPI2_IOCSTATUS_MASK;
4543 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4544 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4545 ioc->name, __FILE__, __LINE__, __func__);
4546 goto out;
4547 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304548
4549 if (i == 0)
4550 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
4551 PhyData[0].ControllerDevHandle);
4552 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06004553 ioc->sas_hba.phy[i].phy_id = i;
4554 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
4555 phy_pg0, ioc->sas_hba.parent_dev);
4556 }
4557 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304558 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06004559 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4560 ioc->name, __FILE__, __LINE__, __func__);
4561 goto out;
4562 }
Eric Moore635374e2009-03-09 01:21:12 -06004563 ioc->sas_hba.enclosure_handle =
4564 le16_to_cpu(sas_device_pg0.EnclosureHandle);
4565 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4566 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
4567 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
4568 (unsigned long long) ioc->sas_hba.sas_address,
4569 ioc->sas_hba.num_phys) ;
4570
4571 if (ioc->sas_hba.enclosure_handle) {
4572 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
4573 &enclosure_pg0,
4574 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4575 ioc->sas_hba.enclosure_handle))) {
4576 ioc->sas_hba.enclosure_logical_id =
4577 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
4578 }
4579 }
4580
4581 out:
4582 kfree(sas_iounit_pg1);
4583 kfree(sas_iounit_pg0);
4584}
4585
4586/**
4587 * _scsih_expander_add - creating expander object
4588 * @ioc: per adapter object
4589 * @handle: expander handle
4590 *
4591 * Creating expander object, stored in ioc->sas_expander_list.
4592 *
4593 * Return 0 for success, else error.
4594 */
4595static int
4596_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4597{
4598 struct _sas_node *sas_expander;
4599 Mpi2ConfigReply_t mpi_reply;
4600 Mpi2ExpanderPage0_t expander_pg0;
4601 Mpi2ExpanderPage1_t expander_pg1;
4602 Mpi2SasEnclosurePage0_t enclosure_pg0;
4603 u32 ioc_status;
4604 u16 parent_handle;
Kashyap, Desaic97951e2011-06-14 10:54:56 +05304605 u64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004606 int i;
4607 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05304608 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06004609 int rc = 0;
4610
4611 if (!handle)
4612 return -1;
4613
Eric Moore3cb54692010-07-08 14:44:34 -06004614 if (ioc->shost_recovery || ioc->pci_error_recovery)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304615 return -1;
4616
Eric Moore635374e2009-03-09 01:21:12 -06004617 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
4618 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
4619 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4620 ioc->name, __FILE__, __LINE__, __func__);
4621 return -1;
4622 }
4623
4624 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4625 MPI2_IOCSTATUS_MASK;
4626 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4627 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4628 ioc->name, __FILE__, __LINE__, __func__);
4629 return -1;
4630 }
4631
4632 /* handle out of order topology events */
4633 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304634 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
4635 != 0) {
4636 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4637 ioc->name, __FILE__, __LINE__, __func__);
4638 return -1;
4639 }
4640 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06004641 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304642 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
4643 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004644 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4645 if (!sas_expander) {
4646 rc = _scsih_expander_add(ioc, parent_handle);
4647 if (rc != 0)
4648 return rc;
4649 }
4650 }
4651
Eric Moore635374e2009-03-09 01:21:12 -06004652 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304653 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06004654 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
4655 sas_address);
4656 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4657
4658 if (sas_expander)
4659 return 0;
4660
4661 sas_expander = kzalloc(sizeof(struct _sas_node),
4662 GFP_KERNEL);
4663 if (!sas_expander) {
4664 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4665 ioc->name, __FILE__, __LINE__, __func__);
4666 return -1;
4667 }
4668
4669 sas_expander->handle = handle;
4670 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304671 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06004672 sas_expander->sas_address = sas_address;
4673
4674 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
4675 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304676 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06004677 sas_expander->sas_address, sas_expander->num_phys);
4678
4679 if (!sas_expander->num_phys)
4680 goto out_fail;
4681 sas_expander->phy = kcalloc(sas_expander->num_phys,
4682 sizeof(struct _sas_phy), GFP_KERNEL);
4683 if (!sas_expander->phy) {
4684 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4685 ioc->name, __FILE__, __LINE__, __func__);
4686 rc = -1;
4687 goto out_fail;
4688 }
4689
4690 INIT_LIST_HEAD(&sas_expander->sas_port_list);
4691 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304692 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004693 if (!mpt2sas_port) {
4694 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4695 ioc->name, __FILE__, __LINE__, __func__);
4696 rc = -1;
4697 goto out_fail;
4698 }
4699 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
4700
4701 for (i = 0 ; i < sas_expander->num_phys ; i++) {
4702 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
4703 &expander_pg1, i, handle))) {
4704 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4705 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05304706 rc = -1;
4707 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06004708 }
4709 sas_expander->phy[i].handle = handle;
4710 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05304711
4712 if ((mpt2sas_transport_add_expander_phy(ioc,
4713 &sas_expander->phy[i], expander_pg1,
4714 sas_expander->parent_dev))) {
4715 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4716 ioc->name, __FILE__, __LINE__, __func__);
4717 rc = -1;
4718 goto out_fail;
4719 }
Eric Moore635374e2009-03-09 01:21:12 -06004720 }
4721
4722 if (sas_expander->enclosure_handle) {
4723 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
4724 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4725 sas_expander->enclosure_handle))) {
4726 sas_expander->enclosure_logical_id =
4727 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
4728 }
4729 }
4730
4731 _scsih_expander_node_add(ioc, sas_expander);
4732 return 0;
4733
4734 out_fail:
4735
Kashyap, Desai20f58952009-08-07 19:34:26 +05304736 if (mpt2sas_port)
4737 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304738 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004739 kfree(sas_expander);
4740 return rc;
4741}
4742
4743/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05304744 * _scsih_done - scsih callback handler.
4745 * @ioc: per adapter object
4746 * @smid: system request message index
4747 * @msix_index: MSIX table index supplied by the OS
4748 * @reply: reply message frame(lower 32bit addr)
4749 *
4750 * Callback handler when sending internal generated message frames.
4751 * The callback index passed is `ioc->scsih_cb_idx`
4752 *
4753 * Return 1 meaning mf should be freed from _base_interrupt
4754 * 0 means the mf is freed from this function.
4755 */
4756static u8
4757_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
4758{
4759 MPI2DefaultReply_t *mpi_reply;
4760
4761 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
4762 if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
4763 return 1;
4764 if (ioc->scsih_cmds.smid != smid)
4765 return 1;
4766 ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
4767 if (mpi_reply) {
4768 memcpy(ioc->scsih_cmds.reply, mpi_reply,
4769 mpi_reply->MsgLength*4);
4770 ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
4771 }
4772 ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
4773 complete(&ioc->scsih_cmds.done);
4774 return 1;
4775}
4776
4777/**
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304778 * mpt2sas_expander_remove - removing expander object
Eric Moore635374e2009-03-09 01:21:12 -06004779 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304780 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06004781 *
4782 * Return nothing.
4783 */
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304784void
4785mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06004786{
4787 struct _sas_node *sas_expander;
4788 unsigned long flags;
4789
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304790 if (ioc->shost_recovery)
4791 return;
4792
Eric Moore635374e2009-03-09 01:21:12 -06004793 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304794 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
4795 sas_address);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304796 if (!sas_expander) {
4797 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4798 return;
4799 }
4800 list_del(&sas_expander->list);
Eric Moore635374e2009-03-09 01:21:12 -06004801 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4802 _scsih_expander_node_remove(ioc, sas_expander);
4803}
4804
4805/**
Kashyap, Desaib4344272010-03-17 16:24:14 +05304806 * _scsih_check_access_status - check access flags
4807 * @ioc: per adapter object
4808 * @sas_address: sas address
4809 * @handle: sas device handle
4810 * @access_flags: errors returned during discovery of the device
4811 *
4812 * Return 0 for success, else failure
4813 */
4814static u8
4815_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
4816 u16 handle, u8 access_status)
4817{
4818 u8 rc = 1;
4819 char *desc = NULL;
4820
4821 switch (access_status) {
4822 case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS:
4823 case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION:
4824 rc = 0;
4825 break;
4826 case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED:
4827 desc = "sata capability failed";
4828 break;
4829 case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT:
4830 desc = "sata affiliation conflict";
4831 break;
4832 case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE:
4833 desc = "route not addressable";
4834 break;
4835 case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE:
4836 desc = "smp error not addressable";
4837 break;
4838 case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED:
4839 desc = "device blocked";
4840 break;
4841 case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED:
4842 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN:
4843 case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT:
4844 case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG:
4845 case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION:
4846 case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER:
4847 case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN:
4848 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN:
4849 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN:
4850 case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION:
4851 case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE:
4852 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX:
4853 desc = "sata initialization failed";
4854 break;
4855 default:
4856 desc = "unknown";
4857 break;
4858 }
4859
4860 if (!rc)
4861 return 0;
4862
4863 printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), "
4864 "handle(0x%04x)\n", ioc->name, desc,
4865 (unsigned long long)sas_address, handle);
4866 return rc;
4867}
4868
4869static void
4870_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4871{
4872 Mpi2ConfigReply_t mpi_reply;
4873 Mpi2SasDevicePage0_t sas_device_pg0;
4874 struct _sas_device *sas_device;
4875 u32 ioc_status;
4876 unsigned long flags;
4877 u64 sas_address;
4878 struct scsi_target *starget;
4879 struct MPT2SAS_TARGET *sas_target_priv_data;
4880 u32 device_info;
4881
4882 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4883 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
4884 return;
4885
4886 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
4887 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
4888 return;
4889
4890 /* check if this is end device */
4891 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4892 if (!(_scsih_is_end_device(device_info)))
4893 return;
4894
4895 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4896 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4897 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4898 sas_address);
4899
4900 if (!sas_device) {
4901 printk(MPT2SAS_ERR_FMT "device is not present "
4902 "handle(0x%04x), no sas_device!!!\n", ioc->name, handle);
4903 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4904 return;
4905 }
4906
4907 if (unlikely(sas_device->handle != handle)) {
4908 starget = sas_device->starget;
4909 sas_target_priv_data = starget->hostdata;
4910 starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)"
4911 " to (0x%04x)!!!\n", sas_device->handle, handle);
4912 sas_target_priv_data->handle = handle;
4913 sas_device->handle = handle;
4914 }
4915 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4916
4917 /* check if device is present */
4918 if (!(le16_to_cpu(sas_device_pg0.Flags) &
4919 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
4920 printk(MPT2SAS_ERR_FMT "device is not present "
4921 "handle(0x%04x), flags!!!\n", ioc->name, handle);
4922 return;
4923 }
4924
4925 /* check if there were any issues with discovery */
4926 if (_scsih_check_access_status(ioc, sas_address, handle,
4927 sas_device_pg0.AccessStatus))
4928 return;
4929 _scsih_ublock_io_device(ioc, handle);
4930
4931}
4932
4933/**
Eric Moore635374e2009-03-09 01:21:12 -06004934 * _scsih_add_device - creating sas device object
4935 * @ioc: per adapter object
4936 * @handle: sas device handle
4937 * @phy_num: phy number end device attached to
4938 * @is_pd: is this hidden raid component
4939 *
4940 * Creating end device object, stored in ioc->sas_device_list.
4941 *
4942 * Returns 0 for success, non-zero for failure.
4943 */
4944static int
4945_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
4946{
4947 Mpi2ConfigReply_t mpi_reply;
4948 Mpi2SasDevicePage0_t sas_device_pg0;
4949 Mpi2SasEnclosurePage0_t enclosure_pg0;
4950 struct _sas_device *sas_device;
4951 u32 ioc_status;
4952 __le64 sas_address;
4953 u32 device_info;
4954 unsigned long flags;
4955
4956 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4957 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4958 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4959 ioc->name, __FILE__, __LINE__, __func__);
4960 return -1;
4961 }
4962
4963 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4964 MPI2_IOCSTATUS_MASK;
4965 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4966 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4967 ioc->name, __FILE__, __LINE__, __func__);
4968 return -1;
4969 }
4970
Kashyap, Desaib4344272010-03-17 16:24:14 +05304971 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4972
Eric Moore635374e2009-03-09 01:21:12 -06004973 /* check if device is present */
4974 if (!(le16_to_cpu(sas_device_pg0.Flags) &
4975 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
4976 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4977 ioc->name, __FILE__, __LINE__, __func__);
4978 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
4979 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
4980 return -1;
4981 }
4982
Kashyap, Desaib4344272010-03-17 16:24:14 +05304983 /* check if there were any issues with discovery */
4984 if (_scsih_check_access_status(ioc, sas_address, handle,
4985 sas_device_pg0.AccessStatus))
Eric Moore635374e2009-03-09 01:21:12 -06004986 return -1;
Eric Moore635374e2009-03-09 01:21:12 -06004987
4988 /* check if this is end device */
4989 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4990 if (!(_scsih_is_end_device(device_info))) {
4991 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4992 ioc->name, __FILE__, __LINE__, __func__);
4993 return -1;
4994 }
4995
Eric Moore635374e2009-03-09 01:21:12 -06004996
4997 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4998 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4999 sas_address);
5000 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5001
Kashyap, Desaib4344272010-03-17 16:24:14 +05305002 if (sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06005003 return 0;
Eric Moore635374e2009-03-09 01:21:12 -06005004
5005 sas_device = kzalloc(sizeof(struct _sas_device),
5006 GFP_KERNEL);
5007 if (!sas_device) {
5008 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5009 ioc->name, __FILE__, __LINE__, __func__);
5010 return -1;
5011 }
5012
5013 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305014 if (_scsih_get_sas_address(ioc, le16_to_cpu
5015 (sas_device_pg0.ParentDevHandle),
5016 &sas_device->sas_address_parent) != 0)
5017 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5018 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06005019 sas_device->enclosure_handle =
5020 le16_to_cpu(sas_device_pg0.EnclosureHandle);
5021 sas_device->slot =
5022 le16_to_cpu(sas_device_pg0.Slot);
5023 sas_device->device_info = device_info;
5024 sas_device->sas_address = sas_address;
Kashyap, Desai7fbae672010-06-17 13:45:17 +05305025 sas_device->phy = sas_device_pg0.PhyNum;
Eric Moore635374e2009-03-09 01:21:12 -06005026
5027 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05305028 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
5029 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
5030 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06005031 sas_device->enclosure_logical_id =
5032 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06005033
5034 /* get device name */
5035 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
5036
5037 if (ioc->wait_for_port_enable_to_complete)
5038 _scsih_sas_device_init_add(ioc, sas_device);
5039 else
5040 _scsih_sas_device_add(ioc, sas_device);
5041
5042 return 0;
5043}
5044
5045/**
Kashyap, Desai1278b112010-03-09 17:34:13 +05305046 * _scsih_remove_device - removing sas device object
5047 * @ioc: per adapter object
5048 * @sas_device_delete: the sas_device object
5049 *
5050 * Return nothing.
5051 */
5052static void
5053_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
5054 struct _sas_device *sas_device)
5055{
5056 struct _sas_device sas_device_backup;
5057 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05305058
Kashyap, Desai1278b112010-03-09 17:34:13 +05305059 if (!sas_device)
5060 return;
Eric Moore635374e2009-03-09 01:21:12 -06005061
Kashyap, Desai1278b112010-03-09 17:34:13 +05305062 memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));
Eric Moore635374e2009-03-09 01:21:12 -06005063 _scsih_sas_device_remove(ioc, sas_device);
5064
Kashyap, Desai1278b112010-03-09 17:34:13 +05305065 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
5066 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
5067 sas_device_backup.handle, (unsigned long long)
5068 sas_device_backup.sas_address));
5069
5070 if (sas_device_backup.starget && sas_device_backup.starget->hostdata) {
5071 sas_target_priv_data = sas_device_backup.starget->hostdata;
5072 sas_target_priv_data->deleted = 1;
5073 }
5074
Kashyap, Desai1278b112010-03-09 17:34:13 +05305075 _scsih_ublock_io_device(ioc, sas_device_backup.handle);
5076
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05305077 if (!ioc->hide_drives)
5078 mpt2sas_transport_port_remove(ioc,
5079 sas_device_backup.sas_address,
5080 sas_device_backup.sas_address_parent);
Kashyap, Desai1278b112010-03-09 17:34:13 +05305081
5082 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
5083 "(0x%016llx)\n", ioc->name, sas_device_backup.handle,
5084 (unsigned long long) sas_device_backup.sas_address);
5085
5086 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
5087 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
5088 sas_device_backup.handle, (unsigned long long)
5089 sas_device_backup.sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06005090}
5091
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305092/**
5093 * mpt2sas_device_remove - removing device object
5094 * @ioc: per adapter object
5095 * @sas_address: expander sas_address
5096 *
5097 * Return nothing.
5098 */
5099void
5100mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
5101{
5102 struct _sas_device *sas_device;
5103 unsigned long flags;
5104
5105 if (ioc->shost_recovery)
5106 return;
5107
5108 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5109 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5110 sas_address);
5111 if (!sas_device) {
5112 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5113 return;
5114 }
5115 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5116 _scsih_remove_device(ioc, sas_device);
5117}
5118
Eric Moore635374e2009-03-09 01:21:12 -06005119#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5120/**
5121 * _scsih_sas_topology_change_event_debug - debug for topology event
5122 * @ioc: per adapter object
5123 * @event_data: event data payload
5124 * Context: user.
5125 */
5126static void
5127_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5128 Mpi2EventDataSasTopologyChangeList_t *event_data)
5129{
5130 int i;
5131 u16 handle;
5132 u16 reason_code;
5133 u8 phy_number;
5134 char *status_str = NULL;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305135 u8 link_rate, prev_link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06005136
5137 switch (event_data->ExpStatus) {
5138 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
5139 status_str = "add";
5140 break;
5141 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
5142 status_str = "remove";
5143 break;
5144 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305145 case 0:
Eric Moore635374e2009-03-09 01:21:12 -06005146 status_str = "responding";
5147 break;
5148 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
5149 status_str = "remove delay";
5150 break;
5151 default:
5152 status_str = "unknown status";
5153 break;
5154 }
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305155 printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n",
Eric Moore635374e2009-03-09 01:21:12 -06005156 ioc->name, status_str);
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305157 printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) "
Eric Moore635374e2009-03-09 01:21:12 -06005158 "start_phy(%02d), count(%d)\n",
5159 le16_to_cpu(event_data->ExpanderDevHandle),
5160 le16_to_cpu(event_data->EnclosureHandle),
5161 event_data->StartPhyNum, event_data->NumEntries);
5162 for (i = 0; i < event_data->NumEntries; i++) {
5163 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
5164 if (!handle)
5165 continue;
5166 phy_number = event_data->StartPhyNum + i;
5167 reason_code = event_data->PHY[i].PhyStatus &
5168 MPI2_EVENT_SAS_TOPO_RC_MASK;
5169 switch (reason_code) {
5170 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305171 status_str = "target add";
Eric Moore635374e2009-03-09 01:21:12 -06005172 break;
5173 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305174 status_str = "target remove";
Eric Moore635374e2009-03-09 01:21:12 -06005175 break;
5176 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305177 status_str = "delay target remove";
Eric Moore635374e2009-03-09 01:21:12 -06005178 break;
5179 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305180 status_str = "link rate change";
Eric Moore635374e2009-03-09 01:21:12 -06005181 break;
5182 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305183 status_str = "target responding";
Eric Moore635374e2009-03-09 01:21:12 -06005184 break;
5185 default:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305186 status_str = "unknown";
Eric Moore635374e2009-03-09 01:21:12 -06005187 break;
5188 }
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305189 link_rate = event_data->PHY[i].LinkRate >> 4;
5190 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305191 printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:"
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305192 " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
5193 handle, status_str, link_rate, prev_link_rate);
5194
Eric Moore635374e2009-03-09 01:21:12 -06005195 }
5196}
5197#endif
5198
5199/**
5200 * _scsih_sas_topology_change_event - handle topology changes
5201 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305202 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005203 * Context: user.
5204 *
5205 */
5206static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305207_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06005208 struct fw_event_work *fw_event)
5209{
5210 int i;
5211 u16 parent_handle, handle;
5212 u16 reason_code;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305213 u8 phy_number, max_phys;
Eric Moore635374e2009-03-09 01:21:12 -06005214 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305215 struct _sas_device *sas_device;
5216 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06005217 unsigned long flags;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305218 u8 link_rate, prev_link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305219 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005220
5221#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5222 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5223 _scsih_sas_topology_change_event_debug(ioc, event_data);
5224#endif
5225
Eric Moore3cb54692010-07-08 14:44:34 -06005226 if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery)
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305227 return;
5228
Eric Moore635374e2009-03-09 01:21:12 -06005229 if (!ioc->sas_hba.num_phys)
5230 _scsih_sas_host_add(ioc);
5231 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305232 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005233
5234 if (fw_event->ignore) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305235 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander "
Eric Moore635374e2009-03-09 01:21:12 -06005236 "event\n", ioc->name));
5237 return;
5238 }
5239
5240 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
5241
5242 /* handle expander add */
5243 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
5244 if (_scsih_expander_add(ioc, parent_handle) != 0)
5245 return;
5246
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305247 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5248 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
5249 parent_handle);
5250 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305251 if (sas_expander) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305252 sas_address = sas_expander->sas_address;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305253 max_phys = sas_expander->num_phys;
5254 } else if (parent_handle < ioc->sas_hba.num_phys) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305255 sas_address = ioc->sas_hba.sas_address;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305256 max_phys = ioc->sas_hba.num_phys;
5257 } else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305258 return;
5259
Eric Moore635374e2009-03-09 01:21:12 -06005260 /* handle siblings events */
5261 for (i = 0; i < event_data->NumEntries; i++) {
5262 if (fw_event->ignore) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305263 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring "
Eric Moore635374e2009-03-09 01:21:12 -06005264 "expander event\n", ioc->name));
5265 return;
5266 }
Eric Moore3cb54692010-07-08 14:44:34 -06005267 if (ioc->shost_recovery || ioc->remove_host ||
5268 ioc->pci_error_recovery)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305269 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05305270 phy_number = event_data->StartPhyNum + i;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305271 if (phy_number >= max_phys)
5272 continue;
Kashyap, Desai308609c2009-09-14 11:07:23 +05305273 reason_code = event_data->PHY[i].PhyStatus &
5274 MPI2_EVENT_SAS_TOPO_RC_MASK;
5275 if ((event_data->PHY[i].PhyStatus &
5276 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
5277 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06005278 continue;
5279 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
5280 if (!handle)
5281 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305282 link_rate = event_data->PHY[i].LinkRate >> 4;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305283 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Eric Moore635374e2009-03-09 01:21:12 -06005284 switch (reason_code) {
5285 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305286
5287 if (link_rate == prev_link_rate)
5288 break;
5289
5290 mpt2sas_transport_update_links(ioc, sas_address,
5291 handle, phy_number, link_rate);
5292
Kashyap, Desaib4344272010-03-17 16:24:14 +05305293 if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
5294 break;
5295
5296 _scsih_check_device(ioc, handle);
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305297 break;
Eric Moore635374e2009-03-09 01:21:12 -06005298 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305299
5300 mpt2sas_transport_update_links(ioc, sas_address,
5301 handle, phy_number, link_rate);
5302
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305303 _scsih_add_device(ioc, handle, phy_number, 0);
Eric Moore635374e2009-03-09 01:21:12 -06005304 break;
5305 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305306
5307 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5308 sas_device = _scsih_sas_device_find_by_handle(ioc,
5309 handle);
5310 if (!sas_device) {
5311 spin_unlock_irqrestore(&ioc->sas_device_lock,
5312 flags);
5313 break;
5314 }
5315 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5316 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005317 break;
5318 }
5319 }
5320
5321 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305322 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
5323 sas_expander)
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305324 mpt2sas_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06005325
5326}
5327
5328#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5329/**
5330 * _scsih_sas_device_status_change_event_debug - debug for device event
5331 * @event_data: event data payload
5332 * Context: user.
5333 *
5334 * Return nothing.
5335 */
5336static void
5337_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5338 Mpi2EventDataSasDeviceStatusChange_t *event_data)
5339{
5340 char *reason_str = NULL;
5341
5342 switch (event_data->ReasonCode) {
5343 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
5344 reason_str = "smart data";
5345 break;
5346 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
5347 reason_str = "unsupported device discovered";
5348 break;
5349 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
5350 reason_str = "internal device reset";
5351 break;
5352 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
5353 reason_str = "internal task abort";
5354 break;
5355 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
5356 reason_str = "internal task abort set";
5357 break;
5358 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
5359 reason_str = "internal clear task set";
5360 break;
5361 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
5362 reason_str = "internal query task";
5363 break;
5364 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
5365 reason_str = "sata init failure";
5366 break;
5367 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
5368 reason_str = "internal device reset complete";
5369 break;
5370 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
5371 reason_str = "internal task abort complete";
5372 break;
5373 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
5374 reason_str = "internal async notification";
5375 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305376 case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
5377 reason_str = "expander reduced functionality";
5378 break;
5379 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
5380 reason_str = "expander reduced functionality complete";
5381 break;
Eric Moore635374e2009-03-09 01:21:12 -06005382 default:
5383 reason_str = "unknown reason";
5384 break;
5385 }
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305386 printk(MPT2SAS_INFO_FMT "device status change: (%s)\n"
Eric Moore635374e2009-03-09 01:21:12 -06005387 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
5388 reason_str, le16_to_cpu(event_data->DevHandle),
5389 (unsigned long long)le64_to_cpu(event_data->SASAddress));
5390 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305391 printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
Eric Moore635374e2009-03-09 01:21:12 -06005392 event_data->ASC, event_data->ASCQ);
5393 printk(KERN_INFO "\n");
5394}
5395#endif
5396
5397/**
5398 * _scsih_sas_device_status_change_event - handle device status change
5399 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305400 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005401 * Context: user.
5402 *
5403 * Return nothing.
5404 */
5405static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305406_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
5407 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005408{
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305409 struct MPT2SAS_TARGET *target_priv_data;
5410 struct _sas_device *sas_device;
Kashyap, Desaic97951e2011-06-14 10:54:56 +05305411 u64 sas_address;
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305412 unsigned long flags;
5413 Mpi2EventDataSasDeviceStatusChange_t *event_data =
5414 fw_event->event_data;
5415
Eric Moore635374e2009-03-09 01:21:12 -06005416#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5417 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305418 _scsih_sas_device_status_change_event_debug(ioc,
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305419 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005420#endif
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305421
Kashyap, Desaiefe82a12011-01-04 11:34:17 +05305422 /* In MPI Revision K (0xC), the internal device reset complete was
5423 * implemented, so avoid setting tm_busy flag for older firmware.
5424 */
5425 if ((ioc->facts.HeaderVersion >> 8) < 0xC)
5426 return;
5427
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05305428 if (event_data->ReasonCode !=
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305429 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05305430 event_data->ReasonCode !=
5431 MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305432 return;
5433
5434 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5435 sas_address = le64_to_cpu(event_data->SASAddress);
5436 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5437 sas_address);
5438 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5439
5440 if (!sas_device || !sas_device->starget)
5441 return;
5442
5443 target_priv_data = sas_device->starget->hostdata;
5444 if (!target_priv_data)
5445 return;
5446
5447 if (event_data->ReasonCode ==
5448 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
5449 target_priv_data->tm_busy = 1;
5450 else
5451 target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06005452}
5453
5454#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5455/**
5456 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
5457 * @ioc: per adapter object
5458 * @event_data: event data payload
5459 * Context: user.
5460 *
5461 * Return nothing.
5462 */
5463static void
5464_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5465 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
5466{
5467 char *reason_str = NULL;
5468
5469 switch (event_data->ReasonCode) {
5470 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
5471 reason_str = "enclosure add";
5472 break;
5473 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
5474 reason_str = "enclosure remove";
5475 break;
5476 default:
5477 reason_str = "unknown reason";
5478 break;
5479 }
5480
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305481 printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n"
Eric Moore635374e2009-03-09 01:21:12 -06005482 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
5483 " number slots(%d)\n", ioc->name, reason_str,
5484 le16_to_cpu(event_data->EnclosureHandle),
5485 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
5486 le16_to_cpu(event_data->StartSlot));
5487}
5488#endif
5489
5490/**
5491 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
5492 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305493 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005494 * Context: user.
5495 *
5496 * Return nothing.
5497 */
5498static void
5499_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305500 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005501{
5502#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5503 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5504 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305505 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005506#endif
5507}
5508
5509/**
5510 * _scsih_sas_broadcast_primative_event - handle broadcast events
5511 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305512 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005513 * Context: user.
5514 *
5515 * Return nothing.
5516 */
5517static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305518_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
5519 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005520{
5521 struct scsi_cmnd *scmd;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305522 struct scsi_device *sdev;
Eric Moore635374e2009-03-09 01:21:12 -06005523 u16 smid, handle;
5524 u32 lun;
5525 struct MPT2SAS_DEVICE *sas_device_priv_data;
5526 u32 termination_count;
5527 u32 query_count;
5528 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305529#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5530 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
5531#endif
Kashyap, Desai463217b2009-10-05 15:53:06 +05305532 u16 ioc_status;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305533 unsigned long flags;
5534 int r;
5535
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005536 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primitive: "
Eric Moore635374e2009-03-09 01:21:12 -06005537 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
5538 event_data->PortWidth));
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305539 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
Eric Moore635374e2009-03-09 01:21:12 -06005540 __func__));
5541
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305542 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
5543 ioc->broadcast_aen_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06005544 termination_count = 0;
5545 query_count = 0;
5546 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05305547 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06005548 scmd = _scsih_scsi_lookup_get(ioc, smid);
5549 if (!scmd)
5550 continue;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305551 sdev = scmd->device;
5552 sas_device_priv_data = sdev->hostdata;
Eric Moore635374e2009-03-09 01:21:12 -06005553 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
5554 continue;
5555 /* skip hidden raid components */
5556 if (sas_device_priv_data->sas_target->flags &
5557 MPT_TARGET_FLAGS_RAID_COMPONENT)
5558 continue;
5559 /* skip volumes */
5560 if (sas_device_priv_data->sas_target->flags &
5561 MPT_TARGET_FLAGS_VOLUME)
5562 continue;
5563
5564 handle = sas_device_priv_data->sas_target->handle;
5565 lun = sas_device_priv_data->lun;
5566 query_count++;
5567
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305568 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05305569 mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
5570 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL);
Eric Moore8901cbb2009-04-21 15:41:32 -06005571 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Kashyap, Desai463217b2009-10-05 15:53:06 +05305572 ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
5573 & MPI2_IOCSTATUS_MASK;
5574 if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) &&
Eric Moore635374e2009-03-09 01:21:12 -06005575 (mpi_reply->ResponseCode ==
5576 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
5577 mpi_reply->ResponseCode ==
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305578 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) {
5579 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06005580 continue;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305581 }
5582 r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id,
5583 sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
5584 scmd);
5585 if (r == FAILED)
5586 sdev_printk(KERN_WARNING, sdev, "task abort: FAILED "
5587 "scmd(%p)\n", scmd);
Eric Moore635374e2009-03-09 01:21:12 -06005588 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305589 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06005590 }
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305591 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06005592
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305593 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -06005594 "%s - exit, query_count = %d termination_count = %d\n",
5595 ioc->name, __func__, query_count, termination_count));
5596}
5597
5598/**
5599 * _scsih_sas_discovery_event - handle discovery events
5600 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305601 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005602 * Context: user.
5603 *
5604 * Return nothing.
5605 */
5606static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305607_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
5608 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005609{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305610 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
5611
Eric Moore635374e2009-03-09 01:21:12 -06005612#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5613 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305614 printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name,
Eric Moore635374e2009-03-09 01:21:12 -06005615 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
5616 "start" : "stop");
5617 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05305618 printk("discovery_status(0x%08x)",
5619 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06005620 printk("\n");
5621 }
5622#endif
5623
5624 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
5625 !ioc->sas_hba.num_phys)
5626 _scsih_sas_host_add(ioc);
5627}
5628
5629/**
5630 * _scsih_reprobe_lun - reprobing lun
5631 * @sdev: scsi device struct
5632 * @no_uld_attach: sdev->no_uld_attach flag setting
5633 *
5634 **/
5635static void
5636_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
5637{
5638 int rc;
5639
5640 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
5641 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
5642 sdev->no_uld_attach ? "hidding" : "exposing");
5643 rc = scsi_device_reprobe(sdev);
5644}
5645
5646/**
5647 * _scsih_reprobe_target - reprobing target
5648 * @starget: scsi target struct
5649 * @no_uld_attach: sdev->no_uld_attach flag setting
5650 *
5651 * Note: no_uld_attach flag determines whether the disk device is attached
5652 * to block layer. A value of `1` means to not attach.
5653 **/
5654static void
5655_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
5656{
5657 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
5658
5659 if (no_uld_attach)
5660 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
5661 else
5662 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
5663
5664 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
5665 _scsih_reprobe_lun);
5666}
5667/**
5668 * _scsih_sas_volume_add - add new volume
5669 * @ioc: per adapter object
5670 * @element: IR config element data
5671 * Context: user.
5672 *
5673 * Return nothing.
5674 */
5675static void
5676_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
5677 Mpi2EventIrConfigElement_t *element)
5678{
5679 struct _raid_device *raid_device;
5680 unsigned long flags;
5681 u64 wwid;
5682 u16 handle = le16_to_cpu(element->VolDevHandle);
5683 int rc;
5684
Eric Moore635374e2009-03-09 01:21:12 -06005685 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
5686 if (!wwid) {
5687 printk(MPT2SAS_ERR_FMT
5688 "failure at %s:%d/%s()!\n", ioc->name,
5689 __FILE__, __LINE__, __func__);
5690 return;
5691 }
5692
5693 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5694 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
5695 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5696
5697 if (raid_device)
5698 return;
5699
5700 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
5701 if (!raid_device) {
5702 printk(MPT2SAS_ERR_FMT
5703 "failure at %s:%d/%s()!\n", ioc->name,
5704 __FILE__, __LINE__, __func__);
5705 return;
5706 }
5707
5708 raid_device->id = ioc->sas_id++;
5709 raid_device->channel = RAID_CHANNEL;
5710 raid_device->handle = handle;
5711 raid_device->wwid = wwid;
5712 _scsih_raid_device_add(ioc, raid_device);
5713 if (!ioc->wait_for_port_enable_to_complete) {
5714 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5715 raid_device->id, 0);
5716 if (rc)
5717 _scsih_raid_device_remove(ioc, raid_device);
5718 } else
5719 _scsih_determine_boot_device(ioc, raid_device, 1);
5720}
5721
5722/**
5723 * _scsih_sas_volume_delete - delete volume
5724 * @ioc: per adapter object
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305725 * @handle: volume device handle
Eric Moore635374e2009-03-09 01:21:12 -06005726 * Context: user.
5727 *
5728 * Return nothing.
5729 */
5730static void
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305731_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
Eric Moore635374e2009-03-09 01:21:12 -06005732{
5733 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06005734 unsigned long flags;
5735 struct MPT2SAS_TARGET *sas_target_priv_data;
5736
Eric Moore635374e2009-03-09 01:21:12 -06005737 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5738 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5739 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5740 if (!raid_device)
5741 return;
5742 if (raid_device->starget) {
5743 sas_target_priv_data = raid_device->starget->hostdata;
5744 sas_target_priv_data->deleted = 1;
5745 scsi_remove_target(&raid_device->starget->dev);
5746 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305747 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
5748 "(0x%016llx)\n", ioc->name, raid_device->handle,
5749 (unsigned long long) raid_device->wwid);
Eric Moore635374e2009-03-09 01:21:12 -06005750 _scsih_raid_device_remove(ioc, raid_device);
5751}
5752
5753/**
5754 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
5755 * @ioc: per adapter object
5756 * @element: IR config element data
5757 * Context: user.
5758 *
5759 * Return nothing.
5760 */
5761static void
5762_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
5763 Mpi2EventIrConfigElement_t *element)
5764{
5765 struct _sas_device *sas_device;
5766 unsigned long flags;
5767 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
5768
5769 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5770 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5771 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5772 if (!sas_device)
5773 return;
5774
5775 /* exposing raid component */
5776 sas_device->volume_handle = 0;
5777 sas_device->volume_wwid = 0;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305778 clear_bit(handle, ioc->pd_handles);
Eric Moore635374e2009-03-09 01:21:12 -06005779 _scsih_reprobe_target(sas_device->starget, 0);
5780}
5781
5782/**
5783 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
5784 * @ioc: per adapter object
5785 * @element: IR config element data
5786 * Context: user.
5787 *
5788 * Return nothing.
5789 */
5790static void
5791_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
5792 Mpi2EventIrConfigElement_t *element)
5793{
5794 struct _sas_device *sas_device;
5795 unsigned long flags;
5796 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
5797
5798 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5799 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5800 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5801 if (!sas_device)
5802 return;
5803
5804 /* hiding raid component */
5805 mpt2sas_config_get_volume_handle(ioc, handle,
5806 &sas_device->volume_handle);
5807 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
5808 &sas_device->volume_wwid);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305809 set_bit(handle, ioc->pd_handles);
Eric Moore635374e2009-03-09 01:21:12 -06005810 _scsih_reprobe_target(sas_device->starget, 1);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05305811
Eric Moore635374e2009-03-09 01:21:12 -06005812}
5813
5814/**
5815 * _scsih_sas_pd_delete - delete pd component
5816 * @ioc: per adapter object
5817 * @element: IR config element data
5818 * Context: user.
5819 *
5820 * Return nothing.
5821 */
5822static void
5823_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
5824 Mpi2EventIrConfigElement_t *element)
5825{
5826 struct _sas_device *sas_device;
5827 unsigned long flags;
5828 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
5829
5830 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5831 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5832 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5833 if (!sas_device)
5834 return;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305835 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005836}
5837
5838/**
5839 * _scsih_sas_pd_add - remove pd component
5840 * @ioc: per adapter object
5841 * @element: IR config element data
5842 * Context: user.
5843 *
5844 * Return nothing.
5845 */
5846static void
5847_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
5848 Mpi2EventIrConfigElement_t *element)
5849{
5850 struct _sas_device *sas_device;
5851 unsigned long flags;
5852 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305853 Mpi2ConfigReply_t mpi_reply;
5854 Mpi2SasDevicePage0_t sas_device_pg0;
5855 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305856 u64 sas_address;
5857 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06005858
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305859 set_bit(handle, ioc->pd_handles);
5860
Eric Moore635374e2009-03-09 01:21:12 -06005861 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5862 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5863 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05305864 if (sas_device)
Kashyap, Desai62727a72009-08-07 19:35:18 +05305865 return;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305866
5867 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
5868 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
5869 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5870 ioc->name, __FILE__, __LINE__, __func__);
5871 return;
5872 }
5873
5874 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5875 MPI2_IOCSTATUS_MASK;
5876 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5877 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5878 ioc->name, __FILE__, __LINE__, __func__);
5879 return;
5880 }
5881
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305882 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
5883 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
5884 mpt2sas_transport_update_links(ioc, sas_address, handle,
5885 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305886
5887 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06005888}
5889
5890#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5891/**
5892 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
5893 * @ioc: per adapter object
5894 * @event_data: event data payload
5895 * Context: user.
5896 *
5897 * Return nothing.
5898 */
5899static void
5900_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5901 Mpi2EventDataIrConfigChangeList_t *event_data)
5902{
5903 Mpi2EventIrConfigElement_t *element;
5904 u8 element_type;
5905 int i;
5906 char *reason_str = NULL, *element_str = NULL;
5907
5908 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
5909
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305910 printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n",
Eric Moore635374e2009-03-09 01:21:12 -06005911 ioc->name, (le32_to_cpu(event_data->Flags) &
5912 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
5913 "foreign" : "native", event_data->NumElements);
5914 for (i = 0; i < event_data->NumElements; i++, element++) {
5915 switch (element->ReasonCode) {
5916 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
5917 reason_str = "add";
5918 break;
5919 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
5920 reason_str = "remove";
5921 break;
5922 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
5923 reason_str = "no change";
5924 break;
5925 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
5926 reason_str = "hide";
5927 break;
5928 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
5929 reason_str = "unhide";
5930 break;
5931 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
5932 reason_str = "volume_created";
5933 break;
5934 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
5935 reason_str = "volume_deleted";
5936 break;
5937 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
5938 reason_str = "pd_created";
5939 break;
5940 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
5941 reason_str = "pd_deleted";
5942 break;
5943 default:
5944 reason_str = "unknown reason";
5945 break;
5946 }
5947 element_type = le16_to_cpu(element->ElementFlags) &
5948 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
5949 switch (element_type) {
5950 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
5951 element_str = "volume";
5952 break;
5953 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
5954 element_str = "phys disk";
5955 break;
5956 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
5957 element_str = "hot spare";
5958 break;
5959 default:
5960 element_str = "unknown element";
5961 break;
5962 }
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305963 printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), "
Eric Moore635374e2009-03-09 01:21:12 -06005964 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
5965 reason_str, le16_to_cpu(element->VolDevHandle),
5966 le16_to_cpu(element->PhysDiskDevHandle),
5967 element->PhysDiskNum);
5968 }
5969}
5970#endif
5971
5972/**
5973 * _scsih_sas_ir_config_change_event - handle ir configuration change events
5974 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305975 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005976 * Context: user.
5977 *
5978 * Return nothing.
5979 */
5980static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305981_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
5982 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005983{
5984 Mpi2EventIrConfigElement_t *element;
5985 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305986 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305987 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005988
5989#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05305990 if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5991 && !ioc->hide_ir_msg)
Eric Moore635374e2009-03-09 01:21:12 -06005992 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
5993
5994#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05305995 foreign_config = (le32_to_cpu(event_data->Flags) &
5996 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06005997
5998 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
5999 for (i = 0; i < event_data->NumElements; i++, element++) {
6000
6001 switch (element->ReasonCode) {
6002 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
6003 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05306004 if (!foreign_config)
6005 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006006 break;
6007 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
6008 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05306009 if (!foreign_config)
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306010 _scsih_sas_volume_delete(ioc,
6011 le16_to_cpu(element->VolDevHandle));
Eric Moore635374e2009-03-09 01:21:12 -06006012 break;
6013 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306014 if (!ioc->is_warpdrive)
6015 _scsih_sas_pd_hide(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006016 break;
6017 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306018 if (!ioc->is_warpdrive)
6019 _scsih_sas_pd_expose(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006020 break;
6021 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306022 if (!ioc->is_warpdrive)
6023 _scsih_sas_pd_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006024 break;
6025 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306026 if (!ioc->is_warpdrive)
6027 _scsih_sas_pd_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006028 break;
6029 }
6030 }
6031}
6032
6033/**
6034 * _scsih_sas_ir_volume_event - IR volume event
6035 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306036 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006037 * Context: user.
6038 *
6039 * Return nothing.
6040 */
6041static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306042_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
6043 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006044{
6045 u64 wwid;
6046 unsigned long flags;
6047 struct _raid_device *raid_device;
6048 u16 handle;
6049 u32 state;
6050 int rc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306051 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06006052
6053 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
6054 return;
6055
6056 handle = le16_to_cpu(event_data->VolDevHandle);
6057 state = le32_to_cpu(event_data->NewValue);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306058 if (!ioc->hide_ir_msg)
6059 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
6060 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
6061 le32_to_cpu(event_data->PreviousValue), state));
Eric Moore635374e2009-03-09 01:21:12 -06006062
Eric Moore635374e2009-03-09 01:21:12 -06006063 switch (state) {
6064 case MPI2_RAID_VOL_STATE_MISSING:
6065 case MPI2_RAID_VOL_STATE_FAILED:
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306066 _scsih_sas_volume_delete(ioc, handle);
Eric Moore635374e2009-03-09 01:21:12 -06006067 break;
6068
6069 case MPI2_RAID_VOL_STATE_ONLINE:
6070 case MPI2_RAID_VOL_STATE_DEGRADED:
6071 case MPI2_RAID_VOL_STATE_OPTIMAL:
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306072
6073 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6074 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
6075 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6076
Eric Moore635374e2009-03-09 01:21:12 -06006077 if (raid_device)
6078 break;
6079
6080 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
6081 if (!wwid) {
6082 printk(MPT2SAS_ERR_FMT
6083 "failure at %s:%d/%s()!\n", ioc->name,
6084 __FILE__, __LINE__, __func__);
6085 break;
6086 }
6087
6088 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
6089 if (!raid_device) {
6090 printk(MPT2SAS_ERR_FMT
6091 "failure at %s:%d/%s()!\n", ioc->name,
6092 __FILE__, __LINE__, __func__);
6093 break;
6094 }
6095
6096 raid_device->id = ioc->sas_id++;
6097 raid_device->channel = RAID_CHANNEL;
6098 raid_device->handle = handle;
6099 raid_device->wwid = wwid;
6100 _scsih_raid_device_add(ioc, raid_device);
6101 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6102 raid_device->id, 0);
6103 if (rc)
6104 _scsih_raid_device_remove(ioc, raid_device);
6105 break;
6106
6107 case MPI2_RAID_VOL_STATE_INITIALIZING:
6108 default:
6109 break;
6110 }
6111}
6112
6113/**
6114 * _scsih_sas_ir_physical_disk_event - PD event
6115 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306116 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006117 * Context: user.
6118 *
6119 * Return nothing.
6120 */
6121static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306122_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
6123 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006124{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306125 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06006126 u32 state;
6127 struct _sas_device *sas_device;
6128 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306129 Mpi2ConfigReply_t mpi_reply;
6130 Mpi2SasDevicePage0_t sas_device_pg0;
6131 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306132 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306133 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06006134
6135 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
6136 return;
6137
6138 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
6139 state = le32_to_cpu(event_data->NewValue);
6140
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306141 if (!ioc->hide_ir_msg)
6142 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
6143 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
6144 le32_to_cpu(event_data->PreviousValue), state));
Eric Moore635374e2009-03-09 01:21:12 -06006145
Eric Moore635374e2009-03-09 01:21:12 -06006146 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06006147 case MPI2_RAID_PD_STATE_ONLINE:
6148 case MPI2_RAID_PD_STATE_DEGRADED:
6149 case MPI2_RAID_PD_STATE_REBUILDING:
6150 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306151 case MPI2_RAID_PD_STATE_HOT_SPARE:
6152
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306153 if (!ioc->is_warpdrive)
6154 set_bit(handle, ioc->pd_handles);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306155
6156 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6157 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
6158 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6159
6160 if (sas_device)
Kashyap, Desai62727a72009-08-07 19:35:18 +05306161 return;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306162
6163 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
6164 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
6165 handle))) {
6166 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6167 ioc->name, __FILE__, __LINE__, __func__);
6168 return;
6169 }
6170
6171 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6172 MPI2_IOCSTATUS_MASK;
6173 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
6174 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6175 ioc->name, __FILE__, __LINE__, __func__);
6176 return;
6177 }
6178
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306179 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
6180 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
6181 mpt2sas_transport_update_links(ioc, sas_address, handle,
6182 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05306183
6184 _scsih_add_device(ioc, handle, 0, 1);
6185
Eric Moore635374e2009-03-09 01:21:12 -06006186 break;
6187
Kashyap, Desai62727a72009-08-07 19:35:18 +05306188 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06006189 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
6190 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
Eric Moore635374e2009-03-09 01:21:12 -06006191 default:
6192 break;
6193 }
6194}
6195
6196#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
6197/**
6198 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
6199 * @ioc: per adapter object
6200 * @event_data: event data payload
6201 * Context: user.
6202 *
6203 * Return nothing.
6204 */
6205static void
6206_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
6207 Mpi2EventDataIrOperationStatus_t *event_data)
6208{
6209 char *reason_str = NULL;
6210
6211 switch (event_data->RAIDOperation) {
6212 case MPI2_EVENT_IR_RAIDOP_RESYNC:
6213 reason_str = "resync";
6214 break;
6215 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
6216 reason_str = "online capacity expansion";
6217 break;
6218 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
6219 reason_str = "consistency check";
6220 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05306221 case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
6222 reason_str = "background init";
6223 break;
6224 case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
6225 reason_str = "make data consistent";
Eric Moore635374e2009-03-09 01:21:12 -06006226 break;
6227 }
6228
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05306229 if (!reason_str)
6230 return;
6231
Eric Moore635374e2009-03-09 01:21:12 -06006232 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
6233 "\thandle(0x%04x), percent complete(%d)\n",
6234 ioc->name, reason_str,
6235 le16_to_cpu(event_data->VolDevHandle),
6236 event_data->PercentComplete);
6237}
6238#endif
6239
6240/**
6241 * _scsih_sas_ir_operation_status_event - handle RAID operation events
6242 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306243 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006244 * Context: user.
6245 *
6246 * Return nothing.
6247 */
6248static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306249_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
6250 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006251{
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306252 Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data;
6253 static struct _raid_device *raid_device;
6254 unsigned long flags;
6255 u16 handle;
6256
Eric Moore635374e2009-03-09 01:21:12 -06006257#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306258 if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
6259 && !ioc->hide_ir_msg)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306260 _scsih_sas_ir_operation_status_event_debug(ioc,
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306261 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06006262#endif
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306263
6264 /* code added for raid transport support */
6265 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
6266
6267 handle = le16_to_cpu(event_data->VolDevHandle);
6268
6269 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6270 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
6271 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6272
6273 if (!raid_device)
6274 return;
6275
6276 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
6277 raid_device->percent_complete =
6278 event_data->PercentComplete;
6279 }
Eric Moore635374e2009-03-09 01:21:12 -06006280}
6281
6282/**
Kashyap, Desai14695852010-03-30 10:52:44 +05306283 * _scsih_prep_device_scan - initialize parameters prior to device scan
6284 * @ioc: per adapter object
6285 *
6286 * Set the deleted flag prior to device scan. If the device is found during
6287 * the scan, then we clear the deleted flag.
6288 */
6289static void
6290_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc)
6291{
6292 struct MPT2SAS_DEVICE *sas_device_priv_data;
6293 struct scsi_device *sdev;
6294
6295 shost_for_each_device(sdev, ioc->shost) {
6296 sas_device_priv_data = sdev->hostdata;
6297 if (sas_device_priv_data && sas_device_priv_data->sas_target)
6298 sas_device_priv_data->sas_target->deleted = 1;
6299 }
6300}
6301
6302/**
Eric Moore635374e2009-03-09 01:21:12 -06006303 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
6304 * @ioc: per adapter object
6305 * @sas_address: sas address
6306 * @slot: enclosure slot id
6307 * @handle: device handle
6308 *
6309 * After host reset, find out whether devices are still responding.
6310 * Used in _scsi_remove_unresponsive_sas_devices.
6311 *
6312 * Return nothing.
6313 */
6314static void
6315_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
6316 u16 slot, u16 handle)
6317{
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306318 struct MPT2SAS_TARGET *sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06006319 struct scsi_target *starget;
6320 struct _sas_device *sas_device;
6321 unsigned long flags;
6322
6323 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6324 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
6325 if (sas_device->sas_address == sas_address &&
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306326 sas_device->slot == slot) {
Eric Moore635374e2009-03-09 01:21:12 -06006327 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306328 starget = sas_device->starget;
Kashyap, Desai14695852010-03-30 10:52:44 +05306329 if (starget && starget->hostdata) {
6330 sas_target_priv_data = starget->hostdata;
6331 sas_target_priv_data->tm_busy = 0;
6332 sas_target_priv_data->deleted = 0;
6333 } else
6334 sas_target_priv_data = NULL;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306335 if (starget)
6336 starget_printk(KERN_INFO, starget,
6337 "handle(0x%04x), sas_addr(0x%016llx), "
6338 "enclosure logical id(0x%016llx), "
6339 "slot(%d)\n", handle,
6340 (unsigned long long)sas_device->sas_address,
6341 (unsigned long long)
6342 sas_device->enclosure_logical_id,
6343 sas_device->slot);
Eric Moore635374e2009-03-09 01:21:12 -06006344 if (sas_device->handle == handle)
6345 goto out;
6346 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
6347 sas_device->handle);
6348 sas_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05306349 if (sas_target_priv_data)
6350 sas_target_priv_data->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06006351 goto out;
6352 }
6353 }
6354 out:
6355 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6356}
6357
6358/**
6359 * _scsih_search_responding_sas_devices -
6360 * @ioc: per adapter object
6361 *
6362 * After host reset, find out whether devices are still responding.
6363 * If not remove.
6364 *
6365 * Return nothing.
6366 */
6367static void
6368_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
6369{
6370 Mpi2SasDevicePage0_t sas_device_pg0;
6371 Mpi2ConfigReply_t mpi_reply;
6372 u16 ioc_status;
6373 __le64 sas_address;
6374 u16 handle;
6375 u32 device_info;
6376 u16 slot;
6377
6378 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
6379
6380 if (list_empty(&ioc->sas_device_list))
6381 return;
6382
6383 handle = 0xFFFF;
6384 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
6385 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
6386 handle))) {
6387 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6388 MPI2_IOCSTATUS_MASK;
6389 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6390 break;
6391 handle = le16_to_cpu(sas_device_pg0.DevHandle);
6392 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
6393 if (!(_scsih_is_end_device(device_info)))
6394 continue;
6395 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
6396 slot = le16_to_cpu(sas_device_pg0.Slot);
6397 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
6398 handle);
6399 }
6400}
6401
6402/**
6403 * _scsih_mark_responding_raid_device - mark a raid_device as responding
6404 * @ioc: per adapter object
6405 * @wwid: world wide identifier for raid volume
6406 * @handle: device handle
6407 *
6408 * After host reset, find out whether devices are still responding.
6409 * Used in _scsi_remove_unresponsive_raid_devices.
6410 *
6411 * Return nothing.
6412 */
6413static void
6414_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
6415 u16 handle)
6416{
6417 struct MPT2SAS_TARGET *sas_target_priv_data;
6418 struct scsi_target *starget;
6419 struct _raid_device *raid_device;
6420 unsigned long flags;
6421
6422 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6423 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
6424 if (raid_device->wwid == wwid && raid_device->starget) {
Kashyap, Desai14695852010-03-30 10:52:44 +05306425 starget = raid_device->starget;
6426 if (starget && starget->hostdata) {
6427 sas_target_priv_data = starget->hostdata;
6428 sas_target_priv_data->deleted = 0;
6429 } else
6430 sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06006431 raid_device->responding = 1;
6432 starget_printk(KERN_INFO, raid_device->starget,
6433 "handle(0x%04x), wwid(0x%016llx)\n", handle,
6434 (unsigned long long)raid_device->wwid);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306435 /*
6436 * WARPDRIVE: The handles of the PDs might have changed
6437 * across the host reset so re-initialize the
6438 * required data for Direct IO
6439 */
6440 _scsih_init_warpdrive_properties(ioc, raid_device);
Eric Moore635374e2009-03-09 01:21:12 -06006441 if (raid_device->handle == handle)
6442 goto out;
6443 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
6444 raid_device->handle);
6445 raid_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05306446 if (sas_target_priv_data)
6447 sas_target_priv_data->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06006448 goto out;
6449 }
6450 }
6451 out:
6452 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6453}
6454
6455/**
6456 * _scsih_search_responding_raid_devices -
6457 * @ioc: per adapter object
6458 *
6459 * After host reset, find out whether devices are still responding.
6460 * If not remove.
6461 *
6462 * Return nothing.
6463 */
6464static void
6465_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
6466{
6467 Mpi2RaidVolPage1_t volume_pg1;
Kashyap, Desaid417d1c2010-06-17 13:48:10 +05306468 Mpi2RaidVolPage0_t volume_pg0;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306469 Mpi2RaidPhysDiskPage0_t pd_pg0;
Eric Moore635374e2009-03-09 01:21:12 -06006470 Mpi2ConfigReply_t mpi_reply;
6471 u16 ioc_status;
6472 u16 handle;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306473 u8 phys_disk_num;
Eric Moore635374e2009-03-09 01:21:12 -06006474
6475 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
6476
6477 if (list_empty(&ioc->raid_device_list))
6478 return;
6479
6480 handle = 0xFFFF;
6481 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
6482 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
6483 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6484 MPI2_IOCSTATUS_MASK;
6485 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6486 break;
6487 handle = le16_to_cpu(volume_pg1.DevHandle);
Kashyap, Desaid417d1c2010-06-17 13:48:10 +05306488
6489 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
6490 &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
6491 sizeof(Mpi2RaidVolPage0_t)))
6492 continue;
6493
6494 if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
6495 volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
6496 volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED)
6497 _scsih_mark_responding_raid_device(ioc,
6498 le64_to_cpu(volume_pg1.WWID), handle);
Eric Moore635374e2009-03-09 01:21:12 -06006499 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306500
6501 /* refresh the pd_handles */
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306502 if (!ioc->is_warpdrive) {
6503 phys_disk_num = 0xFF;
6504 memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
6505 while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
6506 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
6507 phys_disk_num))) {
6508 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6509 MPI2_IOCSTATUS_MASK;
6510 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6511 break;
6512 phys_disk_num = pd_pg0.PhysDiskNum;
6513 handle = le16_to_cpu(pd_pg0.DevHandle);
6514 set_bit(handle, ioc->pd_handles);
6515 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306516 }
Eric Moore635374e2009-03-09 01:21:12 -06006517}
6518
6519/**
6520 * _scsih_mark_responding_expander - mark a expander as responding
6521 * @ioc: per adapter object
6522 * @sas_address: sas address
6523 * @handle:
6524 *
6525 * After host reset, find out whether devices are still responding.
6526 * Used in _scsi_remove_unresponsive_expanders.
6527 *
6528 * Return nothing.
6529 */
6530static void
6531_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
6532 u16 handle)
6533{
6534 struct _sas_node *sas_expander;
6535 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306536 int i;
Eric Moore635374e2009-03-09 01:21:12 -06006537
6538 spin_lock_irqsave(&ioc->sas_node_lock, flags);
6539 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306540 if (sas_expander->sas_address != sas_address)
6541 continue;
6542 sas_expander->responding = 1;
6543 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06006544 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306545 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
6546 " from(0x%04x) to (0x%04x)!!!\n",
6547 (unsigned long long)sas_expander->sas_address,
6548 sas_expander->handle, handle);
6549 sas_expander->handle = handle;
6550 for (i = 0 ; i < sas_expander->num_phys ; i++)
6551 sas_expander->phy[i].handle = handle;
6552 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06006553 }
6554 out:
6555 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
6556}
6557
6558/**
6559 * _scsih_search_responding_expanders -
6560 * @ioc: per adapter object
6561 *
6562 * After host reset, find out whether devices are still responding.
6563 * If not remove.
6564 *
6565 * Return nothing.
6566 */
6567static void
6568_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
6569{
6570 Mpi2ExpanderPage0_t expander_pg0;
6571 Mpi2ConfigReply_t mpi_reply;
6572 u16 ioc_status;
Kashyap, Desaic97951e2011-06-14 10:54:56 +05306573 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06006574 u16 handle;
6575
6576 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
6577
6578 if (list_empty(&ioc->sas_expander_list))
6579 return;
6580
6581 handle = 0xFFFF;
6582 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
6583 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
6584
6585 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6586 MPI2_IOCSTATUS_MASK;
6587 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6588 break;
6589
6590 handle = le16_to_cpu(expander_pg0.DevHandle);
6591 sas_address = le64_to_cpu(expander_pg0.SASAddress);
6592 printk(KERN_INFO "\texpander present: handle(0x%04x), "
6593 "sas_addr(0x%016llx)\n", handle,
6594 (unsigned long long)sas_address);
6595 _scsih_mark_responding_expander(ioc, sas_address, handle);
6596 }
6597
6598}
6599
6600/**
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306601 * _scsih_remove_unresponding_sas_devices - removing unresponding devices
Eric Moore635374e2009-03-09 01:21:12 -06006602 * @ioc: per adapter object
6603 *
6604 * Return nothing.
6605 */
6606static void
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306607_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06006608{
6609 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306610 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06006611 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06006612
Eric Moore635374e2009-03-09 01:21:12 -06006613
6614 list_for_each_entry_safe(sas_device, sas_device_next,
6615 &ioc->sas_device_list, list) {
6616 if (sas_device->responding) {
6617 sas_device->responding = 0;
6618 continue;
6619 }
6620 if (sas_device->starget)
6621 starget_printk(KERN_INFO, sas_device->starget,
6622 "removing: handle(0x%04x), sas_addr(0x%016llx), "
6623 "enclosure logical id(0x%016llx), slot(%d)\n",
6624 sas_device->handle,
6625 (unsigned long long)sas_device->sas_address,
6626 (unsigned long long)
6627 sas_device->enclosure_logical_id,
6628 sas_device->slot);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306629 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06006630 }
6631
6632 list_for_each_entry_safe(raid_device, raid_device_next,
6633 &ioc->raid_device_list, list) {
6634 if (raid_device->responding) {
6635 raid_device->responding = 0;
6636 continue;
6637 }
6638 if (raid_device->starget) {
6639 starget_printk(KERN_INFO, raid_device->starget,
6640 "removing: handle(0x%04x), wwid(0x%016llx)\n",
6641 raid_device->handle,
6642 (unsigned long long)raid_device->wwid);
6643 scsi_remove_target(&raid_device->starget->dev);
6644 }
6645 _scsih_raid_device_remove(ioc, raid_device);
6646 }
6647
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306648 retry_expander_search:
6649 sas_expander = NULL;
6650 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06006651 if (sas_expander->responding) {
6652 sas_expander->responding = 0;
6653 continue;
6654 }
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05306655 mpt2sas_expander_remove(ioc, sas_expander->sas_address);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306656 goto retry_expander_search;
6657 }
6658}
6659
6660/**
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306661 * _scsih_hide_unhide_sas_devices - add/remove device to/from OS
6662 * @ioc: per adapter object
6663 *
6664 * Return nothing.
6665 */
6666static void
6667_scsih_hide_unhide_sas_devices(struct MPT2SAS_ADAPTER *ioc)
6668{
6669 struct _sas_device *sas_device, *sas_device_next;
6670
6671 if (!ioc->is_warpdrive || ioc->mfg_pg10_hide_flag !=
6672 MFG_PAGE10_HIDE_IF_VOL_PRESENT)
6673 return;
6674
6675 if (ioc->hide_drives) {
6676 if (_scsih_get_num_volumes(ioc))
6677 return;
6678 ioc->hide_drives = 0;
6679 list_for_each_entry_safe(sas_device, sas_device_next,
6680 &ioc->sas_device_list, list) {
6681 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
6682 sas_device->sas_address_parent)) {
6683 _scsih_sas_device_remove(ioc, sas_device);
6684 } else if (!sas_device->starget) {
6685 mpt2sas_transport_port_remove(ioc,
6686 sas_device->sas_address,
6687 sas_device->sas_address_parent);
6688 _scsih_sas_device_remove(ioc, sas_device);
6689 }
6690 }
6691 } else {
6692 if (!_scsih_get_num_volumes(ioc))
6693 return;
6694 ioc->hide_drives = 1;
6695 list_for_each_entry_safe(sas_device, sas_device_next,
6696 &ioc->sas_device_list, list) {
6697 mpt2sas_transport_port_remove(ioc,
6698 sas_device->sas_address,
6699 sas_device->sas_address_parent);
6700 }
6701 }
6702}
6703
6704/**
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306705 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
6706 * @ioc: per adapter object
6707 * @reset_phase: phase
6708 *
6709 * The handler for doing any required cleanup or initialization.
6710 *
6711 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
6712 * MPT2_IOC_DONE_RESET
6713 *
6714 * Return nothing.
6715 */
6716void
6717mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
6718{
6719 switch (reset_phase) {
6720 case MPT2_IOC_PRE_RESET:
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306721 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306722 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306723 break;
6724 case MPT2_IOC_AFTER_RESET:
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306725 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306726 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306727 if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
6728 ioc->scsih_cmds.status |= MPT2_CMD_RESET;
6729 mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
6730 complete(&ioc->scsih_cmds.done);
6731 }
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306732 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
6733 ioc->tm_cmds.status |= MPT2_CMD_RESET;
6734 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
6735 complete(&ioc->tm_cmds.done);
6736 }
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306737 _scsih_fw_event_cleanup_queue(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306738 _scsih_flush_running_cmds(ioc);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306739 _scsih_queue_rescan(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306740 break;
6741 case MPT2_IOC_DONE_RESET:
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306742 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306743 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306744 _scsih_sas_host_refresh(ioc);
Kashyap, Desai14695852010-03-30 10:52:44 +05306745 _scsih_prep_device_scan(ioc);
6746 _scsih_search_responding_sas_devices(ioc);
6747 _scsih_search_responding_raid_devices(ioc);
6748 _scsih_search_responding_expanders(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05306749 break;
Eric Moore635374e2009-03-09 01:21:12 -06006750 }
6751}
6752
6753/**
6754 * _firmware_event_work - delayed task for processing firmware events
6755 * @ioc: per adapter object
6756 * @work: equal to the fw_event_work object
6757 * Context: user.
6758 *
6759 * Return nothing.
6760 */
6761static void
6762_firmware_event_work(struct work_struct *work)
6763{
6764 struct fw_event_work *fw_event = container_of(work,
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306765 struct fw_event_work, delayed_work.work);
Eric Moore635374e2009-03-09 01:21:12 -06006766 unsigned long flags;
6767 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
6768
Eric Moore635374e2009-03-09 01:21:12 -06006769 /* the queue is being flushed so ignore this event */
Eric Moore3cb54692010-07-08 14:44:34 -06006770 if (ioc->remove_host || fw_event->cancel_pending_work ||
6771 ioc->pci_error_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06006772 _scsih_fw_event_free(ioc, fw_event);
6773 return;
6774 }
Eric Moore635374e2009-03-09 01:21:12 -06006775
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306776 if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) {
6777 _scsih_fw_event_free(ioc, fw_event);
6778 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
6779 if (ioc->shost_recovery) {
6780 init_completion(&ioc->shost_recovery_done);
6781 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
6782 flags);
6783 wait_for_completion(&ioc->shost_recovery_done);
6784 } else
6785 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
6786 flags);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306787 _scsih_remove_unresponding_sas_devices(ioc);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306788 _scsih_hide_unhide_sas_devices(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006789 return;
6790 }
Eric Moore635374e2009-03-09 01:21:12 -06006791
6792 switch (fw_event->event) {
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05306793 case MPT2SAS_TURN_ON_FAULT_LED:
6794 _scsih_turn_on_fault_led(ioc, fw_event->device_handle);
6795 break;
Eric Moore635374e2009-03-09 01:21:12 -06006796 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306797 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006798 break;
6799 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306800 _scsih_sas_device_status_change_event(ioc,
6801 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006802 break;
6803 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306804 _scsih_sas_discovery_event(ioc,
6805 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006806 break;
6807 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306808 _scsih_sas_broadcast_primative_event(ioc,
6809 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006810 break;
6811 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
6812 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306813 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006814 break;
6815 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306816 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006817 break;
6818 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306819 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006820 break;
6821 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306822 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006823 break;
6824 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306825 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06006826 break;
Eric Moore635374e2009-03-09 01:21:12 -06006827 }
6828 _scsih_fw_event_free(ioc, fw_event);
6829}
6830
6831/**
6832 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
6833 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306834 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06006835 * @reply: reply message frame(lower 32bit addr)
6836 * Context: interrupt.
6837 *
6838 * This function merely adds a new work task into ioc->firmware_event_thread.
6839 * The tasks are worked from _firmware_event_work in user context.
6840 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306841 * Return 1 meaning mf should be freed from _base_interrupt
6842 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06006843 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306844u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306845mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
6846 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06006847{
6848 struct fw_event_work *fw_event;
6849 Mpi2EventNotificationReply_t *mpi_reply;
Eric Moore635374e2009-03-09 01:21:12 -06006850 u16 event;
Kashyap, Desaie94f6742010-03-17 16:24:52 +05306851 u16 sz;
Eric Moore635374e2009-03-09 01:21:12 -06006852
6853 /* events turned off due to host reset or driver unloading */
Eric Moore3cb54692010-07-08 14:44:34 -06006854 if (ioc->remove_host || ioc->pci_error_recovery)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306855 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006856
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306857 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06006858 event = le16_to_cpu(mpi_reply->Event);
6859
6860 switch (event) {
6861 /* handle these */
6862 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
6863 {
6864 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
6865 (Mpi2EventDataSasBroadcastPrimitive_t *)
6866 mpi_reply->EventData;
6867
6868 if (baen_data->Primitive !=
6869 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
6870 ioc->broadcast_aen_busy)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306871 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006872 ioc->broadcast_aen_busy = 1;
6873 break;
6874 }
6875
6876 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
6877 _scsih_check_topo_delete_events(ioc,
6878 (Mpi2EventDataSasTopologyChangeList_t *)
6879 mpi_reply->EventData);
6880 break;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306881 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
6882 _scsih_check_ir_config_unhide_events(ioc,
6883 (Mpi2EventDataIrConfigChangeList_t *)
6884 mpi_reply->EventData);
6885 break;
6886 case MPI2_EVENT_IR_VOLUME:
6887 _scsih_check_volume_delete_events(ioc,
6888 (Mpi2EventDataIrVolume_t *)
6889 mpi_reply->EventData);
6890 break;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306891 case MPI2_EVENT_LOG_ENTRY_ADDED:
6892 {
6893 Mpi2EventDataLogEntryAdded_t *log_entry;
6894 u32 *log_code;
6895
6896 if (!ioc->is_warpdrive)
6897 break;
6898
6899 log_entry = (Mpi2EventDataLogEntryAdded_t *)
6900 mpi_reply->EventData;
6901 log_code = (u32 *)log_entry->LogData;
6902
6903 if (le16_to_cpu(log_entry->LogEntryQualifier)
6904 != MPT2_WARPDRIVE_LOGENTRY)
6905 break;
6906
6907 switch (le32_to_cpu(*log_code)) {
6908 case MPT2_WARPDRIVE_LC_SSDT:
6909 printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
6910 "IO Throttling has occurred in the WarpDrive "
6911 "subsystem. Check WarpDrive documentation for "
6912 "additional details.\n", ioc->name);
6913 break;
6914 case MPT2_WARPDRIVE_LC_SSDLW:
6915 printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
6916 "Program/Erase Cycles for the WarpDrive subsystem "
6917 "in degraded range. Check WarpDrive documentation "
6918 "for additional details.\n", ioc->name);
6919 break;
6920 case MPT2_WARPDRIVE_LC_SSDLF:
6921 printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
6922 "There are no Program/Erase Cycles for the "
6923 "WarpDrive subsystem. The storage device will be "
6924 "in read-only mode. Check WarpDrive documentation "
6925 "for additional details.\n", ioc->name);
6926 break;
6927 case MPT2_WARPDRIVE_LC_BRMF:
6928 printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
6929 "The Backup Rail Monitor has failed on the "
6930 "WarpDrive subsystem. Check WarpDrive "
6931 "documentation for additional details.\n",
6932 ioc->name);
6933 break;
6934 }
6935
6936 break;
6937 }
Eric Moore635374e2009-03-09 01:21:12 -06006938 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
6939 case MPI2_EVENT_IR_OPERATION_STATUS:
6940 case MPI2_EVENT_SAS_DISCOVERY:
6941 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
Eric Moore635374e2009-03-09 01:21:12 -06006942 case MPI2_EVENT_IR_PHYSICAL_DISK:
Eric Moore635374e2009-03-09 01:21:12 -06006943 break;
6944
6945 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306946 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006947 }
6948
6949 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
6950 if (!fw_event) {
6951 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6952 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306953 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006954 }
Kashyap, Desaie94f6742010-03-17 16:24:52 +05306955 sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
6956 fw_event->event_data = kzalloc(sz, GFP_ATOMIC);
Eric Moore635374e2009-03-09 01:21:12 -06006957 if (!fw_event->event_data) {
6958 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6959 ioc->name, __FILE__, __LINE__, __func__);
6960 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306961 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006962 }
6963
6964 memcpy(fw_event->event_data, mpi_reply->EventData,
Kashyap, Desaie94f6742010-03-17 16:24:52 +05306965 sz);
Eric Moore635374e2009-03-09 01:21:12 -06006966 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306967 fw_event->VF_ID = mpi_reply->VF_ID;
6968 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06006969 fw_event->event = event;
6970 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306971 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006972}
6973
6974/* shost template */
6975static struct scsi_host_template scsih_driver_template = {
6976 .module = THIS_MODULE,
6977 .name = "Fusion MPT SAS Host",
6978 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06006979 .queuecommand = _scsih_qcmd,
6980 .target_alloc = _scsih_target_alloc,
6981 .slave_alloc = _scsih_slave_alloc,
6982 .slave_configure = _scsih_slave_configure,
6983 .target_destroy = _scsih_target_destroy,
6984 .slave_destroy = _scsih_slave_destroy,
6985 .change_queue_depth = _scsih_change_queue_depth,
6986 .change_queue_type = _scsih_change_queue_type,
6987 .eh_abort_handler = _scsih_abort,
6988 .eh_device_reset_handler = _scsih_dev_reset,
6989 .eh_target_reset_handler = _scsih_target_reset,
6990 .eh_host_reset_handler = _scsih_host_reset,
6991 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06006992 .can_queue = 1,
6993 .this_id = -1,
6994 .sg_tablesize = MPT2SAS_SG_DEPTH,
6995 .max_sectors = 8192,
6996 .cmd_per_lun = 7,
6997 .use_clustering = ENABLE_CLUSTERING,
6998 .shost_attrs = mpt2sas_host_attrs,
6999 .sdev_attrs = mpt2sas_dev_attrs,
7000};
7001
7002/**
7003 * _scsih_expander_node_remove - removing expander device from list.
7004 * @ioc: per adapter object
7005 * @sas_expander: the sas_device object
7006 * Context: Calling function should acquire ioc->sas_node_lock.
7007 *
7008 * Removing object and freeing associated memory from the
7009 * ioc->sas_expander_list.
7010 *
7011 * Return nothing.
7012 */
7013static void
7014_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
7015 struct _sas_node *sas_expander)
7016{
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307017 struct _sas_port *mpt2sas_port, *next;
Eric Moore635374e2009-03-09 01:21:12 -06007018
7019 /* remove sibling ports attached to this expander */
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307020 list_for_each_entry_safe(mpt2sas_port, next,
Eric Moore635374e2009-03-09 01:21:12 -06007021 &sas_expander->sas_port_list, port_list) {
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307022 if (ioc->shost_recovery)
7023 return;
Eric Moore635374e2009-03-09 01:21:12 -06007024 if (mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307025 SAS_END_DEVICE)
7026 mpt2sas_device_remove(ioc,
7027 mpt2sas_port->remote_identify.sas_address);
7028 else if (mpt2sas_port->remote_identify.device_type ==
7029 SAS_EDGE_EXPANDER_DEVICE ||
Eric Moore635374e2009-03-09 01:21:12 -06007030 mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307031 SAS_FANOUT_EXPANDER_DEVICE)
7032 mpt2sas_expander_remove(ioc,
7033 mpt2sas_port->remote_identify.sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06007034 }
7035
7036 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307037 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06007038
7039 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
7040 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
7041 sas_expander->handle, (unsigned long long)
7042 sas_expander->sas_address);
7043
Eric Moore635374e2009-03-09 01:21:12 -06007044 kfree(sas_expander->phy);
7045 kfree(sas_expander);
7046}
7047
7048/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05307049 * _scsih_ir_shutdown - IR shutdown notification
7050 * @ioc: per adapter object
7051 *
7052 * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
7053 * the host system is shutting down.
7054 *
7055 * Return nothing.
7056 */
7057static void
7058_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
7059{
7060 Mpi2RaidActionRequest_t *mpi_request;
7061 Mpi2RaidActionReply_t *mpi_reply;
7062 u16 smid;
7063
7064 /* is IR firmware build loaded ? */
7065 if (!ioc->ir_firmware)
7066 return;
7067
7068 /* are there any volumes ? */
7069 if (list_empty(&ioc->raid_device_list))
7070 return;
7071
7072 mutex_lock(&ioc->scsih_cmds.mutex);
7073
7074 if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
7075 printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
7076 ioc->name, __func__);
7077 goto out;
7078 }
7079 ioc->scsih_cmds.status = MPT2_CMD_PENDING;
7080
7081 smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
7082 if (!smid) {
7083 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
7084 ioc->name, __func__);
7085 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
7086 goto out;
7087 }
7088
7089 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
7090 ioc->scsih_cmds.smid = smid;
7091 memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
7092
7093 mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
7094 mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
7095
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307096 if (!ioc->hide_ir_msg)
7097 printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
Kashyap, Desai744090d2009-10-05 15:56:56 +05307098 init_completion(&ioc->scsih_cmds.done);
7099 mpt2sas_base_put_smid_default(ioc, smid);
7100 wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
7101
7102 if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
7103 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
7104 ioc->name, __func__);
7105 goto out;
7106 }
7107
7108 if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
7109 mpi_reply = ioc->scsih_cmds.reply;
7110
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307111 if (!ioc->hide_ir_msg)
7112 printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
7113 "ioc_status(0x%04x), loginfo(0x%08x)\n",
7114 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
7115 le32_to_cpu(mpi_reply->IOCLogInfo));
Kashyap, Desai744090d2009-10-05 15:56:56 +05307116 }
7117
7118 out:
7119 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
7120 mutex_unlock(&ioc->scsih_cmds.mutex);
7121}
7122
7123/**
7124 * _scsih_shutdown - routine call during system shutdown
7125 * @pdev: PCI device struct
7126 *
7127 * Return nothing.
7128 */
7129static void
7130_scsih_shutdown(struct pci_dev *pdev)
7131{
7132 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7133 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05307134 struct workqueue_struct *wq;
7135 unsigned long flags;
7136
7137 ioc->remove_host = 1;
7138 _scsih_fw_event_cleanup_queue(ioc);
7139
7140 spin_lock_irqsave(&ioc->fw_event_lock, flags);
7141 wq = ioc->firmware_event_thread;
7142 ioc->firmware_event_thread = NULL;
7143 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
7144 if (wq)
7145 destroy_workqueue(wq);
Kashyap, Desai744090d2009-10-05 15:56:56 +05307146
7147 _scsih_ir_shutdown(ioc);
7148 mpt2sas_base_detach(ioc);
7149}
7150
7151/**
Eric Moored5d135b2009-05-18 13:02:08 -06007152 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06007153 * @pdev: PCI device struct
7154 *
Kashyap, Desai744090d2009-10-05 15:56:56 +05307155 * Routine called when unloading the driver.
Eric Moore635374e2009-03-09 01:21:12 -06007156 * Return nothing.
7157 */
7158static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06007159_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06007160{
7161 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7162 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307163 struct _sas_port *mpt2sas_port, *next_port;
Kashyap, Desaid7384b22009-12-16 18:50:06 +05307164 struct _raid_device *raid_device, *next;
7165 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06007166 struct workqueue_struct *wq;
7167 unsigned long flags;
7168
7169 ioc->remove_host = 1;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05307170 _scsih_fw_event_cleanup_queue(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007171
7172 spin_lock_irqsave(&ioc->fw_event_lock, flags);
7173 wq = ioc->firmware_event_thread;
7174 ioc->firmware_event_thread = NULL;
7175 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
7176 if (wq)
7177 destroy_workqueue(wq);
7178
Kashyap, Desaid7384b22009-12-16 18:50:06 +05307179 /* release all the volumes */
Kashyap, Desai3a9c9132011-01-04 11:40:23 +05307180 _scsih_ir_shutdown(ioc);
Kashyap, Desaid7384b22009-12-16 18:50:06 +05307181 list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
7182 list) {
7183 if (raid_device->starget) {
7184 sas_target_priv_data =
7185 raid_device->starget->hostdata;
7186 sas_target_priv_data->deleted = 1;
7187 scsi_remove_target(&raid_device->starget->dev);
7188 }
7189 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
7190 "(0x%016llx)\n", ioc->name, raid_device->handle,
7191 (unsigned long long) raid_device->wwid);
7192 _scsih_raid_device_remove(ioc, raid_device);
7193 }
7194
Eric Moore635374e2009-03-09 01:21:12 -06007195 /* free ports attached to the sas_host */
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307196 list_for_each_entry_safe(mpt2sas_port, next_port,
Eric Moore635374e2009-03-09 01:21:12 -06007197 &ioc->sas_hba.sas_port_list, port_list) {
7198 if (mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307199 SAS_END_DEVICE)
7200 mpt2sas_device_remove(ioc,
Eric Moore635374e2009-03-09 01:21:12 -06007201 mpt2sas_port->remote_identify.sas_address);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307202 else if (mpt2sas_port->remote_identify.device_type ==
7203 SAS_EDGE_EXPANDER_DEVICE ||
7204 mpt2sas_port->remote_identify.device_type ==
7205 SAS_FANOUT_EXPANDER_DEVICE)
7206 mpt2sas_expander_remove(ioc,
7207 mpt2sas_port->remote_identify.sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06007208 }
7209
7210 /* free phys attached to the sas_host */
7211 if (ioc->sas_hba.num_phys) {
7212 kfree(ioc->sas_hba.phy);
7213 ioc->sas_hba.phy = NULL;
7214 ioc->sas_hba.num_phys = 0;
7215 }
7216
7217 sas_remove_host(shost);
Kashyap, Desai744090d2009-10-05 15:56:56 +05307218 _scsih_shutdown(pdev);
Eric Moore635374e2009-03-09 01:21:12 -06007219 list_del(&ioc->list);
7220 scsi_remove_host(shost);
7221 scsi_host_put(shost);
7222}
7223
7224/**
7225 * _scsih_probe_boot_devices - reports 1st device
7226 * @ioc: per adapter object
7227 *
7228 * If specified in bios page 2, this routine reports the 1st
7229 * device scsi-ml or sas transport for persistent boot device
7230 * purposes. Please refer to function _scsih_determine_boot_device()
7231 */
7232static void
7233_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
7234{
7235 u8 is_raid;
7236 void *device;
7237 struct _sas_device *sas_device;
7238 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307239 u16 handle;
7240 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06007241 u64 sas_address;
7242 unsigned long flags;
7243 int rc;
7244
7245 device = NULL;
7246 if (ioc->req_boot_device.device) {
7247 device = ioc->req_boot_device.device;
7248 is_raid = ioc->req_boot_device.is_raid;
7249 } else if (ioc->req_alt_boot_device.device) {
7250 device = ioc->req_alt_boot_device.device;
7251 is_raid = ioc->req_alt_boot_device.is_raid;
7252 } else if (ioc->current_boot_device.device) {
7253 device = ioc->current_boot_device.device;
7254 is_raid = ioc->current_boot_device.is_raid;
7255 }
7256
7257 if (!device)
7258 return;
7259
7260 if (is_raid) {
7261 raid_device = device;
7262 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
7263 raid_device->id, 0);
7264 if (rc)
7265 _scsih_raid_device_remove(ioc, raid_device);
7266 } else {
7267 sas_device = device;
7268 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307269 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06007270 sas_address = sas_device->sas_address;
7271 spin_lock_irqsave(&ioc->sas_device_lock, flags);
7272 list_move_tail(&sas_device->list, &ioc->sas_device_list);
7273 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307274
7275 if (ioc->hide_drives)
7276 return;
Eric Moore635374e2009-03-09 01:21:12 -06007277 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307278 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06007279 _scsih_sas_device_remove(ioc, sas_device);
7280 } else if (!sas_device->starget) {
7281 mpt2sas_transport_port_remove(ioc, sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307282 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06007283 _scsih_sas_device_remove(ioc, sas_device);
7284 }
7285 }
7286}
7287
7288/**
7289 * _scsih_probe_raid - reporting raid volumes to scsi-ml
7290 * @ioc: per adapter object
7291 *
7292 * Called during initial loading of the driver.
7293 */
7294static void
7295_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
7296{
7297 struct _raid_device *raid_device, *raid_next;
7298 int rc;
7299
7300 list_for_each_entry_safe(raid_device, raid_next,
7301 &ioc->raid_device_list, list) {
7302 if (raid_device->starget)
7303 continue;
7304 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
7305 raid_device->id, 0);
7306 if (rc)
7307 _scsih_raid_device_remove(ioc, raid_device);
7308 }
7309}
7310
7311/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307312 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06007313 * @ioc: per adapter object
7314 *
7315 * Called during initial loading of the driver.
7316 */
7317static void
7318_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
7319{
7320 struct _sas_device *sas_device, *next;
7321 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06007322
7323 /* SAS Device List */
7324 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
7325 list) {
7326 spin_lock_irqsave(&ioc->sas_device_lock, flags);
7327 list_move_tail(&sas_device->list, &ioc->sas_device_list);
7328 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
7329
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307330 if (ioc->hide_drives)
7331 continue;
7332
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307333 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
7334 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06007335 _scsih_sas_device_remove(ioc, sas_device);
7336 } else if (!sas_device->starget) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307337 mpt2sas_transport_port_remove(ioc,
7338 sas_device->sas_address,
7339 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06007340 _scsih_sas_device_remove(ioc, sas_device);
7341 }
7342 }
7343}
7344
7345/**
7346 * _scsih_probe_devices - probing for devices
7347 * @ioc: per adapter object
7348 *
7349 * Called during initial loading of the driver.
7350 */
7351static void
7352_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
7353{
7354 u16 volume_mapping_flags =
7355 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
7356 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
7357
7358 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
7359 return; /* return when IOC doesn't support initiator mode */
7360
7361 _scsih_probe_boot_devices(ioc);
7362
7363 if (ioc->ir_firmware) {
7364 if ((volume_mapping_flags &
7365 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
7366 _scsih_probe_sas(ioc);
7367 _scsih_probe_raid(ioc);
7368 } else {
7369 _scsih_probe_raid(ioc);
7370 _scsih_probe_sas(ioc);
7371 }
7372 } else
7373 _scsih_probe_sas(ioc);
7374}
7375
7376/**
Eric Moored5d135b2009-05-18 13:02:08 -06007377 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06007378 * @pdev: PCI device struct
7379 * @id: pci device id
7380 *
7381 * Returns 0 success, anything else error.
7382 */
7383static int
Eric Moored5d135b2009-05-18 13:02:08 -06007384_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06007385{
7386 struct MPT2SAS_ADAPTER *ioc;
7387 struct Scsi_Host *shost;
7388
7389 shost = scsi_host_alloc(&scsih_driver_template,
7390 sizeof(struct MPT2SAS_ADAPTER));
7391 if (!shost)
7392 return -ENODEV;
7393
7394 /* init local params */
7395 ioc = shost_priv(shost);
7396 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
7397 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06007398 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06007399 ioc->shost = shost;
7400 ioc->id = mpt_ids++;
7401 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
7402 ioc->pdev = pdev;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307403 if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) {
7404 ioc->is_warpdrive = 1;
7405 ioc->hide_ir_msg = 1;
7406 } else
7407 ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
Eric Moore635374e2009-03-09 01:21:12 -06007408 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
7409 ioc->tm_cb_idx = tm_cb_idx;
7410 ioc->ctl_cb_idx = ctl_cb_idx;
7411 ioc->base_cb_idx = base_cb_idx;
7412 ioc->transport_cb_idx = transport_cb_idx;
Kashyap, Desai744090d2009-10-05 15:56:56 +05307413 ioc->scsih_cb_idx = scsih_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06007414 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307415 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307416 ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307417 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06007418 ioc->logging_level = logging_level;
7419 /* misc semaphores and spin locks */
Kashyap, Desaid2742132010-06-17 13:28:55 +05307420 mutex_init(&ioc->reset_in_progress_mutex);
Eric Moore635374e2009-03-09 01:21:12 -06007421 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
7422 spin_lock_init(&ioc->scsi_lookup_lock);
7423 spin_lock_init(&ioc->sas_device_lock);
7424 spin_lock_init(&ioc->sas_node_lock);
7425 spin_lock_init(&ioc->fw_event_lock);
7426 spin_lock_init(&ioc->raid_device_lock);
7427
7428 INIT_LIST_HEAD(&ioc->sas_device_list);
7429 INIT_LIST_HEAD(&ioc->sas_device_init_list);
7430 INIT_LIST_HEAD(&ioc->sas_expander_list);
7431 INIT_LIST_HEAD(&ioc->fw_event_list);
7432 INIT_LIST_HEAD(&ioc->raid_device_list);
7433 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307434 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307435 INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
Eric Moore635374e2009-03-09 01:21:12 -06007436
7437 /* init shost parameters */
Eric Moored334aa72010-04-22 10:47:40 -06007438 shost->max_cmd_len = 32;
Eric Moore635374e2009-03-09 01:21:12 -06007439 shost->max_lun = max_lun;
7440 shost->transportt = mpt2sas_transport_template;
7441 shost->unique_id = ioc->id;
7442
Kashyap, Desaia3e1e552011-06-14 10:56:12 +05307443 if (max_sectors != 0xFFFF) {
7444 if (max_sectors < 64) {
7445 shost->max_sectors = 64;
7446 printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
7447 "for max_sectors, range is 64 to 8192. Assigning "
7448 "value of 64.\n", ioc->name, max_sectors);
7449 } else if (max_sectors > 8192) {
7450 shost->max_sectors = 8192;
7451 printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
7452 "for max_sectors, range is 64 to 8192. Assigning "
7453 "default value of 8192.\n", ioc->name,
7454 max_sectors);
7455 } else {
7456 shost->max_sectors = max_sectors & 0xFFFE;
7457 printk(MPT2SAS_INFO_FMT "The max_sectors value is "
7458 "set to %d\n", ioc->name, shost->max_sectors);
7459 }
7460 }
7461
Eric Moore635374e2009-03-09 01:21:12 -06007462 if ((scsi_add_host(shost, &pdev->dev))) {
7463 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7464 ioc->name, __FILE__, __LINE__, __func__);
7465 list_del(&ioc->list);
7466 goto out_add_shost_fail;
7467 }
7468
Eric Moore3c621b32009-05-18 12:59:41 -06007469 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
Eric Moored334aa72010-04-22 10:47:40 -06007470 | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307471 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06007472
Eric Moore635374e2009-03-09 01:21:12 -06007473 /* event thread */
7474 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
7475 "fw_event%d", ioc->id);
7476 ioc->firmware_event_thread = create_singlethread_workqueue(
7477 ioc->firmware_event_name);
7478 if (!ioc->firmware_event_thread) {
7479 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7480 ioc->name, __FILE__, __LINE__, __func__);
7481 goto out_thread_fail;
7482 }
7483
7484 ioc->wait_for_port_enable_to_complete = 1;
7485 if ((mpt2sas_base_attach(ioc))) {
7486 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7487 ioc->name, __FILE__, __LINE__, __func__);
7488 goto out_attach_fail;
7489 }
7490
7491 ioc->wait_for_port_enable_to_complete = 0;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307492 if (ioc->is_warpdrive) {
7493 if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS)
7494 ioc->hide_drives = 0;
7495 else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS)
7496 ioc->hide_drives = 1;
7497 else {
7498 if (_scsih_get_num_volumes(ioc))
7499 ioc->hide_drives = 1;
7500 else
7501 ioc->hide_drives = 0;
7502 }
7503 } else
7504 ioc->hide_drives = 0;
7505
Eric Moore635374e2009-03-09 01:21:12 -06007506 _scsih_probe_devices(ioc);
7507 return 0;
7508
7509 out_attach_fail:
7510 destroy_workqueue(ioc->firmware_event_thread);
7511 out_thread_fail:
7512 list_del(&ioc->list);
7513 scsi_remove_host(shost);
7514 out_add_shost_fail:
7515 return -ENODEV;
7516}
7517
7518#ifdef CONFIG_PM
7519/**
Eric Moored5d135b2009-05-18 13:02:08 -06007520 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06007521 * @pdev: PCI device struct
7522 * @state: PM state change to (usually PCI_D3)
7523 *
7524 * Returns 0 success, anything else error.
7525 */
7526static int
Eric Moored5d135b2009-05-18 13:02:08 -06007527_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06007528{
7529 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7530 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaic97951e2011-06-14 10:54:56 +05307531 pci_power_t device_state;
Eric Moore635374e2009-03-09 01:21:12 -06007532
Kashyap, Desaie4750c92009-08-07 19:37:59 +05307533 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007534 scsi_block_requests(shost);
7535 device_state = pci_choose_state(pdev, state);
7536 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
7537 "operating state [D%d]\n", ioc->name, pdev,
7538 pci_name(pdev), device_state);
7539
7540 mpt2sas_base_free_resources(ioc);
7541 pci_save_state(pdev);
7542 pci_disable_device(pdev);
7543 pci_set_power_state(pdev, device_state);
7544 return 0;
7545}
7546
7547/**
Eric Moored5d135b2009-05-18 13:02:08 -06007548 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06007549 * @pdev: PCI device struct
7550 *
7551 * Returns 0 success, anything else error.
7552 */
7553static int
Eric Moored5d135b2009-05-18 13:02:08 -06007554_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06007555{
7556 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7557 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaic97951e2011-06-14 10:54:56 +05307558 pci_power_t device_state = pdev->current_state;
Eric Moore635374e2009-03-09 01:21:12 -06007559 int r;
7560
7561 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
7562 "operating state [D%d]\n", ioc->name, pdev,
7563 pci_name(pdev), device_state);
7564
7565 pci_set_power_state(pdev, PCI_D0);
7566 pci_enable_wake(pdev, PCI_D0, 0);
7567 pci_restore_state(pdev);
7568 ioc->pdev = pdev;
7569 r = mpt2sas_base_map_resources(ioc);
7570 if (r)
7571 return r;
7572
7573 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
7574 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05307575 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007576 return 0;
7577}
7578#endif /* CONFIG_PM */
7579
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307580/**
7581 * _scsih_pci_error_detected - Called when a PCI error is detected.
7582 * @pdev: PCI device struct
7583 * @state: PCI channel state
7584 *
7585 * Description: Called when a PCI error is detected.
7586 *
7587 * Return value:
7588 * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
7589 */
7590static pci_ers_result_t
7591_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
7592{
7593 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7594 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7595
7596 printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n",
7597 ioc->name, state);
7598
7599 switch (state) {
7600 case pci_channel_io_normal:
7601 return PCI_ERS_RESULT_CAN_RECOVER;
7602 case pci_channel_io_frozen:
Eric Moore3cb54692010-07-08 14:44:34 -06007603 /* Fatal error, prepare for slot reset */
7604 ioc->pci_error_recovery = 1;
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307605 scsi_block_requests(ioc->shost);
7606 mpt2sas_base_stop_watchdog(ioc);
7607 mpt2sas_base_free_resources(ioc);
7608 return PCI_ERS_RESULT_NEED_RESET;
7609 case pci_channel_io_perm_failure:
Eric Moore3cb54692010-07-08 14:44:34 -06007610 /* Permanent error, prepare for device removal */
7611 ioc->pci_error_recovery = 1;
7612 mpt2sas_base_stop_watchdog(ioc);
7613 _scsih_flush_running_cmds(ioc);
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307614 return PCI_ERS_RESULT_DISCONNECT;
7615 }
7616 return PCI_ERS_RESULT_NEED_RESET;
7617}
7618
7619/**
7620 * _scsih_pci_slot_reset - Called when PCI slot has been reset.
7621 * @pdev: PCI device struct
7622 *
7623 * Description: This routine is called by the pci error recovery
7624 * code after the PCI slot has been reset, just before we
7625 * should resume normal operations.
7626 */
7627static pci_ers_result_t
7628_scsih_pci_slot_reset(struct pci_dev *pdev)
7629{
7630 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7631 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7632 int rc;
7633
7634 printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
7635 ioc->name);
7636
Eric Moore3cb54692010-07-08 14:44:34 -06007637 ioc->pci_error_recovery = 0;
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307638 ioc->pdev = pdev;
Eric Moore3cb54692010-07-08 14:44:34 -06007639 pci_restore_state(pdev);
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307640 rc = mpt2sas_base_map_resources(ioc);
7641 if (rc)
7642 return PCI_ERS_RESULT_DISCONNECT;
7643
7644
7645 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
7646 FORCE_BIG_HAMMER);
7647
7648 printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name,
7649 (rc == 0) ? "success" : "failed");
7650
7651 if (!rc)
7652 return PCI_ERS_RESULT_RECOVERED;
7653 else
7654 return PCI_ERS_RESULT_DISCONNECT;
7655}
7656
7657/**
7658 * _scsih_pci_resume() - resume normal ops after PCI reset
7659 * @pdev: pointer to PCI device
7660 *
7661 * Called when the error recovery driver tells us that its
7662 * OK to resume normal operation. Use completion to allow
7663 * halted scsi ops to resume.
7664 */
7665static void
7666_scsih_pci_resume(struct pci_dev *pdev)
7667{
7668 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7669 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7670
7671 printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name);
7672
7673 pci_cleanup_aer_uncorrect_error_status(pdev);
7674 mpt2sas_base_start_watchdog(ioc);
7675 scsi_unblock_requests(ioc->shost);
7676}
7677
7678/**
7679 * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
7680 * @pdev: pointer to PCI device
7681 */
7682static pci_ers_result_t
7683_scsih_pci_mmio_enabled(struct pci_dev *pdev)
7684{
7685 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7686 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7687
7688 printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n",
7689 ioc->name);
7690
7691 /* TODO - dump whatever for debugging purposes */
7692
7693 /* Request a slot reset. */
7694 return PCI_ERS_RESULT_NEED_RESET;
7695}
7696
7697static struct pci_error_handlers _scsih_err_handler = {
7698 .error_detected = _scsih_pci_error_detected,
7699 .mmio_enabled = _scsih_pci_mmio_enabled,
7700 .slot_reset = _scsih_pci_slot_reset,
7701 .resume = _scsih_pci_resume,
7702};
Eric Moore635374e2009-03-09 01:21:12 -06007703
7704static struct pci_driver scsih_driver = {
7705 .name = MPT2SAS_DRIVER_NAME,
7706 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06007707 .probe = _scsih_probe,
7708 .remove = __devexit_p(_scsih_remove),
Kashyap, Desai744090d2009-10-05 15:56:56 +05307709 .shutdown = _scsih_shutdown,
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05307710 .err_handler = &_scsih_err_handler,
Eric Moore635374e2009-03-09 01:21:12 -06007711#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06007712 .suspend = _scsih_suspend,
7713 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06007714#endif
7715};
7716
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307717/* raid transport support */
7718static struct raid_function_template mpt2sas_raid_functions = {
7719 .cookie = &scsih_driver_template,
7720 .is_raid = _scsih_is_raid,
7721 .get_resync = _scsih_get_resync,
7722 .get_state = _scsih_get_state,
7723};
Eric Moore635374e2009-03-09 01:21:12 -06007724
7725/**
Eric Moored5d135b2009-05-18 13:02:08 -06007726 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06007727 *
7728 * Returns 0 success, anything else error.
7729 */
7730static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06007731_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06007732{
7733 int error;
7734
7735 mpt_ids = 0;
7736 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
7737 MPT2SAS_DRIVER_VERSION);
7738
7739 mpt2sas_transport_template =
7740 sas_attach_transport(&mpt2sas_transport_functions);
7741 if (!mpt2sas_transport_template)
7742 return -ENODEV;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307743 /* raid transport support */
7744 mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
7745 if (!mpt2sas_raid_template) {
7746 sas_release_transport(mpt2sas_transport_template);
7747 return -ENODEV;
7748 }
Eric Moore635374e2009-03-09 01:21:12 -06007749
7750 mpt2sas_base_initialize_callback_handler();
7751
7752 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06007753 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06007754
Uwe Kleine-König65155b32010-06-11 12:17:01 +02007755 /* task management callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06007756 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06007757
7758 /* base internal commands callback handler */
7759 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
7760
7761 /* transport internal commands callback handler */
7762 transport_cb_idx = mpt2sas_base_register_callback_handler(
7763 mpt2sas_transport_done);
7764
Kashyap, Desai744090d2009-10-05 15:56:56 +05307765 /* scsih internal commands callback handler */
7766 scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
7767
Eric Moore635374e2009-03-09 01:21:12 -06007768 /* configuration page API internal commands callback handler */
7769 config_cb_idx = mpt2sas_base_register_callback_handler(
7770 mpt2sas_config_done);
7771
7772 /* ctl module callback handler */
7773 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
7774
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307775 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
7776 _scsih_tm_tr_complete);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307777
7778 tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler(
7779 _scsih_tm_volume_tr_complete);
7780
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307781 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
7782 _scsih_sas_control_complete);
7783
Eric Moore635374e2009-03-09 01:21:12 -06007784 mpt2sas_ctl_init();
7785
7786 error = pci_register_driver(&scsih_driver);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307787 if (error) {
7788 /* raid transport support */
7789 raid_class_release(mpt2sas_raid_template);
Eric Moore635374e2009-03-09 01:21:12 -06007790 sas_release_transport(mpt2sas_transport_template);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307791 }
Eric Moore635374e2009-03-09 01:21:12 -06007792
7793 return error;
7794}
7795
7796/**
Eric Moored5d135b2009-05-18 13:02:08 -06007797 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06007798 *
7799 * Returns 0 success, anything else error.
7800 */
7801static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06007802_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06007803{
7804 printk(KERN_INFO "mpt2sas version %s unloading\n",
7805 MPT2SAS_DRIVER_VERSION);
7806
7807 pci_unregister_driver(&scsih_driver);
7808
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307809 mpt2sas_ctl_exit();
7810
Eric Moore635374e2009-03-09 01:21:12 -06007811 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
7812 mpt2sas_base_release_callback_handler(tm_cb_idx);
7813 mpt2sas_base_release_callback_handler(base_cb_idx);
7814 mpt2sas_base_release_callback_handler(transport_cb_idx);
Kashyap, Desai744090d2009-10-05 15:56:56 +05307815 mpt2sas_base_release_callback_handler(scsih_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06007816 mpt2sas_base_release_callback_handler(config_cb_idx);
7817 mpt2sas_base_release_callback_handler(ctl_cb_idx);
7818
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307819 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307820 mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307821 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
7822
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05307823 /* raid transport support */
7824 raid_class_release(mpt2sas_raid_template);
7825 sas_release_transport(mpt2sas_transport_template);
7826
Eric Moore635374e2009-03-09 01:21:12 -06007827}
7828
Eric Moored5d135b2009-05-18 13:02:08 -06007829module_init(_scsih_init);
7830module_exit(_scsih_exit);