blob: bb5659ca128d4a6a066698b42d433ac7d50bff89 [file] [log] [blame]
Eric Moore635374e2009-03-09 01:21:12 -06001/*
2 * Scsi Host Layer for MPT (Message Passing Technology) based controllers
3 *
4 * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
Kashyap, Desai31b7f2e2010-03-17 16:28:04 +05305 * Copyright (C) 2007-2010 LSI Corporation
Eric Moore635374e2009-03-09 01:21:12 -06006 * (mailto:DL-MPTFusionLinux@lsi.com)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * NO WARRANTY
19 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
20 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
21 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
22 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
23 * solely responsible for determining the appropriateness of using and
24 * distributing the Program and assumes all risks associated with its
25 * exercise of rights under this Agreement, including but not limited to
26 * the risks and costs of program errors, damage to or loss of data,
27 * programs or equipment, and unavailability or interruption of operations.
28
29 * DISCLAIMER OF LIABILITY
30 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
31 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
36 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
37
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
41 * USA.
42 */
43
44#include <linux/version.h>
45#include <linux/module.h>
46#include <linux/kernel.h>
47#include <linux/init.h>
48#include <linux/errno.h>
49#include <linux/blkdev.h>
50#include <linux/sched.h>
51#include <linux/workqueue.h>
52#include <linux/delay.h>
53#include <linux/pci.h>
54#include <linux/interrupt.h>
Kashyap, Desaief7c80c2010-04-05 14:20:07 +053055#include <linux/aer.h>
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +053056#include <linux/raid_class.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090057#include <linux/slab.h>
Eric Moore635374e2009-03-09 01:21:12 -060058
59#include "mpt2sas_base.h"
60
61MODULE_AUTHOR(MPT2SAS_AUTHOR);
62MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
63MODULE_LICENSE("GPL");
64MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
65
66#define RAID_CHANNEL 1
67
68/* forward proto's */
69static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
70 struct _sas_node *sas_expander);
71static void _firmware_event_work(struct work_struct *work);
72
73/* global parameters */
Eric Mooreba33fad2009-03-15 21:37:18 -060074LIST_HEAD(mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -060075
76/* local parameters */
Eric Moore635374e2009-03-09 01:21:12 -060077static u8 scsi_io_cb_idx = -1;
78static u8 tm_cb_idx = -1;
79static u8 ctl_cb_idx = -1;
80static u8 base_cb_idx = -1;
81static u8 transport_cb_idx = -1;
Kashyap, Desai744090d2009-10-05 15:56:56 +053082static u8 scsih_cb_idx = -1;
Eric Moore635374e2009-03-09 01:21:12 -060083static u8 config_cb_idx = -1;
84static int mpt_ids;
85
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053086static u8 tm_tr_cb_idx = -1 ;
87static u8 tm_sas_control_cb_idx = -1;
88
Eric Moore635374e2009-03-09 01:21:12 -060089/* command line options */
Eric Mooreba33fad2009-03-15 21:37:18 -060090static u32 logging_level;
Eric Moore635374e2009-03-09 01:21:12 -060091MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
92 "(default=0)");
93
94/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
95#define MPT2SAS_MAX_LUN (16895)
96static int max_lun = MPT2SAS_MAX_LUN;
97module_param(max_lun, int, 0);
98MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
99
100/**
101 * struct sense_info - common structure for obtaining sense keys
102 * @skey: sense key
103 * @asc: additional sense code
104 * @ascq: additional sense code qualifier
105 */
106struct sense_info {
107 u8 skey;
108 u8 asc;
109 u8 ascq;
110};
111
112
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530113#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF)
114
Eric Moore635374e2009-03-09 01:21:12 -0600115/**
116 * struct fw_event_work - firmware event struct
117 * @list: link list framework
118 * @work: work object (ioc->fault_reset_work_q)
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530119 * @cancel_pending_work: flag set during reset handling
Eric Moore635374e2009-03-09 01:21:12 -0600120 * @ioc: per adapter object
121 * @VF_ID: virtual function id
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530122 * @VP_ID: virtual port id
Eric Moore635374e2009-03-09 01:21:12 -0600123 * @ignore: flag meaning this event has been marked to ignore
124 * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
125 * @event_data: reply event data payload follows
126 *
127 * This object stored on ioc->fw_event_list.
128 */
129struct fw_event_work {
130 struct list_head list;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530131 u8 cancel_pending_work;
132 struct delayed_work delayed_work;
Eric Moore635374e2009-03-09 01:21:12 -0600133 struct MPT2SAS_ADAPTER *ioc;
134 u8 VF_ID;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530135 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600136 u8 ignore;
137 u16 event;
138 void *event_data;
139};
140
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +0530141/* raid transport support */
142static struct raid_template *mpt2sas_raid_template;
143
Eric Moore635374e2009-03-09 01:21:12 -0600144/**
145 * struct _scsi_io_transfer - scsi io transfer
146 * @handle: sas device handle (assigned by firmware)
147 * @is_raid: flag set for hidden raid components
148 * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
149 * @data_length: data transfer length
150 * @data_dma: dma pointer to data
151 * @sense: sense data
152 * @lun: lun number
153 * @cdb_length: cdb length
154 * @cdb: cdb contents
Eric Moore635374e2009-03-09 01:21:12 -0600155 * @timeout: timeout for this command
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530156 * @VF_ID: virtual function id
157 * @VP_ID: virtual port id
158 * @valid_reply: flag set for reply message
Eric Moore635374e2009-03-09 01:21:12 -0600159 * @sense_length: sense length
160 * @ioc_status: ioc status
161 * @scsi_state: scsi state
162 * @scsi_status: scsi staus
163 * @log_info: log information
164 * @transfer_length: data length transfer when there is a reply message
165 *
166 * Used for sending internal scsi commands to devices within this module.
167 * Refer to _scsi_send_scsi_io().
168 */
169struct _scsi_io_transfer {
170 u16 handle;
171 u8 is_raid;
172 enum dma_data_direction dir;
173 u32 data_length;
174 dma_addr_t data_dma;
175 u8 sense[SCSI_SENSE_BUFFERSIZE];
176 u32 lun;
177 u8 cdb_length;
178 u8 cdb[32];
179 u8 timeout;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530180 u8 VF_ID;
181 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600182 u8 valid_reply;
183 /* the following bits are only valid when 'valid_reply = 1' */
184 u32 sense_length;
185 u16 ioc_status;
186 u8 scsi_state;
187 u8 scsi_status;
188 u32 log_info;
189 u32 transfer_length;
190};
191
192/*
193 * The pci device ids are defined in mpi/mpi2_cnfg.h.
194 */
195static struct pci_device_id scsih_pci_table[] = {
196 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
197 PCI_ANY_ID, PCI_ANY_ID },
198 /* Falcon ~ 2008*/
199 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
200 PCI_ANY_ID, PCI_ANY_ID },
201 /* Liberator ~ 2108 */
202 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
203 PCI_ANY_ID, PCI_ANY_ID },
204 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
205 PCI_ANY_ID, PCI_ANY_ID },
206 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
207 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530208 /* Meteor ~ 2116 */
Eric Moore635374e2009-03-09 01:21:12 -0600209 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
210 PCI_ANY_ID, PCI_ANY_ID },
211 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
212 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530213 /* Thunderbolt ~ 2208 */
214 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
215 PCI_ANY_ID, PCI_ANY_ID },
216 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
217 PCI_ANY_ID, PCI_ANY_ID },
218 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
219 PCI_ANY_ID, PCI_ANY_ID },
220 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
221 PCI_ANY_ID, PCI_ANY_ID },
222 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
223 PCI_ANY_ID, PCI_ANY_ID },
224 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
225 PCI_ANY_ID, PCI_ANY_ID },
226 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7,
227 PCI_ANY_ID, PCI_ANY_ID },
228 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8,
229 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore635374e2009-03-09 01:21:12 -0600230 {0} /* Terminating entry */
231};
232MODULE_DEVICE_TABLE(pci, scsih_pci_table);
233
234/**
Eric Moored5d135b2009-05-18 13:02:08 -0600235 * _scsih_set_debug_level - global setting of ioc->logging_level.
Eric Moore635374e2009-03-09 01:21:12 -0600236 *
237 * Note: The logging levels are defined in mpt2sas_debug.h.
238 */
239static int
Eric Moored5d135b2009-05-18 13:02:08 -0600240_scsih_set_debug_level(const char *val, struct kernel_param *kp)
Eric Moore635374e2009-03-09 01:21:12 -0600241{
242 int ret = param_set_int(val, kp);
243 struct MPT2SAS_ADAPTER *ioc;
244
245 if (ret)
246 return ret;
247
248 printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
Eric Mooreba33fad2009-03-15 21:37:18 -0600249 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
Eric Moore635374e2009-03-09 01:21:12 -0600250 ioc->logging_level = logging_level;
251 return 0;
252}
Eric Moored5d135b2009-05-18 13:02:08 -0600253module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
Eric Moore635374e2009-03-09 01:21:12 -0600254 &logging_level, 0644);
255
256/**
257 * _scsih_srch_boot_sas_address - search based on sas_address
258 * @sas_address: sas address
259 * @boot_device: boot device object from bios page 2
260 *
261 * Returns 1 when there's a match, 0 means no match.
262 */
263static inline int
264_scsih_srch_boot_sas_address(u64 sas_address,
265 Mpi2BootDeviceSasWwid_t *boot_device)
266{
267 return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
268}
269
270/**
271 * _scsih_srch_boot_device_name - search based on device name
272 * @device_name: device name specified in INDENTIFY fram
273 * @boot_device: boot device object from bios page 2
274 *
275 * Returns 1 when there's a match, 0 means no match.
276 */
277static inline int
278_scsih_srch_boot_device_name(u64 device_name,
279 Mpi2BootDeviceDeviceName_t *boot_device)
280{
281 return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
282}
283
284/**
285 * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
286 * @enclosure_logical_id: enclosure logical id
287 * @slot_number: slot number
288 * @boot_device: boot device object from bios page 2
289 *
290 * Returns 1 when there's a match, 0 means no match.
291 */
292static inline int
293_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
294 Mpi2BootDeviceEnclosureSlot_t *boot_device)
295{
296 return (enclosure_logical_id == le64_to_cpu(boot_device->
297 EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
298 SlotNumber)) ? 1 : 0;
299}
300
301/**
302 * _scsih_is_boot_device - search for matching boot device.
303 * @sas_address: sas address
304 * @device_name: device name specified in INDENTIFY fram
305 * @enclosure_logical_id: enclosure logical id
306 * @slot_number: slot number
307 * @form: specifies boot device form
308 * @boot_device: boot device object from bios page 2
309 *
310 * Returns 1 when there's a match, 0 means no match.
311 */
312static int
313_scsih_is_boot_device(u64 sas_address, u64 device_name,
314 u64 enclosure_logical_id, u16 slot, u8 form,
315 Mpi2BiosPage2BootDevice_t *boot_device)
316{
317 int rc = 0;
318
319 switch (form) {
320 case MPI2_BIOSPAGE2_FORM_SAS_WWID:
321 if (!sas_address)
322 break;
323 rc = _scsih_srch_boot_sas_address(
324 sas_address, &boot_device->SasWwid);
325 break;
326 case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
327 if (!enclosure_logical_id)
328 break;
329 rc = _scsih_srch_boot_encl_slot(
330 enclosure_logical_id,
331 slot, &boot_device->EnclosureSlot);
332 break;
333 case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
334 if (!device_name)
335 break;
336 rc = _scsih_srch_boot_device_name(
337 device_name, &boot_device->DeviceName);
338 break;
339 case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
340 break;
341 }
342
343 return rc;
344}
345
346/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530347 * _scsih_get_sas_address - set the sas_address for given device handle
348 * @handle: device handle
349 * @sas_address: sas address
350 *
351 * Returns 0 success, non-zero when failure
352 */
353static int
354_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
355 u64 *sas_address)
356{
357 Mpi2SasDevicePage0_t sas_device_pg0;
358 Mpi2ConfigReply_t mpi_reply;
359 u32 ioc_status;
360
361 if (handle <= ioc->sas_hba.num_phys) {
362 *sas_address = ioc->sas_hba.sas_address;
363 return 0;
364 } else
365 *sas_address = 0;
366
367 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
368 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
369 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
370 ioc->name, __FILE__, __LINE__, __func__);
371 return -ENXIO;
372 }
373
374 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
375 MPI2_IOCSTATUS_MASK;
376 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
377 printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
378 "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
379 __FILE__, __LINE__, __func__);
380 return -EIO;
381 }
382
383 *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
384 return 0;
385}
386
387/**
Eric Moore635374e2009-03-09 01:21:12 -0600388 * _scsih_determine_boot_device - determine boot device.
389 * @ioc: per adapter object
390 * @device: either sas_device or raid_device object
391 * @is_raid: [flag] 1 = raid object, 0 = sas object
392 *
393 * Determines whether this device should be first reported device to
394 * to scsi-ml or sas transport, this purpose is for persistant boot device.
395 * There are primary, alternate, and current entries in bios page 2. The order
396 * priority is primary, alternate, then current. This routine saves
397 * the corresponding device object and is_raid flag in the ioc object.
398 * The saved data to be used later in _scsih_probe_boot_devices().
399 */
400static void
401_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
402 void *device, u8 is_raid)
403{
404 struct _sas_device *sas_device;
405 struct _raid_device *raid_device;
406 u64 sas_address;
407 u64 device_name;
408 u64 enclosure_logical_id;
409 u16 slot;
410
411 /* only process this function when driver loads */
412 if (!ioc->wait_for_port_enable_to_complete)
413 return;
414
415 if (!is_raid) {
416 sas_device = device;
417 sas_address = sas_device->sas_address;
418 device_name = sas_device->device_name;
419 enclosure_logical_id = sas_device->enclosure_logical_id;
420 slot = sas_device->slot;
421 } else {
422 raid_device = device;
423 sas_address = raid_device->wwid;
424 device_name = 0;
425 enclosure_logical_id = 0;
426 slot = 0;
427 }
428
429 if (!ioc->req_boot_device.device) {
430 if (_scsih_is_boot_device(sas_address, device_name,
431 enclosure_logical_id, slot,
432 (ioc->bios_pg2.ReqBootDeviceForm &
433 MPI2_BIOSPAGE2_FORM_MASK),
434 &ioc->bios_pg2.RequestedBootDevice)) {
435 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
436 "%s: req_boot_device(0x%016llx)\n",
437 ioc->name, __func__,
438 (unsigned long long)sas_address));
439 ioc->req_boot_device.device = device;
440 ioc->req_boot_device.is_raid = is_raid;
441 }
442 }
443
444 if (!ioc->req_alt_boot_device.device) {
445 if (_scsih_is_boot_device(sas_address, device_name,
446 enclosure_logical_id, slot,
447 (ioc->bios_pg2.ReqAltBootDeviceForm &
448 MPI2_BIOSPAGE2_FORM_MASK),
449 &ioc->bios_pg2.RequestedAltBootDevice)) {
450 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
451 "%s: req_alt_boot_device(0x%016llx)\n",
452 ioc->name, __func__,
453 (unsigned long long)sas_address));
454 ioc->req_alt_boot_device.device = device;
455 ioc->req_alt_boot_device.is_raid = is_raid;
456 }
457 }
458
459 if (!ioc->current_boot_device.device) {
460 if (_scsih_is_boot_device(sas_address, device_name,
461 enclosure_logical_id, slot,
462 (ioc->bios_pg2.CurrentBootDeviceForm &
463 MPI2_BIOSPAGE2_FORM_MASK),
464 &ioc->bios_pg2.CurrentBootDevice)) {
465 dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
466 "%s: current_boot_device(0x%016llx)\n",
467 ioc->name, __func__,
468 (unsigned long long)sas_address));
469 ioc->current_boot_device.device = device;
470 ioc->current_boot_device.is_raid = is_raid;
471 }
472 }
473}
474
475/**
476 * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
477 * @ioc: per adapter object
478 * @sas_address: sas address
479 * Context: Calling function should acquire ioc->sas_device_lock
480 *
481 * This searches for sas_device based on sas_address, then return sas_device
482 * object.
483 */
484struct _sas_device *
485mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
486 u64 sas_address)
487{
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530488 struct _sas_device *sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600489
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530490 list_for_each_entry(sas_device, &ioc->sas_device_list, list)
491 if (sas_device->sas_address == sas_address)
492 return sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600493
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530494 list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
495 if (sas_device->sas_address == sas_address)
496 return sas_device;
497
498 return NULL;
Eric Moore635374e2009-03-09 01:21:12 -0600499}
500
501/**
502 * _scsih_sas_device_find_by_handle - sas device search
503 * @ioc: per adapter object
504 * @handle: sas device handle (assigned by firmware)
505 * Context: Calling function should acquire ioc->sas_device_lock
506 *
507 * This searches for sas_device based on sas_address, then return sas_device
508 * object.
509 */
510static struct _sas_device *
511_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
512{
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530513 struct _sas_device *sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600514
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530515 list_for_each_entry(sas_device, &ioc->sas_device_list, list)
516 if (sas_device->handle == handle)
517 return sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600518
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530519 list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
520 if (sas_device->handle == handle)
521 return sas_device;
522
523 return NULL;
Eric Moore635374e2009-03-09 01:21:12 -0600524}
525
526/**
527 * _scsih_sas_device_remove - remove sas_device from list.
528 * @ioc: per adapter object
529 * @sas_device: the sas_device object
530 * Context: This function will acquire ioc->sas_device_lock.
531 *
532 * Removing object and freeing associated memory from the ioc->sas_device_list.
533 */
534static void
535_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
536 struct _sas_device *sas_device)
537{
538 unsigned long flags;
539
540 spin_lock_irqsave(&ioc->sas_device_lock, flags);
541 list_del(&sas_device->list);
542 memset(sas_device, 0, sizeof(struct _sas_device));
543 kfree(sas_device);
544 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
545}
546
547/**
548 * _scsih_sas_device_add - insert sas_device to the list.
549 * @ioc: per adapter object
550 * @sas_device: the sas_device object
551 * Context: This function will acquire ioc->sas_device_lock.
552 *
553 * Adding new object to the ioc->sas_device_list.
554 */
555static void
556_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
557 struct _sas_device *sas_device)
558{
559 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -0600560
561 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
562 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
563 sas_device->handle, (unsigned long long)sas_device->sas_address));
564
565 spin_lock_irqsave(&ioc->sas_device_lock, flags);
566 list_add_tail(&sas_device->list, &ioc->sas_device_list);
567 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
568
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530569 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
570 sas_device->sas_address_parent))
Eric Moore635374e2009-03-09 01:21:12 -0600571 _scsih_sas_device_remove(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -0600572}
573
574/**
575 * _scsih_sas_device_init_add - insert sas_device to the list.
576 * @ioc: per adapter object
577 * @sas_device: the sas_device object
578 * Context: This function will acquire ioc->sas_device_lock.
579 *
580 * Adding new object at driver load time to the ioc->sas_device_init_list.
581 */
582static void
583_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
584 struct _sas_device *sas_device)
585{
586 unsigned long flags;
587
588 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
589 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
590 sas_device->handle, (unsigned long long)sas_device->sas_address));
591
592 spin_lock_irqsave(&ioc->sas_device_lock, flags);
593 list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
594 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
595 _scsih_determine_boot_device(ioc, sas_device, 0);
596}
597
598/**
Eric Moore635374e2009-03-09 01:21:12 -0600599 * _scsih_raid_device_find_by_id - raid device search
600 * @ioc: per adapter object
601 * @id: sas device target id
602 * @channel: sas device channel
603 * Context: Calling function should acquire ioc->raid_device_lock
604 *
605 * This searches for raid_device based on target id, then return raid_device
606 * object.
607 */
608static struct _raid_device *
609_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
610{
611 struct _raid_device *raid_device, *r;
612
613 r = NULL;
614 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
615 if (raid_device->id == id && raid_device->channel == channel) {
616 r = raid_device;
617 goto out;
618 }
619 }
620
621 out:
622 return r;
623}
624
625/**
626 * _scsih_raid_device_find_by_handle - raid device search
627 * @ioc: per adapter object
628 * @handle: sas device handle (assigned by firmware)
629 * Context: Calling function should acquire ioc->raid_device_lock
630 *
631 * This searches for raid_device based on handle, then return raid_device
632 * object.
633 */
634static struct _raid_device *
635_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
636{
637 struct _raid_device *raid_device, *r;
638
639 r = NULL;
640 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
641 if (raid_device->handle != handle)
642 continue;
643 r = raid_device;
644 goto out;
645 }
646
647 out:
648 return r;
649}
650
651/**
652 * _scsih_raid_device_find_by_wwid - raid device search
653 * @ioc: per adapter object
654 * @handle: sas device handle (assigned by firmware)
655 * Context: Calling function should acquire ioc->raid_device_lock
656 *
657 * This searches for raid_device based on wwid, then return raid_device
658 * object.
659 */
660static struct _raid_device *
661_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
662{
663 struct _raid_device *raid_device, *r;
664
665 r = NULL;
666 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
667 if (raid_device->wwid != wwid)
668 continue;
669 r = raid_device;
670 goto out;
671 }
672
673 out:
674 return r;
675}
676
677/**
678 * _scsih_raid_device_add - add raid_device object
679 * @ioc: per adapter object
680 * @raid_device: raid_device object
681 *
682 * This is added to the raid_device_list link list.
683 */
684static void
685_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
686 struct _raid_device *raid_device)
687{
688 unsigned long flags;
689
690 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
691 "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
692 raid_device->handle, (unsigned long long)raid_device->wwid));
693
694 spin_lock_irqsave(&ioc->raid_device_lock, flags);
695 list_add_tail(&raid_device->list, &ioc->raid_device_list);
696 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
697}
698
699/**
700 * _scsih_raid_device_remove - delete raid_device object
701 * @ioc: per adapter object
702 * @raid_device: raid_device object
703 *
704 * This is removed from the raid_device_list link list.
705 */
706static void
707_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
708 struct _raid_device *raid_device)
709{
710 unsigned long flags;
711
712 spin_lock_irqsave(&ioc->raid_device_lock, flags);
713 list_del(&raid_device->list);
714 memset(raid_device, 0, sizeof(struct _raid_device));
715 kfree(raid_device);
716 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
717}
718
719/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530720 * mpt2sas_scsih_expander_find_by_handle - expander device search
721 * @ioc: per adapter object
722 * @handle: expander handle (assigned by firmware)
723 * Context: Calling function should acquire ioc->sas_device_lock
724 *
725 * This searches for expander device based on handle, then returns the
726 * sas_node object.
727 */
728struct _sas_node *
729mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
730{
731 struct _sas_node *sas_expander, *r;
732
733 r = NULL;
734 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
735 if (sas_expander->handle != handle)
736 continue;
737 r = sas_expander;
738 goto out;
739 }
740 out:
741 return r;
742}
743
744/**
Eric Moore635374e2009-03-09 01:21:12 -0600745 * mpt2sas_scsih_expander_find_by_sas_address - expander device search
746 * @ioc: per adapter object
747 * @sas_address: sas address
748 * Context: Calling function should acquire ioc->sas_node_lock.
749 *
750 * This searches for expander device based on sas_address, then returns the
751 * sas_node object.
752 */
753struct _sas_node *
754mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
755 u64 sas_address)
756{
757 struct _sas_node *sas_expander, *r;
758
759 r = NULL;
760 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
761 if (sas_expander->sas_address != sas_address)
762 continue;
763 r = sas_expander;
764 goto out;
765 }
766 out:
767 return r;
768}
769
770/**
771 * _scsih_expander_node_add - insert expander device to the list.
772 * @ioc: per adapter object
773 * @sas_expander: the sas_device object
774 * Context: This function will acquire ioc->sas_node_lock.
775 *
776 * Adding new object to the ioc->sas_expander_list.
777 *
778 * Return nothing.
779 */
780static void
781_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
782 struct _sas_node *sas_expander)
783{
784 unsigned long flags;
785
786 spin_lock_irqsave(&ioc->sas_node_lock, flags);
787 list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
788 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
789}
790
791/**
792 * _scsih_is_end_device - determines if device is an end device
793 * @device_info: bitfield providing information about the device.
794 * Context: none
795 *
796 * Returns 1 if end device.
797 */
798static int
799_scsih_is_end_device(u32 device_info)
800{
801 if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
802 ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
803 (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
804 (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
805 return 1;
806 else
807 return 0;
808}
809
810/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530811 * mptscsih_get_scsi_lookup - returns scmd entry
Eric Moore635374e2009-03-09 01:21:12 -0600812 * @ioc: per adapter object
813 * @smid: system request message index
Eric Moore635374e2009-03-09 01:21:12 -0600814 *
815 * Returns the smid stored scmd pointer.
816 */
817static struct scsi_cmnd *
818_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
819{
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530820 return ioc->scsi_lookup[smid - 1].scmd;
Eric Moore635374e2009-03-09 01:21:12 -0600821}
822
823/**
824 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
825 * @ioc: per adapter object
826 * @smid: system request message index
827 * @scmd: pointer to scsi command object
828 * Context: This function will acquire ioc->scsi_lookup_lock.
829 *
830 * This will search for a scmd pointer in the scsi_lookup array,
831 * returning the revelent smid. A returned value of zero means invalid.
832 */
833static u16
834_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
835 *scmd)
836{
837 u16 smid;
838 unsigned long flags;
839 int i;
840
841 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
842 smid = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530843 for (i = 0; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600844 if (ioc->scsi_lookup[i].scmd == scmd) {
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530845 smid = ioc->scsi_lookup[i].smid;
Eric Moore635374e2009-03-09 01:21:12 -0600846 goto out;
847 }
848 }
849 out:
850 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
851 return smid;
852}
853
854/**
855 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
856 * @ioc: per adapter object
857 * @id: target id
858 * @channel: channel
859 * Context: This function will acquire ioc->scsi_lookup_lock.
860 *
861 * This will search for a matching channel:id in the scsi_lookup array,
862 * returning 1 if found.
863 */
864static u8
865_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
866 int channel)
867{
868 u8 found;
869 unsigned long flags;
870 int i;
871
872 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
873 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530874 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600875 if (ioc->scsi_lookup[i].scmd &&
876 (ioc->scsi_lookup[i].scmd->device->id == id &&
877 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
878 found = 1;
879 goto out;
880 }
881 }
882 out:
883 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
884 return found;
885}
886
887/**
Eric Moore993e0da2009-05-18 13:00:45 -0600888 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
889 * @ioc: per adapter object
890 * @id: target id
891 * @lun: lun number
892 * @channel: channel
893 * Context: This function will acquire ioc->scsi_lookup_lock.
894 *
895 * This will search for a matching channel:id:lun in the scsi_lookup array,
896 * returning 1 if found.
897 */
898static u8
899_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
900 unsigned int lun, int channel)
901{
902 u8 found;
903 unsigned long flags;
904 int i;
905
906 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
907 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530908 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore993e0da2009-05-18 13:00:45 -0600909 if (ioc->scsi_lookup[i].scmd &&
910 (ioc->scsi_lookup[i].scmd->device->id == id &&
911 ioc->scsi_lookup[i].scmd->device->channel == channel &&
912 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
913 found = 1;
914 goto out;
915 }
916 }
917 out:
918 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
919 return found;
920}
921
922/**
Eric Moore635374e2009-03-09 01:21:12 -0600923 * _scsih_get_chain_buffer_dma - obtain block of chains (dma address)
924 * @ioc: per adapter object
925 * @smid: system request message index
926 *
927 * Returns phys pointer to chain buffer.
928 */
929static dma_addr_t
930_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
931{
932 return ioc->chain_dma + ((smid - 1) * (ioc->request_sz *
933 ioc->chains_needed_per_io));
934}
935
936/**
937 * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request
938 * @ioc: per adapter object
939 * @smid: system request message index
940 *
941 * Returns virt pointer to chain buffer.
942 */
943static void *
944_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
945{
946 return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz *
947 ioc->chains_needed_per_io)));
948}
949
950/**
951 * _scsih_build_scatter_gather - main sg creation routine
952 * @ioc: per adapter object
953 * @scmd: scsi command
954 * @smid: system request message index
955 * Context: none.
956 *
957 * The main routine that builds scatter gather table from a given
958 * scsi request sent via the .queuecommand main handler.
959 *
960 * Returns 0 success, anything else error
961 */
962static int
963_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
964 struct scsi_cmnd *scmd, u16 smid)
965{
966 Mpi2SCSIIORequest_t *mpi_request;
967 dma_addr_t chain_dma;
968 struct scatterlist *sg_scmd;
969 void *sg_local, *chain;
970 u32 chain_offset;
971 u32 chain_length;
972 u32 chain_flags;
FUJITA Tomonoribb789d02010-03-09 11:09:50 +0900973 int sges_left;
Eric Moore635374e2009-03-09 01:21:12 -0600974 u32 sges_in_segment;
975 u32 sgl_flags;
976 u32 sgl_flags_last_element;
977 u32 sgl_flags_end_buffer;
978
979 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
980
981 /* init scatter gather flags */
982 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
983 if (scmd->sc_data_direction == DMA_TO_DEVICE)
984 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
985 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
986 << MPI2_SGE_FLAGS_SHIFT;
987 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
988 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
989 << MPI2_SGE_FLAGS_SHIFT;
990 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
991
992 sg_scmd = scsi_sglist(scmd);
993 sges_left = scsi_dma_map(scmd);
FUJITA Tomonoribb789d02010-03-09 11:09:50 +0900994 if (sges_left < 0) {
Eric Moore635374e2009-03-09 01:21:12 -0600995 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
996 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
997 return -ENOMEM;
998 }
999
1000 sg_local = &mpi_request->SGL;
1001 sges_in_segment = ioc->max_sges_in_main_message;
1002 if (sges_left <= sges_in_segment)
1003 goto fill_in_last_segment;
1004
1005 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
1006 (sges_in_segment * ioc->sge_size))/4;
1007
1008 /* fill in main message segment when there is a chain following */
1009 while (sges_in_segment) {
1010 if (sges_in_segment == 1)
1011 ioc->base_add_sg_single(sg_local,
1012 sgl_flags_last_element | sg_dma_len(sg_scmd),
1013 sg_dma_address(sg_scmd));
1014 else
1015 ioc->base_add_sg_single(sg_local, sgl_flags |
1016 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1017 sg_scmd = sg_next(sg_scmd);
1018 sg_local += ioc->sge_size;
1019 sges_left--;
1020 sges_in_segment--;
1021 }
1022
1023 /* initializing the chain flags and pointers */
1024 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
1025 chain = _scsih_get_chain_buffer(ioc, smid);
1026 chain_dma = _scsih_get_chain_buffer_dma(ioc, smid);
1027 do {
1028 sges_in_segment = (sges_left <=
1029 ioc->max_sges_in_chain_message) ? sges_left :
1030 ioc->max_sges_in_chain_message;
1031 chain_offset = (sges_left == sges_in_segment) ?
1032 0 : (sges_in_segment * ioc->sge_size)/4;
1033 chain_length = sges_in_segment * ioc->sge_size;
1034 if (chain_offset) {
1035 chain_offset = chain_offset <<
1036 MPI2_SGE_CHAIN_OFFSET_SHIFT;
1037 chain_length += ioc->sge_size;
1038 }
1039 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
1040 chain_length, chain_dma);
1041 sg_local = chain;
1042 if (!chain_offset)
1043 goto fill_in_last_segment;
1044
1045 /* fill in chain segments */
1046 while (sges_in_segment) {
1047 if (sges_in_segment == 1)
1048 ioc->base_add_sg_single(sg_local,
1049 sgl_flags_last_element |
1050 sg_dma_len(sg_scmd),
1051 sg_dma_address(sg_scmd));
1052 else
1053 ioc->base_add_sg_single(sg_local, sgl_flags |
1054 sg_dma_len(sg_scmd),
1055 sg_dma_address(sg_scmd));
1056 sg_scmd = sg_next(sg_scmd);
1057 sg_local += ioc->sge_size;
1058 sges_left--;
1059 sges_in_segment--;
1060 }
1061
1062 chain_dma += ioc->request_sz;
1063 chain += ioc->request_sz;
1064 } while (1);
1065
1066
1067 fill_in_last_segment:
1068
1069 /* fill the last segment */
1070 while (sges_left) {
1071 if (sges_left == 1)
1072 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1073 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1074 else
1075 ioc->base_add_sg_single(sg_local, sgl_flags |
1076 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1077 sg_scmd = sg_next(sg_scmd);
1078 sg_local += ioc->sge_size;
1079 sges_left--;
1080 }
1081
1082 return 0;
1083}
1084
1085/**
Eric Moored5d135b2009-05-18 13:02:08 -06001086 * _scsih_change_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001087 * @sdev: scsi device struct
1088 * @qdepth: requested queue depth
Mike Christiee881a172009-10-15 17:46:39 -07001089 * @reason: calling context
Eric Moore635374e2009-03-09 01:21:12 -06001090 *
1091 * Returns queue depth.
1092 */
1093static int
Mike Christiee881a172009-10-15 17:46:39 -07001094_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
Eric Moore635374e2009-03-09 01:21:12 -06001095{
1096 struct Scsi_Host *shost = sdev->host;
1097 int max_depth;
1098 int tag_type;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301099 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1100 struct MPT2SAS_DEVICE *sas_device_priv_data;
1101 struct MPT2SAS_TARGET *sas_target_priv_data;
1102 struct _sas_device *sas_device;
1103 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06001104
Mike Christiee881a172009-10-15 17:46:39 -07001105 if (reason != SCSI_QDEPTH_DEFAULT)
1106 return -EOPNOTSUPP;
1107
Eric Moore635374e2009-03-09 01:21:12 -06001108 max_depth = shost->can_queue;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301109
1110 /* limit max device queue for SATA to 32 */
1111 sas_device_priv_data = sdev->hostdata;
1112 if (!sas_device_priv_data)
1113 goto not_sata;
1114 sas_target_priv_data = sas_device_priv_data->sas_target;
1115 if (!sas_target_priv_data)
1116 goto not_sata;
1117 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
1118 goto not_sata;
1119 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1120 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1121 sas_device_priv_data->sas_target->sas_address);
1122 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1123 if (sas_device && sas_device->device_info &
1124 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1125 max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
1126
1127 not_sata:
1128
Eric Moore635374e2009-03-09 01:21:12 -06001129 if (!sdev->tagged_supported)
1130 max_depth = 1;
1131 if (qdepth > max_depth)
1132 qdepth = max_depth;
1133 tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG;
1134 scsi_adjust_queue_depth(sdev, tag_type, qdepth);
1135
1136 if (sdev->inquiry_len > 7)
1137 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1138 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1139 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1140 sdev->ordered_tags, sdev->scsi_level,
1141 (sdev->inquiry[7] & 2) >> 1);
1142
1143 return sdev->queue_depth;
1144}
1145
1146/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301147 * _scsih_change_queue_type - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001148 * @sdev: scsi device struct
1149 * @tag_type: requested tag type
1150 *
1151 * Returns queue tag type.
1152 */
1153static int
Eric Moored5d135b2009-05-18 13:02:08 -06001154_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001155{
1156 if (sdev->tagged_supported) {
1157 scsi_set_tag_type(sdev, tag_type);
1158 if (tag_type)
1159 scsi_activate_tcq(sdev, sdev->queue_depth);
1160 else
1161 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1162 } else
1163 tag_type = 0;
1164
1165 return tag_type;
1166}
1167
1168/**
Eric Moored5d135b2009-05-18 13:02:08 -06001169 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001170 * @starget: scsi target struct
1171 *
1172 * Returns 0 if ok. Any other return is assumed to be an error and
1173 * the device is ignored.
1174 */
1175static int
Eric Moored5d135b2009-05-18 13:02:08 -06001176_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001177{
1178 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1179 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1180 struct MPT2SAS_TARGET *sas_target_priv_data;
1181 struct _sas_device *sas_device;
1182 struct _raid_device *raid_device;
1183 unsigned long flags;
1184 struct sas_rphy *rphy;
1185
1186 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1187 if (!sas_target_priv_data)
1188 return -ENOMEM;
1189
1190 starget->hostdata = sas_target_priv_data;
1191 sas_target_priv_data->starget = starget;
1192 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1193
1194 /* RAID volumes */
1195 if (starget->channel == RAID_CHANNEL) {
1196 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1197 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1198 starget->channel);
1199 if (raid_device) {
1200 sas_target_priv_data->handle = raid_device->handle;
1201 sas_target_priv_data->sas_address = raid_device->wwid;
1202 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
1203 raid_device->starget = starget;
1204 }
1205 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1206 return 0;
1207 }
1208
1209 /* sas/sata devices */
1210 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1211 rphy = dev_to_rphy(starget->dev.parent);
1212 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1213 rphy->identify.sas_address);
1214
1215 if (sas_device) {
1216 sas_target_priv_data->handle = sas_device->handle;
1217 sas_target_priv_data->sas_address = sas_device->sas_address;
1218 sas_device->starget = starget;
1219 sas_device->id = starget->id;
1220 sas_device->channel = starget->channel;
1221 if (sas_device->hidden_raid_component)
1222 sas_target_priv_data->flags |=
1223 MPT_TARGET_FLAGS_RAID_COMPONENT;
1224 }
1225 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1226
1227 return 0;
1228}
1229
1230/**
Eric Moored5d135b2009-05-18 13:02:08 -06001231 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001232 * @starget: scsi target struct
1233 *
1234 * Returns nothing.
1235 */
1236static void
Eric Moored5d135b2009-05-18 13:02:08 -06001237_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001238{
1239 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1240 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1241 struct MPT2SAS_TARGET *sas_target_priv_data;
1242 struct _sas_device *sas_device;
1243 struct _raid_device *raid_device;
1244 unsigned long flags;
1245 struct sas_rphy *rphy;
1246
1247 sas_target_priv_data = starget->hostdata;
1248 if (!sas_target_priv_data)
1249 return;
1250
1251 if (starget->channel == RAID_CHANNEL) {
1252 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1253 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1254 starget->channel);
1255 if (raid_device) {
1256 raid_device->starget = NULL;
1257 raid_device->sdev = NULL;
1258 }
1259 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1260 goto out;
1261 }
1262
1263 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1264 rphy = dev_to_rphy(starget->dev.parent);
1265 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1266 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001267 if (sas_device && (sas_device->starget == starget) &&
1268 (sas_device->id == starget->id) &&
1269 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001270 sas_device->starget = NULL;
1271
1272 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1273
1274 out:
1275 kfree(sas_target_priv_data);
1276 starget->hostdata = NULL;
1277}
1278
1279/**
Eric Moored5d135b2009-05-18 13:02:08 -06001280 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001281 * @sdev: scsi device struct
1282 *
1283 * Returns 0 if ok. Any other return is assumed to be an error and
1284 * the device is ignored.
1285 */
1286static int
Eric Moored5d135b2009-05-18 13:02:08 -06001287_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001288{
1289 struct Scsi_Host *shost;
1290 struct MPT2SAS_ADAPTER *ioc;
1291 struct MPT2SAS_TARGET *sas_target_priv_data;
1292 struct MPT2SAS_DEVICE *sas_device_priv_data;
1293 struct scsi_target *starget;
1294 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06001295 unsigned long flags;
1296
1297 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1298 if (!sas_device_priv_data)
1299 return -ENOMEM;
1300
1301 sas_device_priv_data->lun = sdev->lun;
1302 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1303
1304 starget = scsi_target(sdev);
1305 sas_target_priv_data = starget->hostdata;
1306 sas_target_priv_data->num_luns++;
1307 sas_device_priv_data->sas_target = sas_target_priv_data;
1308 sdev->hostdata = sas_device_priv_data;
1309 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1310 sdev->no_uld_attach = 1;
1311
1312 shost = dev_to_shost(&starget->dev);
1313 ioc = shost_priv(shost);
1314 if (starget->channel == RAID_CHANNEL) {
1315 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1316 raid_device = _scsih_raid_device_find_by_id(ioc,
1317 starget->id, starget->channel);
1318 if (raid_device)
1319 raid_device->sdev = sdev; /* raid is single lun */
1320 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06001321 }
1322
Eric Moore635374e2009-03-09 01:21:12 -06001323 return 0;
1324}
1325
1326/**
Eric Moored5d135b2009-05-18 13:02:08 -06001327 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001328 * @sdev: scsi device struct
1329 *
1330 * Returns nothing.
1331 */
1332static void
Eric Moored5d135b2009-05-18 13:02:08 -06001333_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001334{
1335 struct MPT2SAS_TARGET *sas_target_priv_data;
1336 struct scsi_target *starget;
1337
1338 if (!sdev->hostdata)
1339 return;
1340
1341 starget = scsi_target(sdev);
1342 sas_target_priv_data = starget->hostdata;
1343 sas_target_priv_data->num_luns--;
1344 kfree(sdev->hostdata);
1345 sdev->hostdata = NULL;
1346}
1347
1348/**
Eric Moored5d135b2009-05-18 13:02:08 -06001349 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001350 * @ioc: per adapter object
1351 * @sas_device: the sas_device object
1352 * @sdev: scsi device struct
1353 */
1354static void
Eric Moored5d135b2009-05-18 13:02:08 -06001355_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06001356 struct _sas_device *sas_device, struct scsi_device *sdev)
1357{
1358 Mpi2ConfigReply_t mpi_reply;
1359 Mpi2SasDevicePage0_t sas_device_pg0;
1360 u32 ioc_status;
1361 u16 flags;
1362 u32 device_info;
1363
1364 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
1365 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
1366 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1367 ioc->name, __FILE__, __LINE__, __func__);
1368 return;
1369 }
1370
1371 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1372 MPI2_IOCSTATUS_MASK;
1373 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1374 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1375 ioc->name, __FILE__, __LINE__, __func__);
1376 return;
1377 }
1378
1379 flags = le16_to_cpu(sas_device_pg0.Flags);
Kashyap, Desaie94f6742010-03-17 16:24:52 +05301380 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
Eric Moore635374e2009-03-09 01:21:12 -06001381
1382 sdev_printk(KERN_INFO, sdev,
1383 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1384 "sw_preserve(%s)\n",
1385 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1386 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1387 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1388 "n",
1389 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1390 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1391 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1392}
1393
1394/**
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301395 * _scsih_is_raid - return boolean indicating device is raid volume
1396 * @dev the device struct object
1397 */
1398static int
1399_scsih_is_raid(struct device *dev)
1400{
1401 struct scsi_device *sdev = to_scsi_device(dev);
1402
1403 return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
1404}
1405
1406/**
1407 * _scsih_get_resync - get raid volume resync percent complete
1408 * @dev the device struct object
1409 */
1410static void
1411_scsih_get_resync(struct device *dev)
1412{
1413 struct scsi_device *sdev = to_scsi_device(dev);
1414 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1415 static struct _raid_device *raid_device;
1416 unsigned long flags;
1417 Mpi2RaidVolPage0_t vol_pg0;
1418 Mpi2ConfigReply_t mpi_reply;
1419 u32 volume_status_flags;
1420 u8 percent_complete = 0;
1421
1422 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1423 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1424 sdev->channel);
1425 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1426
1427 if (!raid_device)
1428 goto out;
1429
1430 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1431 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1432 sizeof(Mpi2RaidVolPage0_t))) {
1433 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1434 ioc->name, __FILE__, __LINE__, __func__);
1435 goto out;
1436 }
1437
1438 volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1439 if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
1440 percent_complete = raid_device->percent_complete;
1441 out:
1442 raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
1443}
1444
1445/**
1446 * _scsih_get_state - get raid volume level
1447 * @dev the device struct object
1448 */
1449static void
1450_scsih_get_state(struct device *dev)
1451{
1452 struct scsi_device *sdev = to_scsi_device(dev);
1453 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1454 static struct _raid_device *raid_device;
1455 unsigned long flags;
1456 Mpi2RaidVolPage0_t vol_pg0;
1457 Mpi2ConfigReply_t mpi_reply;
1458 u32 volstate;
1459 enum raid_state state = RAID_STATE_UNKNOWN;
1460
1461 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1462 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1463 sdev->channel);
1464 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1465
1466 if (!raid_device)
1467 goto out;
1468
1469 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
1470 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
1471 sizeof(Mpi2RaidVolPage0_t))) {
1472 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1473 ioc->name, __FILE__, __LINE__, __func__);
1474 goto out;
1475 }
1476
1477 volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1478 if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
1479 state = RAID_STATE_RESYNCING;
1480 goto out;
1481 }
1482
1483 switch (vol_pg0.VolumeState) {
1484 case MPI2_RAID_VOL_STATE_OPTIMAL:
1485 case MPI2_RAID_VOL_STATE_ONLINE:
1486 state = RAID_STATE_ACTIVE;
1487 break;
1488 case MPI2_RAID_VOL_STATE_DEGRADED:
1489 state = RAID_STATE_DEGRADED;
1490 break;
1491 case MPI2_RAID_VOL_STATE_FAILED:
1492 case MPI2_RAID_VOL_STATE_MISSING:
1493 state = RAID_STATE_OFFLINE;
1494 break;
1495 }
1496 out:
1497 raid_set_state(mpt2sas_raid_template, dev, state);
1498}
1499
1500/**
1501 * _scsih_set_level - set raid level
1502 * @sdev: scsi device struct
1503 * @raid_device: raid_device object
1504 */
1505static void
1506_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
1507{
1508 enum raid_level level = RAID_LEVEL_UNKNOWN;
1509
1510 switch (raid_device->volume_type) {
1511 case MPI2_RAID_VOL_TYPE_RAID0:
1512 level = RAID_LEVEL_0;
1513 break;
1514 case MPI2_RAID_VOL_TYPE_RAID10:
1515 level = RAID_LEVEL_10;
1516 break;
1517 case MPI2_RAID_VOL_TYPE_RAID1E:
1518 level = RAID_LEVEL_1E;
1519 break;
1520 case MPI2_RAID_VOL_TYPE_RAID1:
1521 level = RAID_LEVEL_1;
1522 break;
1523 }
1524
1525 raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
1526}
1527
1528/**
Eric Moore635374e2009-03-09 01:21:12 -06001529 * _scsih_get_volume_capabilities - volume capabilities
1530 * @ioc: per adapter object
1531 * @sas_device: the raid_device object
1532 */
1533static void
1534_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1535 struct _raid_device *raid_device)
1536{
1537 Mpi2RaidVolPage0_t *vol_pg0;
1538 Mpi2RaidPhysDiskPage0_t pd_pg0;
1539 Mpi2SasDevicePage0_t sas_device_pg0;
1540 Mpi2ConfigReply_t mpi_reply;
1541 u16 sz;
1542 u8 num_pds;
1543
1544 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1545 &num_pds)) || !num_pds) {
1546 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1547 ioc->name, __FILE__, __LINE__, __func__);
1548 return;
1549 }
1550
1551 raid_device->num_pds = num_pds;
1552 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1553 sizeof(Mpi2RaidVol0PhysDisk_t));
1554 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1555 if (!vol_pg0) {
1556 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1557 ioc->name, __FILE__, __LINE__, __func__);
1558 return;
1559 }
1560
1561 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1562 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1563 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1564 ioc->name, __FILE__, __LINE__, __func__);
1565 kfree(vol_pg0);
1566 return;
1567 }
1568
1569 raid_device->volume_type = vol_pg0->VolumeType;
1570
1571 /* figure out what the underlying devices are by
1572 * obtaining the device_info bits for the 1st device
1573 */
1574 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1575 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1576 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1577 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1578 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1579 le16_to_cpu(pd_pg0.DevHandle)))) {
1580 raid_device->device_info =
1581 le32_to_cpu(sas_device_pg0.DeviceInfo);
1582 }
1583 }
1584
1585 kfree(vol_pg0);
1586}
1587
1588/**
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301589 * _scsih_enable_tlr - setting TLR flags
1590 * @ioc: per adapter object
1591 * @sdev: scsi device struct
1592 *
1593 * Enabling Transaction Layer Retries for tape devices when
1594 * vpd page 0x90 is present
1595 *
1596 */
1597static void
1598_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev)
1599{
1600 /* only for TAPE */
1601 if (sdev->type != TYPE_TAPE)
1602 return;
1603
1604 if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR))
1605 return;
1606
1607 sas_enable_tlr(sdev);
1608 sdev_printk(KERN_INFO, sdev, "TLR %s\n",
1609 sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled");
1610 return;
1611
1612}
1613
1614/**
Eric Moored5d135b2009-05-18 13:02:08 -06001615 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001616 * @sdev: scsi device struct
1617 *
1618 * Returns 0 if ok. Any other return is assumed to be an error and
1619 * the device is ignored.
1620 */
1621static int
Eric Moored5d135b2009-05-18 13:02:08 -06001622_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001623{
1624 struct Scsi_Host *shost = sdev->host;
1625 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1626 struct MPT2SAS_DEVICE *sas_device_priv_data;
1627 struct MPT2SAS_TARGET *sas_target_priv_data;
1628 struct _sas_device *sas_device;
1629 struct _raid_device *raid_device;
1630 unsigned long flags;
1631 int qdepth;
1632 u8 ssp_target = 0;
1633 char *ds = "";
1634 char *r_level = "";
1635
1636 qdepth = 1;
1637 sas_device_priv_data = sdev->hostdata;
1638 sas_device_priv_data->configured_lun = 1;
1639 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1640 sas_target_priv_data = sas_device_priv_data->sas_target;
1641
1642 /* raid volume handling */
1643 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1644
1645 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1646 raid_device = _scsih_raid_device_find_by_handle(ioc,
1647 sas_target_priv_data->handle);
1648 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1649 if (!raid_device) {
1650 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1651 ioc->name, __FILE__, __LINE__, __func__);
1652 return 0;
1653 }
1654
1655 _scsih_get_volume_capabilities(ioc, raid_device);
1656
1657 /* RAID Queue Depth Support
1658 * IS volume = underlying qdepth of drive type, either
1659 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
1660 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
1661 */
1662 if (raid_device->device_info &
1663 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1664 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1665 ds = "SSP";
1666 } else {
1667 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1668 if (raid_device->device_info &
1669 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1670 ds = "SATA";
1671 else
1672 ds = "STP";
1673 }
1674
1675 switch (raid_device->volume_type) {
1676 case MPI2_RAID_VOL_TYPE_RAID0:
1677 r_level = "RAID0";
1678 break;
1679 case MPI2_RAID_VOL_TYPE_RAID1E:
1680 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05301681 if (ioc->manu_pg10.OEMIdentifier &&
1682 (ioc->manu_pg10.GenericFlags0 &
1683 MFG10_GF0_R10_DISPLAY) &&
1684 !(raid_device->num_pds % 2))
1685 r_level = "RAID10";
1686 else
1687 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06001688 break;
1689 case MPI2_RAID_VOL_TYPE_RAID1:
1690 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1691 r_level = "RAID1";
1692 break;
1693 case MPI2_RAID_VOL_TYPE_RAID10:
1694 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1695 r_level = "RAID10";
1696 break;
1697 case MPI2_RAID_VOL_TYPE_UNKNOWN:
1698 default:
1699 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
1700 r_level = "RAIDX";
1701 break;
1702 }
1703
1704 sdev_printk(KERN_INFO, sdev, "%s: "
1705 "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
1706 r_level, raid_device->handle,
1707 (unsigned long long)raid_device->wwid,
1708 raid_device->num_pds, ds);
Mike Christiee881a172009-10-15 17:46:39 -07001709 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301710 /* raid transport support */
1711 _scsih_set_level(sdev, raid_device);
Eric Moore635374e2009-03-09 01:21:12 -06001712 return 0;
1713 }
1714
1715 /* non-raid handling */
1716 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1717 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1718 sas_device_priv_data->sas_target->sas_address);
1719 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1720 if (sas_device) {
1721 if (sas_target_priv_data->flags &
1722 MPT_TARGET_FLAGS_RAID_COMPONENT) {
1723 mpt2sas_config_get_volume_handle(ioc,
1724 sas_device->handle, &sas_device->volume_handle);
1725 mpt2sas_config_get_volume_wwid(ioc,
1726 sas_device->volume_handle,
1727 &sas_device->volume_wwid);
1728 }
1729 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
1730 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
1731 ssp_target = 1;
1732 ds = "SSP";
1733 } else {
1734 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
1735 if (sas_device->device_info &
1736 MPI2_SAS_DEVICE_INFO_STP_TARGET)
1737 ds = "STP";
1738 else if (sas_device->device_info &
1739 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1740 ds = "SATA";
1741 }
1742
1743 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
1744 "sas_addr(0x%016llx), device_name(0x%016llx)\n",
1745 ds, sas_device->handle,
1746 (unsigned long long)sas_device->sas_address,
1747 (unsigned long long)sas_device->device_name);
1748 sdev_printk(KERN_INFO, sdev, "%s: "
1749 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
1750 (unsigned long long) sas_device->enclosure_logical_id,
1751 sas_device->slot);
1752
1753 if (!ssp_target)
Eric Moored5d135b2009-05-18 13:02:08 -06001754 _scsih_display_sata_capabilities(ioc, sas_device, sdev);
Eric Moore635374e2009-03-09 01:21:12 -06001755 }
1756
Mike Christiee881a172009-10-15 17:46:39 -07001757 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Eric Moore635374e2009-03-09 01:21:12 -06001758
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301759 if (ssp_target) {
Eric Moore635374e2009-03-09 01:21:12 -06001760 sas_read_port_mode_page(sdev);
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301761 _scsih_enable_tlr(ioc, sdev);
1762 }
Eric Moore635374e2009-03-09 01:21:12 -06001763 return 0;
1764}
1765
1766/**
Eric Moored5d135b2009-05-18 13:02:08 -06001767 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06001768 * @sdev: scsi device struct
1769 * @bdev: pointer to block device context
1770 * @capacity: device size (in 512 byte sectors)
1771 * @params: three element array to place output:
1772 * params[0] number of heads (max 255)
1773 * params[1] number of sectors (max 63)
1774 * params[2] number of cylinders
1775 *
1776 * Return nothing.
1777 */
1778static int
Eric Moored5d135b2009-05-18 13:02:08 -06001779_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06001780 sector_t capacity, int params[])
1781{
1782 int heads;
1783 int sectors;
1784 sector_t cylinders;
1785 ulong dummy;
1786
1787 heads = 64;
1788 sectors = 32;
1789
1790 dummy = heads * sectors;
1791 cylinders = capacity;
1792 sector_div(cylinders, dummy);
1793
1794 /*
1795 * Handle extended translation size for logical drives
1796 * > 1Gb
1797 */
1798 if ((ulong)capacity >= 0x200000) {
1799 heads = 255;
1800 sectors = 63;
1801 dummy = heads * sectors;
1802 cylinders = capacity;
1803 sector_div(cylinders, dummy);
1804 }
1805
1806 /* return result */
1807 params[0] = heads;
1808 params[1] = sectors;
1809 params[2] = cylinders;
1810
1811 return 0;
1812}
1813
1814/**
1815 * _scsih_response_code - translation of device response code
1816 * @ioc: per adapter object
1817 * @response_code: response code returned by the device
1818 *
1819 * Return nothing.
1820 */
1821static void
1822_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
1823{
1824 char *desc;
1825
1826 switch (response_code) {
1827 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1828 desc = "task management request completed";
1829 break;
1830 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1831 desc = "invalid frame";
1832 break;
1833 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1834 desc = "task management request not supported";
1835 break;
1836 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1837 desc = "task management request failed";
1838 break;
1839 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1840 desc = "task management request succeeded";
1841 break;
1842 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1843 desc = "invalid lun";
1844 break;
1845 case 0xA:
1846 desc = "overlapped tag attempted";
1847 break;
1848 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1849 desc = "task queued, however not sent to target";
1850 break;
1851 default:
1852 desc = "unknown";
1853 break;
1854 }
1855 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
1856 ioc->name, response_code, desc);
1857}
1858
1859/**
Eric Moored5d135b2009-05-18 13:02:08 -06001860 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06001861 * @ioc: per adapter object
1862 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301863 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001864 * @reply: reply message frame(lower 32bit addr)
1865 * Context: none.
1866 *
1867 * The callback handler when using scsih_issue_tm.
1868 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301869 * Return 1 meaning mf should be freed from _base_interrupt
1870 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06001871 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301872static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05301873_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06001874{
1875 MPI2DefaultReply_t *mpi_reply;
1876
1877 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301878 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001879 if (ioc->tm_cmds.smid != smid)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301880 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001881 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
1882 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
1883 if (mpi_reply) {
1884 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
1885 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
1886 }
1887 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
1888 complete(&ioc->tm_cmds.done);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05301889 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001890}
1891
1892/**
1893 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
1894 * @ioc: per adapter object
1895 * @handle: device handle
1896 *
1897 * During taskmangement request, we need to freeze the device queue.
1898 */
1899void
1900mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1901{
1902 struct MPT2SAS_DEVICE *sas_device_priv_data;
1903 struct scsi_device *sdev;
1904 u8 skip = 0;
1905
1906 shost_for_each_device(sdev, ioc->shost) {
1907 if (skip)
1908 continue;
1909 sas_device_priv_data = sdev->hostdata;
1910 if (!sas_device_priv_data)
1911 continue;
1912 if (sas_device_priv_data->sas_target->handle == handle) {
1913 sas_device_priv_data->sas_target->tm_busy = 1;
1914 skip = 1;
1915 ioc->ignore_loginfos = 1;
1916 }
1917 }
1918}
1919
1920/**
1921 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
1922 * @ioc: per adapter object
1923 * @handle: device handle
1924 *
1925 * During taskmangement request, we need to freeze the device queue.
1926 */
1927void
1928mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
1929{
1930 struct MPT2SAS_DEVICE *sas_device_priv_data;
1931 struct scsi_device *sdev;
1932 u8 skip = 0;
1933
1934 shost_for_each_device(sdev, ioc->shost) {
1935 if (skip)
1936 continue;
1937 sas_device_priv_data = sdev->hostdata;
1938 if (!sas_device_priv_data)
1939 continue;
1940 if (sas_device_priv_data->sas_target->handle == handle) {
1941 sas_device_priv_data->sas_target->tm_busy = 0;
1942 skip = 1;
1943 ioc->ignore_loginfos = 0;
1944 }
1945 }
1946}
1947
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301948
Eric Moore635374e2009-03-09 01:21:12 -06001949/**
1950 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
1951 * @ioc: per adapter struct
1952 * @device_handle: device handle
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301953 * @channel: the channel assigned by the OS
1954 * @id: the id assigned by the OS
Eric Moore635374e2009-03-09 01:21:12 -06001955 * @lun: lun number
1956 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
1957 * @smid_task: smid assigned to the task
1958 * @timeout: timeout in seconds
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301959 * Context: user
Eric Moore635374e2009-03-09 01:21:12 -06001960 *
1961 * A generic API for sending task management requests to firmware.
1962 *
Eric Moore635374e2009-03-09 01:21:12 -06001963 * The callback index is set inside `ioc->tm_cb_idx`.
1964 *
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301965 * Return SUCCESS or FAILED.
Eric Moore635374e2009-03-09 01:21:12 -06001966 */
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301967int
1968mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
1969 uint id, uint lun, u8 type, u16 smid_task, ulong timeout,
1970 struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06001971{
1972 Mpi2SCSITaskManagementRequest_t *mpi_request;
1973 Mpi2SCSITaskManagementReply_t *mpi_reply;
1974 u16 smid = 0;
1975 u32 ioc_state;
1976 unsigned long timeleft;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301977 struct scsi_cmnd *scmd_lookup;
1978 int rc;
Eric Moore635374e2009-03-09 01:21:12 -06001979
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301980 mutex_lock(&ioc->tm_cmds.mutex);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301981 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
1982 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
1983 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301984 rc = FAILED;
1985 goto err_out;
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05301986 }
1987
Kashyap, Desai6558bbb2010-03-17 16:23:36 +05301988 if (ioc->shost_recovery || ioc->remove_host) {
Eric Moore635374e2009-03-09 01:21:12 -06001989 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1990 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301991 rc = FAILED;
1992 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06001993 }
Eric Moore635374e2009-03-09 01:21:12 -06001994
1995 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
1996 if (ioc_state & MPI2_DOORBELL_USED) {
1997 dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
1998 "active!\n", ioc->name));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05301999 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2000 FORCE_BIG_HAMMER);
2001 rc = SUCCESS;
2002 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002003 }
2004
2005 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
2006 mpt2sas_base_fault_info(ioc, ioc_state &
2007 MPI2_DOORBELL_DATA_MASK);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302008 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2009 FORCE_BIG_HAMMER);
2010 rc = SUCCESS;
2011 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002012 }
2013
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302014 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06002015 if (!smid) {
2016 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2017 ioc->name, __func__);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302018 rc = FAILED;
2019 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002020 }
2021
2022 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302023 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
2024 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06002025 ioc->tm_cmds.status = MPT2_CMD_PENDING;
2026 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2027 ioc->tm_cmds.smid = smid;
2028 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2029 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2030 mpi_request->DevHandle = cpu_to_le16(handle);
2031 mpi_request->TaskType = type;
2032 mpi_request->TaskMID = cpu_to_le16(smid_task);
2033 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
2034 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05302035 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302036 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002037 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
Eric Moore635374e2009-03-09 01:21:12 -06002038 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
2039 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
2040 ioc->name, __func__);
2041 _debug_dump_mf(mpi_request,
2042 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302043 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) {
2044 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2045 FORCE_BIG_HAMMER);
2046 rc = SUCCESS;
2047 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2048 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2049 goto err_out;
2050 }
Eric Moore635374e2009-03-09 01:21:12 -06002051 }
2052
2053 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
2054 mpi_reply = ioc->tm_cmds.reply;
2055 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
2056 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
2057 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
2058 le32_to_cpu(mpi_reply->IOCLogInfo),
2059 le32_to_cpu(mpi_reply->TerminationCount)));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302060 if (ioc->logging_level & MPT_DEBUG_TM) {
Eric Moore635374e2009-03-09 01:21:12 -06002061 _scsih_response_code(ioc, mpi_reply->ResponseCode);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302062 if (mpi_reply->IOCStatus)
2063 _debug_dump_mf(mpi_request,
2064 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
2065 }
Eric Moore635374e2009-03-09 01:21:12 -06002066 }
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302067
2068 /* sanity check:
2069 * Check to see the commands were terminated.
2070 * This is only needed for eh callbacks, hence the scmd check.
2071 */
2072 rc = FAILED;
2073 if (scmd == NULL)
2074 goto bypass_sanity_checks;
2075 switch (type) {
2076 case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
2077 scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task);
2078 if (scmd_lookup && (scmd_lookup->serial_number ==
2079 scmd->serial_number))
2080 rc = FAILED;
2081 else
2082 rc = SUCCESS;
2083 break;
2084
2085 case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2086 if (_scsih_scsi_lookup_find_by_target(ioc, id, channel))
2087 rc = FAILED;
2088 else
2089 rc = SUCCESS;
2090 break;
2091
2092 case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
2093 if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel))
2094 rc = FAILED;
2095 else
2096 rc = SUCCESS;
2097 break;
2098 }
2099
2100 bypass_sanity_checks:
2101
2102 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2103 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2104 mutex_unlock(&ioc->tm_cmds.mutex);
2105
2106 return rc;
2107
2108 err_out:
2109 mutex_unlock(&ioc->tm_cmds.mutex);
2110 return rc;
Eric Moore635374e2009-03-09 01:21:12 -06002111}
2112
2113/**
Eric Moored5d135b2009-05-18 13:02:08 -06002114 * _scsih_abort - eh threads main abort routine
Eric Moore635374e2009-03-09 01:21:12 -06002115 * @sdev: scsi device struct
2116 *
2117 * Returns SUCCESS if command aborted else FAILED
2118 */
2119static int
Eric Moored5d135b2009-05-18 13:02:08 -06002120_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002121{
2122 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2123 struct MPT2SAS_DEVICE *sas_device_priv_data;
2124 u16 smid;
2125 u16 handle;
2126 int r;
Eric Moore635374e2009-03-09 01:21:12 -06002127
2128 printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
2129 ioc->name, scmd);
2130 scsi_print_command(scmd);
2131
2132 sas_device_priv_data = scmd->device->hostdata;
2133 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2134 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
2135 ioc->name, scmd);
2136 scmd->result = DID_NO_CONNECT << 16;
2137 scmd->scsi_done(scmd);
2138 r = SUCCESS;
2139 goto out;
2140 }
2141
2142 /* search for the command */
2143 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
2144 if (!smid) {
2145 scmd->result = DID_RESET << 16;
2146 r = SUCCESS;
2147 goto out;
2148 }
2149
2150 /* for hidden raid components and volumes this is not supported */
2151 if (sas_device_priv_data->sas_target->flags &
2152 MPT_TARGET_FLAGS_RAID_COMPONENT ||
2153 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
2154 scmd->result = DID_RESET << 16;
2155 r = FAILED;
2156 goto out;
2157 }
2158
Kashyap, Desaifa7f3162009-09-23 17:26:58 +05302159 mpt2sas_halt_firmware(ioc);
2160
Eric Moore635374e2009-03-09 01:21:12 -06002161 handle = sas_device_priv_data->sas_target->handle;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302162 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2163 scmd->device->id, scmd->device->lun,
2164 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002165
2166 out:
2167 printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
2168 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2169 return r;
2170}
2171
Eric Moore635374e2009-03-09 01:21:12 -06002172/**
Eric Moored5d135b2009-05-18 13:02:08 -06002173 * _scsih_dev_reset - eh threads main device reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002174 * @sdev: scsi device struct
2175 *
2176 * Returns SUCCESS if command aborted else FAILED
2177 */
2178static int
Eric Moored5d135b2009-05-18 13:02:08 -06002179_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002180{
2181 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2182 struct MPT2SAS_DEVICE *sas_device_priv_data;
2183 struct _sas_device *sas_device;
2184 unsigned long flags;
2185 u16 handle;
2186 int r;
2187
Eric Moore993e0da2009-05-18 13:00:45 -06002188 printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
Eric Moore635374e2009-03-09 01:21:12 -06002189 ioc->name, scmd);
2190 scsi_print_command(scmd);
2191
2192 sas_device_priv_data = scmd->device->hostdata;
2193 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2194 printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
2195 ioc->name, scmd);
2196 scmd->result = DID_NO_CONNECT << 16;
2197 scmd->scsi_done(scmd);
2198 r = SUCCESS;
2199 goto out;
2200 }
2201
2202 /* for hidden raid components obtain the volume_handle */
2203 handle = 0;
2204 if (sas_device_priv_data->sas_target->flags &
2205 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2206 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2207 sas_device = _scsih_sas_device_find_by_handle(ioc,
2208 sas_device_priv_data->sas_target->handle);
2209 if (sas_device)
2210 handle = sas_device->volume_handle;
2211 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2212 } else
2213 handle = sas_device_priv_data->sas_target->handle;
2214
2215 if (!handle) {
2216 scmd->result = DID_RESET << 16;
2217 r = FAILED;
2218 goto out;
2219 }
2220
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302221 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2222 scmd->device->id, scmd->device->lun,
2223 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002224
2225 out:
2226 printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
2227 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2228 return r;
2229}
2230
2231/**
Eric Moored5d135b2009-05-18 13:02:08 -06002232 * _scsih_target_reset - eh threads main target reset routine
Eric Moore993e0da2009-05-18 13:00:45 -06002233 * @sdev: scsi device struct
2234 *
2235 * Returns SUCCESS if command aborted else FAILED
2236 */
2237static int
Eric Moored5d135b2009-05-18 13:02:08 -06002238_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06002239{
2240 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2241 struct MPT2SAS_DEVICE *sas_device_priv_data;
2242 struct _sas_device *sas_device;
2243 unsigned long flags;
2244 u16 handle;
2245 int r;
2246
2247 printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
2248 ioc->name, scmd);
2249 scsi_print_command(scmd);
2250
2251 sas_device_priv_data = scmd->device->hostdata;
2252 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
2253 printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
2254 ioc->name, scmd);
2255 scmd->result = DID_NO_CONNECT << 16;
2256 scmd->scsi_done(scmd);
2257 r = SUCCESS;
2258 goto out;
2259 }
2260
2261 /* for hidden raid components obtain the volume_handle */
2262 handle = 0;
2263 if (sas_device_priv_data->sas_target->flags &
2264 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2265 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2266 sas_device = _scsih_sas_device_find_by_handle(ioc,
2267 sas_device_priv_data->sas_target->handle);
2268 if (sas_device)
2269 handle = sas_device->volume_handle;
2270 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2271 } else
2272 handle = sas_device_priv_data->sas_target->handle;
2273
2274 if (!handle) {
2275 scmd->result = DID_RESET << 16;
2276 r = FAILED;
2277 goto out;
2278 }
2279
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302280 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2281 scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
2282 30, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002283
2284 out:
2285 printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
2286 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2287 return r;
2288}
2289
2290/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302291 * _scsih_host_reset - eh threads main host reset routine
Eric Moore635374e2009-03-09 01:21:12 -06002292 * @sdev: scsi device struct
2293 *
2294 * Returns SUCCESS if command aborted else FAILED
2295 */
2296static int
Eric Moored5d135b2009-05-18 13:02:08 -06002297_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002298{
2299 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2300 int r, retval;
2301
2302 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2303 ioc->name, scmd);
2304 scsi_print_command(scmd);
2305
2306 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2307 FORCE_BIG_HAMMER);
2308 r = (retval < 0) ? FAILED : SUCCESS;
2309 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2310 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2311
2312 return r;
2313}
2314
2315/**
2316 * _scsih_fw_event_add - insert and queue up fw_event
2317 * @ioc: per adapter object
2318 * @fw_event: object describing the event
2319 * Context: This function will acquire ioc->fw_event_lock.
2320 *
2321 * This adds the firmware event object into link list, then queues it up to
2322 * be processed from user context.
2323 *
2324 * Return nothing.
2325 */
2326static void
2327_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2328{
2329 unsigned long flags;
2330
2331 if (ioc->firmware_event_thread == NULL)
2332 return;
2333
2334 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2335 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302336 INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work);
2337 queue_delayed_work(ioc->firmware_event_thread,
2338 &fw_event->delayed_work, 0);
Eric Moore635374e2009-03-09 01:21:12 -06002339 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2340}
2341
2342/**
2343 * _scsih_fw_event_free - delete fw_event
2344 * @ioc: per adapter object
2345 * @fw_event: object describing the event
2346 * Context: This function will acquire ioc->fw_event_lock.
2347 *
2348 * This removes firmware event object from link list, frees associated memory.
2349 *
2350 * Return nothing.
2351 */
2352static void
2353_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2354 *fw_event)
2355{
2356 unsigned long flags;
2357
2358 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2359 list_del(&fw_event->list);
2360 kfree(fw_event->event_data);
2361 kfree(fw_event);
2362 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2363}
2364
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302365
Eric Moore635374e2009-03-09 01:21:12 -06002366/**
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302367 * _scsih_queue_rescan - queue a topology rescan from user context
Eric Moore635374e2009-03-09 01:21:12 -06002368 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06002369 *
2370 * Return nothing.
2371 */
2372static void
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302373_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06002374{
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302375 struct fw_event_work *fw_event;
2376
2377 if (ioc->wait_for_port_enable_to_complete)
2378 return;
2379 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
2380 if (!fw_event)
2381 return;
2382 fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET;
2383 fw_event->ioc = ioc;
2384 _scsih_fw_event_add(ioc, fw_event);
2385}
2386
2387/**
2388 * _scsih_fw_event_cleanup_queue - cleanup event queue
2389 * @ioc: per adapter object
2390 *
2391 * Walk the firmware event queue, either killing timers, or waiting
2392 * for outstanding events to complete
2393 *
2394 * Return nothing.
2395 */
2396static void
2397_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)
2398{
2399 struct fw_event_work *fw_event, *next;
2400
2401 if (list_empty(&ioc->fw_event_list) ||
2402 !ioc->firmware_event_thread || in_interrupt())
Eric Moore635374e2009-03-09 01:21:12 -06002403 return;
2404
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302405 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
2406 if (cancel_delayed_work(&fw_event->delayed_work)) {
2407 _scsih_fw_event_free(ioc, fw_event);
2408 continue;
2409 }
2410 fw_event->cancel_pending_work = 1;
2411 }
Eric Moore635374e2009-03-09 01:21:12 -06002412}
2413
Eric Moore635374e2009-03-09 01:21:12 -06002414/**
2415 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2416 * @ioc: per adapter object
2417 * @handle: device handle
2418 *
2419 * During device pull we need to appropiately set the sdev state.
2420 */
2421static void
2422_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2423{
2424 struct MPT2SAS_DEVICE *sas_device_priv_data;
2425 struct scsi_device *sdev;
2426
2427 shost_for_each_device(sdev, ioc->shost) {
2428 sas_device_priv_data = sdev->hostdata;
2429 if (!sas_device_priv_data)
2430 continue;
2431 if (!sas_device_priv_data->block)
2432 continue;
2433 if (sas_device_priv_data->sas_target->handle == handle) {
2434 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2435 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2436 "handle(0x%04x)\n", ioc->name, handle));
2437 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302438 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002439 }
2440 }
2441}
2442
2443/**
2444 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2445 * @ioc: per adapter object
2446 * @handle: device handle
2447 *
2448 * During device pull we need to appropiately set the sdev state.
2449 */
2450static void
2451_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2452{
2453 struct MPT2SAS_DEVICE *sas_device_priv_data;
2454 struct scsi_device *sdev;
2455
2456 shost_for_each_device(sdev, ioc->shost) {
2457 sas_device_priv_data = sdev->hostdata;
2458 if (!sas_device_priv_data)
2459 continue;
2460 if (sas_device_priv_data->block)
2461 continue;
2462 if (sas_device_priv_data->sas_target->handle == handle) {
2463 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2464 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2465 "handle(0x%04x)\n", ioc->name, handle));
2466 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302467 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002468 }
2469 }
2470}
2471
2472/**
2473 * _scsih_block_io_to_children_attached_to_ex
2474 * @ioc: per adapter object
2475 * @sas_expander: the sas_device object
2476 *
2477 * This routine set sdev state to SDEV_BLOCK for all devices
2478 * attached to this expander. This function called when expander is
2479 * pulled.
2480 */
2481static void
2482_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
2483 struct _sas_node *sas_expander)
2484{
2485 struct _sas_port *mpt2sas_port;
2486 struct _sas_device *sas_device;
2487 struct _sas_node *expander_sibling;
2488 unsigned long flags;
2489
2490 if (!sas_expander)
2491 return;
2492
2493 list_for_each_entry(mpt2sas_port,
2494 &sas_expander->sas_port_list, port_list) {
2495 if (mpt2sas_port->remote_identify.device_type ==
2496 SAS_END_DEVICE) {
2497 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2498 sas_device =
2499 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2500 mpt2sas_port->remote_identify.sas_address);
2501 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2502 if (!sas_device)
2503 continue;
2504 _scsih_block_io_device(ioc, sas_device->handle);
2505 }
2506 }
2507
2508 list_for_each_entry(mpt2sas_port,
2509 &sas_expander->sas_port_list, port_list) {
2510
2511 if (mpt2sas_port->remote_identify.device_type ==
2512 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2513 mpt2sas_port->remote_identify.device_type ==
2514 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2515
2516 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2517 expander_sibling =
2518 mpt2sas_scsih_expander_find_by_sas_address(
2519 ioc, mpt2sas_port->remote_identify.sas_address);
2520 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2521 _scsih_block_io_to_children_attached_to_ex(ioc,
2522 expander_sibling);
2523 }
2524 }
2525}
2526
2527/**
2528 * _scsih_block_io_to_children_attached_directly
2529 * @ioc: per adapter object
2530 * @event_data: topology change event data
2531 *
2532 * This routine set sdev state to SDEV_BLOCK for all devices
2533 * direct attached during device pull.
2534 */
2535static void
2536_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
2537 Mpi2EventDataSasTopologyChangeList_t *event_data)
2538{
2539 int i;
2540 u16 handle;
2541 u16 reason_code;
2542 u8 phy_number;
2543
2544 for (i = 0; i < event_data->NumEntries; i++) {
2545 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2546 if (!handle)
2547 continue;
2548 phy_number = event_data->StartPhyNum + i;
2549 reason_code = event_data->PHY[i].PhyStatus &
2550 MPI2_EVENT_SAS_TOPO_RC_MASK;
2551 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
2552 _scsih_block_io_device(ioc, handle);
2553 }
2554}
2555
2556/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302557 * _scsih_tm_tr_send - send task management request
2558 * @ioc: per adapter object
2559 * @handle: device handle
2560 * Context: interrupt time.
2561 *
2562 * This code is to initiate the device removal handshake protocal
2563 * with controller firmware. This function will issue target reset
2564 * using high priority request queue. It will send a sas iounit
2565 * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
2566 *
2567 * This is designed to send muliple task management request at the same
2568 * time to the fifo. If the fifo is full, we will append the request,
2569 * and process it in a future completion.
2570 */
2571static void
2572_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2573{
2574 Mpi2SCSITaskManagementRequest_t *mpi_request;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302575 u16 smid;
2576 struct _sas_device *sas_device;
2577 unsigned long flags;
2578 struct _tr_list *delayed_tr;
2579
Kashyap, Desai1278b112010-03-09 17:34:13 +05302580 if (ioc->shost_recovery || ioc->remove_host) {
2581 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
2582 "progress!\n", __func__, ioc->name));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302583 return;
2584 }
2585
2586 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2587 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desai1278b112010-03-09 17:34:13 +05302588 if (sas_device && sas_device->hidden_raid_component) {
2589 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302590 return;
Kashyap, Desai1278b112010-03-09 17:34:13 +05302591 }
2592 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302593
2594 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
2595 if (!smid) {
2596 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
2597 if (!delayed_tr)
2598 return;
2599 INIT_LIST_HEAD(&delayed_tr->list);
2600 delayed_tr->handle = handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05302601 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
2602 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2603 "DELAYED:tr:handle(0x%04x), (open)\n",
2604 ioc->name, handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302605 return;
2606 }
2607
Kashyap, Desai1278b112010-03-09 17:34:13 +05302608 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
2609 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
2610 ioc->tm_tr_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302611 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2612 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
2613 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2614 mpi_request->DevHandle = cpu_to_le16(handle);
2615 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302616 mpt2sas_base_put_smid_hi_priority(ioc, smid);
2617}
2618
2619
2620
2621/**
2622 * _scsih_sas_control_complete - completion routine
2623 * @ioc: per adapter object
2624 * @smid: system request message index
2625 * @msix_index: MSIX table index supplied by the OS
2626 * @reply: reply message frame(lower 32bit addr)
2627 * Context: interrupt time.
2628 *
2629 * This is the sas iounit controll completion routine.
2630 * This code is part of the code to initiate the device removal
2631 * handshake protocal with controller firmware.
2632 *
2633 * Return 1 meaning mf should be freed from _base_interrupt
2634 * 0 means the mf is freed from this function.
2635 */
2636static u8
2637_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
2638 u8 msix_index, u32 reply)
2639{
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302640 Mpi2SasIoUnitControlReply_t *mpi_reply =
2641 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2642
Kashyap, Desai1278b112010-03-09 17:34:13 +05302643 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2644 "sc_complete:handle(0x%04x), (open) "
2645 "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
2646 ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
2647 le16_to_cpu(mpi_reply->IOCStatus),
2648 le32_to_cpu(mpi_reply->IOCLogInfo)));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302649 return 1;
2650}
2651
2652/**
2653 * _scsih_tm_tr_complete -
2654 * @ioc: per adapter object
2655 * @smid: system request message index
2656 * @msix_index: MSIX table index supplied by the OS
2657 * @reply: reply message frame(lower 32bit addr)
2658 * Context: interrupt time.
2659 *
2660 * This is the target reset completion routine.
2661 * This code is part of the code to initiate the device removal
2662 * handshake protocal with controller firmware.
2663 * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE)
2664 *
2665 * Return 1 meaning mf should be freed from _base_interrupt
2666 * 0 means the mf is freed from this function.
2667 */
2668static u8
2669_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
2670 u32 reply)
2671{
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302672 u16 handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05302673 Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302674 Mpi2SCSITaskManagementReply_t *mpi_reply =
2675 mpt2sas_base_get_reply_virt_addr(ioc, reply);
2676 Mpi2SasIoUnitControlRequest_t *mpi_request;
2677 u16 smid_sas_ctrl;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302678 struct _tr_list *delayed_tr;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302679
Kashyap, Desai1278b112010-03-09 17:34:13 +05302680 if (ioc->shost_recovery || ioc->remove_host) {
2681 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
2682 "progress!\n", __func__, ioc->name));
2683 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302684 }
2685
Kashyap, Desai1278b112010-03-09 17:34:13 +05302686 mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
2687 handle = le16_to_cpu(mpi_request_tm->DevHandle);
2688 if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
2689 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: "
2690 "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle,
2691 le16_to_cpu(mpi_reply->DevHandle), smid));
2692 return 0;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302693 }
2694
Kashyap, Desai1278b112010-03-09 17:34:13 +05302695 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
2696 "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
2697 "loginfo(0x%08x), completed(%d)\n", ioc->name,
2698 handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
2699 le32_to_cpu(mpi_reply->IOCLogInfo),
2700 le32_to_cpu(mpi_reply->TerminationCount)));
2701
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302702 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
2703 if (!smid_sas_ctrl) {
2704 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2705 ioc->name, __func__);
Kashyap, Desai1278b112010-03-09 17:34:13 +05302706 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302707 }
2708
Kashyap, Desai1278b112010-03-09 17:34:13 +05302709 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), "
2710 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl,
2711 ioc->tm_sas_control_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302712 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
2713 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
2714 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
2715 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
Kashyap, Desai1278b112010-03-09 17:34:13 +05302716 mpi_request->DevHandle = mpi_request_tm->DevHandle;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302717 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
Kashyap, Desai1278b112010-03-09 17:34:13 +05302718
2719 if (!list_empty(&ioc->delayed_tr_list)) {
2720 delayed_tr = list_entry(ioc->delayed_tr_list.next,
2721 struct _tr_list, list);
2722 mpt2sas_base_free_smid(ioc, smid);
2723 _scsih_tm_tr_send(ioc, delayed_tr->handle);
2724 list_del(&delayed_tr->list);
2725 kfree(delayed_tr);
2726 return 0; /* tells base_interrupt not to free mf */
2727 }
2728 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302729}
2730
2731/**
Eric Moore635374e2009-03-09 01:21:12 -06002732 * _scsih_check_topo_delete_events - sanity check on topo events
2733 * @ioc: per adapter object
2734 * @event_data: the event data payload
2735 *
2736 * This routine added to better handle cable breaker.
2737 *
2738 * This handles the case where driver recieves multiple expander
2739 * add and delete events in a single shot. When there is a delete event
2740 * the routine will void any pending add events waiting in the event queue.
2741 *
2742 * Return nothing.
2743 */
2744static void
2745_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
2746 Mpi2EventDataSasTopologyChangeList_t *event_data)
2747{
2748 struct fw_event_work *fw_event;
2749 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
2750 u16 expander_handle;
2751 struct _sas_node *sas_expander;
2752 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302753 int i, reason_code;
2754 u16 handle;
2755
2756 for (i = 0 ; i < event_data->NumEntries; i++) {
2757 if (event_data->PHY[i].PhyStatus &
2758 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
2759 continue;
2760 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
2761 if (!handle)
2762 continue;
2763 reason_code = event_data->PHY[i].PhyStatus &
2764 MPI2_EVENT_SAS_TOPO_RC_MASK;
2765 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
2766 _scsih_tm_tr_send(ioc, handle);
2767 }
Eric Moore635374e2009-03-09 01:21:12 -06002768
2769 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
2770 if (expander_handle < ioc->sas_hba.num_phys) {
2771 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2772 return;
2773 }
2774
2775 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
2776 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
2777 spin_lock_irqsave(&ioc->sas_node_lock, flags);
2778 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
2779 expander_handle);
2780 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
2781 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
2782 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
2783 _scsih_block_io_to_children_attached_directly(ioc, event_data);
2784
2785 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
2786 return;
2787
2788 /* mark ignore flag for pending events */
2789 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2790 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
2791 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
2792 fw_event->ignore)
2793 continue;
2794 local_event_data = fw_event->event_data;
2795 if (local_event_data->ExpStatus ==
2796 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
2797 local_event_data->ExpStatus ==
2798 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
2799 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
2800 expander_handle) {
2801 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
2802 "setting ignoring flag\n", ioc->name));
2803 fw_event->ignore = 1;
2804 }
2805 }
2806 }
2807 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2808}
2809
2810/**
Eric Moore635374e2009-03-09 01:21:12 -06002811 * _scsih_flush_running_cmds - completing outstanding commands.
2812 * @ioc: per adapter object
2813 *
2814 * The flushing out of all pending scmd commands following host reset,
2815 * where all IO is dropped to the floor.
2816 *
2817 * Return nothing.
2818 */
2819static void
2820_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
2821{
2822 struct scsi_cmnd *scmd;
2823 u16 smid;
2824 u16 count = 0;
2825
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302826 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
2827 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002828 if (!scmd)
2829 continue;
2830 count++;
2831 mpt2sas_base_free_smid(ioc, smid);
2832 scsi_dma_unmap(scmd);
2833 scmd->result = DID_RESET << 16;
2834 scmd->scsi_done(scmd);
2835 }
2836 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
2837 ioc->name, count));
2838}
2839
2840/**
Eric Moore3c621b32009-05-18 12:59:41 -06002841 * _scsih_setup_eedp - setup MPI request for EEDP transfer
2842 * @scmd: pointer to scsi command object
2843 * @mpi_request: pointer to the SCSI_IO reqest message frame
2844 *
2845 * Supporting protection 1 and 3.
2846 *
2847 * Returns nothing
2848 */
2849static void
2850_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
2851{
2852 u16 eedp_flags;
2853 unsigned char prot_op = scsi_get_prot_op(scmd);
2854 unsigned char prot_type = scsi_get_prot_type(scmd);
2855
2856 if (prot_type == SCSI_PROT_DIF_TYPE0 ||
2857 prot_type == SCSI_PROT_DIF_TYPE2 ||
2858 prot_op == SCSI_PROT_NORMAL)
2859 return;
2860
2861 if (prot_op == SCSI_PROT_READ_STRIP)
2862 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
2863 else if (prot_op == SCSI_PROT_WRITE_INSERT)
2864 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
2865 else
2866 return;
2867
Eric Moore3c621b32009-05-18 12:59:41 -06002868 switch (prot_type) {
2869 case SCSI_PROT_DIF_TYPE1:
2870
2871 /*
2872 * enable ref/guard checking
2873 * auto increment ref tag
2874 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05302875 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
Eric Moore3c621b32009-05-18 12:59:41 -06002876 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
2877 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
2878 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
2879 cpu_to_be32(scsi_get_lba(scmd));
2880
2881 break;
2882
2883 case SCSI_PROT_DIF_TYPE3:
2884
2885 /*
2886 * enable guard checking
2887 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05302888 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
Eric Moore3c621b32009-05-18 12:59:41 -06002889 break;
2890 }
Kashyap, Desai463217b2009-10-05 15:53:06 +05302891 mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
2892 mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
Eric Moore3c621b32009-05-18 12:59:41 -06002893}
2894
2895/**
2896 * _scsih_eedp_error_handling - return sense code for EEDP errors
2897 * @scmd: pointer to scsi command object
2898 * @ioc_status: ioc status
2899 *
2900 * Returns nothing
2901 */
2902static void
2903_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
2904{
2905 u8 ascq;
2906 u8 sk;
2907 u8 host_byte;
2908
2909 switch (ioc_status) {
2910 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2911 ascq = 0x01;
2912 break;
2913 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2914 ascq = 0x02;
2915 break;
2916 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2917 ascq = 0x03;
2918 break;
2919 default:
2920 ascq = 0x00;
2921 break;
2922 }
2923
2924 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
2925 sk = ILLEGAL_REQUEST;
2926 host_byte = DID_ABORT;
2927 } else {
2928 sk = ABORTED_COMMAND;
2929 host_byte = DID_OK;
2930 }
2931
2932 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
2933 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
2934 SAM_STAT_CHECK_CONDITION;
2935}
2936
2937/**
Eric Moored5d135b2009-05-18 13:02:08 -06002938 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06002939 * @scmd: pointer to scsi command object
2940 * @done: function pointer to be invoked on completion
2941 *
2942 * The callback index is set inside `ioc->scsi_io_cb_idx`.
2943 *
2944 * Returns 0 on success. If there's a failure, return either:
2945 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
2946 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
2947 */
2948static int
Eric Moored5d135b2009-05-18 13:02:08 -06002949_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06002950{
2951 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2952 struct MPT2SAS_DEVICE *sas_device_priv_data;
2953 struct MPT2SAS_TARGET *sas_target_priv_data;
2954 Mpi2SCSIIORequest_t *mpi_request;
2955 u32 mpi_control;
2956 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06002957
2958 scmd->scsi_done = done;
2959 sas_device_priv_data = scmd->device->hostdata;
2960 if (!sas_device_priv_data) {
2961 scmd->result = DID_NO_CONNECT << 16;
2962 scmd->scsi_done(scmd);
2963 return 0;
2964 }
2965
2966 sas_target_priv_data = sas_device_priv_data->sas_target;
2967 if (!sas_target_priv_data || sas_target_priv_data->handle ==
2968 MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
2969 scmd->result = DID_NO_CONNECT << 16;
2970 scmd->scsi_done(scmd);
2971 return 0;
2972 }
2973
2974 /* see if we are busy with task managment stuff */
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05302975 if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302976 return SCSI_MLQUEUE_DEVICE_BUSY;
2977 else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06002978 return SCSI_MLQUEUE_HOST_BUSY;
Eric Moore635374e2009-03-09 01:21:12 -06002979
2980 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
2981 mpi_control = MPI2_SCSIIO_CONTROL_READ;
2982 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
2983 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
2984 else
2985 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
2986
2987 /* set tags */
2988 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
2989 if (scmd->device->tagged_supported) {
2990 if (scmd->device->ordered_tags)
2991 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
2992 else
2993 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
2994 } else
2995/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
2996/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
2997 */
2998 mpi_control |= (0x500);
2999
3000 } else
3001 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
Kashyap, Desai3ed21522010-02-17 16:08:36 +05303002 /* Make sure Device is not raid volume */
3003 if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
3004 sas_is_tlr_enabled(scmd->device))
Eric Moore635374e2009-03-09 01:21:12 -06003005 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
3006
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303007 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06003008 if (!smid) {
3009 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
3010 ioc->name, __func__);
3011 goto out;
3012 }
3013 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3014 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06003015 _scsih_setup_eedp(scmd, mpi_request);
Eric Moore635374e2009-03-09 01:21:12 -06003016 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3017 if (sas_device_priv_data->sas_target->flags &
3018 MPT_TARGET_FLAGS_RAID_COMPONENT)
3019 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
3020 else
3021 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
3022 mpi_request->DevHandle =
3023 cpu_to_le16(sas_device_priv_data->sas_target->handle);
3024 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
3025 mpi_request->Control = cpu_to_le32(mpi_control);
3026 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
3027 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
3028 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
3029 mpi_request->SenseBufferLowAddress =
Kashyap, Desaiec9472c2009-09-23 17:34:13 +05303030 mpt2sas_base_get_sense_buffer_dma(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003031 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
3032 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
3033 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303034 mpi_request->VF_ID = 0; /* TODO */
3035 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003036 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
3037 mpi_request->LUN);
3038 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
3039
3040 if (!mpi_request->DataLength) {
3041 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
3042 } else {
3043 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
3044 mpt2sas_base_free_smid(ioc, smid);
3045 goto out;
3046 }
3047 }
3048
Kashyap, Desai58287fd2010-03-17 16:27:25 +05303049 if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST))
3050 mpt2sas_base_put_smid_scsi_io(ioc, smid,
3051 sas_device_priv_data->sas_target->handle);
3052 else
3053 mpt2sas_base_put_smid_default(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003054 return 0;
3055
3056 out:
3057 return SCSI_MLQUEUE_HOST_BUSY;
3058}
3059
3060/**
3061 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
3062 * @sense_buffer: sense data returned by target
3063 * @data: normalized skey/asc/ascq
3064 *
3065 * Return nothing.
3066 */
3067static void
3068_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
3069{
3070 if ((sense_buffer[0] & 0x7F) >= 0x72) {
3071 /* descriptor format */
3072 data->skey = sense_buffer[1] & 0x0F;
3073 data->asc = sense_buffer[2];
3074 data->ascq = sense_buffer[3];
3075 } else {
3076 /* fixed format */
3077 data->skey = sense_buffer[2] & 0x0F;
3078 data->asc = sense_buffer[12];
3079 data->ascq = sense_buffer[13];
3080 }
3081}
3082
3083#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3084/**
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02003085 * _scsih_scsi_ioc_info - translated non-successfull SCSI_IO request
Eric Moore635374e2009-03-09 01:21:12 -06003086 * @ioc: per adapter object
3087 * @scmd: pointer to scsi command object
3088 * @mpi_reply: reply mf payload returned from firmware
3089 *
3090 * scsi_status - SCSI Status code returned from target device
3091 * scsi_state - state info associated with SCSI_IO determined by ioc
3092 * ioc_status - ioc supplied status info
3093 *
3094 * Return nothing.
3095 */
3096static void
3097_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
3098 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
3099{
3100 u32 response_info;
3101 u8 *response_bytes;
3102 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
3103 MPI2_IOCSTATUS_MASK;
3104 u8 scsi_state = mpi_reply->SCSIState;
3105 u8 scsi_status = mpi_reply->SCSIStatus;
3106 char *desc_ioc_state = NULL;
3107 char *desc_scsi_status = NULL;
3108 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05303109 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3110
3111 if (log_info == 0x31170000)
3112 return;
Eric Moore635374e2009-03-09 01:21:12 -06003113
3114 switch (ioc_status) {
3115 case MPI2_IOCSTATUS_SUCCESS:
3116 desc_ioc_state = "success";
3117 break;
3118 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3119 desc_ioc_state = "invalid function";
3120 break;
3121 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3122 desc_ioc_state = "scsi recovered error";
3123 break;
3124 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
3125 desc_ioc_state = "scsi invalid dev handle";
3126 break;
3127 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3128 desc_ioc_state = "scsi device not there";
3129 break;
3130 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3131 desc_ioc_state = "scsi data overrun";
3132 break;
3133 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3134 desc_ioc_state = "scsi data underrun";
3135 break;
3136 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3137 desc_ioc_state = "scsi io data error";
3138 break;
3139 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3140 desc_ioc_state = "scsi protocol error";
3141 break;
3142 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3143 desc_ioc_state = "scsi task terminated";
3144 break;
3145 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3146 desc_ioc_state = "scsi residual mismatch";
3147 break;
3148 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3149 desc_ioc_state = "scsi task mgmt failed";
3150 break;
3151 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3152 desc_ioc_state = "scsi ioc terminated";
3153 break;
3154 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3155 desc_ioc_state = "scsi ext terminated";
3156 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003157 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3158 desc_ioc_state = "eedp guard error";
3159 break;
3160 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3161 desc_ioc_state = "eedp ref tag error";
3162 break;
3163 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3164 desc_ioc_state = "eedp app tag error";
3165 break;
Eric Moore635374e2009-03-09 01:21:12 -06003166 default:
3167 desc_ioc_state = "unknown";
3168 break;
3169 }
3170
3171 switch (scsi_status) {
3172 case MPI2_SCSI_STATUS_GOOD:
3173 desc_scsi_status = "good";
3174 break;
3175 case MPI2_SCSI_STATUS_CHECK_CONDITION:
3176 desc_scsi_status = "check condition";
3177 break;
3178 case MPI2_SCSI_STATUS_CONDITION_MET:
3179 desc_scsi_status = "condition met";
3180 break;
3181 case MPI2_SCSI_STATUS_BUSY:
3182 desc_scsi_status = "busy";
3183 break;
3184 case MPI2_SCSI_STATUS_INTERMEDIATE:
3185 desc_scsi_status = "intermediate";
3186 break;
3187 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
3188 desc_scsi_status = "intermediate condmet";
3189 break;
3190 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
3191 desc_scsi_status = "reservation conflict";
3192 break;
3193 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
3194 desc_scsi_status = "command terminated";
3195 break;
3196 case MPI2_SCSI_STATUS_TASK_SET_FULL:
3197 desc_scsi_status = "task set full";
3198 break;
3199 case MPI2_SCSI_STATUS_ACA_ACTIVE:
3200 desc_scsi_status = "aca active";
3201 break;
3202 case MPI2_SCSI_STATUS_TASK_ABORTED:
3203 desc_scsi_status = "task aborted";
3204 break;
3205 default:
3206 desc_scsi_status = "unknown";
3207 break;
3208 }
3209
3210 desc_scsi_state[0] = '\0';
3211 if (!scsi_state)
3212 desc_scsi_state = " ";
3213 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3214 strcat(desc_scsi_state, "response info ");
3215 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3216 strcat(desc_scsi_state, "state terminated ");
3217 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
3218 strcat(desc_scsi_state, "no status ");
3219 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
3220 strcat(desc_scsi_state, "autosense failed ");
3221 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
3222 strcat(desc_scsi_state, "autosense valid ");
3223
3224 scsi_print_command(scmd);
3225 printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
3226 "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
3227 le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
3228 ioc_status, smid);
3229 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
3230 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
3231 scsi_get_resid(scmd));
3232 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
3233 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
3234 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
3235 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
3236 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
3237 scsi_status, desc_scsi_state, scsi_state);
3238
3239 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3240 struct sense_info data;
3241 _scsih_normalize_sense(scmd->sense_buffer, &data);
3242 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
Kashyap, Desaie94f6742010-03-17 16:24:52 +05303243 "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey,
3244 data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));
Eric Moore635374e2009-03-09 01:21:12 -06003245 }
3246
3247 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
3248 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
3249 response_bytes = (u8 *)&response_info;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303250 _scsih_response_code(ioc, response_bytes[0]);
Eric Moore635374e2009-03-09 01:21:12 -06003251 }
3252}
3253#endif
3254
3255/**
3256 * _scsih_smart_predicted_fault - illuminate Fault LED
3257 * @ioc: per adapter object
3258 * @handle: device handle
3259 *
3260 * Return nothing.
3261 */
3262static void
3263_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3264{
3265 Mpi2SepReply_t mpi_reply;
3266 Mpi2SepRequest_t mpi_request;
3267 struct scsi_target *starget;
3268 struct MPT2SAS_TARGET *sas_target_priv_data;
3269 Mpi2EventNotificationReply_t *event_reply;
3270 Mpi2EventDataSasDeviceStatusChange_t *event_data;
3271 struct _sas_device *sas_device;
3272 ssize_t sz;
3273 unsigned long flags;
3274
3275 /* only handle non-raid devices */
3276 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3277 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
3278 if (!sas_device) {
3279 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3280 return;
3281 }
3282 starget = sas_device->starget;
3283 sas_target_priv_data = starget->hostdata;
3284
3285 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
3286 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
3287 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3288 return;
3289 }
3290 starget_printk(KERN_WARNING, starget, "predicted fault\n");
3291 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
3292
3293 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
3294 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
3295 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
3296 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
3297 mpi_request.SlotStatus =
Kashyap, Desaie94f6742010-03-17 16:24:52 +05303298 cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
Eric Moore635374e2009-03-09 01:21:12 -06003299 mpi_request.DevHandle = cpu_to_le16(handle);
3300 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
3301 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
3302 &mpi_request)) != 0) {
3303 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3304 ioc->name, __FILE__, __LINE__, __func__);
3305 return;
3306 }
3307
3308 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
3309 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3310 "enclosure_processor: ioc_status (0x%04x), "
3311 "loginfo(0x%08x)\n", ioc->name,
3312 le16_to_cpu(mpi_reply.IOCStatus),
3313 le32_to_cpu(mpi_reply.IOCLogInfo)));
3314 return;
3315 }
3316 }
3317
3318 /* insert into event log */
3319 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
3320 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
3321 event_reply = kzalloc(sz, GFP_KERNEL);
3322 if (!event_reply) {
3323 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3324 ioc->name, __FILE__, __LINE__, __func__);
3325 return;
3326 }
3327
3328 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
3329 event_reply->Event =
3330 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
3331 event_reply->MsgLength = sz/4;
3332 event_reply->EventDataLength =
3333 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
3334 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
3335 event_reply->EventData;
3336 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
3337 event_data->ASC = 0x5D;
3338 event_data->DevHandle = cpu_to_le16(handle);
3339 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
3340 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
3341 kfree(event_reply);
3342}
3343
3344/**
Eric Moored5d135b2009-05-18 13:02:08 -06003345 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06003346 * @ioc: per adapter object
3347 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303348 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06003349 * @reply: reply message frame(lower 32bit addr)
3350 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303351 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06003352 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303353 * Return 1 meaning mf should be freed from _base_interrupt
3354 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06003355 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303356static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05303357_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06003358{
3359 Mpi2SCSIIORequest_t *mpi_request;
3360 Mpi2SCSIIOReply_t *mpi_reply;
3361 struct scsi_cmnd *scmd;
3362 u16 ioc_status;
3363 u32 xfer_cnt;
3364 u8 scsi_state;
3365 u8 scsi_status;
3366 u32 log_info;
3367 struct MPT2SAS_DEVICE *sas_device_priv_data;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303368 u32 response_code = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003369
3370 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303371 scmd = _scsih_scsi_lookup_get(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003372 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303373 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003374
3375 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3376
3377 if (mpi_reply == NULL) {
3378 scmd->result = DID_OK << 16;
3379 goto out;
3380 }
3381
3382 sas_device_priv_data = scmd->device->hostdata;
3383 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
3384 sas_device_priv_data->sas_target->deleted) {
3385 scmd->result = DID_NO_CONNECT << 16;
3386 goto out;
3387 }
3388
3389 /* turning off TLR */
Kashyap, Desai9982f592009-09-23 17:23:07 +05303390 scsi_state = mpi_reply->SCSIState;
3391 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
3392 response_code =
3393 le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
Eric Moore635374e2009-03-09 01:21:12 -06003394 if (!sas_device_priv_data->tlr_snoop_check) {
3395 sas_device_priv_data->tlr_snoop_check++;
Kashyap, Desai3ed21522010-02-17 16:08:36 +05303396 if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
3397 sas_is_tlr_enabled(scmd->device) &&
Kashyap, Desai84f0b042009-12-16 18:56:28 +05303398 response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
3399 sas_disable_tlr(scmd->device);
3400 sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
3401 }
Eric Moore635374e2009-03-09 01:21:12 -06003402 }
3403
3404 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
3405 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
3406 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
3407 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
3408 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
3409 else
3410 log_info = 0;
3411 ioc_status &= MPI2_IOCSTATUS_MASK;
Eric Moore635374e2009-03-09 01:21:12 -06003412 scsi_status = mpi_reply->SCSIStatus;
3413
3414 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
3415 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
3416 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
3417 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
3418 ioc_status = MPI2_IOCSTATUS_SUCCESS;
3419 }
3420
3421 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
3422 struct sense_info data;
3423 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
3424 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06003425 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06003426 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06003427 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06003428 _scsih_normalize_sense(scmd->sense_buffer, &data);
3429 /* failure prediction threshold exceeded */
3430 if (data.asc == 0x5D)
3431 _scsih_smart_predicted_fault(ioc,
3432 le16_to_cpu(mpi_reply->DevHandle));
3433 }
3434
3435 switch (ioc_status) {
3436 case MPI2_IOCSTATUS_BUSY:
3437 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
3438 scmd->result = SAM_STAT_BUSY;
3439 break;
3440
3441 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
3442 scmd->result = DID_NO_CONNECT << 16;
3443 break;
3444
3445 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
3446 if (sas_device_priv_data->block) {
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05303447 scmd->result = DID_TRANSPORT_DISRUPTED << 16;
3448 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06003449 }
Eric Moore635374e2009-03-09 01:21:12 -06003450 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
3451 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
3452 scmd->result = DID_RESET << 16;
3453 break;
3454
3455 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
3456 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
3457 scmd->result = DID_SOFT_ERROR << 16;
3458 else
3459 scmd->result = (DID_OK << 16) | scsi_status;
3460 break;
3461
3462 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
3463 scmd->result = (DID_OK << 16) | scsi_status;
3464
3465 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
3466 break;
3467
3468 if (xfer_cnt < scmd->underflow) {
3469 if (scsi_status == SAM_STAT_BUSY)
3470 scmd->result = SAM_STAT_BUSY;
3471 else
3472 scmd->result = DID_SOFT_ERROR << 16;
3473 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3474 MPI2_SCSI_STATE_NO_SCSI_STATUS))
3475 scmd->result = DID_SOFT_ERROR << 16;
3476 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3477 scmd->result = DID_RESET << 16;
3478 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
3479 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
3480 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
3481 scmd->result = (DRIVER_SENSE << 24) |
3482 SAM_STAT_CHECK_CONDITION;
3483 scmd->sense_buffer[0] = 0x70;
3484 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
3485 scmd->sense_buffer[12] = 0x20;
3486 scmd->sense_buffer[13] = 0;
3487 }
3488 break;
3489
3490 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
3491 scsi_set_resid(scmd, 0);
3492 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
3493 case MPI2_IOCSTATUS_SUCCESS:
3494 scmd->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9982f592009-09-23 17:23:07 +05303495 if (response_code ==
3496 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
3497 (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
3498 MPI2_SCSI_STATE_NO_SCSI_STATUS)))
Eric Moore635374e2009-03-09 01:21:12 -06003499 scmd->result = DID_SOFT_ERROR << 16;
3500 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
3501 scmd->result = DID_RESET << 16;
3502 break;
3503
Eric Moore3c621b32009-05-18 12:59:41 -06003504 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3505 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3506 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3507 _scsih_eedp_error_handling(scmd, ioc_status);
3508 break;
Eric Moore635374e2009-03-09 01:21:12 -06003509 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
3510 case MPI2_IOCSTATUS_INVALID_FUNCTION:
3511 case MPI2_IOCSTATUS_INVALID_SGL:
3512 case MPI2_IOCSTATUS_INTERNAL_ERROR:
3513 case MPI2_IOCSTATUS_INVALID_FIELD:
3514 case MPI2_IOCSTATUS_INVALID_STATE:
3515 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
3516 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
3517 default:
3518 scmd->result = DID_SOFT_ERROR << 16;
3519 break;
3520
3521 }
3522
3523#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
3524 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
3525 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
3526#endif
3527
3528 out:
3529 scsi_dma_unmap(scmd);
3530 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303531 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06003532}
3533
3534/**
Eric Moore635374e2009-03-09 01:21:12 -06003535 * _scsih_sas_host_refresh - refreshing sas host object contents
3536 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06003537 * Context: user
3538 *
3539 * During port enable, fw will send topology events for every device. Its
3540 * possible that the handles may change from the previous setting, so this
3541 * code keeping handles updating if changed.
3542 *
3543 * Return nothing.
3544 */
3545static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303546_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06003547{
3548 u16 sz;
3549 u16 ioc_status;
3550 int i;
3551 Mpi2ConfigReply_t mpi_reply;
3552 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303553 u16 attached_handle;
Eric Moore635374e2009-03-09 01:21:12 -06003554
3555 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
3556 "updating handles for sas_host(0x%016llx)\n",
3557 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
3558
3559 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
3560 * sizeof(Mpi2SasIOUnit0PhyData_t));
3561 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3562 if (!sas_iounit_pg0) {
3563 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3564 ioc->name, __FILE__, __LINE__, __func__);
3565 return;
3566 }
Eric Moore635374e2009-03-09 01:21:12 -06003567
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303568 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3569 sas_iounit_pg0, sz)) != 0)
3570 goto out;
3571 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
3572 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
3573 goto out;
3574 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3575 if (i == 0)
3576 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3577 PhyData[0].ControllerDevHandle);
3578 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
3579 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
3580 AttachedDevHandle);
3581 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
3582 attached_handle, i, sas_iounit_pg0->PhyData[i].
3583 NegotiatedLinkRate >> 4);
3584 }
Eric Moore635374e2009-03-09 01:21:12 -06003585 out:
3586 kfree(sas_iounit_pg0);
3587}
3588
3589/**
3590 * _scsih_sas_host_add - create sas host object
3591 * @ioc: per adapter object
3592 *
3593 * Creating host side data object, stored in ioc->sas_hba
3594 *
3595 * Return nothing.
3596 */
3597static void
3598_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
3599{
3600 int i;
3601 Mpi2ConfigReply_t mpi_reply;
3602 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
3603 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
3604 Mpi2SasPhyPage0_t phy_pg0;
3605 Mpi2SasDevicePage0_t sas_device_pg0;
3606 Mpi2SasEnclosurePage0_t enclosure_pg0;
3607 u16 ioc_status;
3608 u16 sz;
3609 u16 device_missing_delay;
3610
3611 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
3612 if (!ioc->sas_hba.num_phys) {
3613 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3614 ioc->name, __FILE__, __LINE__, __func__);
3615 return;
3616 }
3617
3618 /* sas_iounit page 0 */
3619 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
3620 sizeof(Mpi2SasIOUnit0PhyData_t));
3621 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
3622 if (!sas_iounit_pg0) {
3623 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3624 ioc->name, __FILE__, __LINE__, __func__);
3625 return;
3626 }
3627 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
3628 sas_iounit_pg0, sz))) {
3629 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3630 ioc->name, __FILE__, __LINE__, __func__);
3631 goto out;
3632 }
3633 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3634 MPI2_IOCSTATUS_MASK;
3635 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3636 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3637 ioc->name, __FILE__, __LINE__, __func__);
3638 goto out;
3639 }
3640
3641 /* sas_iounit page 1 */
3642 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
3643 sizeof(Mpi2SasIOUnit1PhyData_t));
3644 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
3645 if (!sas_iounit_pg1) {
3646 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3647 ioc->name, __FILE__, __LINE__, __func__);
3648 goto out;
3649 }
3650 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
3651 sas_iounit_pg1, sz))) {
3652 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3653 ioc->name, __FILE__, __LINE__, __func__);
3654 goto out;
3655 }
3656 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3657 MPI2_IOCSTATUS_MASK;
3658 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3659 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3660 ioc->name, __FILE__, __LINE__, __func__);
3661 goto out;
3662 }
3663
3664 ioc->io_missing_delay =
3665 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
3666 device_missing_delay =
3667 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
3668 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
3669 ioc->device_missing_delay = (device_missing_delay &
3670 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
3671 else
3672 ioc->device_missing_delay = device_missing_delay &
3673 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
3674
3675 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
3676 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
3677 sizeof(struct _sas_phy), GFP_KERNEL);
3678 if (!ioc->sas_hba.phy) {
3679 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3680 ioc->name, __FILE__, __LINE__, __func__);
3681 goto out;
3682 }
3683 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
3684 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
3685 i))) {
3686 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3687 ioc->name, __FILE__, __LINE__, __func__);
3688 goto out;
3689 }
3690 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3691 MPI2_IOCSTATUS_MASK;
3692 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3693 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3694 ioc->name, __FILE__, __LINE__, __func__);
3695 goto out;
3696 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303697
3698 if (i == 0)
3699 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
3700 PhyData[0].ControllerDevHandle);
3701 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06003702 ioc->sas_hba.phy[i].phy_id = i;
3703 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
3704 phy_pg0, ioc->sas_hba.parent_dev);
3705 }
3706 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303707 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06003708 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3709 ioc->name, __FILE__, __LINE__, __func__);
3710 goto out;
3711 }
Eric Moore635374e2009-03-09 01:21:12 -06003712 ioc->sas_hba.enclosure_handle =
3713 le16_to_cpu(sas_device_pg0.EnclosureHandle);
3714 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
3715 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
3716 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
3717 (unsigned long long) ioc->sas_hba.sas_address,
3718 ioc->sas_hba.num_phys) ;
3719
3720 if (ioc->sas_hba.enclosure_handle) {
3721 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3722 &enclosure_pg0,
3723 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3724 ioc->sas_hba.enclosure_handle))) {
3725 ioc->sas_hba.enclosure_logical_id =
3726 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3727 }
3728 }
3729
3730 out:
3731 kfree(sas_iounit_pg1);
3732 kfree(sas_iounit_pg0);
3733}
3734
3735/**
3736 * _scsih_expander_add - creating expander object
3737 * @ioc: per adapter object
3738 * @handle: expander handle
3739 *
3740 * Creating expander object, stored in ioc->sas_expander_list.
3741 *
3742 * Return 0 for success, else error.
3743 */
3744static int
3745_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3746{
3747 struct _sas_node *sas_expander;
3748 Mpi2ConfigReply_t mpi_reply;
3749 Mpi2ExpanderPage0_t expander_pg0;
3750 Mpi2ExpanderPage1_t expander_pg1;
3751 Mpi2SasEnclosurePage0_t enclosure_pg0;
3752 u32 ioc_status;
3753 u16 parent_handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303754 __le64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06003755 int i;
3756 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303757 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06003758 int rc = 0;
3759
3760 if (!handle)
3761 return -1;
3762
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303763 if (ioc->shost_recovery)
3764 return -1;
3765
Eric Moore635374e2009-03-09 01:21:12 -06003766 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
3767 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
3768 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3769 ioc->name, __FILE__, __LINE__, __func__);
3770 return -1;
3771 }
3772
3773 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
3774 MPI2_IOCSTATUS_MASK;
3775 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3776 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3777 ioc->name, __FILE__, __LINE__, __func__);
3778 return -1;
3779 }
3780
3781 /* handle out of order topology events */
3782 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303783 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
3784 != 0) {
3785 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3786 ioc->name, __FILE__, __LINE__, __func__);
3787 return -1;
3788 }
3789 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06003790 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303791 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3792 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003793 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3794 if (!sas_expander) {
3795 rc = _scsih_expander_add(ioc, parent_handle);
3796 if (rc != 0)
3797 return rc;
3798 }
3799 }
3800
Eric Moore635374e2009-03-09 01:21:12 -06003801 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303802 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06003803 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3804 sas_address);
3805 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3806
3807 if (sas_expander)
3808 return 0;
3809
3810 sas_expander = kzalloc(sizeof(struct _sas_node),
3811 GFP_KERNEL);
3812 if (!sas_expander) {
3813 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3814 ioc->name, __FILE__, __LINE__, __func__);
3815 return -1;
3816 }
3817
3818 sas_expander->handle = handle;
3819 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303820 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06003821 sas_expander->sas_address = sas_address;
3822
3823 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
3824 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303825 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06003826 sas_expander->sas_address, sas_expander->num_phys);
3827
3828 if (!sas_expander->num_phys)
3829 goto out_fail;
3830 sas_expander->phy = kcalloc(sas_expander->num_phys,
3831 sizeof(struct _sas_phy), GFP_KERNEL);
3832 if (!sas_expander->phy) {
3833 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3834 ioc->name, __FILE__, __LINE__, __func__);
3835 rc = -1;
3836 goto out_fail;
3837 }
3838
3839 INIT_LIST_HEAD(&sas_expander->sas_port_list);
3840 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303841 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003842 if (!mpt2sas_port) {
3843 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3844 ioc->name, __FILE__, __LINE__, __func__);
3845 rc = -1;
3846 goto out_fail;
3847 }
3848 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
3849
3850 for (i = 0 ; i < sas_expander->num_phys ; i++) {
3851 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
3852 &expander_pg1, i, handle))) {
3853 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3854 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05303855 rc = -1;
3856 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06003857 }
3858 sas_expander->phy[i].handle = handle;
3859 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05303860
3861 if ((mpt2sas_transport_add_expander_phy(ioc,
3862 &sas_expander->phy[i], expander_pg1,
3863 sas_expander->parent_dev))) {
3864 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
3865 ioc->name, __FILE__, __LINE__, __func__);
3866 rc = -1;
3867 goto out_fail;
3868 }
Eric Moore635374e2009-03-09 01:21:12 -06003869 }
3870
3871 if (sas_expander->enclosure_handle) {
3872 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
3873 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
3874 sas_expander->enclosure_handle))) {
3875 sas_expander->enclosure_logical_id =
3876 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
3877 }
3878 }
3879
3880 _scsih_expander_node_add(ioc, sas_expander);
3881 return 0;
3882
3883 out_fail:
3884
Kashyap, Desai20f58952009-08-07 19:34:26 +05303885 if (mpt2sas_port)
3886 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303887 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06003888 kfree(sas_expander);
3889 return rc;
3890}
3891
3892/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05303893 * _scsih_done - scsih callback handler.
3894 * @ioc: per adapter object
3895 * @smid: system request message index
3896 * @msix_index: MSIX table index supplied by the OS
3897 * @reply: reply message frame(lower 32bit addr)
3898 *
3899 * Callback handler when sending internal generated message frames.
3900 * The callback index passed is `ioc->scsih_cb_idx`
3901 *
3902 * Return 1 meaning mf should be freed from _base_interrupt
3903 * 0 means the mf is freed from this function.
3904 */
3905static u8
3906_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
3907{
3908 MPI2DefaultReply_t *mpi_reply;
3909
3910 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
3911 if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
3912 return 1;
3913 if (ioc->scsih_cmds.smid != smid)
3914 return 1;
3915 ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
3916 if (mpi_reply) {
3917 memcpy(ioc->scsih_cmds.reply, mpi_reply,
3918 mpi_reply->MsgLength*4);
3919 ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
3920 }
3921 ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
3922 complete(&ioc->scsih_cmds.done);
3923 return 1;
3924}
3925
3926/**
Eric Moore635374e2009-03-09 01:21:12 -06003927 * _scsih_expander_remove - removing expander object
3928 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303929 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06003930 *
3931 * Return nothing.
3932 */
3933static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303934_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06003935{
3936 struct _sas_node *sas_expander;
3937 unsigned long flags;
3938
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05303939 if (ioc->shost_recovery)
3940 return;
3941
Eric Moore635374e2009-03-09 01:21:12 -06003942 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05303943 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
3944 sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06003945 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3946 _scsih_expander_node_remove(ioc, sas_expander);
3947}
3948
3949/**
Kashyap, Desaib4344272010-03-17 16:24:14 +05303950 * _scsih_check_access_status - check access flags
3951 * @ioc: per adapter object
3952 * @sas_address: sas address
3953 * @handle: sas device handle
3954 * @access_flags: errors returned during discovery of the device
3955 *
3956 * Return 0 for success, else failure
3957 */
3958static u8
3959_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
3960 u16 handle, u8 access_status)
3961{
3962 u8 rc = 1;
3963 char *desc = NULL;
3964
3965 switch (access_status) {
3966 case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS:
3967 case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION:
3968 rc = 0;
3969 break;
3970 case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED:
3971 desc = "sata capability failed";
3972 break;
3973 case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT:
3974 desc = "sata affiliation conflict";
3975 break;
3976 case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE:
3977 desc = "route not addressable";
3978 break;
3979 case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE:
3980 desc = "smp error not addressable";
3981 break;
3982 case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED:
3983 desc = "device blocked";
3984 break;
3985 case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED:
3986 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN:
3987 case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT:
3988 case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG:
3989 case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION:
3990 case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER:
3991 case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN:
3992 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN:
3993 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN:
3994 case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION:
3995 case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE:
3996 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX:
3997 desc = "sata initialization failed";
3998 break;
3999 default:
4000 desc = "unknown";
4001 break;
4002 }
4003
4004 if (!rc)
4005 return 0;
4006
4007 printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), "
4008 "handle(0x%04x)\n", ioc->name, desc,
4009 (unsigned long long)sas_address, handle);
4010 return rc;
4011}
4012
4013static void
4014_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4015{
4016 Mpi2ConfigReply_t mpi_reply;
4017 Mpi2SasDevicePage0_t sas_device_pg0;
4018 struct _sas_device *sas_device;
4019 u32 ioc_status;
4020 unsigned long flags;
4021 u64 sas_address;
4022 struct scsi_target *starget;
4023 struct MPT2SAS_TARGET *sas_target_priv_data;
4024 u32 device_info;
4025
4026 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4027 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
4028 return;
4029
4030 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
4031 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
4032 return;
4033
4034 /* check if this is end device */
4035 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4036 if (!(_scsih_is_end_device(device_info)))
4037 return;
4038
4039 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4040 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4041 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4042 sas_address);
4043
4044 if (!sas_device) {
4045 printk(MPT2SAS_ERR_FMT "device is not present "
4046 "handle(0x%04x), no sas_device!!!\n", ioc->name, handle);
4047 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4048 return;
4049 }
4050
4051 if (unlikely(sas_device->handle != handle)) {
4052 starget = sas_device->starget;
4053 sas_target_priv_data = starget->hostdata;
4054 starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)"
4055 " to (0x%04x)!!!\n", sas_device->handle, handle);
4056 sas_target_priv_data->handle = handle;
4057 sas_device->handle = handle;
4058 }
4059 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4060
4061 /* check if device is present */
4062 if (!(le16_to_cpu(sas_device_pg0.Flags) &
4063 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
4064 printk(MPT2SAS_ERR_FMT "device is not present "
4065 "handle(0x%04x), flags!!!\n", ioc->name, handle);
4066 return;
4067 }
4068
4069 /* check if there were any issues with discovery */
4070 if (_scsih_check_access_status(ioc, sas_address, handle,
4071 sas_device_pg0.AccessStatus))
4072 return;
4073 _scsih_ublock_io_device(ioc, handle);
4074
4075}
4076
4077/**
Eric Moore635374e2009-03-09 01:21:12 -06004078 * _scsih_add_device - creating sas device object
4079 * @ioc: per adapter object
4080 * @handle: sas device handle
4081 * @phy_num: phy number end device attached to
4082 * @is_pd: is this hidden raid component
4083 *
4084 * Creating end device object, stored in ioc->sas_device_list.
4085 *
4086 * Returns 0 for success, non-zero for failure.
4087 */
4088static int
4089_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
4090{
4091 Mpi2ConfigReply_t mpi_reply;
4092 Mpi2SasDevicePage0_t sas_device_pg0;
4093 Mpi2SasEnclosurePage0_t enclosure_pg0;
4094 struct _sas_device *sas_device;
4095 u32 ioc_status;
4096 __le64 sas_address;
4097 u32 device_info;
4098 unsigned long flags;
4099
4100 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
4101 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
4102 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4103 ioc->name, __FILE__, __LINE__, __func__);
4104 return -1;
4105 }
4106
4107 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4108 MPI2_IOCSTATUS_MASK;
4109 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4110 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4111 ioc->name, __FILE__, __LINE__, __func__);
4112 return -1;
4113 }
4114
Kashyap, Desaib4344272010-03-17 16:24:14 +05304115 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4116
Eric Moore635374e2009-03-09 01:21:12 -06004117 /* check if device is present */
4118 if (!(le16_to_cpu(sas_device_pg0.Flags) &
4119 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
4120 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4121 ioc->name, __FILE__, __LINE__, __func__);
4122 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
4123 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
4124 return -1;
4125 }
4126
Kashyap, Desaib4344272010-03-17 16:24:14 +05304127 /* check if there were any issues with discovery */
4128 if (_scsih_check_access_status(ioc, sas_address, handle,
4129 sas_device_pg0.AccessStatus))
Eric Moore635374e2009-03-09 01:21:12 -06004130 return -1;
Eric Moore635374e2009-03-09 01:21:12 -06004131
4132 /* check if this is end device */
4133 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
4134 if (!(_scsih_is_end_device(device_info))) {
4135 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4136 ioc->name, __FILE__, __LINE__, __func__);
4137 return -1;
4138 }
4139
Eric Moore635374e2009-03-09 01:21:12 -06004140
4141 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4142 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4143 sas_address);
4144 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4145
Kashyap, Desaib4344272010-03-17 16:24:14 +05304146 if (sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06004147 return 0;
Eric Moore635374e2009-03-09 01:21:12 -06004148
4149 sas_device = kzalloc(sizeof(struct _sas_device),
4150 GFP_KERNEL);
4151 if (!sas_device) {
4152 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4153 ioc->name, __FILE__, __LINE__, __func__);
4154 return -1;
4155 }
4156
4157 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304158 if (_scsih_get_sas_address(ioc, le16_to_cpu
4159 (sas_device_pg0.ParentDevHandle),
4160 &sas_device->sas_address_parent) != 0)
4161 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4162 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06004163 sas_device->enclosure_handle =
4164 le16_to_cpu(sas_device_pg0.EnclosureHandle);
4165 sas_device->slot =
4166 le16_to_cpu(sas_device_pg0.Slot);
4167 sas_device->device_info = device_info;
4168 sas_device->sas_address = sas_address;
4169 sas_device->hidden_raid_component = is_pd;
4170
4171 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05304172 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
4173 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4174 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06004175 sas_device->enclosure_logical_id =
4176 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06004177
4178 /* get device name */
4179 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
4180
4181 if (ioc->wait_for_port_enable_to_complete)
4182 _scsih_sas_device_init_add(ioc, sas_device);
4183 else
4184 _scsih_sas_device_add(ioc, sas_device);
4185
4186 return 0;
4187}
4188
4189/**
Kashyap, Desai1278b112010-03-09 17:34:13 +05304190 * _scsih_remove_pd_device - removing sas device pd object
Eric Moore635374e2009-03-09 01:21:12 -06004191 * @ioc: per adapter object
Kashyap, Desai1278b112010-03-09 17:34:13 +05304192 * @sas_device_delete: the sas_device object
Eric Moore635374e2009-03-09 01:21:12 -06004193 *
Kashyap, Desai1278b112010-03-09 17:34:13 +05304194 * For hidden raid components, we do driver-fw handshake from
4195 * hotplug work threads.
Eric Moore635374e2009-03-09 01:21:12 -06004196 * Return nothing.
4197 */
4198static void
Kashyap, Desai1278b112010-03-09 17:34:13 +05304199_scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
4200 sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06004201{
Eric Moore635374e2009-03-09 01:21:12 -06004202 Mpi2SasIoUnitControlReply_t mpi_reply;
4203 Mpi2SasIoUnitControlRequest_t mpi_request;
Kashyap, Desai1278b112010-03-09 17:34:13 +05304204 u16 vol_handle, handle;
Eric Moore635374e2009-03-09 01:21:12 -06004205
Kashyap, Desai1278b112010-03-09 17:34:13 +05304206 handle = sas_device.handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304207 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
4208 " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
Kashyap, Desai1278b112010-03-09 17:34:13 +05304209 (unsigned long long) sas_device.sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06004210
Kashyap, Desai1278b112010-03-09 17:34:13 +05304211 vol_handle = sas_device.volume_handle;
4212 if (!vol_handle)
4213 return;
4214 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
4215 "handle(0x%04x)\n", ioc->name, vol_handle));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05304216 mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0,
4217 MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL);
Kashyap, Desai1278b112010-03-09 17:34:13 +05304218 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
4219 "done: handle(0x%04x)\n", ioc->name, vol_handle));
4220 if (ioc->shost_recovery)
4221 return;
Eric Moore635374e2009-03-09 01:21:12 -06004222
4223 /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
4224 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
4225 "(0x%04x)\n", ioc->name, handle));
4226 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
4227 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
4228 mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
Kashyap, Desai1278b112010-03-09 17:34:13 +05304229 mpi_request.DevHandle = cpu_to_le16(handle);
Eric Moore635374e2009-03-09 01:21:12 -06004230 if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
Kashyap, Desai1278b112010-03-09 17:34:13 +05304231 &mpi_request)) != 0)
Eric Moore635374e2009-03-09 01:21:12 -06004232 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4233 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06004234
4235 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
4236 "(0x%04x), loginfo(0x%08x)\n", ioc->name,
4237 le16_to_cpu(mpi_reply.IOCStatus),
4238 le32_to_cpu(mpi_reply.IOCLogInfo)));
4239
Kashyap, Desai1278b112010-03-09 17:34:13 +05304240 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x),"
4241 " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
4242 (unsigned long long) sas_device.sas_address));
4243}
Kashyap, Desai34a03be2009-08-20 13:23:19 +05304244
Kashyap, Desai1278b112010-03-09 17:34:13 +05304245/**
4246 * _scsih_remove_device - removing sas device object
4247 * @ioc: per adapter object
4248 * @sas_device_delete: the sas_device object
4249 *
4250 * Return nothing.
4251 */
4252static void
4253_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
4254 struct _sas_device *sas_device)
4255{
4256 struct _sas_device sas_device_backup;
4257 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05304258
Kashyap, Desai1278b112010-03-09 17:34:13 +05304259 if (!sas_device)
4260 return;
Eric Moore635374e2009-03-09 01:21:12 -06004261
Kashyap, Desai1278b112010-03-09 17:34:13 +05304262 memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));
Eric Moore635374e2009-03-09 01:21:12 -06004263 _scsih_sas_device_remove(ioc, sas_device);
4264
Kashyap, Desai1278b112010-03-09 17:34:13 +05304265 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
4266 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
4267 sas_device_backup.handle, (unsigned long long)
4268 sas_device_backup.sas_address));
4269
4270 if (sas_device_backup.starget && sas_device_backup.starget->hostdata) {
4271 sas_target_priv_data = sas_device_backup.starget->hostdata;
4272 sas_target_priv_data->deleted = 1;
4273 }
4274
4275 if (sas_device_backup.hidden_raid_component)
4276 _scsih_remove_pd_device(ioc, sas_device_backup);
4277
4278 _scsih_ublock_io_device(ioc, sas_device_backup.handle);
4279
4280 mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address,
4281 sas_device_backup.sas_address_parent);
4282
4283 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
4284 "(0x%016llx)\n", ioc->name, sas_device_backup.handle,
4285 (unsigned long long) sas_device_backup.sas_address);
4286
4287 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
4288 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
4289 sas_device_backup.handle, (unsigned long long)
4290 sas_device_backup.sas_address));
Eric Moore635374e2009-03-09 01:21:12 -06004291}
4292
4293#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4294/**
4295 * _scsih_sas_topology_change_event_debug - debug for topology event
4296 * @ioc: per adapter object
4297 * @event_data: event data payload
4298 * Context: user.
4299 */
4300static void
4301_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4302 Mpi2EventDataSasTopologyChangeList_t *event_data)
4303{
4304 int i;
4305 u16 handle;
4306 u16 reason_code;
4307 u8 phy_number;
4308 char *status_str = NULL;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304309 u8 link_rate, prev_link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06004310
4311 switch (event_data->ExpStatus) {
4312 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
4313 status_str = "add";
4314 break;
4315 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
4316 status_str = "remove";
4317 break;
4318 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304319 case 0:
Eric Moore635374e2009-03-09 01:21:12 -06004320 status_str = "responding";
4321 break;
4322 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
4323 status_str = "remove delay";
4324 break;
4325 default:
4326 status_str = "unknown status";
4327 break;
4328 }
4329 printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
4330 ioc->name, status_str);
4331 printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
4332 "start_phy(%02d), count(%d)\n",
4333 le16_to_cpu(event_data->ExpanderDevHandle),
4334 le16_to_cpu(event_data->EnclosureHandle),
4335 event_data->StartPhyNum, event_data->NumEntries);
4336 for (i = 0; i < event_data->NumEntries; i++) {
4337 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4338 if (!handle)
4339 continue;
4340 phy_number = event_data->StartPhyNum + i;
4341 reason_code = event_data->PHY[i].PhyStatus &
4342 MPI2_EVENT_SAS_TOPO_RC_MASK;
4343 switch (reason_code) {
4344 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304345 status_str = "target add";
Eric Moore635374e2009-03-09 01:21:12 -06004346 break;
4347 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304348 status_str = "target remove";
Eric Moore635374e2009-03-09 01:21:12 -06004349 break;
4350 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304351 status_str = "delay target remove";
Eric Moore635374e2009-03-09 01:21:12 -06004352 break;
4353 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304354 status_str = "link rate change";
Eric Moore635374e2009-03-09 01:21:12 -06004355 break;
4356 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304357 status_str = "target responding";
Eric Moore635374e2009-03-09 01:21:12 -06004358 break;
4359 default:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304360 status_str = "unknown";
Eric Moore635374e2009-03-09 01:21:12 -06004361 break;
4362 }
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304363 link_rate = event_data->PHY[i].LinkRate >> 4;
4364 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
4365 printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:"
4366 " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
4367 handle, status_str, link_rate, prev_link_rate);
4368
Eric Moore635374e2009-03-09 01:21:12 -06004369 }
4370}
4371#endif
4372
4373/**
4374 * _scsih_sas_topology_change_event - handle topology changes
4375 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304376 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004377 * Context: user.
4378 *
4379 */
4380static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304381_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06004382 struct fw_event_work *fw_event)
4383{
4384 int i;
4385 u16 parent_handle, handle;
4386 u16 reason_code;
4387 u8 phy_number;
4388 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304389 struct _sas_device *sas_device;
4390 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06004391 unsigned long flags;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304392 u8 link_rate, prev_link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304393 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06004394
4395#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4396 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4397 _scsih_sas_topology_change_event_debug(ioc, event_data);
4398#endif
4399
Kashyap, Desai6558bbb2010-03-17 16:23:36 +05304400 if (ioc->shost_recovery || ioc->remove_host)
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304401 return;
4402
Eric Moore635374e2009-03-09 01:21:12 -06004403 if (!ioc->sas_hba.num_phys)
4404 _scsih_sas_host_add(ioc);
4405 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304406 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06004407
4408 if (fw_event->ignore) {
4409 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
4410 "event\n", ioc->name));
4411 return;
4412 }
4413
4414 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
4415
4416 /* handle expander add */
4417 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
4418 if (_scsih_expander_add(ioc, parent_handle) != 0)
4419 return;
4420
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304421 spin_lock_irqsave(&ioc->sas_node_lock, flags);
4422 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
4423 parent_handle);
4424 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4425 if (sas_expander)
4426 sas_address = sas_expander->sas_address;
4427 else if (parent_handle < ioc->sas_hba.num_phys)
4428 sas_address = ioc->sas_hba.sas_address;
4429 else
4430 return;
4431
Eric Moore635374e2009-03-09 01:21:12 -06004432 /* handle siblings events */
4433 for (i = 0; i < event_data->NumEntries; i++) {
4434 if (fw_event->ignore) {
4435 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
4436 "expander event\n", ioc->name));
4437 return;
4438 }
Kashyap, Desai6558bbb2010-03-17 16:23:36 +05304439 if (ioc->shost_recovery || ioc->remove_host)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304440 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05304441 phy_number = event_data->StartPhyNum + i;
4442 reason_code = event_data->PHY[i].PhyStatus &
4443 MPI2_EVENT_SAS_TOPO_RC_MASK;
4444 if ((event_data->PHY[i].PhyStatus &
4445 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
4446 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06004447 continue;
4448 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
4449 if (!handle)
4450 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304451 link_rate = event_data->PHY[i].LinkRate >> 4;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304452 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Eric Moore635374e2009-03-09 01:21:12 -06004453 switch (reason_code) {
4454 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304455
4456 if (link_rate == prev_link_rate)
4457 break;
4458
4459 mpt2sas_transport_update_links(ioc, sas_address,
4460 handle, phy_number, link_rate);
4461
Kashyap, Desaib4344272010-03-17 16:24:14 +05304462 if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
4463 break;
4464
4465 _scsih_check_device(ioc, handle);
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304466 break;
Eric Moore635374e2009-03-09 01:21:12 -06004467 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304468
4469 mpt2sas_transport_update_links(ioc, sas_address,
4470 handle, phy_number, link_rate);
4471
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05304472 _scsih_add_device(ioc, handle, phy_number, 0);
Eric Moore635374e2009-03-09 01:21:12 -06004473 break;
4474 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304475
4476 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4477 sas_device = _scsih_sas_device_find_by_handle(ioc,
4478 handle);
4479 if (!sas_device) {
4480 spin_unlock_irqrestore(&ioc->sas_device_lock,
4481 flags);
4482 break;
4483 }
4484 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4485 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004486 break;
4487 }
4488 }
4489
4490 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304491 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
4492 sas_expander)
4493 _scsih_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06004494
4495}
4496
4497#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4498/**
4499 * _scsih_sas_device_status_change_event_debug - debug for device event
4500 * @event_data: event data payload
4501 * Context: user.
4502 *
4503 * Return nothing.
4504 */
4505static void
4506_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4507 Mpi2EventDataSasDeviceStatusChange_t *event_data)
4508{
4509 char *reason_str = NULL;
4510
4511 switch (event_data->ReasonCode) {
4512 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
4513 reason_str = "smart data";
4514 break;
4515 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
4516 reason_str = "unsupported device discovered";
4517 break;
4518 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
4519 reason_str = "internal device reset";
4520 break;
4521 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
4522 reason_str = "internal task abort";
4523 break;
4524 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
4525 reason_str = "internal task abort set";
4526 break;
4527 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
4528 reason_str = "internal clear task set";
4529 break;
4530 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
4531 reason_str = "internal query task";
4532 break;
4533 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
4534 reason_str = "sata init failure";
4535 break;
4536 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
4537 reason_str = "internal device reset complete";
4538 break;
4539 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
4540 reason_str = "internal task abort complete";
4541 break;
4542 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
4543 reason_str = "internal async notification";
4544 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05304545 case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
4546 reason_str = "expander reduced functionality";
4547 break;
4548 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
4549 reason_str = "expander reduced functionality complete";
4550 break;
Eric Moore635374e2009-03-09 01:21:12 -06004551 default:
4552 reason_str = "unknown reason";
4553 break;
4554 }
4555 printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
4556 "\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
4557 reason_str, le16_to_cpu(event_data->DevHandle),
4558 (unsigned long long)le64_to_cpu(event_data->SASAddress));
4559 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
4560 printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
4561 event_data->ASC, event_data->ASCQ);
4562 printk(KERN_INFO "\n");
4563}
4564#endif
4565
4566/**
4567 * _scsih_sas_device_status_change_event - handle device status change
4568 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304569 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004570 * Context: user.
4571 *
4572 * Return nothing.
4573 */
4574static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304575_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
4576 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004577{
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304578 struct MPT2SAS_TARGET *target_priv_data;
4579 struct _sas_device *sas_device;
4580 __le64 sas_address;
4581 unsigned long flags;
4582 Mpi2EventDataSasDeviceStatusChange_t *event_data =
4583 fw_event->event_data;
4584
Eric Moore635374e2009-03-09 01:21:12 -06004585#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4586 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304587 _scsih_sas_device_status_change_event_debug(ioc,
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304588 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004589#endif
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304590
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05304591 if (event_data->ReasonCode !=
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304592 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05304593 event_data->ReasonCode !=
4594 MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05304595 return;
4596
4597 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4598 sas_address = le64_to_cpu(event_data->SASAddress);
4599 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4600 sas_address);
4601 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4602
4603 if (!sas_device || !sas_device->starget)
4604 return;
4605
4606 target_priv_data = sas_device->starget->hostdata;
4607 if (!target_priv_data)
4608 return;
4609
4610 if (event_data->ReasonCode ==
4611 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
4612 target_priv_data->tm_busy = 1;
4613 else
4614 target_priv_data->tm_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004615}
4616
4617#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4618/**
4619 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
4620 * @ioc: per adapter object
4621 * @event_data: event data payload
4622 * Context: user.
4623 *
4624 * Return nothing.
4625 */
4626static void
4627_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
4628 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
4629{
4630 char *reason_str = NULL;
4631
4632 switch (event_data->ReasonCode) {
4633 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
4634 reason_str = "enclosure add";
4635 break;
4636 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
4637 reason_str = "enclosure remove";
4638 break;
4639 default:
4640 reason_str = "unknown reason";
4641 break;
4642 }
4643
4644 printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
4645 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
4646 " number slots(%d)\n", ioc->name, reason_str,
4647 le16_to_cpu(event_data->EnclosureHandle),
4648 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
4649 le16_to_cpu(event_data->StartSlot));
4650}
4651#endif
4652
4653/**
4654 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
4655 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304656 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004657 * Context: user.
4658 *
4659 * Return nothing.
4660 */
4661static void
4662_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304663 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004664{
4665#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4666 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
4667 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304668 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06004669#endif
4670}
4671
4672/**
4673 * _scsih_sas_broadcast_primative_event - handle broadcast events
4674 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304675 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004676 * Context: user.
4677 *
4678 * Return nothing.
4679 */
4680static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304681_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
4682 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004683{
4684 struct scsi_cmnd *scmd;
4685 u16 smid, handle;
4686 u32 lun;
4687 struct MPT2SAS_DEVICE *sas_device_priv_data;
4688 u32 termination_count;
4689 u32 query_count;
4690 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304691#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4692 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
4693#endif
Kashyap, Desai463217b2009-10-05 15:53:06 +05304694 u16 ioc_status;
Eric Moore635374e2009-03-09 01:21:12 -06004695 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
4696 "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
4697 event_data->PortWidth));
Eric Moore635374e2009-03-09 01:21:12 -06004698 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
4699 __func__));
4700
Eric Moore635374e2009-03-09 01:21:12 -06004701 termination_count = 0;
4702 query_count = 0;
4703 mpi_reply = ioc->tm_cmds.reply;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304704 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Eric Moore635374e2009-03-09 01:21:12 -06004705 scmd = _scsih_scsi_lookup_get(ioc, smid);
4706 if (!scmd)
4707 continue;
4708 sas_device_priv_data = scmd->device->hostdata;
4709 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
4710 continue;
4711 /* skip hidden raid components */
4712 if (sas_device_priv_data->sas_target->flags &
4713 MPT_TARGET_FLAGS_RAID_COMPONENT)
4714 continue;
4715 /* skip volumes */
4716 if (sas_device_priv_data->sas_target->flags &
4717 MPT_TARGET_FLAGS_VOLUME)
4718 continue;
4719
4720 handle = sas_device_priv_data->sas_target->handle;
4721 lun = sas_device_priv_data->lun;
4722 query_count++;
4723
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05304724 mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
4725 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL);
Eric Moore8901cbb2009-04-21 15:41:32 -06004726 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Kashyap, Desai463217b2009-10-05 15:53:06 +05304727 ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
4728 & MPI2_IOCSTATUS_MASK;
4729 if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) &&
Eric Moore635374e2009-03-09 01:21:12 -06004730 (mpi_reply->ResponseCode ==
4731 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4732 mpi_reply->ResponseCode ==
4733 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4734 continue;
4735
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05304736 mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
4737 MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL);
Eric Moore635374e2009-03-09 01:21:12 -06004738 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
4739 }
Eric Moore635374e2009-03-09 01:21:12 -06004740 ioc->broadcast_aen_busy = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004741
4742 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
4743 "%s - exit, query_count = %d termination_count = %d\n",
4744 ioc->name, __func__, query_count, termination_count));
4745}
4746
4747/**
4748 * _scsih_sas_discovery_event - handle discovery events
4749 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304750 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06004751 * Context: user.
4752 *
4753 * Return nothing.
4754 */
4755static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304756_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
4757 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06004758{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304759 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
4760
Eric Moore635374e2009-03-09 01:21:12 -06004761#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4762 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
4763 printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
4764 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
4765 "start" : "stop");
4766 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304767 printk("discovery_status(0x%08x)",
4768 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06004769 printk("\n");
4770 }
4771#endif
4772
4773 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
4774 !ioc->sas_hba.num_phys)
4775 _scsih_sas_host_add(ioc);
4776}
4777
4778/**
4779 * _scsih_reprobe_lun - reprobing lun
4780 * @sdev: scsi device struct
4781 * @no_uld_attach: sdev->no_uld_attach flag setting
4782 *
4783 **/
4784static void
4785_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
4786{
4787 int rc;
4788
4789 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
4790 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
4791 sdev->no_uld_attach ? "hidding" : "exposing");
4792 rc = scsi_device_reprobe(sdev);
4793}
4794
4795/**
4796 * _scsih_reprobe_target - reprobing target
4797 * @starget: scsi target struct
4798 * @no_uld_attach: sdev->no_uld_attach flag setting
4799 *
4800 * Note: no_uld_attach flag determines whether the disk device is attached
4801 * to block layer. A value of `1` means to not attach.
4802 **/
4803static void
4804_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
4805{
4806 struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata;
4807
4808 if (no_uld_attach)
4809 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4810 else
4811 sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4812
4813 starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
4814 _scsih_reprobe_lun);
4815}
4816/**
4817 * _scsih_sas_volume_add - add new volume
4818 * @ioc: per adapter object
4819 * @element: IR config element data
4820 * Context: user.
4821 *
4822 * Return nothing.
4823 */
4824static void
4825_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
4826 Mpi2EventIrConfigElement_t *element)
4827{
4828 struct _raid_device *raid_device;
4829 unsigned long flags;
4830 u64 wwid;
4831 u16 handle = le16_to_cpu(element->VolDevHandle);
4832 int rc;
4833
Eric Moore635374e2009-03-09 01:21:12 -06004834 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
4835 if (!wwid) {
4836 printk(MPT2SAS_ERR_FMT
4837 "failure at %s:%d/%s()!\n", ioc->name,
4838 __FILE__, __LINE__, __func__);
4839 return;
4840 }
4841
4842 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4843 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
4844 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4845
4846 if (raid_device)
4847 return;
4848
4849 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
4850 if (!raid_device) {
4851 printk(MPT2SAS_ERR_FMT
4852 "failure at %s:%d/%s()!\n", ioc->name,
4853 __FILE__, __LINE__, __func__);
4854 return;
4855 }
4856
4857 raid_device->id = ioc->sas_id++;
4858 raid_device->channel = RAID_CHANNEL;
4859 raid_device->handle = handle;
4860 raid_device->wwid = wwid;
4861 _scsih_raid_device_add(ioc, raid_device);
4862 if (!ioc->wait_for_port_enable_to_complete) {
4863 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
4864 raid_device->id, 0);
4865 if (rc)
4866 _scsih_raid_device_remove(ioc, raid_device);
4867 } else
4868 _scsih_determine_boot_device(ioc, raid_device, 1);
4869}
4870
4871/**
4872 * _scsih_sas_volume_delete - delete volume
4873 * @ioc: per adapter object
4874 * @element: IR config element data
4875 * Context: user.
4876 *
4877 * Return nothing.
4878 */
4879static void
4880_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
4881 Mpi2EventIrConfigElement_t *element)
4882{
4883 struct _raid_device *raid_device;
4884 u16 handle = le16_to_cpu(element->VolDevHandle);
4885 unsigned long flags;
4886 struct MPT2SAS_TARGET *sas_target_priv_data;
4887
Eric Moore635374e2009-03-09 01:21:12 -06004888 spin_lock_irqsave(&ioc->raid_device_lock, flags);
4889 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
4890 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
4891 if (!raid_device)
4892 return;
4893 if (raid_device->starget) {
4894 sas_target_priv_data = raid_device->starget->hostdata;
4895 sas_target_priv_data->deleted = 1;
4896 scsi_remove_target(&raid_device->starget->dev);
4897 }
4898 _scsih_raid_device_remove(ioc, raid_device);
4899}
4900
4901/**
4902 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
4903 * @ioc: per adapter object
4904 * @element: IR config element data
4905 * Context: user.
4906 *
4907 * Return nothing.
4908 */
4909static void
4910_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
4911 Mpi2EventIrConfigElement_t *element)
4912{
4913 struct _sas_device *sas_device;
4914 unsigned long flags;
4915 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4916
4917 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4918 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4919 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4920 if (!sas_device)
4921 return;
4922
4923 /* exposing raid component */
4924 sas_device->volume_handle = 0;
4925 sas_device->volume_wwid = 0;
4926 sas_device->hidden_raid_component = 0;
4927 _scsih_reprobe_target(sas_device->starget, 0);
4928}
4929
4930/**
4931 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
4932 * @ioc: per adapter object
4933 * @element: IR config element data
4934 * Context: user.
4935 *
4936 * Return nothing.
4937 */
4938static void
4939_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
4940 Mpi2EventIrConfigElement_t *element)
4941{
4942 struct _sas_device *sas_device;
4943 unsigned long flags;
4944 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4945
4946 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4947 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4948 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4949 if (!sas_device)
4950 return;
4951
4952 /* hiding raid component */
4953 mpt2sas_config_get_volume_handle(ioc, handle,
4954 &sas_device->volume_handle);
4955 mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
4956 &sas_device->volume_wwid);
4957 sas_device->hidden_raid_component = 1;
4958 _scsih_reprobe_target(sas_device->starget, 1);
4959}
4960
4961/**
4962 * _scsih_sas_pd_delete - delete pd component
4963 * @ioc: per adapter object
4964 * @element: IR config element data
4965 * Context: user.
4966 *
4967 * Return nothing.
4968 */
4969static void
4970_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
4971 Mpi2EventIrConfigElement_t *element)
4972{
4973 struct _sas_device *sas_device;
4974 unsigned long flags;
4975 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
4976
4977 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4978 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4979 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4980 if (!sas_device)
4981 return;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304982 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06004983}
4984
4985/**
4986 * _scsih_sas_pd_add - remove pd component
4987 * @ioc: per adapter object
4988 * @element: IR config element data
4989 * Context: user.
4990 *
4991 * Return nothing.
4992 */
4993static void
4994_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
4995 Mpi2EventIrConfigElement_t *element)
4996{
4997 struct _sas_device *sas_device;
4998 unsigned long flags;
4999 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305000 Mpi2ConfigReply_t mpi_reply;
5001 Mpi2SasDevicePage0_t sas_device_pg0;
5002 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305003 u64 sas_address;
5004 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06005005
5006 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5007 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5008 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305009 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06005010 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305011 return;
5012 }
5013
5014 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
5015 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
5016 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5017 ioc->name, __FILE__, __LINE__, __func__);
5018 return;
5019 }
5020
5021 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5022 MPI2_IOCSTATUS_MASK;
5023 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5024 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5025 ioc->name, __FILE__, __LINE__, __func__);
5026 return;
5027 }
5028
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305029 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
5030 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
5031 mpt2sas_transport_update_links(ioc, sas_address, handle,
5032 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305033
5034 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06005035}
5036
5037#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5038/**
5039 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
5040 * @ioc: per adapter object
5041 * @event_data: event data payload
5042 * Context: user.
5043 *
5044 * Return nothing.
5045 */
5046static void
5047_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5048 Mpi2EventDataIrConfigChangeList_t *event_data)
5049{
5050 Mpi2EventIrConfigElement_t *element;
5051 u8 element_type;
5052 int i;
5053 char *reason_str = NULL, *element_str = NULL;
5054
5055 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
5056
5057 printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
5058 ioc->name, (le32_to_cpu(event_data->Flags) &
5059 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
5060 "foreign" : "native", event_data->NumElements);
5061 for (i = 0; i < event_data->NumElements; i++, element++) {
5062 switch (element->ReasonCode) {
5063 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
5064 reason_str = "add";
5065 break;
5066 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
5067 reason_str = "remove";
5068 break;
5069 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
5070 reason_str = "no change";
5071 break;
5072 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
5073 reason_str = "hide";
5074 break;
5075 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
5076 reason_str = "unhide";
5077 break;
5078 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
5079 reason_str = "volume_created";
5080 break;
5081 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
5082 reason_str = "volume_deleted";
5083 break;
5084 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
5085 reason_str = "pd_created";
5086 break;
5087 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
5088 reason_str = "pd_deleted";
5089 break;
5090 default:
5091 reason_str = "unknown reason";
5092 break;
5093 }
5094 element_type = le16_to_cpu(element->ElementFlags) &
5095 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
5096 switch (element_type) {
5097 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
5098 element_str = "volume";
5099 break;
5100 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
5101 element_str = "phys disk";
5102 break;
5103 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
5104 element_str = "hot spare";
5105 break;
5106 default:
5107 element_str = "unknown element";
5108 break;
5109 }
5110 printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
5111 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
5112 reason_str, le16_to_cpu(element->VolDevHandle),
5113 le16_to_cpu(element->PhysDiskDevHandle),
5114 element->PhysDiskNum);
5115 }
5116}
5117#endif
5118
5119/**
5120 * _scsih_sas_ir_config_change_event - handle ir configuration change events
5121 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305122 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005123 * Context: user.
5124 *
5125 * Return nothing.
5126 */
5127static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305128_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
5129 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005130{
5131 Mpi2EventIrConfigElement_t *element;
5132 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305133 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305134 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005135
5136#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5137 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5138 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
5139
5140#endif
Kashyap, Desai62727a72009-08-07 19:35:18 +05305141 foreign_config = (le32_to_cpu(event_data->Flags) &
5142 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06005143
5144 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
5145 for (i = 0; i < event_data->NumElements; i++, element++) {
5146
5147 switch (element->ReasonCode) {
5148 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
5149 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305150 if (!foreign_config)
5151 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06005152 break;
5153 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
5154 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305155 if (!foreign_config)
5156 _scsih_sas_volume_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06005157 break;
5158 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
5159 _scsih_sas_pd_hide(ioc, element);
5160 break;
5161 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
5162 _scsih_sas_pd_expose(ioc, element);
5163 break;
5164 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
5165 _scsih_sas_pd_add(ioc, element);
5166 break;
5167 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
5168 _scsih_sas_pd_delete(ioc, element);
5169 break;
5170 }
5171 }
5172}
5173
5174/**
5175 * _scsih_sas_ir_volume_event - IR volume event
5176 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305177 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005178 * Context: user.
5179 *
5180 * Return nothing.
5181 */
5182static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305183_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
5184 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005185{
5186 u64 wwid;
5187 unsigned long flags;
5188 struct _raid_device *raid_device;
5189 u16 handle;
5190 u32 state;
5191 int rc;
5192 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305193 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005194
5195 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
5196 return;
5197
5198 handle = le16_to_cpu(event_data->VolDevHandle);
5199 state = le32_to_cpu(event_data->NewValue);
5200 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
5201 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
5202 le32_to_cpu(event_data->PreviousValue), state));
5203
5204 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5205 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5206 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5207
5208 switch (state) {
5209 case MPI2_RAID_VOL_STATE_MISSING:
5210 case MPI2_RAID_VOL_STATE_FAILED:
5211 if (!raid_device)
5212 break;
5213 if (raid_device->starget) {
5214 sas_target_priv_data = raid_device->starget->hostdata;
5215 sas_target_priv_data->deleted = 1;
5216 scsi_remove_target(&raid_device->starget->dev);
5217 }
5218 _scsih_raid_device_remove(ioc, raid_device);
5219 break;
5220
5221 case MPI2_RAID_VOL_STATE_ONLINE:
5222 case MPI2_RAID_VOL_STATE_DEGRADED:
5223 case MPI2_RAID_VOL_STATE_OPTIMAL:
5224 if (raid_device)
5225 break;
5226
5227 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
5228 if (!wwid) {
5229 printk(MPT2SAS_ERR_FMT
5230 "failure at %s:%d/%s()!\n", ioc->name,
5231 __FILE__, __LINE__, __func__);
5232 break;
5233 }
5234
5235 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
5236 if (!raid_device) {
5237 printk(MPT2SAS_ERR_FMT
5238 "failure at %s:%d/%s()!\n", ioc->name,
5239 __FILE__, __LINE__, __func__);
5240 break;
5241 }
5242
5243 raid_device->id = ioc->sas_id++;
5244 raid_device->channel = RAID_CHANNEL;
5245 raid_device->handle = handle;
5246 raid_device->wwid = wwid;
5247 _scsih_raid_device_add(ioc, raid_device);
5248 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
5249 raid_device->id, 0);
5250 if (rc)
5251 _scsih_raid_device_remove(ioc, raid_device);
5252 break;
5253
5254 case MPI2_RAID_VOL_STATE_INITIALIZING:
5255 default:
5256 break;
5257 }
5258}
5259
5260/**
5261 * _scsih_sas_ir_physical_disk_event - PD event
5262 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305263 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005264 * Context: user.
5265 *
5266 * Return nothing.
5267 */
5268static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305269_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
5270 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005271{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305272 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06005273 u32 state;
5274 struct _sas_device *sas_device;
5275 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305276 Mpi2ConfigReply_t mpi_reply;
5277 Mpi2SasDevicePage0_t sas_device_pg0;
5278 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305279 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305280 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06005281
5282 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
5283 return;
5284
5285 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
5286 state = le32_to_cpu(event_data->NewValue);
5287
5288 dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
5289 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
5290 le32_to_cpu(event_data->PreviousValue), state));
5291
5292 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5293 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5294 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5295
5296 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06005297 case MPI2_RAID_PD_STATE_ONLINE:
5298 case MPI2_RAID_PD_STATE_DEGRADED:
5299 case MPI2_RAID_PD_STATE_REBUILDING:
5300 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desai62727a72009-08-07 19:35:18 +05305301 if (sas_device) {
Eric Moore635374e2009-03-09 01:21:12 -06005302 sas_device->hidden_raid_component = 1;
Kashyap, Desai62727a72009-08-07 19:35:18 +05305303 return;
5304 }
5305
5306 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5307 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
5308 handle))) {
5309 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5310 ioc->name, __FILE__, __LINE__, __func__);
5311 return;
5312 }
5313
5314 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5315 MPI2_IOCSTATUS_MASK;
5316 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5317 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5318 ioc->name, __FILE__, __LINE__, __func__);
5319 return;
5320 }
5321
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305322 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
5323 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
5324 mpt2sas_transport_update_links(ioc, sas_address, handle,
5325 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05305326
5327 _scsih_add_device(ioc, handle, 0, 1);
5328
Eric Moore635374e2009-03-09 01:21:12 -06005329 break;
5330
Kashyap, Desai62727a72009-08-07 19:35:18 +05305331 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06005332 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
5333 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
5334 case MPI2_RAID_PD_STATE_HOT_SPARE:
5335 default:
5336 break;
5337 }
5338}
5339
5340#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5341/**
5342 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
5343 * @ioc: per adapter object
5344 * @event_data: event data payload
5345 * Context: user.
5346 *
5347 * Return nothing.
5348 */
5349static void
5350_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
5351 Mpi2EventDataIrOperationStatus_t *event_data)
5352{
5353 char *reason_str = NULL;
5354
5355 switch (event_data->RAIDOperation) {
5356 case MPI2_EVENT_IR_RAIDOP_RESYNC:
5357 reason_str = "resync";
5358 break;
5359 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
5360 reason_str = "online capacity expansion";
5361 break;
5362 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
5363 reason_str = "consistency check";
5364 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305365 case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
5366 reason_str = "background init";
5367 break;
5368 case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
5369 reason_str = "make data consistent";
Eric Moore635374e2009-03-09 01:21:12 -06005370 break;
5371 }
5372
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305373 if (!reason_str)
5374 return;
5375
Eric Moore635374e2009-03-09 01:21:12 -06005376 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
5377 "\thandle(0x%04x), percent complete(%d)\n",
5378 ioc->name, reason_str,
5379 le16_to_cpu(event_data->VolDevHandle),
5380 event_data->PercentComplete);
5381}
5382#endif
5383
5384/**
5385 * _scsih_sas_ir_operation_status_event - handle RAID operation events
5386 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305387 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005388 * Context: user.
5389 *
5390 * Return nothing.
5391 */
5392static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305393_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
5394 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005395{
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305396 Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data;
5397 static struct _raid_device *raid_device;
5398 unsigned long flags;
5399 u16 handle;
5400
Eric Moore635374e2009-03-09 01:21:12 -06005401#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5402 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305403 _scsih_sas_ir_operation_status_event_debug(ioc,
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305404 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005405#endif
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05305406
5407 /* code added for raid transport support */
5408 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
5409
5410 handle = le16_to_cpu(event_data->VolDevHandle);
5411
5412 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5413 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
5414 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5415
5416 if (!raid_device)
5417 return;
5418
5419 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
5420 raid_device->percent_complete =
5421 event_data->PercentComplete;
5422 }
Eric Moore635374e2009-03-09 01:21:12 -06005423}
5424
5425/**
5426 * _scsih_task_set_full - handle task set full
5427 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305428 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005429 * Context: user.
5430 *
5431 * Throttle back qdepth.
5432 */
5433static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305434_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
5435 *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005436{
5437 unsigned long flags;
5438 struct _sas_device *sas_device;
5439 static struct _raid_device *raid_device;
5440 struct scsi_device *sdev;
5441 int depth;
5442 u16 current_depth;
5443 u16 handle;
5444 int id, channel;
5445 u64 sas_address;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305446 Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005447
5448 current_depth = le16_to_cpu(event_data->CurrentDepth);
5449 handle = le16_to_cpu(event_data->DevHandle);
5450 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5451 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5452 if (!sas_device) {
5453 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5454 return;
5455 }
5456 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5457 id = sas_device->id;
5458 channel = sas_device->channel;
5459 sas_address = sas_device->sas_address;
5460
5461 /* if hidden raid component, then change to volume characteristics */
5462 if (sas_device->hidden_raid_component && sas_device->volume_handle) {
5463 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5464 raid_device = _scsih_raid_device_find_by_handle(
5465 ioc, sas_device->volume_handle);
5466 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5467 if (raid_device) {
5468 id = raid_device->id;
5469 channel = raid_device->channel;
5470 handle = raid_device->handle;
5471 sas_address = raid_device->wwid;
5472 }
5473 }
5474
5475 if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
5476 starget_printk(KERN_DEBUG, sas_device->starget, "task set "
5477 "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
5478 handle, (unsigned long long)sas_address, current_depth);
5479
5480 shost_for_each_device(sdev, ioc->shost) {
5481 if (sdev->id == id && sdev->channel == channel) {
5482 if (current_depth > sdev->queue_depth) {
5483 if (ioc->logging_level &
5484 MPT_DEBUG_TASK_SET_FULL)
5485 sdev_printk(KERN_INFO, sdev, "strange "
5486 "observation, the queue depth is"
5487 " (%d) meanwhile fw queue depth "
5488 "is (%d)\n", sdev->queue_depth,
5489 current_depth);
5490 continue;
5491 }
5492 depth = scsi_track_queue_full(sdev,
5493 current_depth - 1);
5494 if (depth > 0)
5495 sdev_printk(KERN_INFO, sdev, "Queue depth "
5496 "reduced to (%d)\n", depth);
5497 else if (depth < 0)
5498 sdev_printk(KERN_INFO, sdev, "Tagged Command "
5499 "Queueing is being disabled\n");
5500 else if (depth == 0)
5501 if (ioc->logging_level &
5502 MPT_DEBUG_TASK_SET_FULL)
5503 sdev_printk(KERN_INFO, sdev,
5504 "Queue depth not changed yet\n");
5505 }
5506 }
5507}
5508
5509/**
Kashyap, Desai14695852010-03-30 10:52:44 +05305510 * _scsih_prep_device_scan - initialize parameters prior to device scan
5511 * @ioc: per adapter object
5512 *
5513 * Set the deleted flag prior to device scan. If the device is found during
5514 * the scan, then we clear the deleted flag.
5515 */
5516static void
5517_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc)
5518{
5519 struct MPT2SAS_DEVICE *sas_device_priv_data;
5520 struct scsi_device *sdev;
5521
5522 shost_for_each_device(sdev, ioc->shost) {
5523 sas_device_priv_data = sdev->hostdata;
5524 if (sas_device_priv_data && sas_device_priv_data->sas_target)
5525 sas_device_priv_data->sas_target->deleted = 1;
5526 }
5527}
5528
5529/**
Eric Moore635374e2009-03-09 01:21:12 -06005530 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
5531 * @ioc: per adapter object
5532 * @sas_address: sas address
5533 * @slot: enclosure slot id
5534 * @handle: device handle
5535 *
5536 * After host reset, find out whether devices are still responding.
5537 * Used in _scsi_remove_unresponsive_sas_devices.
5538 *
5539 * Return nothing.
5540 */
5541static void
5542_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5543 u16 slot, u16 handle)
5544{
5545 struct MPT2SAS_TARGET *sas_target_priv_data;
5546 struct scsi_target *starget;
5547 struct _sas_device *sas_device;
5548 unsigned long flags;
5549
5550 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5551 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
5552 if (sas_device->sas_address == sas_address &&
5553 sas_device->slot == slot && sas_device->starget) {
5554 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305555 starget = sas_device->starget;
Kashyap, Desai14695852010-03-30 10:52:44 +05305556 if (starget && starget->hostdata) {
5557 sas_target_priv_data = starget->hostdata;
5558 sas_target_priv_data->tm_busy = 0;
5559 sas_target_priv_data->deleted = 0;
5560 } else
5561 sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06005562 starget_printk(KERN_INFO, sas_device->starget,
5563 "handle(0x%04x), sas_addr(0x%016llx), enclosure "
5564 "logical id(0x%016llx), slot(%d)\n", handle,
5565 (unsigned long long)sas_device->sas_address,
5566 (unsigned long long)
5567 sas_device->enclosure_logical_id,
5568 sas_device->slot);
5569 if (sas_device->handle == handle)
5570 goto out;
5571 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5572 sas_device->handle);
5573 sas_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05305574 if (sas_target_priv_data)
5575 sas_target_priv_data->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005576 goto out;
5577 }
5578 }
5579 out:
5580 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5581}
5582
5583/**
5584 * _scsih_search_responding_sas_devices -
5585 * @ioc: per adapter object
5586 *
5587 * After host reset, find out whether devices are still responding.
5588 * If not remove.
5589 *
5590 * Return nothing.
5591 */
5592static void
5593_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
5594{
5595 Mpi2SasDevicePage0_t sas_device_pg0;
5596 Mpi2ConfigReply_t mpi_reply;
5597 u16 ioc_status;
5598 __le64 sas_address;
5599 u16 handle;
5600 u32 device_info;
5601 u16 slot;
5602
5603 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5604
5605 if (list_empty(&ioc->sas_device_list))
5606 return;
5607
5608 handle = 0xFFFF;
5609 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
5610 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
5611 handle))) {
5612 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5613 MPI2_IOCSTATUS_MASK;
5614 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5615 break;
5616 handle = le16_to_cpu(sas_device_pg0.DevHandle);
5617 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5618 if (!(_scsih_is_end_device(device_info)))
5619 continue;
5620 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5621 slot = le16_to_cpu(sas_device_pg0.Slot);
5622 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
5623 handle);
5624 }
5625}
5626
5627/**
5628 * _scsih_mark_responding_raid_device - mark a raid_device as responding
5629 * @ioc: per adapter object
5630 * @wwid: world wide identifier for raid volume
5631 * @handle: device handle
5632 *
5633 * After host reset, find out whether devices are still responding.
5634 * Used in _scsi_remove_unresponsive_raid_devices.
5635 *
5636 * Return nothing.
5637 */
5638static void
5639_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
5640 u16 handle)
5641{
5642 struct MPT2SAS_TARGET *sas_target_priv_data;
5643 struct scsi_target *starget;
5644 struct _raid_device *raid_device;
5645 unsigned long flags;
5646
5647 spin_lock_irqsave(&ioc->raid_device_lock, flags);
5648 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
5649 if (raid_device->wwid == wwid && raid_device->starget) {
Kashyap, Desai14695852010-03-30 10:52:44 +05305650 starget = raid_device->starget;
5651 if (starget && starget->hostdata) {
5652 sas_target_priv_data = starget->hostdata;
5653 sas_target_priv_data->deleted = 0;
5654 } else
5655 sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06005656 raid_device->responding = 1;
5657 starget_printk(KERN_INFO, raid_device->starget,
5658 "handle(0x%04x), wwid(0x%016llx)\n", handle,
5659 (unsigned long long)raid_device->wwid);
5660 if (raid_device->handle == handle)
5661 goto out;
5662 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
5663 raid_device->handle);
5664 raid_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05305665 if (sas_target_priv_data)
5666 sas_target_priv_data->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06005667 goto out;
5668 }
5669 }
5670 out:
5671 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
5672}
5673
5674/**
5675 * _scsih_search_responding_raid_devices -
5676 * @ioc: per adapter object
5677 *
5678 * After host reset, find out whether devices are still responding.
5679 * If not remove.
5680 *
5681 * Return nothing.
5682 */
5683static void
5684_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
5685{
5686 Mpi2RaidVolPage1_t volume_pg1;
5687 Mpi2ConfigReply_t mpi_reply;
5688 u16 ioc_status;
5689 u16 handle;
5690
5691 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5692
5693 if (list_empty(&ioc->raid_device_list))
5694 return;
5695
5696 handle = 0xFFFF;
5697 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
5698 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
5699 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5700 MPI2_IOCSTATUS_MASK;
5701 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5702 break;
5703 handle = le16_to_cpu(volume_pg1.DevHandle);
5704 _scsih_mark_responding_raid_device(ioc,
5705 le64_to_cpu(volume_pg1.WWID), handle);
5706 }
5707}
5708
5709/**
5710 * _scsih_mark_responding_expander - mark a expander as responding
5711 * @ioc: per adapter object
5712 * @sas_address: sas address
5713 * @handle:
5714 *
5715 * After host reset, find out whether devices are still responding.
5716 * Used in _scsi_remove_unresponsive_expanders.
5717 *
5718 * Return nothing.
5719 */
5720static void
5721_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5722 u16 handle)
5723{
5724 struct _sas_node *sas_expander;
5725 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305726 int i;
Eric Moore635374e2009-03-09 01:21:12 -06005727
5728 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5729 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305730 if (sas_expander->sas_address != sas_address)
5731 continue;
5732 sas_expander->responding = 1;
5733 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06005734 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305735 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
5736 " from(0x%04x) to (0x%04x)!!!\n",
5737 (unsigned long long)sas_expander->sas_address,
5738 sas_expander->handle, handle);
5739 sas_expander->handle = handle;
5740 for (i = 0 ; i < sas_expander->num_phys ; i++)
5741 sas_expander->phy[i].handle = handle;
5742 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06005743 }
5744 out:
5745 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
5746}
5747
5748/**
5749 * _scsih_search_responding_expanders -
5750 * @ioc: per adapter object
5751 *
5752 * After host reset, find out whether devices are still responding.
5753 * If not remove.
5754 *
5755 * Return nothing.
5756 */
5757static void
5758_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
5759{
5760 Mpi2ExpanderPage0_t expander_pg0;
5761 Mpi2ConfigReply_t mpi_reply;
5762 u16 ioc_status;
5763 __le64 sas_address;
5764 u16 handle;
5765
5766 printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
5767
5768 if (list_empty(&ioc->sas_expander_list))
5769 return;
5770
5771 handle = 0xFFFF;
5772 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
5773 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
5774
5775 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5776 MPI2_IOCSTATUS_MASK;
5777 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
5778 break;
5779
5780 handle = le16_to_cpu(expander_pg0.DevHandle);
5781 sas_address = le64_to_cpu(expander_pg0.SASAddress);
5782 printk(KERN_INFO "\texpander present: handle(0x%04x), "
5783 "sas_addr(0x%016llx)\n", handle,
5784 (unsigned long long)sas_address);
5785 _scsih_mark_responding_expander(ioc, sas_address, handle);
5786 }
5787
5788}
5789
5790/**
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305791 * _scsih_remove_unresponding_sas_devices - removing unresponding devices
Eric Moore635374e2009-03-09 01:21:12 -06005792 * @ioc: per adapter object
5793 *
5794 * Return nothing.
5795 */
5796static void
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305797_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06005798{
5799 struct _sas_device *sas_device, *sas_device_next;
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305800 struct _sas_node *sas_expander;
Eric Moore635374e2009-03-09 01:21:12 -06005801 struct _raid_device *raid_device, *raid_device_next;
Eric Moore635374e2009-03-09 01:21:12 -06005802
Eric Moore635374e2009-03-09 01:21:12 -06005803
5804 list_for_each_entry_safe(sas_device, sas_device_next,
5805 &ioc->sas_device_list, list) {
5806 if (sas_device->responding) {
5807 sas_device->responding = 0;
5808 continue;
5809 }
5810 if (sas_device->starget)
5811 starget_printk(KERN_INFO, sas_device->starget,
5812 "removing: handle(0x%04x), sas_addr(0x%016llx), "
5813 "enclosure logical id(0x%016llx), slot(%d)\n",
5814 sas_device->handle,
5815 (unsigned long long)sas_device->sas_address,
5816 (unsigned long long)
5817 sas_device->enclosure_logical_id,
5818 sas_device->slot);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305819 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005820 }
5821
5822 list_for_each_entry_safe(raid_device, raid_device_next,
5823 &ioc->raid_device_list, list) {
5824 if (raid_device->responding) {
5825 raid_device->responding = 0;
5826 continue;
5827 }
5828 if (raid_device->starget) {
5829 starget_printk(KERN_INFO, raid_device->starget,
5830 "removing: handle(0x%04x), wwid(0x%016llx)\n",
5831 raid_device->handle,
5832 (unsigned long long)raid_device->wwid);
5833 scsi_remove_target(&raid_device->starget->dev);
5834 }
5835 _scsih_raid_device_remove(ioc, raid_device);
5836 }
5837
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305838 retry_expander_search:
5839 sas_expander = NULL;
5840 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Eric Moore635374e2009-03-09 01:21:12 -06005841 if (sas_expander->responding) {
5842 sas_expander->responding = 0;
5843 continue;
5844 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305845 _scsih_expander_remove(ioc, sas_expander->sas_address);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305846 goto retry_expander_search;
5847 }
5848}
5849
5850/**
5851 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
5852 * @ioc: per adapter object
5853 * @reset_phase: phase
5854 *
5855 * The handler for doing any required cleanup or initialization.
5856 *
5857 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
5858 * MPT2_IOC_DONE_RESET
5859 *
5860 * Return nothing.
5861 */
5862void
5863mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
5864{
5865 switch (reset_phase) {
5866 case MPT2_IOC_PRE_RESET:
5867 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5868 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305869 break;
5870 case MPT2_IOC_AFTER_RESET:
5871 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5872 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305873 if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
5874 ioc->scsih_cmds.status |= MPT2_CMD_RESET;
5875 mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
5876 complete(&ioc->scsih_cmds.done);
5877 }
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305878 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
5879 ioc->tm_cmds.status |= MPT2_CMD_RESET;
5880 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
5881 complete(&ioc->tm_cmds.done);
5882 }
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305883 _scsih_fw_event_cleanup_queue(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305884 _scsih_flush_running_cmds(ioc);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305885 _scsih_queue_rescan(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305886 break;
5887 case MPT2_IOC_DONE_RESET:
5888 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
5889 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305890 _scsih_sas_host_refresh(ioc);
Kashyap, Desai14695852010-03-30 10:52:44 +05305891 _scsih_prep_device_scan(ioc);
5892 _scsih_search_responding_sas_devices(ioc);
5893 _scsih_search_responding_raid_devices(ioc);
5894 _scsih_search_responding_expanders(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05305895 break;
Eric Moore635374e2009-03-09 01:21:12 -06005896 }
5897}
5898
5899/**
5900 * _firmware_event_work - delayed task for processing firmware events
5901 * @ioc: per adapter object
5902 * @work: equal to the fw_event_work object
5903 * Context: user.
5904 *
5905 * Return nothing.
5906 */
5907static void
5908_firmware_event_work(struct work_struct *work)
5909{
5910 struct fw_event_work *fw_event = container_of(work,
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305911 struct fw_event_work, delayed_work.work);
Eric Moore635374e2009-03-09 01:21:12 -06005912 unsigned long flags;
5913 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
5914
Eric Moore635374e2009-03-09 01:21:12 -06005915 /* the queue is being flushed so ignore this event */
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305916 if (ioc->remove_host || fw_event->cancel_pending_work) {
Eric Moore635374e2009-03-09 01:21:12 -06005917 _scsih_fw_event_free(ioc, fw_event);
5918 return;
5919 }
Eric Moore635374e2009-03-09 01:21:12 -06005920
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305921 if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) {
5922 _scsih_fw_event_free(ioc, fw_event);
5923 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
5924 if (ioc->shost_recovery) {
5925 init_completion(&ioc->shost_recovery_done);
5926 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
5927 flags);
5928 wait_for_completion(&ioc->shost_recovery_done);
5929 } else
5930 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
5931 flags);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305932 _scsih_remove_unresponding_sas_devices(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005933 return;
5934 }
Eric Moore635374e2009-03-09 01:21:12 -06005935
5936 switch (fw_event->event) {
5937 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305938 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005939 break;
5940 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305941 _scsih_sas_device_status_change_event(ioc,
5942 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005943 break;
5944 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305945 _scsih_sas_discovery_event(ioc,
5946 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005947 break;
5948 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305949 _scsih_sas_broadcast_primative_event(ioc,
5950 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005951 break;
5952 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
5953 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305954 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005955 break;
5956 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305957 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005958 break;
5959 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305960 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005961 break;
5962 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305963 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005964 break;
5965 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305966 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005967 break;
5968 case MPI2_EVENT_TASK_SET_FULL:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305969 _scsih_task_set_full(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06005970 break;
5971 }
5972 _scsih_fw_event_free(ioc, fw_event);
5973}
5974
5975/**
5976 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
5977 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305978 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06005979 * @reply: reply message frame(lower 32bit addr)
5980 * Context: interrupt.
5981 *
5982 * This function merely adds a new work task into ioc->firmware_event_thread.
5983 * The tasks are worked from _firmware_event_work in user context.
5984 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305985 * Return 1 meaning mf should be freed from _base_interrupt
5986 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06005987 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305988u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305989mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
5990 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06005991{
5992 struct fw_event_work *fw_event;
5993 Mpi2EventNotificationReply_t *mpi_reply;
Eric Moore635374e2009-03-09 01:21:12 -06005994 u16 event;
Kashyap, Desaie94f6742010-03-17 16:24:52 +05305995 u16 sz;
Eric Moore635374e2009-03-09 01:21:12 -06005996
5997 /* events turned off due to host reset or driver unloading */
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05305998 if (ioc->remove_host)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05305999 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006000
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306001 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Eric Moore635374e2009-03-09 01:21:12 -06006002 event = le16_to_cpu(mpi_reply->Event);
6003
6004 switch (event) {
6005 /* handle these */
6006 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
6007 {
6008 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
6009 (Mpi2EventDataSasBroadcastPrimitive_t *)
6010 mpi_reply->EventData;
6011
6012 if (baen_data->Primitive !=
6013 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
6014 ioc->broadcast_aen_busy)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306015 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006016 ioc->broadcast_aen_busy = 1;
6017 break;
6018 }
6019
6020 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
6021 _scsih_check_topo_delete_events(ioc,
6022 (Mpi2EventDataSasTopologyChangeList_t *)
6023 mpi_reply->EventData);
6024 break;
6025
6026 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
6027 case MPI2_EVENT_IR_OPERATION_STATUS:
6028 case MPI2_EVENT_SAS_DISCOVERY:
6029 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
6030 case MPI2_EVENT_IR_VOLUME:
6031 case MPI2_EVENT_IR_PHYSICAL_DISK:
6032 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
6033 case MPI2_EVENT_TASK_SET_FULL:
6034 break;
6035
6036 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306037 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006038 }
6039
6040 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
6041 if (!fw_event) {
6042 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6043 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306044 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006045 }
Kashyap, Desaie94f6742010-03-17 16:24:52 +05306046 sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
6047 fw_event->event_data = kzalloc(sz, GFP_ATOMIC);
Eric Moore635374e2009-03-09 01:21:12 -06006048 if (!fw_event->event_data) {
6049 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6050 ioc->name, __FILE__, __LINE__, __func__);
6051 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306052 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006053 }
6054
6055 memcpy(fw_event->event_data, mpi_reply->EventData,
Kashyap, Desaie94f6742010-03-17 16:24:52 +05306056 sz);
Eric Moore635374e2009-03-09 01:21:12 -06006057 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306058 fw_event->VF_ID = mpi_reply->VF_ID;
6059 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06006060 fw_event->event = event;
6061 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306062 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06006063}
6064
6065/* shost template */
6066static struct scsi_host_template scsih_driver_template = {
6067 .module = THIS_MODULE,
6068 .name = "Fusion MPT SAS Host",
6069 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06006070 .queuecommand = _scsih_qcmd,
6071 .target_alloc = _scsih_target_alloc,
6072 .slave_alloc = _scsih_slave_alloc,
6073 .slave_configure = _scsih_slave_configure,
6074 .target_destroy = _scsih_target_destroy,
6075 .slave_destroy = _scsih_slave_destroy,
6076 .change_queue_depth = _scsih_change_queue_depth,
6077 .change_queue_type = _scsih_change_queue_type,
6078 .eh_abort_handler = _scsih_abort,
6079 .eh_device_reset_handler = _scsih_dev_reset,
6080 .eh_target_reset_handler = _scsih_target_reset,
6081 .eh_host_reset_handler = _scsih_host_reset,
6082 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06006083 .can_queue = 1,
6084 .this_id = -1,
6085 .sg_tablesize = MPT2SAS_SG_DEPTH,
6086 .max_sectors = 8192,
6087 .cmd_per_lun = 7,
6088 .use_clustering = ENABLE_CLUSTERING,
6089 .shost_attrs = mpt2sas_host_attrs,
6090 .sdev_attrs = mpt2sas_dev_attrs,
6091};
6092
6093/**
6094 * _scsih_expander_node_remove - removing expander device from list.
6095 * @ioc: per adapter object
6096 * @sas_expander: the sas_device object
6097 * Context: Calling function should acquire ioc->sas_node_lock.
6098 *
6099 * Removing object and freeing associated memory from the
6100 * ioc->sas_expander_list.
6101 *
6102 * Return nothing.
6103 */
6104static void
6105_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
6106 struct _sas_node *sas_expander)
6107{
6108 struct _sas_port *mpt2sas_port;
6109 struct _sas_device *sas_device;
6110 struct _sas_node *expander_sibling;
6111 unsigned long flags;
6112
6113 if (!sas_expander)
6114 return;
6115
6116 /* remove sibling ports attached to this expander */
6117 retry_device_search:
6118 list_for_each_entry(mpt2sas_port,
6119 &sas_expander->sas_port_list, port_list) {
6120 if (mpt2sas_port->remote_identify.device_type ==
6121 SAS_END_DEVICE) {
6122 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6123 sas_device =
6124 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
6125 mpt2sas_port->remote_identify.sas_address);
6126 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6127 if (!sas_device)
6128 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306129 _scsih_remove_device(ioc, sas_device);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05306130 if (ioc->shost_recovery)
6131 return;
Eric Moore635374e2009-03-09 01:21:12 -06006132 goto retry_device_search;
6133 }
6134 }
6135
6136 retry_expander_search:
6137 list_for_each_entry(mpt2sas_port,
6138 &sas_expander->sas_port_list, port_list) {
6139
6140 if (mpt2sas_port->remote_identify.device_type ==
6141 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
6142 mpt2sas_port->remote_identify.device_type ==
6143 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
6144
6145 spin_lock_irqsave(&ioc->sas_node_lock, flags);
6146 expander_sibling =
6147 mpt2sas_scsih_expander_find_by_sas_address(
6148 ioc, mpt2sas_port->remote_identify.sas_address);
6149 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
6150 if (!expander_sibling)
6151 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306152 _scsih_expander_remove(ioc,
6153 expander_sibling->sas_address);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05306154 if (ioc->shost_recovery)
6155 return;
Eric Moore635374e2009-03-09 01:21:12 -06006156 goto retry_expander_search;
6157 }
6158 }
6159
6160 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306161 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006162
6163 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
6164 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
6165 sas_expander->handle, (unsigned long long)
6166 sas_expander->sas_address);
6167
6168 list_del(&sas_expander->list);
6169 kfree(sas_expander->phy);
6170 kfree(sas_expander);
6171}
6172
6173/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05306174 * _scsih_ir_shutdown - IR shutdown notification
6175 * @ioc: per adapter object
6176 *
6177 * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
6178 * the host system is shutting down.
6179 *
6180 * Return nothing.
6181 */
6182static void
6183_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
6184{
6185 Mpi2RaidActionRequest_t *mpi_request;
6186 Mpi2RaidActionReply_t *mpi_reply;
6187 u16 smid;
6188
6189 /* is IR firmware build loaded ? */
6190 if (!ioc->ir_firmware)
6191 return;
6192
6193 /* are there any volumes ? */
6194 if (list_empty(&ioc->raid_device_list))
6195 return;
6196
6197 mutex_lock(&ioc->scsih_cmds.mutex);
6198
6199 if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
6200 printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
6201 ioc->name, __func__);
6202 goto out;
6203 }
6204 ioc->scsih_cmds.status = MPT2_CMD_PENDING;
6205
6206 smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
6207 if (!smid) {
6208 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
6209 ioc->name, __func__);
6210 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
6211 goto out;
6212 }
6213
6214 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
6215 ioc->scsih_cmds.smid = smid;
6216 memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
6217
6218 mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
6219 mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
6220
6221 printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
6222 init_completion(&ioc->scsih_cmds.done);
6223 mpt2sas_base_put_smid_default(ioc, smid);
6224 wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
6225
6226 if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
6227 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
6228 ioc->name, __func__);
6229 goto out;
6230 }
6231
6232 if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
6233 mpi_reply = ioc->scsih_cmds.reply;
6234
6235 printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
6236 "ioc_status(0x%04x), loginfo(0x%08x)\n",
6237 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
6238 le32_to_cpu(mpi_reply->IOCLogInfo));
6239 }
6240
6241 out:
6242 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
6243 mutex_unlock(&ioc->scsih_cmds.mutex);
6244}
6245
6246/**
6247 * _scsih_shutdown - routine call during system shutdown
6248 * @pdev: PCI device struct
6249 *
6250 * Return nothing.
6251 */
6252static void
6253_scsih_shutdown(struct pci_dev *pdev)
6254{
6255 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6256 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306257 struct workqueue_struct *wq;
6258 unsigned long flags;
6259
6260 ioc->remove_host = 1;
6261 _scsih_fw_event_cleanup_queue(ioc);
6262
6263 spin_lock_irqsave(&ioc->fw_event_lock, flags);
6264 wq = ioc->firmware_event_thread;
6265 ioc->firmware_event_thread = NULL;
6266 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
6267 if (wq)
6268 destroy_workqueue(wq);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306269
6270 _scsih_ir_shutdown(ioc);
6271 mpt2sas_base_detach(ioc);
6272}
6273
6274/**
Eric Moored5d135b2009-05-18 13:02:08 -06006275 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06006276 * @pdev: PCI device struct
6277 *
Kashyap, Desai744090d2009-10-05 15:56:56 +05306278 * Routine called when unloading the driver.
Eric Moore635374e2009-03-09 01:21:12 -06006279 * Return nothing.
6280 */
6281static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06006282_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006283{
6284 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6285 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6286 struct _sas_port *mpt2sas_port;
6287 struct _sas_device *sas_device;
6288 struct _sas_node *expander_sibling;
Kashyap, Desaid7384b22009-12-16 18:50:06 +05306289 struct _raid_device *raid_device, *next;
6290 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06006291 struct workqueue_struct *wq;
6292 unsigned long flags;
6293
6294 ioc->remove_host = 1;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306295 _scsih_fw_event_cleanup_queue(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006296
6297 spin_lock_irqsave(&ioc->fw_event_lock, flags);
6298 wq = ioc->firmware_event_thread;
6299 ioc->firmware_event_thread = NULL;
6300 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
6301 if (wq)
6302 destroy_workqueue(wq);
6303
Kashyap, Desaid7384b22009-12-16 18:50:06 +05306304 /* release all the volumes */
6305 list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
6306 list) {
6307 if (raid_device->starget) {
6308 sas_target_priv_data =
6309 raid_device->starget->hostdata;
6310 sas_target_priv_data->deleted = 1;
6311 scsi_remove_target(&raid_device->starget->dev);
6312 }
6313 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
6314 "(0x%016llx)\n", ioc->name, raid_device->handle,
6315 (unsigned long long) raid_device->wwid);
6316 _scsih_raid_device_remove(ioc, raid_device);
6317 }
6318
Eric Moore635374e2009-03-09 01:21:12 -06006319 /* free ports attached to the sas_host */
6320 retry_again:
6321 list_for_each_entry(mpt2sas_port,
6322 &ioc->sas_hba.sas_port_list, port_list) {
6323 if (mpt2sas_port->remote_identify.device_type ==
6324 SAS_END_DEVICE) {
6325 sas_device =
6326 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
6327 mpt2sas_port->remote_identify.sas_address);
6328 if (sas_device) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306329 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06006330 goto retry_again;
6331 }
6332 } else {
6333 expander_sibling =
6334 mpt2sas_scsih_expander_find_by_sas_address(ioc,
6335 mpt2sas_port->remote_identify.sas_address);
6336 if (expander_sibling) {
6337 _scsih_expander_remove(ioc,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306338 expander_sibling->sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06006339 goto retry_again;
6340 }
6341 }
6342 }
6343
6344 /* free phys attached to the sas_host */
6345 if (ioc->sas_hba.num_phys) {
6346 kfree(ioc->sas_hba.phy);
6347 ioc->sas_hba.phy = NULL;
6348 ioc->sas_hba.num_phys = 0;
6349 }
6350
6351 sas_remove_host(shost);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306352 _scsih_shutdown(pdev);
Eric Moore635374e2009-03-09 01:21:12 -06006353 list_del(&ioc->list);
6354 scsi_remove_host(shost);
6355 scsi_host_put(shost);
6356}
6357
6358/**
6359 * _scsih_probe_boot_devices - reports 1st device
6360 * @ioc: per adapter object
6361 *
6362 * If specified in bios page 2, this routine reports the 1st
6363 * device scsi-ml or sas transport for persistent boot device
6364 * purposes. Please refer to function _scsih_determine_boot_device()
6365 */
6366static void
6367_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
6368{
6369 u8 is_raid;
6370 void *device;
6371 struct _sas_device *sas_device;
6372 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306373 u16 handle;
6374 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06006375 u64 sas_address;
6376 unsigned long flags;
6377 int rc;
6378
6379 device = NULL;
6380 if (ioc->req_boot_device.device) {
6381 device = ioc->req_boot_device.device;
6382 is_raid = ioc->req_boot_device.is_raid;
6383 } else if (ioc->req_alt_boot_device.device) {
6384 device = ioc->req_alt_boot_device.device;
6385 is_raid = ioc->req_alt_boot_device.is_raid;
6386 } else if (ioc->current_boot_device.device) {
6387 device = ioc->current_boot_device.device;
6388 is_raid = ioc->current_boot_device.is_raid;
6389 }
6390
6391 if (!device)
6392 return;
6393
6394 if (is_raid) {
6395 raid_device = device;
6396 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6397 raid_device->id, 0);
6398 if (rc)
6399 _scsih_raid_device_remove(ioc, raid_device);
6400 } else {
6401 sas_device = device;
6402 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306403 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06006404 sas_address = sas_device->sas_address;
6405 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6406 list_move_tail(&sas_device->list, &ioc->sas_device_list);
6407 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6408 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306409 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06006410 _scsih_sas_device_remove(ioc, sas_device);
6411 } else if (!sas_device->starget) {
6412 mpt2sas_transport_port_remove(ioc, sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306413 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006414 _scsih_sas_device_remove(ioc, sas_device);
6415 }
6416 }
6417}
6418
6419/**
6420 * _scsih_probe_raid - reporting raid volumes to scsi-ml
6421 * @ioc: per adapter object
6422 *
6423 * Called during initial loading of the driver.
6424 */
6425static void
6426_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
6427{
6428 struct _raid_device *raid_device, *raid_next;
6429 int rc;
6430
6431 list_for_each_entry_safe(raid_device, raid_next,
6432 &ioc->raid_device_list, list) {
6433 if (raid_device->starget)
6434 continue;
6435 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6436 raid_device->id, 0);
6437 if (rc)
6438 _scsih_raid_device_remove(ioc, raid_device);
6439 }
6440}
6441
6442/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306443 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06006444 * @ioc: per adapter object
6445 *
6446 * Called during initial loading of the driver.
6447 */
6448static void
6449_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
6450{
6451 struct _sas_device *sas_device, *next;
6452 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06006453
6454 /* SAS Device List */
6455 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
6456 list) {
6457 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6458 list_move_tail(&sas_device->list, &ioc->sas_device_list);
6459 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6460
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306461 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
6462 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06006463 _scsih_sas_device_remove(ioc, sas_device);
6464 } else if (!sas_device->starget) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306465 mpt2sas_transport_port_remove(ioc,
6466 sas_device->sas_address,
6467 sas_device->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06006468 _scsih_sas_device_remove(ioc, sas_device);
6469 }
6470 }
6471}
6472
6473/**
6474 * _scsih_probe_devices - probing for devices
6475 * @ioc: per adapter object
6476 *
6477 * Called during initial loading of the driver.
6478 */
6479static void
6480_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
6481{
6482 u16 volume_mapping_flags =
6483 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
6484 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
6485
6486 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
6487 return; /* return when IOC doesn't support initiator mode */
6488
6489 _scsih_probe_boot_devices(ioc);
6490
6491 if (ioc->ir_firmware) {
6492 if ((volume_mapping_flags &
6493 MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) {
6494 _scsih_probe_sas(ioc);
6495 _scsih_probe_raid(ioc);
6496 } else {
6497 _scsih_probe_raid(ioc);
6498 _scsih_probe_sas(ioc);
6499 }
6500 } else
6501 _scsih_probe_sas(ioc);
6502}
6503
6504/**
Eric Moored5d135b2009-05-18 13:02:08 -06006505 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06006506 * @pdev: PCI device struct
6507 * @id: pci device id
6508 *
6509 * Returns 0 success, anything else error.
6510 */
6511static int
Eric Moored5d135b2009-05-18 13:02:08 -06006512_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06006513{
6514 struct MPT2SAS_ADAPTER *ioc;
6515 struct Scsi_Host *shost;
6516
6517 shost = scsi_host_alloc(&scsih_driver_template,
6518 sizeof(struct MPT2SAS_ADAPTER));
6519 if (!shost)
6520 return -ENODEV;
6521
6522 /* init local params */
6523 ioc = shost_priv(shost);
6524 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
6525 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06006526 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06006527 ioc->shost = shost;
6528 ioc->id = mpt_ids++;
6529 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
6530 ioc->pdev = pdev;
6531 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
6532 ioc->tm_cb_idx = tm_cb_idx;
6533 ioc->ctl_cb_idx = ctl_cb_idx;
6534 ioc->base_cb_idx = base_cb_idx;
6535 ioc->transport_cb_idx = transport_cb_idx;
Kashyap, Desai744090d2009-10-05 15:56:56 +05306536 ioc->scsih_cb_idx = scsih_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006537 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306538 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
6539 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06006540 ioc->logging_level = logging_level;
6541 /* misc semaphores and spin locks */
6542 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
6543 spin_lock_init(&ioc->scsi_lookup_lock);
6544 spin_lock_init(&ioc->sas_device_lock);
6545 spin_lock_init(&ioc->sas_node_lock);
6546 spin_lock_init(&ioc->fw_event_lock);
6547 spin_lock_init(&ioc->raid_device_lock);
6548
6549 INIT_LIST_HEAD(&ioc->sas_device_list);
6550 INIT_LIST_HEAD(&ioc->sas_device_init_list);
6551 INIT_LIST_HEAD(&ioc->sas_expander_list);
6552 INIT_LIST_HEAD(&ioc->fw_event_list);
6553 INIT_LIST_HEAD(&ioc->raid_device_list);
6554 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306555 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Eric Moore635374e2009-03-09 01:21:12 -06006556
6557 /* init shost parameters */
6558 shost->max_cmd_len = 16;
6559 shost->max_lun = max_lun;
6560 shost->transportt = mpt2sas_transport_template;
6561 shost->unique_id = ioc->id;
6562
6563 if ((scsi_add_host(shost, &pdev->dev))) {
6564 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6565 ioc->name, __FILE__, __LINE__, __func__);
6566 list_del(&ioc->list);
6567 goto out_add_shost_fail;
6568 }
6569
Eric Moore3c621b32009-05-18 12:59:41 -06006570 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
6571 | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306572 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06006573
Eric Moore635374e2009-03-09 01:21:12 -06006574 /* event thread */
6575 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
6576 "fw_event%d", ioc->id);
6577 ioc->firmware_event_thread = create_singlethread_workqueue(
6578 ioc->firmware_event_name);
6579 if (!ioc->firmware_event_thread) {
6580 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6581 ioc->name, __FILE__, __LINE__, __func__);
6582 goto out_thread_fail;
6583 }
6584
6585 ioc->wait_for_port_enable_to_complete = 1;
6586 if ((mpt2sas_base_attach(ioc))) {
6587 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6588 ioc->name, __FILE__, __LINE__, __func__);
6589 goto out_attach_fail;
6590 }
6591
6592 ioc->wait_for_port_enable_to_complete = 0;
6593 _scsih_probe_devices(ioc);
6594 return 0;
6595
6596 out_attach_fail:
6597 destroy_workqueue(ioc->firmware_event_thread);
6598 out_thread_fail:
6599 list_del(&ioc->list);
6600 scsi_remove_host(shost);
6601 out_add_shost_fail:
6602 return -ENODEV;
6603}
6604
6605#ifdef CONFIG_PM
6606/**
Eric Moored5d135b2009-05-18 13:02:08 -06006607 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006608 * @pdev: PCI device struct
6609 * @state: PM state change to (usually PCI_D3)
6610 *
6611 * Returns 0 success, anything else error.
6612 */
6613static int
Eric Moored5d135b2009-05-18 13:02:08 -06006614_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06006615{
6616 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6617 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6618 u32 device_state;
6619
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306620 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006621 flush_scheduled_work();
6622 scsi_block_requests(shost);
6623 device_state = pci_choose_state(pdev, state);
6624 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
6625 "operating state [D%d]\n", ioc->name, pdev,
6626 pci_name(pdev), device_state);
6627
6628 mpt2sas_base_free_resources(ioc);
6629 pci_save_state(pdev);
6630 pci_disable_device(pdev);
6631 pci_set_power_state(pdev, device_state);
6632 return 0;
6633}
6634
6635/**
Eric Moored5d135b2009-05-18 13:02:08 -06006636 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06006637 * @pdev: PCI device struct
6638 *
6639 * Returns 0 success, anything else error.
6640 */
6641static int
Eric Moored5d135b2009-05-18 13:02:08 -06006642_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06006643{
6644 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6645 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6646 u32 device_state = pdev->current_state;
6647 int r;
6648
6649 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
6650 "operating state [D%d]\n", ioc->name, pdev,
6651 pci_name(pdev), device_state);
6652
6653 pci_set_power_state(pdev, PCI_D0);
6654 pci_enable_wake(pdev, PCI_D0, 0);
6655 pci_restore_state(pdev);
6656 ioc->pdev = pdev;
6657 r = mpt2sas_base_map_resources(ioc);
6658 if (r)
6659 return r;
6660
6661 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
6662 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05306663 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06006664 return 0;
6665}
6666#endif /* CONFIG_PM */
6667
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05306668/**
6669 * _scsih_pci_error_detected - Called when a PCI error is detected.
6670 * @pdev: PCI device struct
6671 * @state: PCI channel state
6672 *
6673 * Description: Called when a PCI error is detected.
6674 *
6675 * Return value:
6676 * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
6677 */
6678static pci_ers_result_t
6679_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
6680{
6681 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6682 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6683
6684 printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n",
6685 ioc->name, state);
6686
6687 switch (state) {
6688 case pci_channel_io_normal:
6689 return PCI_ERS_RESULT_CAN_RECOVER;
6690 case pci_channel_io_frozen:
6691 scsi_block_requests(ioc->shost);
6692 mpt2sas_base_stop_watchdog(ioc);
6693 mpt2sas_base_free_resources(ioc);
6694 return PCI_ERS_RESULT_NEED_RESET;
6695 case pci_channel_io_perm_failure:
6696 _scsih_remove(pdev);
6697 return PCI_ERS_RESULT_DISCONNECT;
6698 }
6699 return PCI_ERS_RESULT_NEED_RESET;
6700}
6701
6702/**
6703 * _scsih_pci_slot_reset - Called when PCI slot has been reset.
6704 * @pdev: PCI device struct
6705 *
6706 * Description: This routine is called by the pci error recovery
6707 * code after the PCI slot has been reset, just before we
6708 * should resume normal operations.
6709 */
6710static pci_ers_result_t
6711_scsih_pci_slot_reset(struct pci_dev *pdev)
6712{
6713 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6714 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6715 int rc;
6716
6717 printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
6718 ioc->name);
6719
6720 ioc->pdev = pdev;
6721 rc = mpt2sas_base_map_resources(ioc);
6722 if (rc)
6723 return PCI_ERS_RESULT_DISCONNECT;
6724
6725
6726 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
6727 FORCE_BIG_HAMMER);
6728
6729 printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name,
6730 (rc == 0) ? "success" : "failed");
6731
6732 if (!rc)
6733 return PCI_ERS_RESULT_RECOVERED;
6734 else
6735 return PCI_ERS_RESULT_DISCONNECT;
6736}
6737
6738/**
6739 * _scsih_pci_resume() - resume normal ops after PCI reset
6740 * @pdev: pointer to PCI device
6741 *
6742 * Called when the error recovery driver tells us that its
6743 * OK to resume normal operation. Use completion to allow
6744 * halted scsi ops to resume.
6745 */
6746static void
6747_scsih_pci_resume(struct pci_dev *pdev)
6748{
6749 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6750 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6751
6752 printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name);
6753
6754 pci_cleanup_aer_uncorrect_error_status(pdev);
6755 mpt2sas_base_start_watchdog(ioc);
6756 scsi_unblock_requests(ioc->shost);
6757}
6758
6759/**
6760 * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
6761 * @pdev: pointer to PCI device
6762 */
6763static pci_ers_result_t
6764_scsih_pci_mmio_enabled(struct pci_dev *pdev)
6765{
6766 struct Scsi_Host *shost = pci_get_drvdata(pdev);
6767 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
6768
6769 printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n",
6770 ioc->name);
6771
6772 /* TODO - dump whatever for debugging purposes */
6773
6774 /* Request a slot reset. */
6775 return PCI_ERS_RESULT_NEED_RESET;
6776}
6777
6778static struct pci_error_handlers _scsih_err_handler = {
6779 .error_detected = _scsih_pci_error_detected,
6780 .mmio_enabled = _scsih_pci_mmio_enabled,
6781 .slot_reset = _scsih_pci_slot_reset,
6782 .resume = _scsih_pci_resume,
6783};
Eric Moore635374e2009-03-09 01:21:12 -06006784
6785static struct pci_driver scsih_driver = {
6786 .name = MPT2SAS_DRIVER_NAME,
6787 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06006788 .probe = _scsih_probe,
6789 .remove = __devexit_p(_scsih_remove),
Kashyap, Desai744090d2009-10-05 15:56:56 +05306790 .shutdown = _scsih_shutdown,
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05306791 .err_handler = &_scsih_err_handler,
Eric Moore635374e2009-03-09 01:21:12 -06006792#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06006793 .suspend = _scsih_suspend,
6794 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06006795#endif
6796};
6797
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306798/* raid transport support */
6799static struct raid_function_template mpt2sas_raid_functions = {
6800 .cookie = &scsih_driver_template,
6801 .is_raid = _scsih_is_raid,
6802 .get_resync = _scsih_get_resync,
6803 .get_state = _scsih_get_state,
6804};
Eric Moore635374e2009-03-09 01:21:12 -06006805
6806/**
Eric Moored5d135b2009-05-18 13:02:08 -06006807 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06006808 *
6809 * Returns 0 success, anything else error.
6810 */
6811static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06006812_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06006813{
6814 int error;
6815
6816 mpt_ids = 0;
6817 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
6818 MPT2SAS_DRIVER_VERSION);
6819
6820 mpt2sas_transport_template =
6821 sas_attach_transport(&mpt2sas_transport_functions);
6822 if (!mpt2sas_transport_template)
6823 return -ENODEV;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306824 /* raid transport support */
6825 mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
6826 if (!mpt2sas_raid_template) {
6827 sas_release_transport(mpt2sas_transport_template);
6828 return -ENODEV;
6829 }
Eric Moore635374e2009-03-09 01:21:12 -06006830
6831 mpt2sas_base_initialize_callback_handler();
6832
6833 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06006834 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06006835
6836 /* task managment callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06006837 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06006838
6839 /* base internal commands callback handler */
6840 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
6841
6842 /* transport internal commands callback handler */
6843 transport_cb_idx = mpt2sas_base_register_callback_handler(
6844 mpt2sas_transport_done);
6845
Kashyap, Desai744090d2009-10-05 15:56:56 +05306846 /* scsih internal commands callback handler */
6847 scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
6848
Eric Moore635374e2009-03-09 01:21:12 -06006849 /* configuration page API internal commands callback handler */
6850 config_cb_idx = mpt2sas_base_register_callback_handler(
6851 mpt2sas_config_done);
6852
6853 /* ctl module callback handler */
6854 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
6855
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306856 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
6857 _scsih_tm_tr_complete);
6858 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
6859 _scsih_sas_control_complete);
6860
Eric Moore635374e2009-03-09 01:21:12 -06006861 mpt2sas_ctl_init();
6862
6863 error = pci_register_driver(&scsih_driver);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306864 if (error) {
6865 /* raid transport support */
6866 raid_class_release(mpt2sas_raid_template);
Eric Moore635374e2009-03-09 01:21:12 -06006867 sas_release_transport(mpt2sas_transport_template);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306868 }
Eric Moore635374e2009-03-09 01:21:12 -06006869
6870 return error;
6871}
6872
6873/**
Eric Moored5d135b2009-05-18 13:02:08 -06006874 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06006875 *
6876 * Returns 0 success, anything else error.
6877 */
6878static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06006879_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06006880{
6881 printk(KERN_INFO "mpt2sas version %s unloading\n",
6882 MPT2SAS_DRIVER_VERSION);
6883
6884 pci_unregister_driver(&scsih_driver);
6885
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306886 mpt2sas_ctl_exit();
6887
Eric Moore635374e2009-03-09 01:21:12 -06006888 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
6889 mpt2sas_base_release_callback_handler(tm_cb_idx);
6890 mpt2sas_base_release_callback_handler(base_cb_idx);
6891 mpt2sas_base_release_callback_handler(transport_cb_idx);
Kashyap, Desai744090d2009-10-05 15:56:56 +05306892 mpt2sas_base_release_callback_handler(scsih_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06006893 mpt2sas_base_release_callback_handler(config_cb_idx);
6894 mpt2sas_base_release_callback_handler(ctl_cb_idx);
6895
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306896 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
6897 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
6898
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306899 /* raid transport support */
6900 raid_class_release(mpt2sas_raid_template);
6901 sas_release_transport(mpt2sas_transport_template);
6902
Eric Moore635374e2009-03-09 01:21:12 -06006903}
6904
Eric Moored5d135b2009-05-18 13:02:08 -06006905module_init(_scsih_init);
6906module_exit(_scsih_exit);