blob: 9de474051507b1f68519a47f52ce573cc6cba084 [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
Eric Moore635374e2009-03-09 01:21:12 -060044#include <linux/module.h>
45#include <linux/kernel.h>
46#include <linux/init.h>
47#include <linux/errno.h>
48#include <linux/blkdev.h>
49#include <linux/sched.h>
50#include <linux/workqueue.h>
51#include <linux/delay.h>
52#include <linux/pci.h>
53#include <linux/interrupt.h>
Kashyap, Desaief7c80c2010-04-05 14:20:07 +053054#include <linux/aer.h>
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +053055#include <linux/raid_class.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090056#include <linux/slab.h>
Eric Moore635374e2009-03-09 01:21:12 -060057
58#include "mpt2sas_base.h"
59
60MODULE_AUTHOR(MPT2SAS_AUTHOR);
61MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
62MODULE_LICENSE("GPL");
63MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
64
65#define RAID_CHANNEL 1
66
67/* forward proto's */
68static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
69 struct _sas_node *sas_expander);
70static void _firmware_event_work(struct work_struct *work);
71
Kashyap, Desaif3eedd62010-06-17 13:46:13 +053072static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid);
73
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +053074static void _scsih_scan_start(struct Scsi_Host *shost);
75static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time);
76
Eric Moore635374e2009-03-09 01:21:12 -060077/* global parameters */
Eric Mooreba33fad2009-03-15 21:37:18 -060078LIST_HEAD(mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -060079
80/* local parameters */
Eric Moore635374e2009-03-09 01:21:12 -060081static u8 scsi_io_cb_idx = -1;
82static u8 tm_cb_idx = -1;
83static u8 ctl_cb_idx = -1;
84static u8 base_cb_idx = -1;
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +053085static u8 port_enable_cb_idx = -1;
Eric Moore635374e2009-03-09 01:21:12 -060086static u8 transport_cb_idx = -1;
Kashyap, Desai744090d2009-10-05 15:56:56 +053087static u8 scsih_cb_idx = -1;
Eric Moore635374e2009-03-09 01:21:12 -060088static u8 config_cb_idx = -1;
89static int mpt_ids;
90
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053091static u8 tm_tr_cb_idx = -1 ;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +053092static u8 tm_tr_volume_cb_idx = -1 ;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +053093static u8 tm_sas_control_cb_idx = -1;
94
Eric Moore635374e2009-03-09 01:21:12 -060095/* command line options */
Eric Mooreba33fad2009-03-15 21:37:18 -060096static u32 logging_level;
Eric Moore635374e2009-03-09 01:21:12 -060097MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
98 "(default=0)");
99
Kashyap, Desaia3e1e552011-06-14 10:56:12 +0530100static ushort max_sectors = 0xFFFF;
101module_param(max_sectors, ushort, 0);
nagalakshmi.nandigama@lsi.com9ac49d32011-12-01 07:52:08 +0530102MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767");
Kashyap, Desaia3e1e552011-06-14 10:56:12 +0530103
Eric Moore635374e2009-03-09 01:21:12 -0600104/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
105#define MPT2SAS_MAX_LUN (16895)
106static int max_lun = MPT2SAS_MAX_LUN;
107module_param(max_lun, int, 0);
108MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
109
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +0530110/* diag_buffer_enable is bitwise
111 * bit 0 set = TRACE
112 * bit 1 set = SNAPSHOT
113 * bit 2 set = EXTENDED
114 *
115 * Either bit can be set, or both
116 */
117static int diag_buffer_enable = -1;
118module_param(diag_buffer_enable, int, 0);
119MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers "
120 "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)");
121
Eric Moore635374e2009-03-09 01:21:12 -0600122/**
123 * struct sense_info - common structure for obtaining sense keys
124 * @skey: sense key
125 * @asc: additional sense code
126 * @ascq: additional sense code qualifier
127 */
128struct sense_info {
129 u8 skey;
130 u8 asc;
131 u8 ascq;
132};
133
134
Kashyap, Desai3ace8e02011-05-04 16:35:58 +0530135#define MPT2SAS_TURN_ON_FAULT_LED (0xFFFC)
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +0530136#define MPT2SAS_PORT_ENABLE_COMPLETE (0xFFFD)
137#define MPT2SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF)
Eric Moore635374e2009-03-09 01:21:12 -0600138/**
139 * struct fw_event_work - firmware event struct
140 * @list: link list framework
141 * @work: work object (ioc->fault_reset_work_q)
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530142 * @cancel_pending_work: flag set during reset handling
Eric Moore635374e2009-03-09 01:21:12 -0600143 * @ioc: per adapter object
Kashyap, Desai3ace8e02011-05-04 16:35:58 +0530144 * @device_handle: device handle
Eric Moore635374e2009-03-09 01:21:12 -0600145 * @VF_ID: virtual function id
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530146 * @VP_ID: virtual port id
Eric Moore635374e2009-03-09 01:21:12 -0600147 * @ignore: flag meaning this event has been marked to ignore
148 * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
149 * @event_data: reply event data payload follows
150 *
151 * This object stored on ioc->fw_event_list.
152 */
153struct fw_event_work {
154 struct list_head list;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +0530155 u8 cancel_pending_work;
156 struct delayed_work delayed_work;
Eric Moore635374e2009-03-09 01:21:12 -0600157 struct MPT2SAS_ADAPTER *ioc;
Kashyap, Desai3ace8e02011-05-04 16:35:58 +0530158 u16 device_handle;
Eric Moore635374e2009-03-09 01:21:12 -0600159 u8 VF_ID;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530160 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600161 u8 ignore;
162 u16 event;
163 void *event_data;
164};
165
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +0530166/* raid transport support */
167static struct raid_template *mpt2sas_raid_template;
168
Eric Moore635374e2009-03-09 01:21:12 -0600169/**
170 * struct _scsi_io_transfer - scsi io transfer
171 * @handle: sas device handle (assigned by firmware)
172 * @is_raid: flag set for hidden raid components
173 * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
174 * @data_length: data transfer length
175 * @data_dma: dma pointer to data
176 * @sense: sense data
177 * @lun: lun number
178 * @cdb_length: cdb length
179 * @cdb: cdb contents
Eric Moore635374e2009-03-09 01:21:12 -0600180 * @timeout: timeout for this command
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530181 * @VF_ID: virtual function id
182 * @VP_ID: virtual port id
183 * @valid_reply: flag set for reply message
Eric Moore635374e2009-03-09 01:21:12 -0600184 * @sense_length: sense length
185 * @ioc_status: ioc status
186 * @scsi_state: scsi state
187 * @scsi_status: scsi staus
188 * @log_info: log information
189 * @transfer_length: data length transfer when there is a reply message
190 *
191 * Used for sending internal scsi commands to devices within this module.
192 * Refer to _scsi_send_scsi_io().
193 */
194struct _scsi_io_transfer {
195 u16 handle;
196 u8 is_raid;
197 enum dma_data_direction dir;
198 u32 data_length;
199 dma_addr_t data_dma;
200 u8 sense[SCSI_SENSE_BUFFERSIZE];
201 u32 lun;
202 u8 cdb_length;
203 u8 cdb[32];
204 u8 timeout;
Kashyap, Desai7b936b02009-09-25 11:44:41 +0530205 u8 VF_ID;
206 u8 VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -0600207 u8 valid_reply;
208 /* the following bits are only valid when 'valid_reply = 1' */
209 u32 sense_length;
210 u16 ioc_status;
211 u8 scsi_state;
212 u8 scsi_status;
213 u32 log_info;
214 u32 transfer_length;
215};
216
217/*
218 * The pci device ids are defined in mpi/mpi2_cnfg.h.
219 */
220static struct pci_device_id scsih_pci_table[] = {
221 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
222 PCI_ANY_ID, PCI_ANY_ID },
223 /* Falcon ~ 2008*/
224 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
225 PCI_ANY_ID, PCI_ANY_ID },
226 /* Liberator ~ 2108 */
227 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
228 PCI_ANY_ID, PCI_ANY_ID },
229 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
230 PCI_ANY_ID, PCI_ANY_ID },
231 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
232 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530233 /* Meteor ~ 2116 */
Eric Moore635374e2009-03-09 01:21:12 -0600234 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
235 PCI_ANY_ID, PCI_ANY_ID },
236 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
237 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desaidb271362009-09-23 17:24:27 +0530238 /* Thunderbolt ~ 2208 */
239 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
240 PCI_ANY_ID, PCI_ANY_ID },
241 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
242 PCI_ANY_ID, PCI_ANY_ID },
243 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
244 PCI_ANY_ID, PCI_ANY_ID },
245 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
246 PCI_ANY_ID, PCI_ANY_ID },
247 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
248 PCI_ANY_ID, PCI_ANY_ID },
249 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
250 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desai203d65b2010-06-17 13:37:59 +0530251 /* Mustang ~ 2308 */
252 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
Kashyap, Desaidb271362009-09-23 17:24:27 +0530253 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desai203d65b2010-06-17 13:37:59 +0530254 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
255 PCI_ANY_ID, PCI_ANY_ID },
256 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
Kashyap, Desaidb271362009-09-23 17:24:27 +0530257 PCI_ANY_ID, PCI_ANY_ID },
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +0530258 /* SSS6200 */
259 { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
260 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore635374e2009-03-09 01:21:12 -0600261 {0} /* Terminating entry */
262};
263MODULE_DEVICE_TABLE(pci, scsih_pci_table);
264
265/**
Eric Moored5d135b2009-05-18 13:02:08 -0600266 * _scsih_set_debug_level - global setting of ioc->logging_level.
Eric Moore635374e2009-03-09 01:21:12 -0600267 *
268 * Note: The logging levels are defined in mpt2sas_debug.h.
269 */
270static int
Eric Moored5d135b2009-05-18 13:02:08 -0600271_scsih_set_debug_level(const char *val, struct kernel_param *kp)
Eric Moore635374e2009-03-09 01:21:12 -0600272{
273 int ret = param_set_int(val, kp);
274 struct MPT2SAS_ADAPTER *ioc;
275
276 if (ret)
277 return ret;
278
279 printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
Eric Mooreba33fad2009-03-15 21:37:18 -0600280 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
Eric Moore635374e2009-03-09 01:21:12 -0600281 ioc->logging_level = logging_level;
282 return 0;
283}
Eric Moored5d135b2009-05-18 13:02:08 -0600284module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
Eric Moore635374e2009-03-09 01:21:12 -0600285 &logging_level, 0644);
286
287/**
288 * _scsih_srch_boot_sas_address - search based on sas_address
289 * @sas_address: sas address
290 * @boot_device: boot device object from bios page 2
291 *
292 * Returns 1 when there's a match, 0 means no match.
293 */
294static inline int
295_scsih_srch_boot_sas_address(u64 sas_address,
296 Mpi2BootDeviceSasWwid_t *boot_device)
297{
298 return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
299}
300
301/**
302 * _scsih_srch_boot_device_name - search based on device name
303 * @device_name: device name specified in INDENTIFY fram
304 * @boot_device: boot device object from bios page 2
305 *
306 * Returns 1 when there's a match, 0 means no match.
307 */
308static inline int
309_scsih_srch_boot_device_name(u64 device_name,
310 Mpi2BootDeviceDeviceName_t *boot_device)
311{
312 return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
313}
314
315/**
316 * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
317 * @enclosure_logical_id: enclosure logical id
318 * @slot_number: slot number
319 * @boot_device: boot device object from bios page 2
320 *
321 * Returns 1 when there's a match, 0 means no match.
322 */
323static inline int
324_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
325 Mpi2BootDeviceEnclosureSlot_t *boot_device)
326{
327 return (enclosure_logical_id == le64_to_cpu(boot_device->
328 EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
329 SlotNumber)) ? 1 : 0;
330}
331
332/**
333 * _scsih_is_boot_device - search for matching boot device.
334 * @sas_address: sas address
335 * @device_name: device name specified in INDENTIFY fram
336 * @enclosure_logical_id: enclosure logical id
337 * @slot_number: slot number
338 * @form: specifies boot device form
339 * @boot_device: boot device object from bios page 2
340 *
341 * Returns 1 when there's a match, 0 means no match.
342 */
343static int
344_scsih_is_boot_device(u64 sas_address, u64 device_name,
345 u64 enclosure_logical_id, u16 slot, u8 form,
346 Mpi2BiosPage2BootDevice_t *boot_device)
347{
348 int rc = 0;
349
350 switch (form) {
351 case MPI2_BIOSPAGE2_FORM_SAS_WWID:
352 if (!sas_address)
353 break;
354 rc = _scsih_srch_boot_sas_address(
355 sas_address, &boot_device->SasWwid);
356 break;
357 case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
358 if (!enclosure_logical_id)
359 break;
360 rc = _scsih_srch_boot_encl_slot(
361 enclosure_logical_id,
362 slot, &boot_device->EnclosureSlot);
363 break;
364 case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
365 if (!device_name)
366 break;
367 rc = _scsih_srch_boot_device_name(
368 device_name, &boot_device->DeviceName);
369 break;
370 case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
371 break;
372 }
373
374 return rc;
375}
376
377/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530378 * _scsih_get_sas_address - set the sas_address for given device handle
379 * @handle: device handle
380 * @sas_address: sas address
381 *
382 * Returns 0 success, non-zero when failure
383 */
384static int
385_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
386 u64 *sas_address)
387{
388 Mpi2SasDevicePage0_t sas_device_pg0;
389 Mpi2ConfigReply_t mpi_reply;
390 u32 ioc_status;
nagalakshmi.nandigama@lsi.com24f09b52011-10-19 15:36:47 +0530391 *sas_address = 0;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530392
393 if (handle <= ioc->sas_hba.num_phys) {
394 *sas_address = ioc->sas_hba.sas_address;
395 return 0;
nagalakshmi.nandigama@lsi.com24f09b52011-10-19 15:36:47 +0530396 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530397
398 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
399 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
nagalakshmi.nandigama@lsi.com24f09b52011-10-19 15:36:47 +0530400 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
401 __FILE__, __LINE__, __func__);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530402 return -ENXIO;
403 }
404
nagalakshmi.nandigama@lsi.com24f09b52011-10-19 15:36:47 +0530405 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
406 if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
407 *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
408 return 0;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530409 }
410
nagalakshmi.nandigama@lsi.com24f09b52011-10-19 15:36:47 +0530411 /* we hit this becuase the given parent handle doesn't exist */
412 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
413 return -ENXIO;
414 /* else error case */
415 printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x), "
416 "failure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
417 __FILE__, __LINE__, __func__);
418 return -EIO;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530419}
420
421/**
Eric Moore635374e2009-03-09 01:21:12 -0600422 * _scsih_determine_boot_device - determine boot device.
423 * @ioc: per adapter object
424 * @device: either sas_device or raid_device object
425 * @is_raid: [flag] 1 = raid object, 0 = sas object
426 *
427 * Determines whether this device should be first reported device to
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300428 * to scsi-ml or sas transport, this purpose is for persistent boot device.
Eric Moore635374e2009-03-09 01:21:12 -0600429 * There are primary, alternate, and current entries in bios page 2. The order
430 * priority is primary, alternate, then current. This routine saves
431 * the corresponding device object and is_raid flag in the ioc object.
432 * The saved data to be used later in _scsih_probe_boot_devices().
433 */
434static void
435_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
436 void *device, u8 is_raid)
437{
438 struct _sas_device *sas_device;
439 struct _raid_device *raid_device;
440 u64 sas_address;
441 u64 device_name;
442 u64 enclosure_logical_id;
443 u16 slot;
444
445 /* only process this function when driver loads */
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +0530446 if (!ioc->is_driver_loading)
447 return;
448
449 /* no Bios, return immediately */
450 if (!ioc->bios_pg3.BiosVersion)
Eric Moore635374e2009-03-09 01:21:12 -0600451 return;
452
453 if (!is_raid) {
454 sas_device = device;
455 sas_address = sas_device->sas_address;
456 device_name = sas_device->device_name;
457 enclosure_logical_id = sas_device->enclosure_logical_id;
458 slot = sas_device->slot;
459 } else {
460 raid_device = device;
461 sas_address = raid_device->wwid;
462 device_name = 0;
463 enclosure_logical_id = 0;
464 slot = 0;
465 }
466
467 if (!ioc->req_boot_device.device) {
468 if (_scsih_is_boot_device(sas_address, device_name,
469 enclosure_logical_id, slot,
470 (ioc->bios_pg2.ReqBootDeviceForm &
471 MPI2_BIOSPAGE2_FORM_MASK),
472 &ioc->bios_pg2.RequestedBootDevice)) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530473 dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -0600474 "%s: req_boot_device(0x%016llx)\n",
475 ioc->name, __func__,
476 (unsigned long long)sas_address));
477 ioc->req_boot_device.device = device;
478 ioc->req_boot_device.is_raid = is_raid;
479 }
480 }
481
482 if (!ioc->req_alt_boot_device.device) {
483 if (_scsih_is_boot_device(sas_address, device_name,
484 enclosure_logical_id, slot,
485 (ioc->bios_pg2.ReqAltBootDeviceForm &
486 MPI2_BIOSPAGE2_FORM_MASK),
487 &ioc->bios_pg2.RequestedAltBootDevice)) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530488 dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -0600489 "%s: req_alt_boot_device(0x%016llx)\n",
490 ioc->name, __func__,
491 (unsigned long long)sas_address));
492 ioc->req_alt_boot_device.device = device;
493 ioc->req_alt_boot_device.is_raid = is_raid;
494 }
495 }
496
497 if (!ioc->current_boot_device.device) {
498 if (_scsih_is_boot_device(sas_address, device_name,
499 enclosure_logical_id, slot,
500 (ioc->bios_pg2.CurrentBootDeviceForm &
501 MPI2_BIOSPAGE2_FORM_MASK),
502 &ioc->bios_pg2.CurrentBootDevice)) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530503 dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -0600504 "%s: current_boot_device(0x%016llx)\n",
505 ioc->name, __func__,
506 (unsigned long long)sas_address));
507 ioc->current_boot_device.device = device;
508 ioc->current_boot_device.is_raid = is_raid;
509 }
510 }
511}
512
513/**
514 * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search
515 * @ioc: per adapter object
516 * @sas_address: sas address
517 * Context: Calling function should acquire ioc->sas_device_lock
518 *
519 * This searches for sas_device based on sas_address, then return sas_device
520 * object.
521 */
522struct _sas_device *
523mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
524 u64 sas_address)
525{
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530526 struct _sas_device *sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600527
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530528 list_for_each_entry(sas_device, &ioc->sas_device_list, list)
529 if (sas_device->sas_address == sas_address)
530 return sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600531
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530532 list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
533 if (sas_device->sas_address == sas_address)
534 return sas_device;
535
536 return NULL;
Eric Moore635374e2009-03-09 01:21:12 -0600537}
538
539/**
540 * _scsih_sas_device_find_by_handle - sas device search
541 * @ioc: per adapter object
542 * @handle: sas device handle (assigned by firmware)
543 * Context: Calling function should acquire ioc->sas_device_lock
544 *
545 * This searches for sas_device based on sas_address, then return sas_device
546 * object.
547 */
548static struct _sas_device *
549_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
550{
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530551 struct _sas_device *sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600552
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530553 list_for_each_entry(sas_device, &ioc->sas_device_list, list)
554 if (sas_device->handle == handle)
555 return sas_device;
Eric Moore635374e2009-03-09 01:21:12 -0600556
Kashyap, Desaicd9843f2010-03-09 16:32:17 +0530557 list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
558 if (sas_device->handle == handle)
559 return sas_device;
560
561 return NULL;
Eric Moore635374e2009-03-09 01:21:12 -0600562}
563
564/**
565 * _scsih_sas_device_remove - remove sas_device from list.
566 * @ioc: per adapter object
567 * @sas_device: the sas_device object
568 * Context: This function will acquire ioc->sas_device_lock.
569 *
570 * Removing object and freeing associated memory from the ioc->sas_device_list.
571 */
572static void
573_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
574 struct _sas_device *sas_device)
575{
576 unsigned long flags;
577
Kashyap, Desai980ead32010-04-08 17:55:22 +0530578 if (!sas_device)
579 return;
580
Eric Moore635374e2009-03-09 01:21:12 -0600581 spin_lock_irqsave(&ioc->sas_device_lock, flags);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +0530582 list_del(&sas_device->list);
583 kfree(sas_device);
Eric Moore635374e2009-03-09 01:21:12 -0600584 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
585}
586
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +0530587
Eric Moore635374e2009-03-09 01:21:12 -0600588/**
589 * _scsih_sas_device_add - insert sas_device to the list.
590 * @ioc: per adapter object
591 * @sas_device: the sas_device object
592 * Context: This function will acquire ioc->sas_device_lock.
593 *
594 * Adding new object to the ioc->sas_device_list.
595 */
596static void
597_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
598 struct _sas_device *sas_device)
599{
600 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -0600601
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530602 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
Eric Moore635374e2009-03-09 01:21:12 -0600603 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
604 sas_device->handle, (unsigned long long)sas_device->sas_address));
605
606 spin_lock_irqsave(&ioc->sas_device_lock, flags);
607 list_add_tail(&sas_device->list, &ioc->sas_device_list);
608 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
609
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530610 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
nagalakshmi.nandigama@lsi.com35116db2011-10-21 10:08:07 +0530611 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -0600612 _scsih_sas_device_remove(ioc, sas_device);
nagalakshmi.nandigama@lsi.com23edb6e2011-12-01 07:43:50 +0530613 } else if (!sas_device->starget) {
614 /* When asyn scanning is enabled, its not possible to remove
615 * devices while scanning is turned on due to an oops in
616 * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start()
617 */
618 if (!ioc->is_driver_loading)
619 mpt2sas_transport_port_remove(ioc,
620 sas_device->sas_address,
621 sas_device->sas_address_parent);
622 _scsih_sas_device_remove(ioc, sas_device);
623 }
Eric Moore635374e2009-03-09 01:21:12 -0600624}
625
626/**
627 * _scsih_sas_device_init_add - insert sas_device to the list.
628 * @ioc: per adapter object
629 * @sas_device: the sas_device object
630 * Context: This function will acquire ioc->sas_device_lock.
631 *
632 * Adding new object at driver load time to the ioc->sas_device_init_list.
633 */
634static void
635_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
636 struct _sas_device *sas_device)
637{
638 unsigned long flags;
639
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530640 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
Eric Moore635374e2009-03-09 01:21:12 -0600641 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
642 sas_device->handle, (unsigned long long)sas_device->sas_address));
643
644 spin_lock_irqsave(&ioc->sas_device_lock, flags);
645 list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
Eric Moore635374e2009-03-09 01:21:12 -0600646 _scsih_determine_boot_device(ioc, sas_device, 0);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +0530647 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -0600648}
649
650/**
Eric Moore635374e2009-03-09 01:21:12 -0600651 * _scsih_raid_device_find_by_id - raid device search
652 * @ioc: per adapter object
653 * @id: sas device target id
654 * @channel: sas device channel
655 * Context: Calling function should acquire ioc->raid_device_lock
656 *
657 * This searches for raid_device based on target id, then return raid_device
658 * object.
659 */
660static struct _raid_device *
661_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
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->id == id && raid_device->channel == channel) {
668 r = raid_device;
669 goto out;
670 }
671 }
672
673 out:
674 return r;
675}
676
677/**
678 * _scsih_raid_device_find_by_handle - raid device search
679 * @ioc: per adapter object
680 * @handle: sas device handle (assigned by firmware)
681 * Context: Calling function should acquire ioc->raid_device_lock
682 *
683 * This searches for raid_device based on handle, then return raid_device
684 * object.
685 */
686static struct _raid_device *
687_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
688{
689 struct _raid_device *raid_device, *r;
690
691 r = NULL;
692 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
693 if (raid_device->handle != handle)
694 continue;
695 r = raid_device;
696 goto out;
697 }
698
699 out:
700 return r;
701}
702
703/**
704 * _scsih_raid_device_find_by_wwid - raid device search
705 * @ioc: per adapter object
706 * @handle: sas device handle (assigned by firmware)
707 * Context: Calling function should acquire ioc->raid_device_lock
708 *
709 * This searches for raid_device based on wwid, then return raid_device
710 * object.
711 */
712static struct _raid_device *
713_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
714{
715 struct _raid_device *raid_device, *r;
716
717 r = NULL;
718 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
719 if (raid_device->wwid != wwid)
720 continue;
721 r = raid_device;
722 goto out;
723 }
724
725 out:
726 return r;
727}
728
729/**
730 * _scsih_raid_device_add - add raid_device object
731 * @ioc: per adapter object
732 * @raid_device: raid_device object
733 *
734 * This is added to the raid_device_list link list.
735 */
736static void
737_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
738 struct _raid_device *raid_device)
739{
740 unsigned long flags;
741
Kashyap, Desaieabb08a2010-06-17 13:43:57 +0530742 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
Eric Moore635374e2009-03-09 01:21:12 -0600743 "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
744 raid_device->handle, (unsigned long long)raid_device->wwid));
745
746 spin_lock_irqsave(&ioc->raid_device_lock, flags);
747 list_add_tail(&raid_device->list, &ioc->raid_device_list);
748 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
749}
750
751/**
752 * _scsih_raid_device_remove - delete raid_device object
753 * @ioc: per adapter object
754 * @raid_device: raid_device object
755 *
Eric Moore635374e2009-03-09 01:21:12 -0600756 */
757static void
758_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
759 struct _raid_device *raid_device)
760{
761 unsigned long flags;
762
763 spin_lock_irqsave(&ioc->raid_device_lock, flags);
764 list_del(&raid_device->list);
Eric Moore635374e2009-03-09 01:21:12 -0600765 kfree(raid_device);
766 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
767}
768
769/**
Kashyap, Desaic5e039b2009-09-23 17:21:29 +0530770 * mpt2sas_scsih_expander_find_by_handle - expander device search
771 * @ioc: per adapter object
772 * @handle: expander handle (assigned by firmware)
773 * Context: Calling function should acquire ioc->sas_device_lock
774 *
775 * This searches for expander device based on handle, then returns the
776 * sas_node object.
777 */
778struct _sas_node *
779mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
780{
781 struct _sas_node *sas_expander, *r;
782
783 r = NULL;
784 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
785 if (sas_expander->handle != handle)
786 continue;
787 r = sas_expander;
788 goto out;
789 }
790 out:
791 return r;
792}
793
794/**
Eric Moore635374e2009-03-09 01:21:12 -0600795 * mpt2sas_scsih_expander_find_by_sas_address - expander device search
796 * @ioc: per adapter object
797 * @sas_address: sas address
798 * Context: Calling function should acquire ioc->sas_node_lock.
799 *
800 * This searches for expander device based on sas_address, then returns the
801 * sas_node object.
802 */
803struct _sas_node *
804mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
805 u64 sas_address)
806{
807 struct _sas_node *sas_expander, *r;
808
809 r = NULL;
810 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
811 if (sas_expander->sas_address != sas_address)
812 continue;
813 r = sas_expander;
814 goto out;
815 }
816 out:
817 return r;
818}
819
820/**
821 * _scsih_expander_node_add - insert expander device to the list.
822 * @ioc: per adapter object
823 * @sas_expander: the sas_device object
824 * Context: This function will acquire ioc->sas_node_lock.
825 *
826 * Adding new object to the ioc->sas_expander_list.
827 *
828 * Return nothing.
829 */
830static void
831_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
832 struct _sas_node *sas_expander)
833{
834 unsigned long flags;
835
836 spin_lock_irqsave(&ioc->sas_node_lock, flags);
837 list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
838 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
839}
840
841/**
842 * _scsih_is_end_device - determines if device is an end device
843 * @device_info: bitfield providing information about the device.
844 * Context: none
845 *
846 * Returns 1 if end device.
847 */
848static int
849_scsih_is_end_device(u32 device_info)
850{
851 if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
852 ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
853 (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
854 (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
855 return 1;
856 else
857 return 0;
858}
859
860/**
Kashyap, Desaiec07a052011-01-05 17:54:32 +0530861 * _scsih_scsi_lookup_get - returns scmd entry
Eric Moore635374e2009-03-09 01:21:12 -0600862 * @ioc: per adapter object
863 * @smid: system request message index
Eric Moore635374e2009-03-09 01:21:12 -0600864 *
865 * Returns the smid stored scmd pointer.
866 */
867static struct scsi_cmnd *
868_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
869{
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530870 return ioc->scsi_lookup[smid - 1].scmd;
Eric Moore635374e2009-03-09 01:21:12 -0600871}
872
873/**
Kashyap, Desaiec07a052011-01-05 17:54:32 +0530874 * _scsih_scsi_lookup_get_clear - returns scmd entry
875 * @ioc: per adapter object
876 * @smid: system request message index
877 *
878 * Returns the smid stored scmd pointer.
879 * Then will derefrence the stored scmd pointer.
880 */
881static inline struct scsi_cmnd *
882_scsih_scsi_lookup_get_clear(struct MPT2SAS_ADAPTER *ioc, u16 smid)
883{
884 unsigned long flags;
885 struct scsi_cmnd *scmd;
886
887 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
888 scmd = ioc->scsi_lookup[smid - 1].scmd;
889 ioc->scsi_lookup[smid - 1].scmd = NULL;
890 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
891
892 return scmd;
893}
894
895/**
Eric Moore635374e2009-03-09 01:21:12 -0600896 * _scsih_scsi_lookup_find_by_scmd - scmd lookup
897 * @ioc: per adapter object
898 * @smid: system request message index
899 * @scmd: pointer to scsi command object
900 * Context: This function will acquire ioc->scsi_lookup_lock.
901 *
902 * This will search for a scmd pointer in the scsi_lookup array,
903 * returning the revelent smid. A returned value of zero means invalid.
904 */
905static u16
906_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
907 *scmd)
908{
909 u16 smid;
910 unsigned long flags;
911 int i;
912
913 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
914 smid = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530915 for (i = 0; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600916 if (ioc->scsi_lookup[i].scmd == scmd) {
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530917 smid = ioc->scsi_lookup[i].smid;
Eric Moore635374e2009-03-09 01:21:12 -0600918 goto out;
919 }
920 }
921 out:
922 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
923 return smid;
924}
925
926/**
927 * _scsih_scsi_lookup_find_by_target - search for matching channel:id
928 * @ioc: per adapter object
929 * @id: target id
930 * @channel: channel
931 * Context: This function will acquire ioc->scsi_lookup_lock.
932 *
933 * This will search for a matching channel:id in the scsi_lookup array,
934 * returning 1 if found.
935 */
936static u8
937_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
938 int channel)
939{
940 u8 found;
941 unsigned long flags;
942 int i;
943
944 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
945 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530946 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore635374e2009-03-09 01:21:12 -0600947 if (ioc->scsi_lookup[i].scmd &&
948 (ioc->scsi_lookup[i].scmd->device->id == id &&
949 ioc->scsi_lookup[i].scmd->device->channel == channel)) {
950 found = 1;
951 goto out;
952 }
953 }
954 out:
955 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
956 return found;
957}
958
959/**
Eric Moore993e0da2009-05-18 13:00:45 -0600960 * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
961 * @ioc: per adapter object
962 * @id: target id
963 * @lun: lun number
964 * @channel: channel
965 * Context: This function will acquire ioc->scsi_lookup_lock.
966 *
967 * This will search for a matching channel:id:lun in the scsi_lookup array,
968 * returning 1 if found.
969 */
970static u8
971_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
972 unsigned int lun, int channel)
973{
974 u8 found;
975 unsigned long flags;
976 int i;
977
978 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
979 found = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +0530980 for (i = 0 ; i < ioc->scsiio_depth; i++) {
Eric Moore993e0da2009-05-18 13:00:45 -0600981 if (ioc->scsi_lookup[i].scmd &&
982 (ioc->scsi_lookup[i].scmd->device->id == id &&
983 ioc->scsi_lookup[i].scmd->device->channel == channel &&
984 ioc->scsi_lookup[i].scmd->device->lun == lun)) {
985 found = 1;
986 goto out;
987 }
988 }
989 out:
990 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
991 return found;
992}
993
994/**
Kashyap, Desai35f805b2010-11-13 04:34:06 +0530995 * _scsih_get_chain_buffer_tracker - obtain chain tracker
Eric Moore635374e2009-03-09 01:21:12 -0600996 * @ioc: per adapter object
Kashyap, Desai35f805b2010-11-13 04:34:06 +0530997 * @smid: smid associated to an IO request
Eric Moore635374e2009-03-09 01:21:12 -0600998 *
Kashyap, Desai35f805b2010-11-13 04:34:06 +0530999 * Returns chain tracker(from ioc->free_chain_list)
Eric Moore635374e2009-03-09 01:21:12 -06001000 */
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301001static struct chain_tracker *
1002_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid)
Eric Moore635374e2009-03-09 01:21:12 -06001003{
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301004 struct chain_tracker *chain_req;
1005 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06001006
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301007 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
1008 if (list_empty(&ioc->free_chain_list)) {
1009 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
nagalakshmi.nandigama@lsi.comaff132d2011-12-01 07:53:08 +05301010 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not "
1011 "available\n", ioc->name));
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301012 return NULL;
1013 }
1014 chain_req = list_entry(ioc->free_chain_list.next,
1015 struct chain_tracker, tracker_list);
1016 list_del_init(&chain_req->tracker_list);
1017 list_add_tail(&chain_req->tracker_list,
1018 &ioc->scsi_lookup[smid - 1].chain_list);
1019 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
1020 return chain_req;
Eric Moore635374e2009-03-09 01:21:12 -06001021}
1022
1023/**
1024 * _scsih_build_scatter_gather - main sg creation routine
1025 * @ioc: per adapter object
1026 * @scmd: scsi command
1027 * @smid: system request message index
1028 * Context: none.
1029 *
1030 * The main routine that builds scatter gather table from a given
1031 * scsi request sent via the .queuecommand main handler.
1032 *
1033 * Returns 0 success, anything else error
1034 */
1035static int
1036_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
1037 struct scsi_cmnd *scmd, u16 smid)
1038{
1039 Mpi2SCSIIORequest_t *mpi_request;
1040 dma_addr_t chain_dma;
1041 struct scatterlist *sg_scmd;
1042 void *sg_local, *chain;
1043 u32 chain_offset;
1044 u32 chain_length;
1045 u32 chain_flags;
FUJITA Tomonoribb789d02010-03-09 11:09:50 +09001046 int sges_left;
Eric Moore635374e2009-03-09 01:21:12 -06001047 u32 sges_in_segment;
1048 u32 sgl_flags;
1049 u32 sgl_flags_last_element;
1050 u32 sgl_flags_end_buffer;
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301051 struct chain_tracker *chain_req;
Eric Moore635374e2009-03-09 01:21:12 -06001052
1053 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1054
1055 /* init scatter gather flags */
1056 sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
1057 if (scmd->sc_data_direction == DMA_TO_DEVICE)
1058 sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
1059 sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
1060 << MPI2_SGE_FLAGS_SHIFT;
1061 sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
1062 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
1063 << MPI2_SGE_FLAGS_SHIFT;
1064 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1065
1066 sg_scmd = scsi_sglist(scmd);
1067 sges_left = scsi_dma_map(scmd);
FUJITA Tomonoribb789d02010-03-09 11:09:50 +09001068 if (sges_left < 0) {
Eric Moore635374e2009-03-09 01:21:12 -06001069 sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
1070 " failed: request for %d bytes!\n", scsi_bufflen(scmd));
1071 return -ENOMEM;
1072 }
1073
1074 sg_local = &mpi_request->SGL;
1075 sges_in_segment = ioc->max_sges_in_main_message;
1076 if (sges_left <= sges_in_segment)
1077 goto fill_in_last_segment;
1078
1079 mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
1080 (sges_in_segment * ioc->sge_size))/4;
1081
1082 /* fill in main message segment when there is a chain following */
1083 while (sges_in_segment) {
1084 if (sges_in_segment == 1)
1085 ioc->base_add_sg_single(sg_local,
1086 sgl_flags_last_element | sg_dma_len(sg_scmd),
1087 sg_dma_address(sg_scmd));
1088 else
1089 ioc->base_add_sg_single(sg_local, sgl_flags |
1090 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1091 sg_scmd = sg_next(sg_scmd);
1092 sg_local += ioc->sge_size;
1093 sges_left--;
1094 sges_in_segment--;
1095 }
1096
1097 /* initializing the chain flags and pointers */
1098 chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301099 chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
1100 if (!chain_req)
1101 return -1;
1102 chain = chain_req->chain_buffer;
1103 chain_dma = chain_req->chain_buffer_dma;
Eric Moore635374e2009-03-09 01:21:12 -06001104 do {
1105 sges_in_segment = (sges_left <=
1106 ioc->max_sges_in_chain_message) ? sges_left :
1107 ioc->max_sges_in_chain_message;
1108 chain_offset = (sges_left == sges_in_segment) ?
1109 0 : (sges_in_segment * ioc->sge_size)/4;
1110 chain_length = sges_in_segment * ioc->sge_size;
1111 if (chain_offset) {
1112 chain_offset = chain_offset <<
1113 MPI2_SGE_CHAIN_OFFSET_SHIFT;
1114 chain_length += ioc->sge_size;
1115 }
1116 ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
1117 chain_length, chain_dma);
1118 sg_local = chain;
1119 if (!chain_offset)
1120 goto fill_in_last_segment;
1121
1122 /* fill in chain segments */
1123 while (sges_in_segment) {
1124 if (sges_in_segment == 1)
1125 ioc->base_add_sg_single(sg_local,
1126 sgl_flags_last_element |
1127 sg_dma_len(sg_scmd),
1128 sg_dma_address(sg_scmd));
1129 else
1130 ioc->base_add_sg_single(sg_local, sgl_flags |
1131 sg_dma_len(sg_scmd),
1132 sg_dma_address(sg_scmd));
1133 sg_scmd = sg_next(sg_scmd);
1134 sg_local += ioc->sge_size;
1135 sges_left--;
1136 sges_in_segment--;
1137 }
1138
Kashyap, Desai35f805b2010-11-13 04:34:06 +05301139 chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
1140 if (!chain_req)
1141 return -1;
1142 chain = chain_req->chain_buffer;
1143 chain_dma = chain_req->chain_buffer_dma;
Eric Moore635374e2009-03-09 01:21:12 -06001144 } while (1);
1145
1146
1147 fill_in_last_segment:
1148
1149 /* fill the last segment */
1150 while (sges_left) {
1151 if (sges_left == 1)
1152 ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
1153 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1154 else
1155 ioc->base_add_sg_single(sg_local, sgl_flags |
1156 sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
1157 sg_scmd = sg_next(sg_scmd);
1158 sg_local += ioc->sge_size;
1159 sges_left--;
1160 }
1161
1162 return 0;
1163}
1164
1165/**
Kashyap, Desaia93c6b42010-11-13 04:39:11 +05301166 * _scsih_adjust_queue_depth - setting device queue depth
Eric Moore635374e2009-03-09 01:21:12 -06001167 * @sdev: scsi device struct
1168 * @qdepth: requested queue depth
1169 *
Kashyap, Desaia93c6b42010-11-13 04:39:11 +05301170 *
1171 * Returns nothing
Eric Moore635374e2009-03-09 01:21:12 -06001172 */
Kashyap, Desaia93c6b42010-11-13 04:39:11 +05301173static void
1174_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
Eric Moore635374e2009-03-09 01:21:12 -06001175{
1176 struct Scsi_Host *shost = sdev->host;
1177 int max_depth;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301178 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1179 struct MPT2SAS_DEVICE *sas_device_priv_data;
1180 struct MPT2SAS_TARGET *sas_target_priv_data;
1181 struct _sas_device *sas_device;
1182 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06001183
1184 max_depth = shost->can_queue;
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301185
1186 /* limit max device queue for SATA to 32 */
1187 sas_device_priv_data = sdev->hostdata;
1188 if (!sas_device_priv_data)
1189 goto not_sata;
1190 sas_target_priv_data = sas_device_priv_data->sas_target;
1191 if (!sas_target_priv_data)
1192 goto not_sata;
1193 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
1194 goto not_sata;
1195 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1196 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1197 sas_device_priv_data->sas_target->sas_address);
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301198 if (sas_device && sas_device->device_info &
1199 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
1200 max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301201 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desaie0077d62009-09-23 17:30:22 +05301202
1203 not_sata:
1204
Eric Moore635374e2009-03-09 01:21:12 -06001205 if (!sdev->tagged_supported)
1206 max_depth = 1;
1207 if (qdepth > max_depth)
1208 qdepth = max_depth;
Kashyap, Desaia93c6b42010-11-13 04:39:11 +05301209 scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
1210}
1211
1212/**
1213 * _scsih_change_queue_depth - setting device queue depth
1214 * @sdev: scsi device struct
1215 * @qdepth: requested queue depth
1216 * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP
1217 * (see include/scsi/scsi_host.h for definition)
1218 *
1219 * Returns queue depth.
1220 */
1221static int
1222_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
1223{
1224 if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP)
1225 _scsih_adjust_queue_depth(sdev, qdepth);
1226 else if (reason == SCSI_QDEPTH_QFULL)
1227 scsi_track_queue_full(sdev, qdepth);
1228 else
1229 return -EOPNOTSUPP;
Eric Moore635374e2009-03-09 01:21:12 -06001230
1231 if (sdev->inquiry_len > 7)
1232 sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
1233 "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
1234 sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
1235 sdev->ordered_tags, sdev->scsi_level,
1236 (sdev->inquiry[7] & 2) >> 1);
1237
1238 return sdev->queue_depth;
1239}
1240
1241/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05301242 * _scsih_change_queue_type - changing device queue tag type
Eric Moore635374e2009-03-09 01:21:12 -06001243 * @sdev: scsi device struct
1244 * @tag_type: requested tag type
1245 *
1246 * Returns queue tag type.
1247 */
1248static int
Eric Moored5d135b2009-05-18 13:02:08 -06001249_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
Eric Moore635374e2009-03-09 01:21:12 -06001250{
1251 if (sdev->tagged_supported) {
1252 scsi_set_tag_type(sdev, tag_type);
1253 if (tag_type)
1254 scsi_activate_tcq(sdev, sdev->queue_depth);
1255 else
1256 scsi_deactivate_tcq(sdev, sdev->queue_depth);
1257 } else
1258 tag_type = 0;
1259
1260 return tag_type;
1261}
1262
1263/**
Eric Moored5d135b2009-05-18 13:02:08 -06001264 * _scsih_target_alloc - target add routine
Eric Moore635374e2009-03-09 01:21:12 -06001265 * @starget: scsi target struct
1266 *
1267 * Returns 0 if ok. Any other return is assumed to be an error and
1268 * the device is ignored.
1269 */
1270static int
Eric Moored5d135b2009-05-18 13:02:08 -06001271_scsih_target_alloc(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001272{
1273 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1274 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1275 struct MPT2SAS_TARGET *sas_target_priv_data;
1276 struct _sas_device *sas_device;
1277 struct _raid_device *raid_device;
1278 unsigned long flags;
1279 struct sas_rphy *rphy;
1280
1281 sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL);
1282 if (!sas_target_priv_data)
1283 return -ENOMEM;
1284
1285 starget->hostdata = sas_target_priv_data;
1286 sas_target_priv_data->starget = starget;
1287 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
1288
1289 /* RAID volumes */
1290 if (starget->channel == RAID_CHANNEL) {
1291 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1292 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1293 starget->channel);
1294 if (raid_device) {
1295 sas_target_priv_data->handle = raid_device->handle;
1296 sas_target_priv_data->sas_address = raid_device->wwid;
1297 sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301298 if (ioc->is_warpdrive)
1299 sas_target_priv_data->raid_device = raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06001300 raid_device->starget = starget;
1301 }
1302 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1303 return 0;
1304 }
1305
1306 /* sas/sata devices */
1307 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1308 rphy = dev_to_rphy(starget->dev.parent);
1309 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1310 rphy->identify.sas_address);
1311
1312 if (sas_device) {
1313 sas_target_priv_data->handle = sas_device->handle;
1314 sas_target_priv_data->sas_address = sas_device->sas_address;
1315 sas_device->starget = starget;
1316 sas_device->id = starget->id;
1317 sas_device->channel = starget->channel;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05301318 if (test_bit(sas_device->handle, ioc->pd_handles))
Eric Moore635374e2009-03-09 01:21:12 -06001319 sas_target_priv_data->flags |=
1320 MPT_TARGET_FLAGS_RAID_COMPONENT;
1321 }
1322 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1323
1324 return 0;
1325}
1326
1327/**
Eric Moored5d135b2009-05-18 13:02:08 -06001328 * _scsih_target_destroy - target destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001329 * @starget: scsi target struct
1330 *
1331 * Returns nothing.
1332 */
1333static void
Eric Moored5d135b2009-05-18 13:02:08 -06001334_scsih_target_destroy(struct scsi_target *starget)
Eric Moore635374e2009-03-09 01:21:12 -06001335{
1336 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1337 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1338 struct MPT2SAS_TARGET *sas_target_priv_data;
1339 struct _sas_device *sas_device;
1340 struct _raid_device *raid_device;
1341 unsigned long flags;
1342 struct sas_rphy *rphy;
1343
1344 sas_target_priv_data = starget->hostdata;
1345 if (!sas_target_priv_data)
1346 return;
1347
1348 if (starget->channel == RAID_CHANNEL) {
1349 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1350 raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
1351 starget->channel);
1352 if (raid_device) {
1353 raid_device->starget = NULL;
1354 raid_device->sdev = NULL;
1355 }
1356 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1357 goto out;
1358 }
1359
1360 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1361 rphy = dev_to_rphy(starget->dev.parent);
1362 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1363 rphy->identify.sas_address);
Eric Moore8901cbb2009-04-21 15:41:32 -06001364 if (sas_device && (sas_device->starget == starget) &&
1365 (sas_device->id == starget->id) &&
1366 (sas_device->channel == starget->channel))
Eric Moore635374e2009-03-09 01:21:12 -06001367 sas_device->starget = NULL;
1368
1369 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1370
1371 out:
1372 kfree(sas_target_priv_data);
1373 starget->hostdata = NULL;
1374}
1375
1376/**
Eric Moored5d135b2009-05-18 13:02:08 -06001377 * _scsih_slave_alloc - device add routine
Eric Moore635374e2009-03-09 01:21:12 -06001378 * @sdev: scsi device struct
1379 *
1380 * Returns 0 if ok. Any other return is assumed to be an error and
1381 * the device is ignored.
1382 */
1383static int
Eric Moored5d135b2009-05-18 13:02:08 -06001384_scsih_slave_alloc(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001385{
1386 struct Scsi_Host *shost;
1387 struct MPT2SAS_ADAPTER *ioc;
1388 struct MPT2SAS_TARGET *sas_target_priv_data;
1389 struct MPT2SAS_DEVICE *sas_device_priv_data;
1390 struct scsi_target *starget;
1391 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06001392 unsigned long flags;
1393
1394 sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
1395 if (!sas_device_priv_data)
1396 return -ENOMEM;
1397
1398 sas_device_priv_data->lun = sdev->lun;
1399 sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
1400
1401 starget = scsi_target(sdev);
1402 sas_target_priv_data = starget->hostdata;
1403 sas_target_priv_data->num_luns++;
1404 sas_device_priv_data->sas_target = sas_target_priv_data;
1405 sdev->hostdata = sas_device_priv_data;
1406 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
1407 sdev->no_uld_attach = 1;
1408
1409 shost = dev_to_shost(&starget->dev);
1410 ioc = shost_priv(shost);
1411 if (starget->channel == RAID_CHANNEL) {
1412 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1413 raid_device = _scsih_raid_device_find_by_id(ioc,
1414 starget->id, starget->channel);
1415 if (raid_device)
1416 raid_device->sdev = sdev; /* raid is single lun */
1417 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06001418 }
1419
Eric Moore635374e2009-03-09 01:21:12 -06001420 return 0;
1421}
1422
1423/**
Eric Moored5d135b2009-05-18 13:02:08 -06001424 * _scsih_slave_destroy - device destroy routine
Eric Moore635374e2009-03-09 01:21:12 -06001425 * @sdev: scsi device struct
1426 *
1427 * Returns nothing.
1428 */
1429static void
Eric Moored5d135b2009-05-18 13:02:08 -06001430_scsih_slave_destroy(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001431{
1432 struct MPT2SAS_TARGET *sas_target_priv_data;
1433 struct scsi_target *starget;
nagalakshmi.nandigama@lsi.com35116db2011-10-21 10:08:07 +05301434 struct Scsi_Host *shost;
1435 struct MPT2SAS_ADAPTER *ioc;
1436 struct _sas_device *sas_device;
1437 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06001438
1439 if (!sdev->hostdata)
1440 return;
1441
1442 starget = scsi_target(sdev);
1443 sas_target_priv_data = starget->hostdata;
1444 sas_target_priv_data->num_luns--;
nagalakshmi.nandigama@lsi.com35116db2011-10-21 10:08:07 +05301445
1446 shost = dev_to_shost(&starget->dev);
1447 ioc = shost_priv(shost);
1448
1449 if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
1450 spin_lock_irqsave(&ioc->sas_device_lock, flags);
1451 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1452 sas_target_priv_data->sas_address);
nagalakshmi.nandigama@lsi.com23edb6e2011-12-01 07:43:50 +05301453 if (sas_device && !sas_target_priv_data->num_luns)
nagalakshmi.nandigama@lsi.com35116db2011-10-21 10:08:07 +05301454 sas_device->starget = NULL;
1455 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1456 }
1457
Eric Moore635374e2009-03-09 01:21:12 -06001458 kfree(sdev->hostdata);
1459 sdev->hostdata = NULL;
1460}
1461
1462/**
Eric Moored5d135b2009-05-18 13:02:08 -06001463 * _scsih_display_sata_capabilities - sata capabilities
Eric Moore635374e2009-03-09 01:21:12 -06001464 * @ioc: per adapter object
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301465 * @handle: device handle
Eric Moore635374e2009-03-09 01:21:12 -06001466 * @sdev: scsi device struct
1467 */
1468static void
Eric Moored5d135b2009-05-18 13:02:08 -06001469_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301470 u16 handle, struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001471{
1472 Mpi2ConfigReply_t mpi_reply;
1473 Mpi2SasDevicePage0_t sas_device_pg0;
1474 u32 ioc_status;
1475 u16 flags;
1476 u32 device_info;
1477
1478 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301479 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06001480 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1481 ioc->name, __FILE__, __LINE__, __func__);
1482 return;
1483 }
1484
1485 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1486 MPI2_IOCSTATUS_MASK;
1487 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1488 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1489 ioc->name, __FILE__, __LINE__, __func__);
1490 return;
1491 }
1492
1493 flags = le16_to_cpu(sas_device_pg0.Flags);
Kashyap, Desaie94f6742010-03-17 16:24:52 +05301494 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
Eric Moore635374e2009-03-09 01:21:12 -06001495
1496 sdev_printk(KERN_INFO, sdev,
1497 "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
1498 "sw_preserve(%s)\n",
1499 (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
1500 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
1501 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
1502 "n",
1503 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
1504 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
1505 (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
1506}
1507
1508/**
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301509 * _scsih_is_raid - return boolean indicating device is raid volume
1510 * @dev the device struct object
1511 */
1512static int
1513_scsih_is_raid(struct device *dev)
1514{
1515 struct scsi_device *sdev = to_scsi_device(dev);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301516 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301517
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301518 if (ioc->is_warpdrive)
1519 return 0;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301520 return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
1521}
1522
1523/**
1524 * _scsih_get_resync - get raid volume resync percent complete
1525 * @dev the device struct object
1526 */
1527static void
1528_scsih_get_resync(struct device *dev)
1529{
1530 struct scsi_device *sdev = to_scsi_device(dev);
1531 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1532 static struct _raid_device *raid_device;
1533 unsigned long flags;
1534 Mpi2RaidVolPage0_t vol_pg0;
1535 Mpi2ConfigReply_t mpi_reply;
1536 u32 volume_status_flags;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301537 u8 percent_complete;
1538 u16 handle;
1539
1540 percent_complete = 0;
1541 handle = 0;
1542 if (ioc->is_warpdrive)
1543 goto out;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301544
1545 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1546 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1547 sdev->channel);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301548 if (raid_device) {
1549 handle = raid_device->handle;
1550 percent_complete = raid_device->percent_complete;
1551 }
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301552 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1553
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301554 if (!handle)
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301555 goto out;
1556
1557 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301558 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301559 sizeof(Mpi2RaidVolPage0_t))) {
1560 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1561 ioc->name, __FILE__, __LINE__, __func__);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301562 percent_complete = 0;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301563 goto out;
1564 }
1565
1566 volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301567 if (!(volume_status_flags &
1568 MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS))
1569 percent_complete = 0;
1570
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301571 out:
1572 raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
1573}
1574
1575/**
1576 * _scsih_get_state - get raid volume level
1577 * @dev the device struct object
1578 */
1579static void
1580_scsih_get_state(struct device *dev)
1581{
1582 struct scsi_device *sdev = to_scsi_device(dev);
1583 struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
1584 static struct _raid_device *raid_device;
1585 unsigned long flags;
1586 Mpi2RaidVolPage0_t vol_pg0;
1587 Mpi2ConfigReply_t mpi_reply;
1588 u32 volstate;
1589 enum raid_state state = RAID_STATE_UNKNOWN;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301590 u16 handle = 0;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301591
1592 spin_lock_irqsave(&ioc->raid_device_lock, flags);
1593 raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
1594 sdev->channel);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301595 if (raid_device)
1596 handle = raid_device->handle;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301597 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1598
1599 if (!raid_device)
1600 goto out;
1601
1602 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301603 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301604 sizeof(Mpi2RaidVolPage0_t))) {
1605 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1606 ioc->name, __FILE__, __LINE__, __func__);
1607 goto out;
1608 }
1609
1610 volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
1611 if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
1612 state = RAID_STATE_RESYNCING;
1613 goto out;
1614 }
1615
1616 switch (vol_pg0.VolumeState) {
1617 case MPI2_RAID_VOL_STATE_OPTIMAL:
1618 case MPI2_RAID_VOL_STATE_ONLINE:
1619 state = RAID_STATE_ACTIVE;
1620 break;
1621 case MPI2_RAID_VOL_STATE_DEGRADED:
1622 state = RAID_STATE_DEGRADED;
1623 break;
1624 case MPI2_RAID_VOL_STATE_FAILED:
1625 case MPI2_RAID_VOL_STATE_MISSING:
1626 state = RAID_STATE_OFFLINE;
1627 break;
1628 }
1629 out:
1630 raid_set_state(mpt2sas_raid_template, dev, state);
1631}
1632
1633/**
1634 * _scsih_set_level - set raid level
1635 * @sdev: scsi device struct
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301636 * @volume_type: volume type
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301637 */
1638static void
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301639_scsih_set_level(struct scsi_device *sdev, u8 volume_type)
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301640{
1641 enum raid_level level = RAID_LEVEL_UNKNOWN;
1642
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301643 switch (volume_type) {
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05301644 case MPI2_RAID_VOL_TYPE_RAID0:
1645 level = RAID_LEVEL_0;
1646 break;
1647 case MPI2_RAID_VOL_TYPE_RAID10:
1648 level = RAID_LEVEL_10;
1649 break;
1650 case MPI2_RAID_VOL_TYPE_RAID1E:
1651 level = RAID_LEVEL_1E;
1652 break;
1653 case MPI2_RAID_VOL_TYPE_RAID1:
1654 level = RAID_LEVEL_1;
1655 break;
1656 }
1657
1658 raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
1659}
1660
1661/**
Eric Moore635374e2009-03-09 01:21:12 -06001662 * _scsih_get_volume_capabilities - volume capabilities
1663 * @ioc: per adapter object
1664 * @sas_device: the raid_device object
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05301665 *
1666 * Returns 0 for success, else 1
Eric Moore635374e2009-03-09 01:21:12 -06001667 */
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05301668static int
Eric Moore635374e2009-03-09 01:21:12 -06001669_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
1670 struct _raid_device *raid_device)
1671{
1672 Mpi2RaidVolPage0_t *vol_pg0;
1673 Mpi2RaidPhysDiskPage0_t pd_pg0;
1674 Mpi2SasDevicePage0_t sas_device_pg0;
1675 Mpi2ConfigReply_t mpi_reply;
1676 u16 sz;
1677 u8 num_pds;
1678
1679 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1680 &num_pds)) || !num_pds) {
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05301681 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
1682 "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
1683 __func__));
1684 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001685 }
1686
1687 raid_device->num_pds = num_pds;
1688 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1689 sizeof(Mpi2RaidVol0PhysDisk_t));
1690 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1691 if (!vol_pg0) {
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05301692 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
1693 "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
1694 __func__));
1695 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001696 }
1697
1698 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1699 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05301700 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
1701 "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
1702 __func__));
Eric Moore635374e2009-03-09 01:21:12 -06001703 kfree(vol_pg0);
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05301704 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06001705 }
1706
1707 raid_device->volume_type = vol_pg0->VolumeType;
1708
1709 /* figure out what the underlying devices are by
1710 * obtaining the device_info bits for the 1st device
1711 */
1712 if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1713 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1714 vol_pg0->PhysDisk[0].PhysDiskNum))) {
1715 if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
1716 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1717 le16_to_cpu(pd_pg0.DevHandle)))) {
1718 raid_device->device_info =
1719 le32_to_cpu(sas_device_pg0.DeviceInfo);
1720 }
1721 }
1722
1723 kfree(vol_pg0);
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05301724 return 0;
Eric Moore635374e2009-03-09 01:21:12 -06001725}
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301726/**
1727 * _scsih_disable_ddio - Disable direct I/O for all the volumes
1728 * @ioc: per adapter object
1729 */
1730static void
1731_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
1732{
1733 Mpi2RaidVolPage1_t vol_pg1;
1734 Mpi2ConfigReply_t mpi_reply;
1735 struct _raid_device *raid_device;
1736 u16 handle;
1737 u16 ioc_status;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301738 unsigned long flags;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301739
1740 handle = 0xFFFF;
1741 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
1742 &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
1743 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1744 MPI2_IOCSTATUS_MASK;
1745 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
1746 break;
1747 handle = le16_to_cpu(vol_pg1.DevHandle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301748 spin_lock_irqsave(&ioc->raid_device_lock, flags);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301749 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
1750 if (raid_device)
1751 raid_device->direct_io_enabled = 0;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301752 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301753 }
1754 return;
1755}
1756
1757
1758/**
1759 * _scsih_get_num_volumes - Get number of volumes in the ioc
1760 * @ioc: per adapter object
1761 */
1762static u8
1763_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc)
1764{
1765 Mpi2RaidVolPage1_t vol_pg1;
1766 Mpi2ConfigReply_t mpi_reply;
1767 u16 handle;
1768 u8 vol_cnt = 0;
1769 u16 ioc_status;
1770
1771 handle = 0xFFFF;
1772 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
1773 &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
1774 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1775 MPI2_IOCSTATUS_MASK;
1776 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
1777 break;
1778 vol_cnt++;
1779 handle = le16_to_cpu(vol_pg1.DevHandle);
1780 }
1781 return vol_cnt;
1782}
1783
1784
1785/**
1786 * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O.
1787 * @ioc: per adapter object
1788 * @raid_device: the raid_device object
1789 */
1790static void
1791_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc,
1792 struct _raid_device *raid_device)
1793{
1794 Mpi2RaidVolPage0_t *vol_pg0;
1795 Mpi2RaidPhysDiskPage0_t pd_pg0;
1796 Mpi2ConfigReply_t mpi_reply;
1797 u16 sz;
1798 u8 num_pds, count;
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05301799 unsigned long stripe_sz, block_sz;
1800 u8 stripe_exp, block_exp;
1801 u64 dev_max_lba;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301802
1803 if (!ioc->is_warpdrive)
1804 return;
1805
1806 if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) {
1807 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1808 "globally as drives are exposed\n", ioc->name);
1809 return;
1810 }
1811 if (_scsih_get_num_volumes(ioc) > 1) {
1812 _scsih_disable_ddio(ioc);
1813 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1814 "globally as number of drives > 1\n", ioc->name);
1815 return;
1816 }
1817 if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
1818 &num_pds)) || !num_pds) {
1819 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1820 "Failure in computing number of drives\n", ioc->name);
1821 return;
1822 }
1823
1824 sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
1825 sizeof(Mpi2RaidVol0PhysDisk_t));
1826 vol_pg0 = kzalloc(sz, GFP_KERNEL);
1827 if (!vol_pg0) {
1828 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1829 "Memory allocation failure for RVPG0\n", ioc->name);
1830 return;
1831 }
1832
1833 if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
1834 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
1835 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1836 "Failure in retrieving RVPG0\n", ioc->name);
1837 kfree(vol_pg0);
1838 return;
1839 }
1840
1841 /*
1842 * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
1843 * assumed for WARPDRIVE, disable direct I/O
1844 */
1845 if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
1846 printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled "
1847 "for the drive with handle(0x%04x): num_mem=%d, "
1848 "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
1849 num_pds, MPT_MAX_WARPDRIVE_PDS);
1850 kfree(vol_pg0);
1851 return;
1852 }
1853 for (count = 0; count < num_pds; count++) {
1854 if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
1855 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
1856 vol_pg0->PhysDisk[count].PhysDiskNum) ||
1857 pd_pg0.DevHandle == MPT2SAS_INVALID_DEVICE_HANDLE) {
1858 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
1859 "disabled for the drive with handle(0x%04x) member"
1860 "handle retrieval failed for member number=%d\n",
1861 ioc->name, raid_device->handle,
1862 vol_pg0->PhysDisk[count].PhysDiskNum);
1863 goto out_error;
1864 }
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05301865 /* Disable direct I/O if member drive lba exceeds 4 bytes */
1866 dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA);
1867 if (dev_max_lba >> 32) {
1868 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
1869 "disabled for the drive with handle(0x%04x) member"
1870 "handle (0x%04x) unsupported max lba 0x%016llx\n",
1871 ioc->name, raid_device->handle,
1872 le16_to_cpu(pd_pg0.DevHandle),
1873 (unsigned long long)dev_max_lba);
1874 goto out_error;
1875 }
1876
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301877 raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
1878 }
1879
1880 /*
1881 * Assumption for WD: Direct I/O is not supported if the volume is
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05301882 * not RAID0
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301883 */
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05301884 if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301885 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1886 "for the drive with handle(0x%04x): type=%d, "
1887 "s_sz=%uK, blk_size=%u\n", ioc->name,
1888 raid_device->handle, raid_device->volume_type,
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05301889 (le32_to_cpu(vol_pg0->StripeSize) *
1890 le16_to_cpu(vol_pg0->BlockSize)) / 1024,
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301891 le16_to_cpu(vol_pg0->BlockSize));
1892 goto out_error;
1893 }
1894
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301895 stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05301896 stripe_exp = find_first_bit(&stripe_sz, 32);
1897 if (stripe_exp == 32) {
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301898 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05301899 "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301900 ioc->name, raid_device->handle,
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05301901 (le32_to_cpu(vol_pg0->StripeSize) *
1902 le16_to_cpu(vol_pg0->BlockSize)) / 1024);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301903 goto out_error;
1904 }
1905 raid_device->stripe_exponent = stripe_exp;
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05301906 block_sz = le16_to_cpu(vol_pg0->BlockSize);
1907 block_exp = find_first_bit(&block_sz, 16);
1908 if (block_exp == 16) {
1909 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
1910 "for the drive with handle(0x%04x) invalid block sz %u\n",
1911 ioc->name, raid_device->handle,
1912 le16_to_cpu(vol_pg0->BlockSize));
1913 goto out_error;
1914 }
1915 raid_device->block_exponent = block_exp;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05301916 raid_device->direct_io_enabled = 1;
1917
1918 printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive"
1919 " with handle(0x%04x)\n", ioc->name, raid_device->handle);
1920 /*
1921 * WARPDRIVE: Though the following fields are not used for direct IO,
1922 * stored for future purpose:
1923 */
1924 raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
1925 raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
1926 raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
1927
1928
1929 kfree(vol_pg0);
1930 return;
1931
1932out_error:
1933 raid_device->direct_io_enabled = 0;
1934 for (count = 0; count < num_pds; count++)
1935 raid_device->pd_handle[count] = 0;
1936 kfree(vol_pg0);
1937 return;
1938}
Eric Moore635374e2009-03-09 01:21:12 -06001939
1940/**
Kashyap, Desai84f0b042009-12-16 18:56:28 +05301941 * _scsih_enable_tlr - setting TLR flags
1942 * @ioc: per adapter object
1943 * @sdev: scsi device struct
1944 *
1945 * Enabling Transaction Layer Retries for tape devices when
1946 * vpd page 0x90 is present
1947 *
1948 */
1949static void
1950_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev)
1951{
1952 /* only for TAPE */
1953 if (sdev->type != TYPE_TAPE)
1954 return;
1955
1956 if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR))
1957 return;
1958
1959 sas_enable_tlr(sdev);
1960 sdev_printk(KERN_INFO, sdev, "TLR %s\n",
1961 sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled");
1962 return;
1963
1964}
1965
1966/**
Eric Moored5d135b2009-05-18 13:02:08 -06001967 * _scsih_slave_configure - device configure routine.
Eric Moore635374e2009-03-09 01:21:12 -06001968 * @sdev: scsi device struct
1969 *
1970 * Returns 0 if ok. Any other return is assumed to be an error and
1971 * the device is ignored.
1972 */
1973static int
Eric Moored5d135b2009-05-18 13:02:08 -06001974_scsih_slave_configure(struct scsi_device *sdev)
Eric Moore635374e2009-03-09 01:21:12 -06001975{
1976 struct Scsi_Host *shost = sdev->host;
1977 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1978 struct MPT2SAS_DEVICE *sas_device_priv_data;
1979 struct MPT2SAS_TARGET *sas_target_priv_data;
1980 struct _sas_device *sas_device;
1981 struct _raid_device *raid_device;
1982 unsigned long flags;
1983 int qdepth;
1984 u8 ssp_target = 0;
1985 char *ds = "";
1986 char *r_level = "";
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301987 u16 handle, volume_handle = 0;
1988 u64 volume_wwid = 0;
Eric Moore635374e2009-03-09 01:21:12 -06001989
1990 qdepth = 1;
1991 sas_device_priv_data = sdev->hostdata;
1992 sas_device_priv_data->configured_lun = 1;
1993 sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
1994 sas_target_priv_data = sas_device_priv_data->sas_target;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05301995 handle = sas_target_priv_data->handle;
Eric Moore635374e2009-03-09 01:21:12 -06001996
1997 /* raid volume handling */
1998 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
1999
2000 spin_lock_irqsave(&ioc->raid_device_lock, flags);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05302001 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
Eric Moore635374e2009-03-09 01:21:12 -06002002 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
2003 if (!raid_device) {
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05302004 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
2005 "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
2006 __LINE__, __func__));
2007 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06002008 }
2009
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05302010 if (_scsih_get_volume_capabilities(ioc, raid_device)) {
2011 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
2012 "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
2013 __LINE__, __func__));
2014 return 1;
2015 }
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302016 /*
2017 * WARPDRIVE: Initialize the required data for Direct IO
2018 */
2019 _scsih_init_warpdrive_properties(ioc, raid_device);
2020
Eric Moore635374e2009-03-09 01:21:12 -06002021 /* RAID Queue Depth Support
2022 * IS volume = underlying qdepth of drive type, either
2023 * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
2024 * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
2025 */
2026 if (raid_device->device_info &
2027 MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
2028 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
2029 ds = "SSP";
2030 } else {
2031 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
2032 if (raid_device->device_info &
2033 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
2034 ds = "SATA";
2035 else
2036 ds = "STP";
2037 }
2038
2039 switch (raid_device->volume_type) {
2040 case MPI2_RAID_VOL_TYPE_RAID0:
2041 r_level = "RAID0";
2042 break;
2043 case MPI2_RAID_VOL_TYPE_RAID1E:
2044 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
Kashyap, Desaied79f122009-08-20 13:23:49 +05302045 if (ioc->manu_pg10.OEMIdentifier &&
Kashyap, Desaic97951e2011-06-14 10:54:56 +05302046 (le32_to_cpu(ioc->manu_pg10.GenericFlags0) &
Kashyap, Desaied79f122009-08-20 13:23:49 +05302047 MFG10_GF0_R10_DISPLAY) &&
2048 !(raid_device->num_pds % 2))
2049 r_level = "RAID10";
2050 else
2051 r_level = "RAID1E";
Eric Moore635374e2009-03-09 01:21:12 -06002052 break;
2053 case MPI2_RAID_VOL_TYPE_RAID1:
2054 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
2055 r_level = "RAID1";
2056 break;
2057 case MPI2_RAID_VOL_TYPE_RAID10:
2058 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
2059 r_level = "RAID10";
2060 break;
2061 case MPI2_RAID_VOL_TYPE_UNKNOWN:
2062 default:
2063 qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
2064 r_level = "RAIDX";
2065 break;
2066 }
2067
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302068 if (!ioc->hide_ir_msg)
2069 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
2070 "wwid(0x%016llx), pd_count(%d), type(%s)\n",
2071 r_level, raid_device->handle,
2072 (unsigned long long)raid_device->wwid,
2073 raid_device->num_pds, ds);
Mike Christiee881a172009-10-15 17:46:39 -07002074 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05302075 /* raid transport support */
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302076 if (!ioc->is_warpdrive)
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05302077 _scsih_set_level(sdev, raid_device->volume_type);
Eric Moore635374e2009-03-09 01:21:12 -06002078 return 0;
2079 }
2080
2081 /* non-raid handling */
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05302082 if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
2083 if (mpt2sas_config_get_volume_handle(ioc, handle,
2084 &volume_handle)) {
2085 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
2086 "failure at %s:%d/%s()!\n", ioc->name,
2087 __FILE__, __LINE__, __func__));
2088 return 1;
2089 }
2090 if (volume_handle && mpt2sas_config_get_volume_wwid(ioc,
2091 volume_handle, &volume_wwid)) {
2092 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
2093 "failure at %s:%d/%s()!\n", ioc->name,
2094 __FILE__, __LINE__, __func__));
2095 return 1;
2096 }
2097 }
2098
Eric Moore635374e2009-03-09 01:21:12 -06002099 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2100 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2101 sas_device_priv_data->sas_target->sas_address);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05302102 if (!sas_device) {
2103 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05302104 dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05302105 "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
2106 __LINE__, __func__));
nagalakshmi.nandigama@lsi.com6faace22011-10-19 15:37:37 +05302107 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06002108 }
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05302109 sas_device->volume_handle = volume_handle;
2110 sas_device->volume_wwid = volume_wwid;
2111 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
2112 qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
2113 ssp_target = 1;
2114 ds = "SSP";
2115 } else {
2116 qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
2117 if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
2118 ds = "STP";
2119 else if (sas_device->device_info &
2120 MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
2121 ds = "SATA";
2122 }
2123 sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
2124 "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
2125 ds, sas_device->handle,
2126 (unsigned long long)sas_device->sas_address,
2127 sas_device->phy,
2128 (unsigned long long)sas_device->device_name);
2129 sdev_printk(KERN_INFO, sdev, "%s: "
2130 "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
2131 (unsigned long long) sas_device->enclosure_logical_id,
2132 sas_device->slot);
2133
2134 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2135 if (!ssp_target)
2136 _scsih_display_sata_capabilities(ioc, handle, sdev);
2137
Eric Moore635374e2009-03-09 01:21:12 -06002138
Mike Christiee881a172009-10-15 17:46:39 -07002139 _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
Eric Moore635374e2009-03-09 01:21:12 -06002140
Kashyap, Desai84f0b042009-12-16 18:56:28 +05302141 if (ssp_target) {
Eric Moore635374e2009-03-09 01:21:12 -06002142 sas_read_port_mode_page(sdev);
Kashyap, Desai84f0b042009-12-16 18:56:28 +05302143 _scsih_enable_tlr(ioc, sdev);
2144 }
Eric Moore635374e2009-03-09 01:21:12 -06002145 return 0;
2146}
2147
2148/**
Eric Moored5d135b2009-05-18 13:02:08 -06002149 * _scsih_bios_param - fetch head, sector, cylinder info for a disk
Eric Moore635374e2009-03-09 01:21:12 -06002150 * @sdev: scsi device struct
2151 * @bdev: pointer to block device context
2152 * @capacity: device size (in 512 byte sectors)
2153 * @params: three element array to place output:
2154 * params[0] number of heads (max 255)
2155 * params[1] number of sectors (max 63)
2156 * params[2] number of cylinders
2157 *
2158 * Return nothing.
2159 */
2160static int
Eric Moored5d135b2009-05-18 13:02:08 -06002161_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
Eric Moore635374e2009-03-09 01:21:12 -06002162 sector_t capacity, int params[])
2163{
2164 int heads;
2165 int sectors;
2166 sector_t cylinders;
2167 ulong dummy;
2168
2169 heads = 64;
2170 sectors = 32;
2171
2172 dummy = heads * sectors;
2173 cylinders = capacity;
2174 sector_div(cylinders, dummy);
2175
2176 /*
2177 * Handle extended translation size for logical drives
2178 * > 1Gb
2179 */
2180 if ((ulong)capacity >= 0x200000) {
2181 heads = 255;
2182 sectors = 63;
2183 dummy = heads * sectors;
2184 cylinders = capacity;
2185 sector_div(cylinders, dummy);
2186 }
2187
2188 /* return result */
2189 params[0] = heads;
2190 params[1] = sectors;
2191 params[2] = cylinders;
2192
2193 return 0;
2194}
2195
2196/**
2197 * _scsih_response_code - translation of device response code
2198 * @ioc: per adapter object
2199 * @response_code: response code returned by the device
2200 *
2201 * Return nothing.
2202 */
2203static void
2204_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
2205{
2206 char *desc;
2207
2208 switch (response_code) {
2209 case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
2210 desc = "task management request completed";
2211 break;
2212 case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
2213 desc = "invalid frame";
2214 break;
2215 case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
2216 desc = "task management request not supported";
2217 break;
2218 case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
2219 desc = "task management request failed";
2220 break;
2221 case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
2222 desc = "task management request succeeded";
2223 break;
2224 case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
2225 desc = "invalid lun";
2226 break;
2227 case 0xA:
2228 desc = "overlapped tag attempted";
2229 break;
2230 case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
2231 desc = "task queued, however not sent to target";
2232 break;
2233 default:
2234 desc = "unknown";
2235 break;
2236 }
2237 printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
2238 ioc->name, response_code, desc);
2239}
2240
2241/**
Eric Moored5d135b2009-05-18 13:02:08 -06002242 * _scsih_tm_done - tm completion routine
Eric Moore635374e2009-03-09 01:21:12 -06002243 * @ioc: per adapter object
2244 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302245 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06002246 * @reply: reply message frame(lower 32bit addr)
2247 * Context: none.
2248 *
2249 * The callback handler when using scsih_issue_tm.
2250 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302251 * Return 1 meaning mf should be freed from _base_interrupt
2252 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06002253 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302254static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302255_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06002256{
2257 MPI2DefaultReply_t *mpi_reply;
2258
2259 if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302260 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06002261 if (ioc->tm_cmds.smid != smid)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302262 return 1;
nagalakshmi.nandigama@lsi.com911ae942011-09-08 06:18:50 +05302263 mpt2sas_base_flush_reply_queues(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06002264 ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
2265 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
2266 if (mpi_reply) {
2267 memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
2268 ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
2269 }
2270 ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
2271 complete(&ioc->tm_cmds.done);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05302272 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06002273}
2274
2275/**
2276 * mpt2sas_scsih_set_tm_flag - set per target tm_busy
2277 * @ioc: per adapter object
2278 * @handle: device handle
2279 *
2280 * During taskmangement request, we need to freeze the device queue.
2281 */
2282void
2283mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2284{
2285 struct MPT2SAS_DEVICE *sas_device_priv_data;
2286 struct scsi_device *sdev;
2287 u8 skip = 0;
2288
2289 shost_for_each_device(sdev, ioc->shost) {
2290 if (skip)
2291 continue;
2292 sas_device_priv_data = sdev->hostdata;
2293 if (!sas_device_priv_data)
2294 continue;
2295 if (sas_device_priv_data->sas_target->handle == handle) {
2296 sas_device_priv_data->sas_target->tm_busy = 1;
2297 skip = 1;
2298 ioc->ignore_loginfos = 1;
2299 }
2300 }
2301}
2302
2303/**
2304 * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
2305 * @ioc: per adapter object
2306 * @handle: device handle
2307 *
2308 * During taskmangement request, we need to freeze the device queue.
2309 */
2310void
2311mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2312{
2313 struct MPT2SAS_DEVICE *sas_device_priv_data;
2314 struct scsi_device *sdev;
2315 u8 skip = 0;
2316
2317 shost_for_each_device(sdev, ioc->shost) {
2318 if (skip)
2319 continue;
2320 sas_device_priv_data = sdev->hostdata;
2321 if (!sas_device_priv_data)
2322 continue;
2323 if (sas_device_priv_data->sas_target->handle == handle) {
2324 sas_device_priv_data->sas_target->tm_busy = 0;
2325 skip = 1;
2326 ioc->ignore_loginfos = 0;
2327 }
2328 }
2329}
2330
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302331
Eric Moore635374e2009-03-09 01:21:12 -06002332/**
2333 * mpt2sas_scsih_issue_tm - main routine for sending tm requests
2334 * @ioc: per adapter struct
2335 * @device_handle: device handle
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302336 * @channel: the channel assigned by the OS
2337 * @id: the id assigned by the OS
Eric Moore635374e2009-03-09 01:21:12 -06002338 * @lun: lun number
2339 * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
2340 * @smid_task: smid assigned to the task
2341 * @timeout: timeout in seconds
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302342 * @serial_number: the serial_number from scmd
2343 * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302344 * Context: user
Eric Moore635374e2009-03-09 01:21:12 -06002345 *
2346 * A generic API for sending task management requests to firmware.
2347 *
Eric Moore635374e2009-03-09 01:21:12 -06002348 * The callback index is set inside `ioc->tm_cb_idx`.
2349 *
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302350 * Return SUCCESS or FAILED.
Eric Moore635374e2009-03-09 01:21:12 -06002351 */
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302352int
2353mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
2354 uint id, uint lun, u8 type, u16 smid_task, ulong timeout,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302355 unsigned long serial_number, enum mutex_type m_type)
Eric Moore635374e2009-03-09 01:21:12 -06002356{
2357 Mpi2SCSITaskManagementRequest_t *mpi_request;
2358 Mpi2SCSITaskManagementReply_t *mpi_reply;
2359 u16 smid = 0;
2360 u32 ioc_state;
2361 unsigned long timeleft;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302362 struct scsiio_tracker *scsi_lookup = NULL;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302363 int rc;
Eric Moore635374e2009-03-09 01:21:12 -06002364
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302365 if (m_type == TM_MUTEX_ON)
2366 mutex_lock(&ioc->tm_cmds.mutex);
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302367 if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
2368 printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
2369 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302370 rc = FAILED;
2371 goto err_out;
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05302372 }
2373
Eric Moore3cb54692010-07-08 14:44:34 -06002374 if (ioc->shost_recovery || ioc->remove_host ||
2375 ioc->pci_error_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06002376 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
2377 __func__, ioc->name);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302378 rc = FAILED;
2379 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002380 }
Eric Moore635374e2009-03-09 01:21:12 -06002381
2382 ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
2383 if (ioc_state & MPI2_DOORBELL_USED) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05302384 dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
Eric Moore635374e2009-03-09 01:21:12 -06002385 "active!\n", ioc->name));
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302386 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302387 FORCE_BIG_HAMMER);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302388 rc = (!rc) ? SUCCESS : FAILED;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302389 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002390 }
2391
2392 if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
2393 mpt2sas_base_fault_info(ioc, ioc_state &
2394 MPI2_DOORBELL_DATA_MASK);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302395 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302396 FORCE_BIG_HAMMER);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302397 rc = (!rc) ? SUCCESS : FAILED;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302398 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002399 }
2400
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302401 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06002402 if (!smid) {
2403 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
2404 ioc->name, __func__);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302405 rc = FAILED;
2406 goto err_out;
Eric Moore635374e2009-03-09 01:21:12 -06002407 }
2408
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302409 if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
2410 scsi_lookup = &ioc->scsi_lookup[smid_task - 1];
2411
Eric Moore635374e2009-03-09 01:21:12 -06002412 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302413 " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
2414 smid_task));
Eric Moore635374e2009-03-09 01:21:12 -06002415 ioc->tm_cmds.status = MPT2_CMD_PENDING;
2416 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
2417 ioc->tm_cmds.smid = smid;
2418 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302419 memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t));
Eric Moore635374e2009-03-09 01:21:12 -06002420 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2421 mpi_request->DevHandle = cpu_to_le16(handle);
2422 mpi_request->TaskType = type;
2423 mpi_request->TaskMID = cpu_to_le16(smid_task);
2424 int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
2425 mpt2sas_scsih_set_tm_flag(ioc, handle);
Kashyap, Desai5b768582009-08-20 13:24:31 +05302426 init_completion(&ioc->tm_cmds.done);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05302427 mpt2sas_base_put_smid_hi_priority(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06002428 timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
Eric Moore635374e2009-03-09 01:21:12 -06002429 if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
2430 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
2431 ioc->name, __func__);
2432 _debug_dump_mf(mpi_request,
2433 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302434 if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) {
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302435 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302436 FORCE_BIG_HAMMER);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302437 rc = (!rc) ? SUCCESS : FAILED;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302438 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
2439 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2440 goto err_out;
2441 }
Eric Moore635374e2009-03-09 01:21:12 -06002442 }
2443
2444 if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
2445 mpi_reply = ioc->tm_cmds.reply;
2446 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
2447 "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
2448 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
2449 le32_to_cpu(mpi_reply->IOCLogInfo),
2450 le32_to_cpu(mpi_reply->TerminationCount)));
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302451 if (ioc->logging_level & MPT_DEBUG_TM) {
Eric Moore635374e2009-03-09 01:21:12 -06002452 _scsih_response_code(ioc, mpi_reply->ResponseCode);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302453 if (mpi_reply->IOCStatus)
2454 _debug_dump_mf(mpi_request,
2455 sizeof(Mpi2SCSITaskManagementRequest_t)/4);
2456 }
Eric Moore635374e2009-03-09 01:21:12 -06002457 }
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302458
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302459 switch (type) {
2460 case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302461 rc = SUCCESS;
2462 if (scsi_lookup->scmd == NULL)
2463 break;
2464 rc = FAILED;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302465 break;
2466
2467 case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
2468 if (_scsih_scsi_lookup_find_by_target(ioc, id, channel))
2469 rc = FAILED;
2470 else
2471 rc = SUCCESS;
2472 break;
2473
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302474 case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302475 case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
2476 if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel))
2477 rc = FAILED;
2478 else
2479 rc = SUCCESS;
2480 break;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302481 case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
2482 rc = SUCCESS;
2483 break;
2484 default:
2485 rc = FAILED;
2486 break;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302487 }
2488
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302489 mpt2sas_scsih_clear_tm_flag(ioc, handle);
2490 ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302491 if (m_type == TM_MUTEX_ON)
2492 mutex_unlock(&ioc->tm_cmds.mutex);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302493
2494 return rc;
2495
2496 err_out:
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302497 if (m_type == TM_MUTEX_ON)
2498 mutex_unlock(&ioc->tm_cmds.mutex);
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302499 return rc;
Eric Moore635374e2009-03-09 01:21:12 -06002500}
2501
2502/**
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302503 * _scsih_tm_display_info - displays info about the device
2504 * @ioc: per adapter struct
2505 * @scmd: pointer to scsi command object
2506 *
2507 * Called by task management callback handlers.
2508 */
2509static void
2510_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
2511{
2512 struct scsi_target *starget = scmd->device->sdev_target;
2513 struct MPT2SAS_TARGET *priv_target = starget->hostdata;
2514 struct _sas_device *sas_device = NULL;
2515 unsigned long flags;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302516 char *device_str = NULL;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302517
2518 if (!priv_target)
2519 return;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302520 if (ioc->hide_ir_msg)
2521 device_str = "WarpDrive";
2522 else
2523 device_str = "volume";
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302524
2525 scsi_print_command(scmd);
2526 if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05302527 starget_printk(KERN_INFO, starget, "%s handle(0x%04x), "
2528 "%s wwid(0x%016llx)\n", device_str, priv_target->handle,
2529 device_str, (unsigned long long)priv_target->sas_address);
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302530 } else {
2531 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2532 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
2533 priv_target->sas_address);
2534 if (sas_device) {
2535 if (priv_target->flags &
2536 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2537 starget_printk(KERN_INFO, starget,
2538 "volume handle(0x%04x), "
2539 "volume wwid(0x%016llx)\n",
2540 sas_device->volume_handle,
2541 (unsigned long long)sas_device->volume_wwid);
2542 }
2543 starget_printk(KERN_INFO, starget,
2544 "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
2545 sas_device->handle,
2546 (unsigned long long)sas_device->sas_address,
2547 sas_device->phy);
2548 starget_printk(KERN_INFO, starget,
2549 "enclosure_logical_id(0x%016llx), slot(%d)\n",
2550 (unsigned long long)sas_device->enclosure_logical_id,
2551 sas_device->slot);
2552 }
2553 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2554 }
2555}
2556
2557/**
Eric Moored5d135b2009-05-18 13:02:08 -06002558 * _scsih_abort - eh threads main abort routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302559 * @scmd: pointer to scsi command object
Eric Moore635374e2009-03-09 01:21:12 -06002560 *
2561 * Returns SUCCESS if command aborted else FAILED
2562 */
2563static int
Eric Moored5d135b2009-05-18 13:02:08 -06002564_scsih_abort(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002565{
2566 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2567 struct MPT2SAS_DEVICE *sas_device_priv_data;
2568 u16 smid;
2569 u16 handle;
2570 int r;
Eric Moore635374e2009-03-09 01:21:12 -06002571
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302572 sdev_printk(KERN_INFO, scmd->device, "attempting task abort! "
2573 "scmd(%p)\n", scmd);
2574 _scsih_tm_display_info(ioc, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002575
2576 sas_device_priv_data = scmd->device->hostdata;
2577 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302578 sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
2579 "scmd(%p)\n", scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002580 scmd->result = DID_NO_CONNECT << 16;
2581 scmd->scsi_done(scmd);
2582 r = SUCCESS;
2583 goto out;
2584 }
2585
2586 /* search for the command */
2587 smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
2588 if (!smid) {
2589 scmd->result = DID_RESET << 16;
2590 r = SUCCESS;
2591 goto out;
2592 }
2593
2594 /* for hidden raid components and volumes this is not supported */
2595 if (sas_device_priv_data->sas_target->flags &
2596 MPT_TARGET_FLAGS_RAID_COMPONENT ||
2597 sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
2598 scmd->result = DID_RESET << 16;
2599 r = FAILED;
2600 goto out;
2601 }
2602
Kashyap, Desaifa7f3162009-09-23 17:26:58 +05302603 mpt2sas_halt_firmware(ioc);
2604
Eric Moore635374e2009-03-09 01:21:12 -06002605 handle = sas_device_priv_data->sas_target->handle;
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302606 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2607 scmd->device->id, scmd->device->lun,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302608 MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
2609 scmd->serial_number, TM_MUTEX_ON);
Eric Moore635374e2009-03-09 01:21:12 -06002610
2611 out:
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302612 sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
2613 ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002614 return r;
2615}
2616
Eric Moore635374e2009-03-09 01:21:12 -06002617/**
Eric Moored5d135b2009-05-18 13:02:08 -06002618 * _scsih_dev_reset - eh threads main device reset routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302619 * @scmd: pointer to scsi command object
Eric Moore635374e2009-03-09 01:21:12 -06002620 *
2621 * Returns SUCCESS if command aborted else FAILED
2622 */
2623static int
Eric Moored5d135b2009-05-18 13:02:08 -06002624_scsih_dev_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002625{
2626 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2627 struct MPT2SAS_DEVICE *sas_device_priv_data;
2628 struct _sas_device *sas_device;
2629 unsigned long flags;
2630 u16 handle;
2631 int r;
2632
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302633 struct scsi_target *starget = scmd->device->sdev_target;
2634
Kashyap, Desai37aaa782010-11-13 04:41:32 +05302635 starget_printk(KERN_INFO, starget, "attempting device reset! "
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302636 "scmd(%p)\n", scmd);
2637 _scsih_tm_display_info(ioc, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002638
2639 sas_device_priv_data = scmd->device->hostdata;
2640 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Kashyap, Desai37aaa782010-11-13 04:41:32 +05302641 starget_printk(KERN_INFO, starget, "device been deleted! "
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302642 "scmd(%p)\n", scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002643 scmd->result = DID_NO_CONNECT << 16;
2644 scmd->scsi_done(scmd);
2645 r = SUCCESS;
2646 goto out;
2647 }
2648
2649 /* for hidden raid components obtain the volume_handle */
2650 handle = 0;
2651 if (sas_device_priv_data->sas_target->flags &
2652 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2653 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2654 sas_device = _scsih_sas_device_find_by_handle(ioc,
2655 sas_device_priv_data->sas_target->handle);
2656 if (sas_device)
2657 handle = sas_device->volume_handle;
2658 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2659 } else
2660 handle = sas_device_priv_data->sas_target->handle;
2661
2662 if (!handle) {
2663 scmd->result = DID_RESET << 16;
2664 r = FAILED;
2665 goto out;
2666 }
2667
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302668 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2669 scmd->device->id, scmd->device->lun,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302670 MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, 0,
2671 TM_MUTEX_ON);
Eric Moore993e0da2009-05-18 13:00:45 -06002672
2673 out:
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302674 sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
2675 ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002676 return r;
2677}
2678
2679/**
Eric Moored5d135b2009-05-18 13:02:08 -06002680 * _scsih_target_reset - eh threads main target reset routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302681 * @scmd: pointer to scsi command object
Eric Moore993e0da2009-05-18 13:00:45 -06002682 *
2683 * Returns SUCCESS if command aborted else FAILED
2684 */
2685static int
Eric Moored5d135b2009-05-18 13:02:08 -06002686_scsih_target_reset(struct scsi_cmnd *scmd)
Eric Moore993e0da2009-05-18 13:00:45 -06002687{
2688 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2689 struct MPT2SAS_DEVICE *sas_device_priv_data;
2690 struct _sas_device *sas_device;
2691 unsigned long flags;
2692 u16 handle;
2693 int r;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302694 struct scsi_target *starget = scmd->device->sdev_target;
Eric Moore993e0da2009-05-18 13:00:45 -06002695
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302696 starget_printk(KERN_INFO, starget, "attempting target reset! "
2697 "scmd(%p)\n", scmd);
2698 _scsih_tm_display_info(ioc, scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002699
2700 sas_device_priv_data = scmd->device->hostdata;
2701 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302702 starget_printk(KERN_INFO, starget, "target been deleted! "
2703 "scmd(%p)\n", scmd);
Eric Moore993e0da2009-05-18 13:00:45 -06002704 scmd->result = DID_NO_CONNECT << 16;
2705 scmd->scsi_done(scmd);
2706 r = SUCCESS;
2707 goto out;
2708 }
2709
2710 /* for hidden raid components obtain the volume_handle */
2711 handle = 0;
2712 if (sas_device_priv_data->sas_target->flags &
2713 MPT_TARGET_FLAGS_RAID_COMPONENT) {
2714 spin_lock_irqsave(&ioc->sas_device_lock, flags);
2715 sas_device = _scsih_sas_device_find_by_handle(ioc,
2716 sas_device_priv_data->sas_target->handle);
2717 if (sas_device)
2718 handle = sas_device->volume_handle;
2719 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
2720 } else
2721 handle = sas_device_priv_data->sas_target->handle;
2722
2723 if (!handle) {
2724 scmd->result = DID_RESET << 16;
2725 r = FAILED;
2726 goto out;
2727 }
2728
Kashyap, Desai8ed9a032010-03-17 16:25:59 +05302729 r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
2730 scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302731 30, 0, TM_MUTEX_ON);
Eric Moore635374e2009-03-09 01:21:12 -06002732
2733 out:
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302734 starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
2735 ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
Eric Moore635374e2009-03-09 01:21:12 -06002736 return r;
2737}
2738
2739/**
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05302740 * _scsih_host_reset - eh threads main host reset routine
Kashyap, Desai8e864a82010-06-17 13:48:46 +05302741 * @scmd: pointer to scsi command object
Eric Moore635374e2009-03-09 01:21:12 -06002742 *
2743 * Returns SUCCESS if command aborted else FAILED
2744 */
2745static int
Eric Moored5d135b2009-05-18 13:02:08 -06002746_scsih_host_reset(struct scsi_cmnd *scmd)
Eric Moore635374e2009-03-09 01:21:12 -06002747{
2748 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
2749 int r, retval;
2750
2751 printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
2752 ioc->name, scmd);
2753 scsi_print_command(scmd);
2754
2755 retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
2756 FORCE_BIG_HAMMER);
2757 r = (retval < 0) ? FAILED : SUCCESS;
2758 printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
2759 ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
2760
2761 return r;
2762}
2763
2764/**
2765 * _scsih_fw_event_add - insert and queue up fw_event
2766 * @ioc: per adapter object
2767 * @fw_event: object describing the event
2768 * Context: This function will acquire ioc->fw_event_lock.
2769 *
2770 * This adds the firmware event object into link list, then queues it up to
2771 * be processed from user context.
2772 *
2773 * Return nothing.
2774 */
2775static void
2776_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
2777{
2778 unsigned long flags;
2779
2780 if (ioc->firmware_event_thread == NULL)
2781 return;
2782
2783 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2784 list_add_tail(&fw_event->list, &ioc->fw_event_list);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302785 INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work);
2786 queue_delayed_work(ioc->firmware_event_thread,
2787 &fw_event->delayed_work, 0);
Eric Moore635374e2009-03-09 01:21:12 -06002788 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2789}
2790
2791/**
2792 * _scsih_fw_event_free - delete fw_event
2793 * @ioc: per adapter object
2794 * @fw_event: object describing the event
2795 * Context: This function will acquire ioc->fw_event_lock.
2796 *
2797 * This removes firmware event object from link list, frees associated memory.
2798 *
2799 * Return nothing.
2800 */
2801static void
2802_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
2803 *fw_event)
2804{
2805 unsigned long flags;
2806
2807 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2808 list_del(&fw_event->list);
2809 kfree(fw_event->event_data);
2810 kfree(fw_event);
2811 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2812}
2813
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302814
Eric Moore635374e2009-03-09 01:21:12 -06002815/**
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05302816 * _scsih_error_recovery_delete_devices - remove devices not responding
Eric Moore635374e2009-03-09 01:21:12 -06002817 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06002818 *
2819 * Return nothing.
2820 */
2821static void
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05302822_scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06002823{
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302824 struct fw_event_work *fw_event;
2825
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05302826 if (ioc->is_driver_loading)
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302827 return;
Dan Carpenter181a9d72011-11-04 21:25:01 +03002828
2829 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
2830 if (!fw_event)
2831 return;
2832
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05302833 fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES;
2834 fw_event->ioc = ioc;
2835 _scsih_fw_event_add(ioc, fw_event);
2836}
2837
2838/**
2839 * mpt2sas_port_enable_complete - port enable completed (fake event)
2840 * @ioc: per adapter object
2841 *
2842 * Return nothing.
2843 */
2844void
2845mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc)
2846{
2847 struct fw_event_work *fw_event;
2848
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302849 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
2850 if (!fw_event)
2851 return;
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05302852 fw_event->event = MPT2SAS_PORT_ENABLE_COMPLETE;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302853 fw_event->ioc = ioc;
2854 _scsih_fw_event_add(ioc, fw_event);
2855}
2856
2857/**
2858 * _scsih_fw_event_cleanup_queue - cleanup event queue
2859 * @ioc: per adapter object
2860 *
2861 * Walk the firmware event queue, either killing timers, or waiting
2862 * for outstanding events to complete
2863 *
2864 * Return nothing.
2865 */
2866static void
2867_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)
2868{
2869 struct fw_event_work *fw_event, *next;
2870
2871 if (list_empty(&ioc->fw_event_list) ||
2872 !ioc->firmware_event_thread || in_interrupt())
Eric Moore635374e2009-03-09 01:21:12 -06002873 return;
2874
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05302875 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
2876 if (cancel_delayed_work(&fw_event->delayed_work)) {
2877 _scsih_fw_event_free(ioc, fw_event);
2878 continue;
2879 }
2880 fw_event->cancel_pending_work = 1;
2881 }
Eric Moore635374e2009-03-09 01:21:12 -06002882}
2883
Eric Moore635374e2009-03-09 01:21:12 -06002884/**
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302885 * _scsih_ublock_io_all_device - unblock every device
2886 * @ioc: per adapter object
2887 *
2888 * change the device state from block to running
2889 */
2890static void
2891_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc)
2892{
2893 struct MPT2SAS_DEVICE *sas_device_priv_data;
2894 struct scsi_device *sdev;
2895
2896 shost_for_each_device(sdev, ioc->shost) {
2897 sas_device_priv_data = sdev->hostdata;
2898 if (!sas_device_priv_data)
2899 continue;
2900 if (!sas_device_priv_data->block)
2901 continue;
2902 sas_device_priv_data->block = 0;
2903 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, "
2904 "handle(0x%04x)\n",
2905 sas_device_priv_data->sas_target->handle));
2906 scsi_internal_device_unblock(sdev);
2907 }
2908}
2909/**
Eric Moore635374e2009-03-09 01:21:12 -06002910 * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
2911 * @ioc: per adapter object
2912 * @handle: device handle
2913 *
2914 * During device pull we need to appropiately set the sdev state.
2915 */
2916static void
2917_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2918{
2919 struct MPT2SAS_DEVICE *sas_device_priv_data;
2920 struct scsi_device *sdev;
2921
2922 shost_for_each_device(sdev, ioc->shost) {
2923 sas_device_priv_data = sdev->hostdata;
2924 if (!sas_device_priv_data)
2925 continue;
2926 if (!sas_device_priv_data->block)
2927 continue;
2928 if (sas_device_priv_data->sas_target->handle == handle) {
2929 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2930 MPT2SAS_INFO_FMT "SDEV_RUNNING: "
2931 "handle(0x%04x)\n", ioc->name, handle));
2932 sas_device_priv_data->block = 0;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302933 scsi_internal_device_unblock(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002934 }
2935 }
2936}
2937
2938/**
Kashyap, Desaif93213d2011-06-14 10:56:43 +05302939 * _scsih_block_io_all_device - set the device state to SDEV_BLOCK
2940 * @ioc: per adapter object
2941 * @handle: device handle
2942 *
2943 * During device pull we need to appropiately set the sdev state.
2944 */
2945static void
2946_scsih_block_io_all_device(struct MPT2SAS_ADAPTER *ioc)
2947{
2948 struct MPT2SAS_DEVICE *sas_device_priv_data;
2949 struct scsi_device *sdev;
2950
2951 shost_for_each_device(sdev, ioc->shost) {
2952 sas_device_priv_data = sdev->hostdata;
2953 if (!sas_device_priv_data)
2954 continue;
2955 if (sas_device_priv_data->block)
2956 continue;
2957 sas_device_priv_data->block = 1;
2958 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, "
2959 "handle(0x%04x)\n",
2960 sas_device_priv_data->sas_target->handle));
2961 scsi_internal_device_block(sdev);
2962 }
2963}
2964
2965
2966/**
Eric Moore635374e2009-03-09 01:21:12 -06002967 * _scsih_block_io_device - set the device state to SDEV_BLOCK
2968 * @ioc: per adapter object
2969 * @handle: device handle
2970 *
2971 * During device pull we need to appropiately set the sdev state.
2972 */
2973static void
2974_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
2975{
2976 struct MPT2SAS_DEVICE *sas_device_priv_data;
2977 struct scsi_device *sdev;
2978
2979 shost_for_each_device(sdev, ioc->shost) {
2980 sas_device_priv_data = sdev->hostdata;
2981 if (!sas_device_priv_data)
2982 continue;
2983 if (sas_device_priv_data->block)
2984 continue;
2985 if (sas_device_priv_data->sas_target->handle == handle) {
2986 dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
2987 MPT2SAS_INFO_FMT "SDEV_BLOCK: "
2988 "handle(0x%04x)\n", ioc->name, handle));
2989 sas_device_priv_data->block = 1;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05302990 scsi_internal_device_block(sdev);
Eric Moore635374e2009-03-09 01:21:12 -06002991 }
2992 }
2993}
2994
2995/**
2996 * _scsih_block_io_to_children_attached_to_ex
2997 * @ioc: per adapter object
2998 * @sas_expander: the sas_device object
2999 *
3000 * This routine set sdev state to SDEV_BLOCK for all devices
3001 * attached to this expander. This function called when expander is
3002 * pulled.
3003 */
3004static void
3005_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
3006 struct _sas_node *sas_expander)
3007{
3008 struct _sas_port *mpt2sas_port;
3009 struct _sas_device *sas_device;
3010 struct _sas_node *expander_sibling;
3011 unsigned long flags;
3012
3013 if (!sas_expander)
3014 return;
3015
3016 list_for_each_entry(mpt2sas_port,
3017 &sas_expander->sas_port_list, port_list) {
3018 if (mpt2sas_port->remote_identify.device_type ==
3019 SAS_END_DEVICE) {
3020 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3021 sas_device =
3022 mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
3023 mpt2sas_port->remote_identify.sas_address);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05303024 if (sas_device)
3025 set_bit(sas_device->handle,
3026 ioc->blocking_handles);
Eric Moore635374e2009-03-09 01:21:12 -06003027 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06003028 }
3029 }
3030
3031 list_for_each_entry(mpt2sas_port,
3032 &sas_expander->sas_port_list, port_list) {
3033
3034 if (mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05303035 SAS_EDGE_EXPANDER_DEVICE ||
Eric Moore635374e2009-03-09 01:21:12 -06003036 mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05303037 SAS_FANOUT_EXPANDER_DEVICE) {
Eric Moore635374e2009-03-09 01:21:12 -06003038 expander_sibling =
3039 mpt2sas_scsih_expander_find_by_sas_address(
3040 ioc, mpt2sas_port->remote_identify.sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06003041 _scsih_block_io_to_children_attached_to_ex(ioc,
3042 expander_sibling);
3043 }
3044 }
3045}
3046
3047/**
3048 * _scsih_block_io_to_children_attached_directly
3049 * @ioc: per adapter object
3050 * @event_data: topology change event data
3051 *
3052 * This routine set sdev state to SDEV_BLOCK for all devices
3053 * direct attached during device pull.
3054 */
3055static void
3056_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
3057 Mpi2EventDataSasTopologyChangeList_t *event_data)
3058{
3059 int i;
3060 u16 handle;
3061 u16 reason_code;
3062 u8 phy_number;
3063
3064 for (i = 0; i < event_data->NumEntries; i++) {
3065 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
3066 if (!handle)
3067 continue;
3068 phy_number = event_data->StartPhyNum + i;
3069 reason_code = event_data->PHY[i].PhyStatus &
3070 MPI2_EVENT_SAS_TOPO_RC_MASK;
3071 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
3072 _scsih_block_io_device(ioc, handle);
3073 }
3074}
3075
3076/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303077 * _scsih_tm_tr_send - send task management request
3078 * @ioc: per adapter object
3079 * @handle: device handle
3080 * Context: interrupt time.
3081 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003082 * This code is to initiate the device removal handshake protocol
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303083 * with controller firmware. This function will issue target reset
3084 * using high priority request queue. It will send a sas iounit
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003085 * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303086 *
3087 * This is designed to send muliple task management request at the same
3088 * time to the fifo. If the fifo is full, we will append the request,
3089 * and process it in a future completion.
3090 */
3091static void
3092_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3093{
3094 Mpi2SCSITaskManagementRequest_t *mpi_request;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303095 u16 smid;
3096 struct _sas_device *sas_device;
nagalakshmi.nandigama@lsi.comf3db0322011-10-19 15:37:14 +05303097 struct MPT2SAS_TARGET *sas_target_priv_data = NULL;
3098 u64 sas_address = 0;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303099 unsigned long flags;
3100 struct _tr_list *delayed_tr;
nagalakshmi.nandigama@lsi.comf881cea2011-10-19 15:37:00 +05303101 u32 ioc_state;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303102
nagalakshmi.nandigama@lsi.comf881cea2011-10-19 15:37:00 +05303103 if (ioc->remove_host) {
3104 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been "
3105 "removed: handle(0x%04x)\n", __func__, ioc->name, handle));
3106 return;
3107 } else if (ioc->pci_error_recovery) {
3108 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci "
3109 "error recovery: handle(0x%04x)\n", __func__, ioc->name,
3110 handle));
3111 return;
3112 }
3113 ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
3114 if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
3115 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not "
3116 "operational: handle(0x%04x)\n", __func__, ioc->name,
3117 handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303118 return;
3119 }
3120
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303121 /* if PD, then return */
3122 if (test_bit(handle, ioc->pd_handles))
3123 return;
3124
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303125 spin_lock_irqsave(&ioc->sas_device_lock, flags);
3126 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303127 if (sas_device && sas_device->starget &&
3128 sas_device->starget->hostdata) {
3129 sas_target_priv_data = sas_device->starget->hostdata;
3130 sas_target_priv_data->deleted = 1;
nagalakshmi.nandigama@lsi.comf3db0322011-10-19 15:37:14 +05303131 sas_address = sas_device->sas_address;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303132 }
3133 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303134
nagalakshmi.nandigama@lsi.comf3db0322011-10-19 15:37:14 +05303135 if (sas_target_priv_data) {
3136 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: "
3137 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle,
3138 (unsigned long long)sas_address));
3139 _scsih_ublock_io_device(ioc, handle);
nagalakshmi.nandigama@lsi.com918134e2011-10-19 15:37:24 +05303140 sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
nagalakshmi.nandigama@lsi.comf3db0322011-10-19 15:37:14 +05303141 }
3142
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303143 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
3144 if (!smid) {
3145 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
3146 if (!delayed_tr)
3147 return;
3148 INIT_LIST_HEAD(&delayed_tr->list);
3149 delayed_tr->handle = handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303150 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
3151 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3152 "DELAYED:tr:handle(0x%04x), (open)\n",
3153 ioc->name, handle));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303154 return;
3155 }
3156
Kashyap, Desai1278b112010-03-09 17:34:13 +05303157 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
3158 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
3159 ioc->tm_tr_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303160 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3161 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
3162 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
3163 mpi_request->DevHandle = cpu_to_le16(handle);
3164 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303165 mpt2sas_base_put_smid_hi_priority(ioc, smid);
3166}
3167
3168
3169
3170/**
3171 * _scsih_sas_control_complete - completion routine
3172 * @ioc: per adapter object
3173 * @smid: system request message index
3174 * @msix_index: MSIX table index supplied by the OS
3175 * @reply: reply message frame(lower 32bit addr)
3176 * Context: interrupt time.
3177 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003178 * This is the sas iounit control completion routine.
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303179 * This code is part of the code to initiate the device removal
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003180 * handshake protocol with controller firmware.
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303181 *
3182 * Return 1 meaning mf should be freed from _base_interrupt
3183 * 0 means the mf is freed from this function.
3184 */
3185static u8
3186_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
3187 u8 msix_index, u32 reply)
3188{
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303189 Mpi2SasIoUnitControlReply_t *mpi_reply =
3190 mpt2sas_base_get_reply_virt_addr(ioc, reply);
nagalakshmi.nandigama@lsi.com298c7942012-03-20 12:07:17 +05303191 if (likely(mpi_reply)) {
3192 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3193 "sc_complete:handle(0x%04x), (open) "
3194 "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
3195 ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
3196 le16_to_cpu(mpi_reply->IOCStatus),
3197 le32_to_cpu(mpi_reply->IOCLogInfo)));
3198 } else {
3199 printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
3200 ioc->name, __FILE__, __LINE__, __func__);
3201 }
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303202 return 1;
3203}
3204
3205/**
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303206 * _scsih_tm_tr_volume_send - send target reset request for volumes
3207 * @ioc: per adapter object
3208 * @handle: device handle
3209 * Context: interrupt time.
3210 *
3211 * This is designed to send muliple task management request at the same
3212 * time to the fifo. If the fifo is full, we will append the request,
3213 * and process it in a future completion.
3214 */
3215static void
3216_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3217{
3218 Mpi2SCSITaskManagementRequest_t *mpi_request;
3219 u16 smid;
3220 struct _tr_list *delayed_tr;
3221
Eric Moore3cb54692010-07-08 14:44:34 -06003222 if (ioc->shost_recovery || ioc->remove_host ||
3223 ioc->pci_error_recovery) {
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303224 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
3225 "progress!\n", __func__, ioc->name));
3226 return;
3227 }
3228
3229 smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx);
3230 if (!smid) {
3231 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
3232 if (!delayed_tr)
3233 return;
3234 INIT_LIST_HEAD(&delayed_tr->list);
3235 delayed_tr->handle = handle;
3236 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list);
3237 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3238 "DELAYED:tr:handle(0x%04x), (open)\n",
3239 ioc->name, handle));
3240 return;
3241 }
3242
3243 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
3244 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
3245 ioc->tm_tr_volume_cb_idx));
3246 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
3247 memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
3248 mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
3249 mpi_request->DevHandle = cpu_to_le16(handle);
3250 mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
3251 mpt2sas_base_put_smid_hi_priority(ioc, smid);
3252}
3253
3254/**
3255 * _scsih_tm_volume_tr_complete - target reset completion
3256 * @ioc: per adapter object
3257 * @smid: system request message index
3258 * @msix_index: MSIX table index supplied by the OS
3259 * @reply: reply message frame(lower 32bit addr)
3260 * Context: interrupt time.
3261 *
3262 * Return 1 meaning mf should be freed from _base_interrupt
3263 * 0 means the mf is freed from this function.
3264 */
3265static u8
3266_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
3267 u8 msix_index, u32 reply)
3268{
3269 u16 handle;
3270 Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
3271 Mpi2SCSITaskManagementReply_t *mpi_reply =
3272 mpt2sas_base_get_reply_virt_addr(ioc, reply);
3273
Eric Moore3cb54692010-07-08 14:44:34 -06003274 if (ioc->shost_recovery || ioc->remove_host ||
3275 ioc->pci_error_recovery) {
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303276 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
3277 "progress!\n", __func__, ioc->name));
3278 return 1;
3279 }
nagalakshmi.nandigama@lsi.com298c7942012-03-20 12:07:17 +05303280 if (unlikely(!mpi_reply)) {
3281 printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
3282 ioc->name, __FILE__, __LINE__, __func__);
3283 return 1;
3284 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303285 mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
3286 handle = le16_to_cpu(mpi_request_tm->DevHandle);
3287 if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
3288 dewtprintk(ioc, printk("spurious interrupt: "
3289 "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle,
3290 le16_to_cpu(mpi_reply->DevHandle), smid));
3291 return 0;
3292 }
3293
3294 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3295 "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
3296 "loginfo(0x%08x), completed(%d)\n", ioc->name,
3297 handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
3298 le32_to_cpu(mpi_reply->IOCLogInfo),
3299 le32_to_cpu(mpi_reply->TerminationCount)));
3300
3301 return _scsih_check_for_pending_tm(ioc, smid);
3302}
3303
3304/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303305 * _scsih_tm_tr_complete -
3306 * @ioc: per adapter object
3307 * @smid: system request message index
3308 * @msix_index: MSIX table index supplied by the OS
3309 * @reply: reply message frame(lower 32bit addr)
3310 * Context: interrupt time.
3311 *
3312 * This is the target reset completion routine.
3313 * This code is part of the code to initiate the device removal
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003314 * handshake protocol with controller firmware.
3315 * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303316 *
3317 * Return 1 meaning mf should be freed from _base_interrupt
3318 * 0 means the mf is freed from this function.
3319 */
3320static u8
3321_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
3322 u32 reply)
3323{
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303324 u16 handle;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303325 Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303326 Mpi2SCSITaskManagementReply_t *mpi_reply =
3327 mpt2sas_base_get_reply_virt_addr(ioc, reply);
3328 Mpi2SasIoUnitControlRequest_t *mpi_request;
3329 u16 smid_sas_ctrl;
nagalakshmi.nandigama@lsi.comf881cea2011-10-19 15:37:00 +05303330 u32 ioc_state;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303331
nagalakshmi.nandigama@lsi.comf881cea2011-10-19 15:37:00 +05303332 if (ioc->remove_host) {
3333 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been "
3334 "removed\n", __func__, ioc->name));
3335 return 1;
3336 } else if (ioc->pci_error_recovery) {
3337 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci "
3338 "error recovery\n", __func__, ioc->name));
3339 return 1;
3340 }
3341 ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
3342 if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
3343 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not "
3344 "operational\n", __func__, ioc->name));
Kashyap, Desai1278b112010-03-09 17:34:13 +05303345 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303346 }
nagalakshmi.nandigama@lsi.com298c7942012-03-20 12:07:17 +05303347 if (unlikely(!mpi_reply)) {
3348 printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
3349 ioc->name, __FILE__, __LINE__, __func__);
3350 return 1;
3351 }
Kashyap, Desai1278b112010-03-09 17:34:13 +05303352 mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
3353 handle = le16_to_cpu(mpi_request_tm->DevHandle);
3354 if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
3355 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: "
3356 "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle,
3357 le16_to_cpu(mpi_reply->DevHandle), smid));
3358 return 0;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303359 }
3360
Kashyap, Desai1278b112010-03-09 17:34:13 +05303361 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3362 "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
3363 "loginfo(0x%08x), completed(%d)\n", ioc->name,
3364 handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
3365 le32_to_cpu(mpi_reply->IOCLogInfo),
3366 le32_to_cpu(mpi_reply->TerminationCount)));
3367
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303368 smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
3369 if (!smid_sas_ctrl) {
3370 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
3371 ioc->name, __func__);
Kashyap, Desai1278b112010-03-09 17:34:13 +05303372 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303373 }
3374
Kashyap, Desai1278b112010-03-09 17:34:13 +05303375 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), "
3376 "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl,
3377 ioc->tm_sas_control_cb_idx));
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303378 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
3379 memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
3380 mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
3381 mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303382 mpi_request->DevHandle = mpi_request_tm->DevHandle;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303383 mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
Kashyap, Desai1278b112010-03-09 17:34:13 +05303384
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303385 return _scsih_check_for_pending_tm(ioc, smid);
3386}
3387
3388/**
3389 * _scsih_check_for_pending_tm - check for pending task management
3390 * @ioc: per adapter object
3391 * @smid: system request message index
3392 *
3393 * This will check delayed target reset list, and feed the
3394 * next reqeust.
3395 *
3396 * Return 1 meaning mf should be freed from _base_interrupt
3397 * 0 means the mf is freed from this function.
3398 */
3399static u8
3400_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid)
3401{
3402 struct _tr_list *delayed_tr;
3403
3404 if (!list_empty(&ioc->delayed_tr_volume_list)) {
3405 delayed_tr = list_entry(ioc->delayed_tr_volume_list.next,
3406 struct _tr_list, list);
3407 mpt2sas_base_free_smid(ioc, smid);
3408 _scsih_tm_tr_volume_send(ioc, delayed_tr->handle);
3409 list_del(&delayed_tr->list);
3410 kfree(delayed_tr);
3411 return 0;
3412 }
3413
Kashyap, Desai1278b112010-03-09 17:34:13 +05303414 if (!list_empty(&ioc->delayed_tr_list)) {
3415 delayed_tr = list_entry(ioc->delayed_tr_list.next,
3416 struct _tr_list, list);
3417 mpt2sas_base_free_smid(ioc, smid);
3418 _scsih_tm_tr_send(ioc, delayed_tr->handle);
3419 list_del(&delayed_tr->list);
3420 kfree(delayed_tr);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303421 return 0;
Kashyap, Desai1278b112010-03-09 17:34:13 +05303422 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303423
Kashyap, Desai1278b112010-03-09 17:34:13 +05303424 return 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303425}
3426
3427/**
Eric Moore635374e2009-03-09 01:21:12 -06003428 * _scsih_check_topo_delete_events - sanity check on topo events
3429 * @ioc: per adapter object
3430 * @event_data: the event data payload
3431 *
3432 * This routine added to better handle cable breaker.
3433 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003434 * This handles the case where driver receives multiple expander
Eric Moore635374e2009-03-09 01:21:12 -06003435 * add and delete events in a single shot. When there is a delete event
3436 * the routine will void any pending add events waiting in the event queue.
3437 *
3438 * Return nothing.
3439 */
3440static void
3441_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
3442 Mpi2EventDataSasTopologyChangeList_t *event_data)
3443{
3444 struct fw_event_work *fw_event;
3445 Mpi2EventDataSasTopologyChangeList_t *local_event_data;
3446 u16 expander_handle;
3447 struct _sas_node *sas_expander;
3448 unsigned long flags;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303449 int i, reason_code;
3450 u16 handle;
3451
3452 for (i = 0 ; i < event_data->NumEntries; i++) {
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05303453 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
3454 if (!handle)
3455 continue;
3456 reason_code = event_data->PHY[i].PhyStatus &
3457 MPI2_EVENT_SAS_TOPO_RC_MASK;
3458 if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
3459 _scsih_tm_tr_send(ioc, handle);
3460 }
Eric Moore635374e2009-03-09 01:21:12 -06003461
3462 expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
3463 if (expander_handle < ioc->sas_hba.num_phys) {
3464 _scsih_block_io_to_children_attached_directly(ioc, event_data);
3465 return;
3466 }
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05303467 if (event_data->ExpStatus ==
3468 MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) {
3469 /* put expander attached devices into blocking state */
Eric Moore635374e2009-03-09 01:21:12 -06003470 spin_lock_irqsave(&ioc->sas_node_lock, flags);
3471 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
3472 expander_handle);
Eric Moore635374e2009-03-09 01:21:12 -06003473 _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05303474 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
3475 do {
3476 handle = find_first_bit(ioc->blocking_handles,
3477 ioc->facts.MaxDevHandle);
3478 if (handle < ioc->facts.MaxDevHandle)
3479 _scsih_block_io_device(ioc, handle);
3480 } while (test_and_clear_bit(handle, ioc->blocking_handles));
Eric Moore635374e2009-03-09 01:21:12 -06003481 } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
3482 _scsih_block_io_to_children_attached_directly(ioc, event_data);
3483
3484 if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
3485 return;
3486
3487 /* mark ignore flag for pending events */
3488 spin_lock_irqsave(&ioc->fw_event_lock, flags);
3489 list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
3490 if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
3491 fw_event->ignore)
3492 continue;
3493 local_event_data = fw_event->event_data;
3494 if (local_event_data->ExpStatus ==
3495 MPI2_EVENT_SAS_TOPO_ES_ADDED ||
3496 local_event_data->ExpStatus ==
3497 MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
3498 if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
3499 expander_handle) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05303500 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -06003501 "setting ignoring flag\n", ioc->name));
3502 fw_event->ignore = 1;
3503 }
3504 }
3505 }
3506 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
3507}
3508
3509/**
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303510 * _scsih_set_volume_delete_flag - setting volume delete flag
3511 * @ioc: per adapter object
3512 * @handle: device handle
3513 *
3514 * This
3515 * Return nothing.
3516 */
3517static void
3518_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
3519{
3520 struct _raid_device *raid_device;
3521 struct MPT2SAS_TARGET *sas_target_priv_data;
3522 unsigned long flags;
3523
3524 spin_lock_irqsave(&ioc->raid_device_lock, flags);
3525 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
3526 if (raid_device && raid_device->starget &&
3527 raid_device->starget->hostdata) {
3528 sas_target_priv_data =
3529 raid_device->starget->hostdata;
3530 sas_target_priv_data->deleted = 1;
3531 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3532 "setting delete flag: handle(0x%04x), "
3533 "wwid(0x%016llx)\n", ioc->name, handle,
3534 (unsigned long long) raid_device->wwid));
3535 }
3536 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
3537}
3538
3539/**
3540 * _scsih_set_volume_handle_for_tr - set handle for target reset to volume
3541 * @handle: input handle
3542 * @a: handle for volume a
3543 * @b: handle for volume b
3544 *
3545 * IR firmware only supports two raid volumes. The purpose of this
3546 * routine is to set the volume handle in either a or b. When the given
3547 * input handle is non-zero, or when a and b have not been set before.
3548 */
3549static void
3550_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b)
3551{
3552 if (!handle || handle == *a || handle == *b)
3553 return;
3554 if (!*a)
3555 *a = handle;
3556 else if (!*b)
3557 *b = handle;
3558}
3559
3560/**
3561 * _scsih_check_ir_config_unhide_events - check for UNHIDE events
3562 * @ioc: per adapter object
3563 * @event_data: the event data payload
3564 * Context: interrupt time.
3565 *
3566 * This routine will send target reset to volume, followed by target
3567 * resets to the PDs. This is called when a PD has been removed, or
3568 * volume has been deleted or removed. When the target reset is sent
3569 * to volume, the PD target resets need to be queued to start upon
3570 * completion of the volume target reset.
3571 *
3572 * Return nothing.
3573 */
3574static void
3575_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc,
3576 Mpi2EventDataIrConfigChangeList_t *event_data)
3577{
3578 Mpi2EventIrConfigElement_t *element;
3579 int i;
3580 u16 handle, volume_handle, a, b;
3581 struct _tr_list *delayed_tr;
3582
3583 a = 0;
3584 b = 0;
3585
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303586 if (ioc->is_warpdrive)
3587 return;
3588
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05303589 /* Volume Resets for Deleted or Removed */
3590 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3591 for (i = 0; i < event_data->NumElements; i++, element++) {
3592 if (element->ReasonCode ==
3593 MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED ||
3594 element->ReasonCode ==
3595 MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
3596 volume_handle = le16_to_cpu(element->VolDevHandle);
3597 _scsih_set_volume_delete_flag(ioc, volume_handle);
3598 _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
3599 }
3600 }
3601
3602 /* Volume Resets for UNHIDE events */
3603 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3604 for (i = 0; i < event_data->NumElements; i++, element++) {
3605 if (le32_to_cpu(event_data->Flags) &
3606 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
3607 continue;
3608 if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) {
3609 volume_handle = le16_to_cpu(element->VolDevHandle);
3610 _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
3611 }
3612 }
3613
3614 if (a)
3615 _scsih_tm_tr_volume_send(ioc, a);
3616 if (b)
3617 _scsih_tm_tr_volume_send(ioc, b);
3618
3619 /* PD target resets */
3620 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3621 for (i = 0; i < event_data->NumElements; i++, element++) {
3622 if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE)
3623 continue;
3624 handle = le16_to_cpu(element->PhysDiskDevHandle);
3625 volume_handle = le16_to_cpu(element->VolDevHandle);
3626 clear_bit(handle, ioc->pd_handles);
3627 if (!volume_handle)
3628 _scsih_tm_tr_send(ioc, handle);
3629 else if (volume_handle == a || volume_handle == b) {
3630 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
3631 BUG_ON(!delayed_tr);
3632 INIT_LIST_HEAD(&delayed_tr->list);
3633 delayed_tr->handle = handle;
3634 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
3635 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
3636 "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name,
3637 handle));
3638 } else
3639 _scsih_tm_tr_send(ioc, handle);
3640 }
3641}
3642
3643
3644/**
3645 * _scsih_check_volume_delete_events - set delete flag for volumes
3646 * @ioc: per adapter object
3647 * @event_data: the event data payload
3648 * Context: interrupt time.
3649 *
3650 * This will handle the case when the cable connected to entire volume is
3651 * pulled. We will take care of setting the deleted flag so normal IO will
3652 * not be sent.
3653 *
3654 * Return nothing.
3655 */
3656static void
3657_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc,
3658 Mpi2EventDataIrVolume_t *event_data)
3659{
3660 u32 state;
3661
3662 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
3663 return;
3664 state = le32_to_cpu(event_data->NewValue);
3665 if (state == MPI2_RAID_VOL_STATE_MISSING || state ==
3666 MPI2_RAID_VOL_STATE_FAILED)
3667 _scsih_set_volume_delete_flag(ioc,
3668 le16_to_cpu(event_data->VolDevHandle));
3669}
3670
3671/**
Eric Moore635374e2009-03-09 01:21:12 -06003672 * _scsih_flush_running_cmds - completing outstanding commands.
3673 * @ioc: per adapter object
3674 *
3675 * The flushing out of all pending scmd commands following host reset,
3676 * where all IO is dropped to the floor.
3677 *
3678 * Return nothing.
3679 */
3680static void
3681_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
3682{
3683 struct scsi_cmnd *scmd;
3684 u16 smid;
3685 u16 count = 0;
3686
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05303687 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
Kashyap, Desaiec07a052011-01-05 17:54:32 +05303688 scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06003689 if (!scmd)
3690 continue;
3691 count++;
3692 mpt2sas_base_free_smid(ioc, smid);
3693 scsi_dma_unmap(scmd);
Eric Moore3cb54692010-07-08 14:44:34 -06003694 if (ioc->pci_error_recovery)
3695 scmd->result = DID_NO_CONNECT << 16;
3696 else
3697 scmd->result = DID_RESET << 16;
Eric Moore635374e2009-03-09 01:21:12 -06003698 scmd->scsi_done(scmd);
3699 }
3700 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
3701 ioc->name, count));
3702}
3703
3704/**
Eric Moore3c621b32009-05-18 12:59:41 -06003705 * _scsih_setup_eedp - setup MPI request for EEDP transfer
3706 * @scmd: pointer to scsi command object
3707 * @mpi_request: pointer to the SCSI_IO reqest message frame
3708 *
3709 * Supporting protection 1 and 3.
3710 *
3711 * Returns nothing
3712 */
3713static void
3714_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
3715{
3716 u16 eedp_flags;
3717 unsigned char prot_op = scsi_get_prot_op(scmd);
3718 unsigned char prot_type = scsi_get_prot_type(scmd);
3719
Eric Moored334aa72010-04-22 10:47:40 -06003720 if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL)
Eric Moore3c621b32009-05-18 12:59:41 -06003721 return;
3722
3723 if (prot_op == SCSI_PROT_READ_STRIP)
3724 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
3725 else if (prot_op == SCSI_PROT_WRITE_INSERT)
3726 eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
3727 else
3728 return;
3729
Eric Moore3c621b32009-05-18 12:59:41 -06003730 switch (prot_type) {
3731 case SCSI_PROT_DIF_TYPE1:
Martin K. Petersen756aca72011-05-18 00:45:22 -04003732 case SCSI_PROT_DIF_TYPE2:
Eric Moore3c621b32009-05-18 12:59:41 -06003733
3734 /*
3735 * enable ref/guard checking
3736 * auto increment ref tag
3737 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05303738 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
Eric Moore3c621b32009-05-18 12:59:41 -06003739 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
3740 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
3741 mpi_request->CDB.EEDP32.PrimaryReferenceTag =
3742 cpu_to_be32(scsi_get_lba(scmd));
Eric Moored334aa72010-04-22 10:47:40 -06003743 break;
Eric Moore3c621b32009-05-18 12:59:41 -06003744
Eric Moore3c621b32009-05-18 12:59:41 -06003745 case SCSI_PROT_DIF_TYPE3:
3746
3747 /*
3748 * enable guard checking
3749 */
Kashyap, Desai463217b2009-10-05 15:53:06 +05303750 eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
Eric Moore3c621b32009-05-18 12:59:41 -06003751 break;
3752 }
Kashyap, Desai463217b2009-10-05 15:53:06 +05303753 mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
3754 mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
Eric Moore3c621b32009-05-18 12:59:41 -06003755}
3756
3757/**
3758 * _scsih_eedp_error_handling - return sense code for EEDP errors
3759 * @scmd: pointer to scsi command object
3760 * @ioc_status: ioc status
3761 *
3762 * Returns nothing
3763 */
3764static void
3765_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
3766{
3767 u8 ascq;
3768 u8 sk;
3769 u8 host_byte;
3770
3771 switch (ioc_status) {
3772 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
3773 ascq = 0x01;
3774 break;
3775 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
3776 ascq = 0x02;
3777 break;
3778 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
3779 ascq = 0x03;
3780 break;
3781 default:
3782 ascq = 0x00;
3783 break;
3784 }
3785
3786 if (scmd->sc_data_direction == DMA_TO_DEVICE) {
3787 sk = ILLEGAL_REQUEST;
3788 host_byte = DID_ABORT;
3789 } else {
3790 sk = ABORTED_COMMAND;
3791 host_byte = DID_OK;
3792 }
3793
3794 scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
3795 scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
3796 SAM_STAT_CHECK_CONDITION;
3797}
3798
3799/**
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303800 * _scsih_scsi_direct_io_get - returns direct io flag
3801 * @ioc: per adapter object
3802 * @smid: system request message index
3803 *
3804 * Returns the smid stored scmd pointer.
3805 */
3806static inline u8
3807_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
3808{
3809 return ioc->scsi_lookup[smid - 1].direct_io;
3810}
3811
3812/**
3813 * _scsih_scsi_direct_io_set - sets direct io flag
3814 * @ioc: per adapter object
3815 * @smid: system request message index
3816 * @direct_io: Zero or non-zero value to set in the direct_io flag
3817 *
3818 * Returns Nothing.
3819 */
3820static inline void
3821_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
3822{
3823 ioc->scsi_lookup[smid - 1].direct_io = direct_io;
3824}
3825
3826
3827/**
3828 * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
3829 * @ioc: per adapter object
3830 * @scmd: pointer to scsi command object
3831 * @raid_device: pointer to raid device data structure
3832 * @mpi_request: pointer to the SCSI_IO reqest message frame
3833 * @smid: system request message index
3834 *
3835 * Returns nothing
3836 */
3837static void
3838_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
3839 struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
3840 u16 smid)
3841{
3842 u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size;
3843 u32 stripe_sz, stripe_exp;
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05303844 u8 num_pds, *cdb_ptr, i;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303845 u8 cdb0 = scmd->cmnd[0];
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05303846 u64 v_llba;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303847
3848 /*
3849 * Try Direct I/O to RAID memeber disks
3850 */
3851 if (cdb0 == READ_16 || cdb0 == READ_10 ||
3852 cdb0 == WRITE_16 || cdb0 == WRITE_10) {
3853 cdb_ptr = mpi_request->CDB.CDB32;
3854
3855 if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4]
3856 | cdb_ptr[5])) {
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05303857 io_size = scsi_bufflen(scmd) >>
3858 raid_device->block_exponent;
3859 i = (cdb0 < READ_16) ? 2 : 6;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303860 /* get virtual lba */
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05303861 v_lba = be32_to_cpu(*(__be32 *)(&cdb_ptr[i]));
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303862
3863 if (((u64)v_lba + (u64)io_size - 1) <=
3864 (u32)raid_device->max_lba) {
3865 stripe_sz = raid_device->stripe_sz;
3866 stripe_exp = raid_device->stripe_exponent;
3867 stripe_off = v_lba & (stripe_sz - 1);
3868
3869 /* Check whether IO falls within a stripe */
3870 if ((stripe_off + io_size) <= stripe_sz) {
3871 num_pds = raid_device->num_pds;
3872 p_lba = v_lba >> stripe_exp;
3873 stripe_unit = p_lba / num_pds;
3874 column = p_lba % num_pds;
3875 p_lba = (stripe_unit << stripe_exp) +
3876 stripe_off;
3877 mpi_request->DevHandle =
3878 cpu_to_le16(raid_device->
3879 pd_handle[column]);
nagalakshmi.nandigama@lsi.comba96bd02011-12-01 07:51:55 +05303880 (*(__be32 *)(&cdb_ptr[i])) =
3881 cpu_to_be32(p_lba);
3882 /*
3883 * WD: To indicate this I/O is directI/O
3884 */
3885 _scsih_scsi_direct_io_set(ioc, smid, 1);
3886 }
3887 }
3888 } else {
3889 io_size = scsi_bufflen(scmd) >>
3890 raid_device->block_exponent;
3891 /* get virtual lba */
3892 v_llba = be64_to_cpu(*(__be64 *)(&cdb_ptr[2]));
3893
3894 if ((v_llba + (u64)io_size - 1) <=
3895 raid_device->max_lba) {
3896 stripe_sz = raid_device->stripe_sz;
3897 stripe_exp = raid_device->stripe_exponent;
3898 stripe_off = (u32) (v_llba & (stripe_sz - 1));
3899
3900 /* Check whether IO falls within a stripe */
3901 if ((stripe_off + io_size) <= stripe_sz) {
3902 num_pds = raid_device->num_pds;
3903 p_lba = (u32)(v_llba >> stripe_exp);
3904 stripe_unit = p_lba / num_pds;
3905 column = p_lba % num_pds;
3906 p_lba = (stripe_unit << stripe_exp) +
3907 stripe_off;
3908 mpi_request->DevHandle =
3909 cpu_to_le16(raid_device->
3910 pd_handle[column]);
3911 (*(__be64 *)(&cdb_ptr[2])) =
3912 cpu_to_be64((u64)p_lba);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303913 /*
3914 * WD: To indicate this I/O is directI/O
3915 */
3916 _scsih_scsi_direct_io_set(ioc, smid, 1);
3917 }
3918 }
3919 }
3920 }
3921}
3922
3923/**
Eric Moored5d135b2009-05-18 13:02:08 -06003924 * _scsih_qcmd - main scsi request entry point
Eric Moore635374e2009-03-09 01:21:12 -06003925 * @scmd: pointer to scsi command object
3926 * @done: function pointer to be invoked on completion
3927 *
3928 * The callback index is set inside `ioc->scsi_io_cb_idx`.
3929 *
3930 * Returns 0 on success. If there's a failure, return either:
3931 * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
3932 * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
3933 */
3934static int
Jeff Garzikf2812332010-11-16 02:10:29 -05003935_scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Eric Moore635374e2009-03-09 01:21:12 -06003936{
3937 struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
3938 struct MPT2SAS_DEVICE *sas_device_priv_data;
3939 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05303940 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06003941 Mpi2SCSIIORequest_t *mpi_request;
3942 u32 mpi_control;
3943 u16 smid;
Eric Moore635374e2009-03-09 01:21:12 -06003944
3945 scmd->scsi_done = done;
3946 sas_device_priv_data = scmd->device->hostdata;
Kashyap, Desai130b9582010-04-08 17:54:32 +05303947 if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
Eric Moore635374e2009-03-09 01:21:12 -06003948 scmd->result = DID_NO_CONNECT << 16;
3949 scmd->scsi_done(scmd);
3950 return 0;
3951 }
3952
Kashyap, Desai78215782011-06-14 10:57:08 +05303953 if (ioc->pci_error_recovery || ioc->remove_host) {
Eric Moore3cb54692010-07-08 14:44:34 -06003954 scmd->result = DID_NO_CONNECT << 16;
3955 scmd->scsi_done(scmd);
3956 return 0;
3957 }
3958
Eric Moore635374e2009-03-09 01:21:12 -06003959 sas_target_priv_data = sas_device_priv_data->sas_target;
Kashyap, Desai130b9582010-04-08 17:54:32 +05303960 /* invalid device handle */
3961 if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
Eric Moore635374e2009-03-09 01:21:12 -06003962 scmd->result = DID_NO_CONNECT << 16;
3963 scmd->scsi_done(scmd);
3964 return 0;
3965 }
3966
Kashyap, Desai130b9582010-04-08 17:54:32 +05303967 /* host recovery or link resets sent via IOCTLs */
3968 if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
Eric Moore635374e2009-03-09 01:21:12 -06003969 return SCSI_MLQUEUE_HOST_BUSY;
Uwe Kleine-König65155b32010-06-11 12:17:01 +02003970 /* device busy with task management */
Kashyap, Desai130b9582010-04-08 17:54:32 +05303971 else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
3972 return SCSI_MLQUEUE_DEVICE_BUSY;
3973 /* device has been deleted */
3974 else if (sas_target_priv_data->deleted) {
3975 scmd->result = DID_NO_CONNECT << 16;
3976 scmd->scsi_done(scmd);
3977 return 0;
3978 }
Eric Moore635374e2009-03-09 01:21:12 -06003979
3980 if (scmd->sc_data_direction == DMA_FROM_DEVICE)
3981 mpi_control = MPI2_SCSIIO_CONTROL_READ;
3982 else if (scmd->sc_data_direction == DMA_TO_DEVICE)
3983 mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
3984 else
3985 mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
3986
3987 /* set tags */
3988 if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
3989 if (scmd->device->tagged_supported) {
3990 if (scmd->device->ordered_tags)
3991 mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
3992 else
3993 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
3994 } else
3995/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */
3996/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED;
3997 */
3998 mpi_control |= (0x500);
3999
4000 } else
4001 mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304002 /* Make sure Device is not raid volume.
4003 * We do not expose raid functionality to upper layer for warpdrive.
4004 */
4005 if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
Eric Moored334aa72010-04-22 10:47:40 -06004006 sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
Eric Moore635374e2009-03-09 01:21:12 -06004007 mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
4008
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304009 smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
Eric Moore635374e2009-03-09 01:21:12 -06004010 if (!smid) {
4011 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
4012 ioc->name, __func__);
4013 goto out;
4014 }
4015 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
4016 memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
Eric Moore3c621b32009-05-18 12:59:41 -06004017 _scsih_setup_eedp(scmd, mpi_request);
Eric Moored334aa72010-04-22 10:47:40 -06004018 if (scmd->cmd_len == 32)
4019 mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
Eric Moore635374e2009-03-09 01:21:12 -06004020 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
4021 if (sas_device_priv_data->sas_target->flags &
4022 MPT_TARGET_FLAGS_RAID_COMPONENT)
4023 mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
4024 else
4025 mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
4026 mpi_request->DevHandle =
4027 cpu_to_le16(sas_device_priv_data->sas_target->handle);
4028 mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
4029 mpi_request->Control = cpu_to_le32(mpi_control);
4030 mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
4031 mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
4032 mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
4033 mpi_request->SenseBufferLowAddress =
Kashyap, Desaiec9472c2009-09-23 17:34:13 +05304034 mpt2sas_base_get_sense_buffer_dma(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06004035 mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
4036 mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
4037 MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304038 mpi_request->VF_ID = 0; /* TODO */
4039 mpi_request->VP_ID = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004040 int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
4041 mpi_request->LUN);
4042 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
4043
4044 if (!mpi_request->DataLength) {
4045 mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
4046 } else {
4047 if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
4048 mpt2sas_base_free_smid(ioc, smid);
4049 goto out;
4050 }
4051 }
4052
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304053 raid_device = sas_target_priv_data->raid_device;
4054 if (raid_device && raid_device->direct_io_enabled)
4055 _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request,
4056 smid);
4057
Kashyap, Desai58287fd2010-03-17 16:27:25 +05304058 if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST))
4059 mpt2sas_base_put_smid_scsi_io(ioc, smid,
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304060 le16_to_cpu(mpi_request->DevHandle));
Kashyap, Desai58287fd2010-03-17 16:27:25 +05304061 else
4062 mpt2sas_base_put_smid_default(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06004063 return 0;
4064
4065 out:
4066 return SCSI_MLQUEUE_HOST_BUSY;
4067}
4068
Jeff Garzikf2812332010-11-16 02:10:29 -05004069static DEF_SCSI_QCMD(_scsih_qcmd)
4070
Eric Moore635374e2009-03-09 01:21:12 -06004071/**
4072 * _scsih_normalize_sense - normalize descriptor and fixed format sense data
4073 * @sense_buffer: sense data returned by target
4074 * @data: normalized skey/asc/ascq
4075 *
4076 * Return nothing.
4077 */
4078static void
4079_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
4080{
4081 if ((sense_buffer[0] & 0x7F) >= 0x72) {
4082 /* descriptor format */
4083 data->skey = sense_buffer[1] & 0x0F;
4084 data->asc = sense_buffer[2];
4085 data->ascq = sense_buffer[3];
4086 } else {
4087 /* fixed format */
4088 data->skey = sense_buffer[2] & 0x0F;
4089 data->asc = sense_buffer[12];
4090 data->ascq = sense_buffer[13];
4091 }
4092}
4093
4094#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4095/**
Lucas De Marchi25985ed2011-03-30 22:57:33 -03004096 * _scsih_scsi_ioc_info - translated non-successful SCSI_IO request
Eric Moore635374e2009-03-09 01:21:12 -06004097 * @ioc: per adapter object
4098 * @scmd: pointer to scsi command object
4099 * @mpi_reply: reply mf payload returned from firmware
4100 *
4101 * scsi_status - SCSI Status code returned from target device
4102 * scsi_state - state info associated with SCSI_IO determined by ioc
4103 * ioc_status - ioc supplied status info
4104 *
4105 * Return nothing.
4106 */
4107static void
4108_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
4109 Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
4110{
4111 u32 response_info;
4112 u8 *response_bytes;
4113 u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
4114 MPI2_IOCSTATUS_MASK;
4115 u8 scsi_state = mpi_reply->SCSIState;
4116 u8 scsi_status = mpi_reply->SCSIStatus;
4117 char *desc_ioc_state = NULL;
4118 char *desc_scsi_status = NULL;
4119 char *desc_scsi_state = ioc->tmp_string;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05304120 u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304121 struct _sas_device *sas_device = NULL;
4122 unsigned long flags;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304123 struct scsi_target *starget = scmd->device->sdev_target;
4124 struct MPT2SAS_TARGET *priv_target = starget->hostdata;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304125 char *device_str = NULL;
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304126
4127 if (!priv_target)
4128 return;
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05304129
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304130 if (ioc->hide_ir_msg)
4131 device_str = "WarpDrive";
4132 else
4133 device_str = "volume";
4134
Kashyap, Desaibe9e8cd72009-08-07 19:36:43 +05304135 if (log_info == 0x31170000)
4136 return;
Eric Moore635374e2009-03-09 01:21:12 -06004137
4138 switch (ioc_status) {
4139 case MPI2_IOCSTATUS_SUCCESS:
4140 desc_ioc_state = "success";
4141 break;
4142 case MPI2_IOCSTATUS_INVALID_FUNCTION:
4143 desc_ioc_state = "invalid function";
4144 break;
4145 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
4146 desc_ioc_state = "scsi recovered error";
4147 break;
4148 case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
4149 desc_ioc_state = "scsi invalid dev handle";
4150 break;
4151 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
4152 desc_ioc_state = "scsi device not there";
4153 break;
4154 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
4155 desc_ioc_state = "scsi data overrun";
4156 break;
4157 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
4158 desc_ioc_state = "scsi data underrun";
4159 break;
4160 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
4161 desc_ioc_state = "scsi io data error";
4162 break;
4163 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
4164 desc_ioc_state = "scsi protocol error";
4165 break;
4166 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
4167 desc_ioc_state = "scsi task terminated";
4168 break;
4169 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
4170 desc_ioc_state = "scsi residual mismatch";
4171 break;
4172 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
4173 desc_ioc_state = "scsi task mgmt failed";
4174 break;
4175 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
4176 desc_ioc_state = "scsi ioc terminated";
4177 break;
4178 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
4179 desc_ioc_state = "scsi ext terminated";
4180 break;
Eric Moore3c621b32009-05-18 12:59:41 -06004181 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
4182 desc_ioc_state = "eedp guard error";
4183 break;
4184 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
4185 desc_ioc_state = "eedp ref tag error";
4186 break;
4187 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
4188 desc_ioc_state = "eedp app tag error";
4189 break;
Eric Moore635374e2009-03-09 01:21:12 -06004190 default:
4191 desc_ioc_state = "unknown";
4192 break;
4193 }
4194
4195 switch (scsi_status) {
4196 case MPI2_SCSI_STATUS_GOOD:
4197 desc_scsi_status = "good";
4198 break;
4199 case MPI2_SCSI_STATUS_CHECK_CONDITION:
4200 desc_scsi_status = "check condition";
4201 break;
4202 case MPI2_SCSI_STATUS_CONDITION_MET:
4203 desc_scsi_status = "condition met";
4204 break;
4205 case MPI2_SCSI_STATUS_BUSY:
4206 desc_scsi_status = "busy";
4207 break;
4208 case MPI2_SCSI_STATUS_INTERMEDIATE:
4209 desc_scsi_status = "intermediate";
4210 break;
4211 case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
4212 desc_scsi_status = "intermediate condmet";
4213 break;
4214 case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
4215 desc_scsi_status = "reservation conflict";
4216 break;
4217 case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
4218 desc_scsi_status = "command terminated";
4219 break;
4220 case MPI2_SCSI_STATUS_TASK_SET_FULL:
4221 desc_scsi_status = "task set full";
4222 break;
4223 case MPI2_SCSI_STATUS_ACA_ACTIVE:
4224 desc_scsi_status = "aca active";
4225 break;
4226 case MPI2_SCSI_STATUS_TASK_ABORTED:
4227 desc_scsi_status = "task aborted";
4228 break;
4229 default:
4230 desc_scsi_status = "unknown";
4231 break;
4232 }
4233
4234 desc_scsi_state[0] = '\0';
4235 if (!scsi_state)
4236 desc_scsi_state = " ";
4237 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
4238 strcat(desc_scsi_state, "response info ");
4239 if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
4240 strcat(desc_scsi_state, "state terminated ");
4241 if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
4242 strcat(desc_scsi_state, "no status ");
4243 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
4244 strcat(desc_scsi_state, "autosense failed ");
4245 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
4246 strcat(desc_scsi_state, "autosense valid ");
4247
4248 scsi_print_command(scmd);
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304249
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304250 if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304251 printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
4252 device_str, (unsigned long long)priv_target->sas_address);
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304253 } else {
4254 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4255 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
4256 priv_target->sas_address);
4257 if (sas_device) {
4258 printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
4259 "phy(%d)\n", ioc->name, sas_device->sas_address,
4260 sas_device->phy);
4261 printk(MPT2SAS_WARN_FMT
4262 "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
4263 ioc->name, sas_device->enclosure_logical_id,
4264 sas_device->slot);
4265 }
4266 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304267 }
Kashyap, Desai7fbae672010-06-17 13:45:17 +05304268
Kashyap, Desai8e864a82010-06-17 13:48:46 +05304269 printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), "
4270 "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle),
4271 desc_ioc_state, ioc_status, smid);
Eric Moore635374e2009-03-09 01:21:12 -06004272 printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
4273 "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
4274 scsi_get_resid(scmd));
4275 printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
4276 "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
4277 le32_to_cpu(mpi_reply->TransferCount), scmd->result);
4278 printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
4279 "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
4280 scsi_status, desc_scsi_state, scsi_state);
4281
4282 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
4283 struct sense_info data;
4284 _scsih_normalize_sense(scmd->sense_buffer, &data);
4285 printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
Kashyap, Desaie94f6742010-03-17 16:24:52 +05304286 "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey,
4287 data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));
Eric Moore635374e2009-03-09 01:21:12 -06004288 }
4289
4290 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
4291 response_info = le32_to_cpu(mpi_reply->ResponseInfo);
4292 response_bytes = (u8 *)&response_info;
Kashyap, Desai9982f592009-09-23 17:23:07 +05304293 _scsih_response_code(ioc, response_bytes[0]);
Eric Moore635374e2009-03-09 01:21:12 -06004294 }
4295}
4296#endif
4297
4298/**
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05304299 * _scsih_turn_on_fault_led - illuminate Fault LED
Eric Moore635374e2009-03-09 01:21:12 -06004300 * @ioc: per adapter object
4301 * @handle: device handle
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05304302 * Context: process
4303 *
4304 * Return nothing.
4305 */
4306static void
4307_scsih_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4308{
4309 Mpi2SepReply_t mpi_reply;
4310 Mpi2SepRequest_t mpi_request;
4311
4312 memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
4313 mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
4314 mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
4315 mpi_request.SlotStatus =
4316 cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
4317 mpi_request.DevHandle = cpu_to_le16(handle);
4318 mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
4319 if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
4320 &mpi_request)) != 0) {
4321 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
4322 __FILE__, __LINE__, __func__);
4323 return;
4324 }
4325
4326 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
4327 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: "
4328 "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name,
4329 le16_to_cpu(mpi_reply.IOCStatus),
4330 le32_to_cpu(mpi_reply.IOCLogInfo)));
4331 return;
4332 }
4333}
4334
4335/**
4336 * _scsih_send_event_to_turn_on_fault_led - fire delayed event
4337 * @ioc: per adapter object
4338 * @handle: device handle
4339 * Context: interrupt.
4340 *
4341 * Return nothing.
4342 */
4343static void
4344_scsih_send_event_to_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4345{
4346 struct fw_event_work *fw_event;
4347
4348 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
4349 if (!fw_event)
4350 return;
4351 fw_event->event = MPT2SAS_TURN_ON_FAULT_LED;
4352 fw_event->device_handle = handle;
4353 fw_event->ioc = ioc;
4354 _scsih_fw_event_add(ioc, fw_event);
4355}
4356
4357/**
4358 * _scsih_smart_predicted_fault - process smart errors
4359 * @ioc: per adapter object
4360 * @handle: device handle
4361 * Context: interrupt.
Eric Moore635374e2009-03-09 01:21:12 -06004362 *
4363 * Return nothing.
4364 */
4365static void
4366_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4367{
Eric Moore635374e2009-03-09 01:21:12 -06004368 struct scsi_target *starget;
4369 struct MPT2SAS_TARGET *sas_target_priv_data;
4370 Mpi2EventNotificationReply_t *event_reply;
4371 Mpi2EventDataSasDeviceStatusChange_t *event_data;
4372 struct _sas_device *sas_device;
4373 ssize_t sz;
4374 unsigned long flags;
4375
4376 /* only handle non-raid devices */
4377 spin_lock_irqsave(&ioc->sas_device_lock, flags);
4378 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
4379 if (!sas_device) {
4380 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4381 return;
4382 }
4383 starget = sas_device->starget;
4384 sas_target_priv_data = starget->hostdata;
4385
4386 if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
4387 ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
4388 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4389 return;
4390 }
4391 starget_printk(KERN_WARNING, starget, "predicted fault\n");
4392 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
4393
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05304394 if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
4395 _scsih_send_event_to_turn_on_fault_led(ioc, handle);
Eric Moore635374e2009-03-09 01:21:12 -06004396
4397 /* insert into event log */
4398 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
4399 sizeof(Mpi2EventDataSasDeviceStatusChange_t);
Anton Blanchardf6a290b42011-11-07 22:05:21 +11004400 event_reply = kzalloc(sz, GFP_ATOMIC);
Eric Moore635374e2009-03-09 01:21:12 -06004401 if (!event_reply) {
4402 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4403 ioc->name, __FILE__, __LINE__, __func__);
4404 return;
4405 }
4406
4407 event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
4408 event_reply->Event =
4409 cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
4410 event_reply->MsgLength = sz/4;
4411 event_reply->EventDataLength =
4412 cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
4413 event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
4414 event_reply->EventData;
4415 event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
4416 event_data->ASC = 0x5D;
4417 event_data->DevHandle = cpu_to_le16(handle);
4418 event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
4419 mpt2sas_ctl_add_to_event_log(ioc, event_reply);
4420 kfree(event_reply);
4421}
4422
4423/**
Eric Moored5d135b2009-05-18 13:02:08 -06004424 * _scsih_io_done - scsi request callback
Eric Moore635374e2009-03-09 01:21:12 -06004425 * @ioc: per adapter object
4426 * @smid: system request message index
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304427 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06004428 * @reply: reply message frame(lower 32bit addr)
4429 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304430 * Callback handler when using _scsih_qcmd.
Eric Moore635374e2009-03-09 01:21:12 -06004431 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304432 * Return 1 meaning mf should be freed from _base_interrupt
4433 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06004434 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304435static u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05304436_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06004437{
4438 Mpi2SCSIIORequest_t *mpi_request;
4439 Mpi2SCSIIOReply_t *mpi_reply;
4440 struct scsi_cmnd *scmd;
4441 u16 ioc_status;
4442 u32 xfer_cnt;
4443 u8 scsi_state;
4444 u8 scsi_status;
4445 u32 log_info;
4446 struct MPT2SAS_DEVICE *sas_device_priv_data;
Kashyap, Desai9982f592009-09-23 17:23:07 +05304447 u32 response_code = 0;
Kashyap, Desai82a45252011-07-05 12:40:23 +05304448 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06004449
4450 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
Kashyap, Desaiec07a052011-01-05 17:54:32 +05304451 scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
Eric Moore635374e2009-03-09 01:21:12 -06004452 if (scmd == NULL)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304453 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06004454
4455 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
4456
4457 if (mpi_reply == NULL) {
4458 scmd->result = DID_OK << 16;
4459 goto out;
4460 }
4461
4462 sas_device_priv_data = scmd->device->hostdata;
4463 if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
4464 sas_device_priv_data->sas_target->deleted) {
4465 scmd->result = DID_NO_CONNECT << 16;
4466 goto out;
4467 }
nagalakshmi.nandigama@lsi.com4da7af92011-12-01 07:53:02 +05304468 ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304469 /*
4470 * WARPDRIVE: If direct_io is set then it is directIO,
4471 * the failed direct I/O should be redirected to volume
4472 */
nagalakshmi.nandigama@lsi.com4da7af92011-12-01 07:53:02 +05304473 if (_scsih_scsi_direct_io_get(ioc, smid) &&
4474 ((ioc_status & MPI2_IOCSTATUS_MASK)
4475 != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
Kashyap, Desai82a45252011-07-05 12:40:23 +05304476 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
4477 ioc->scsi_lookup[smid - 1].scmd = scmd;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304478 _scsih_scsi_direct_io_set(ioc, smid, 0);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05304479 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304480 memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
4481 mpi_request->DevHandle =
4482 cpu_to_le16(sas_device_priv_data->sas_target->handle);
4483 mpt2sas_base_put_smid_scsi_io(ioc, smid,
4484 sas_device_priv_data->sas_target->handle);
4485 return 0;
4486 }
4487
Eric Moore635374e2009-03-09 01:21:12 -06004488
4489 /* turning off TLR */
Kashyap, Desai9982f592009-09-23 17:23:07 +05304490 scsi_state = mpi_reply->SCSIState;
4491 if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
4492 response_code =
4493 le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
Eric Moore635374e2009-03-09 01:21:12 -06004494 if (!sas_device_priv_data->tlr_snoop_check) {
4495 sas_device_priv_data->tlr_snoop_check++;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05304496 /* Make sure Device is not raid volume.
4497 * We do not expose raid functionality to upper layer for warpdrive.
4498 */
4499 if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
Kashyap, Desai3ed21522010-02-17 16:08:36 +05304500 sas_is_tlr_enabled(scmd->device) &&
Kashyap, Desai84f0b042009-12-16 18:56:28 +05304501 response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
4502 sas_disable_tlr(scmd->device);
4503 sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
4504 }
Eric Moore635374e2009-03-09 01:21:12 -06004505 }
4506
4507 xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
4508 scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
Eric Moore635374e2009-03-09 01:21:12 -06004509 if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
4510 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
4511 else
4512 log_info = 0;
4513 ioc_status &= MPI2_IOCSTATUS_MASK;
Eric Moore635374e2009-03-09 01:21:12 -06004514 scsi_status = mpi_reply->SCSIStatus;
4515
4516 if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
4517 (scsi_status == MPI2_SCSI_STATUS_BUSY ||
4518 scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
4519 scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
4520 ioc_status = MPI2_IOCSTATUS_SUCCESS;
4521 }
4522
4523 if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
4524 struct sense_info data;
4525 const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
4526 smid);
Eric Moore0d04df92009-04-21 15:38:43 -06004527 u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
Eric Moore635374e2009-03-09 01:21:12 -06004528 le32_to_cpu(mpi_reply->SenseCount));
Eric Moore0d04df92009-04-21 15:38:43 -06004529 memcpy(scmd->sense_buffer, sense_data, sz);
Eric Moore635374e2009-03-09 01:21:12 -06004530 _scsih_normalize_sense(scmd->sense_buffer, &data);
4531 /* failure prediction threshold exceeded */
4532 if (data.asc == 0x5D)
4533 _scsih_smart_predicted_fault(ioc,
4534 le16_to_cpu(mpi_reply->DevHandle));
4535 }
4536
4537 switch (ioc_status) {
4538 case MPI2_IOCSTATUS_BUSY:
4539 case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
4540 scmd->result = SAM_STAT_BUSY;
4541 break;
4542
4543 case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
4544 scmd->result = DID_NO_CONNECT << 16;
4545 break;
4546
4547 case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
4548 if (sas_device_priv_data->block) {
Kashyap, Desaie4e7c7e2009-09-23 17:33:14 +05304549 scmd->result = DID_TRANSPORT_DISRUPTED << 16;
4550 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06004551 }
nagalakshmi.nandigama@lsi.com3ade1ca2011-12-01 07:42:40 +05304552 scmd->result = DID_SOFT_ERROR << 16;
4553 break;
Eric Moore635374e2009-03-09 01:21:12 -06004554 case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
4555 case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
4556 scmd->result = DID_RESET << 16;
4557 break;
4558
4559 case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
4560 if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
4561 scmd->result = DID_SOFT_ERROR << 16;
4562 else
4563 scmd->result = (DID_OK << 16) | scsi_status;
4564 break;
4565
4566 case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
4567 scmd->result = (DID_OK << 16) | scsi_status;
4568
4569 if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
4570 break;
4571
4572 if (xfer_cnt < scmd->underflow) {
4573 if (scsi_status == SAM_STAT_BUSY)
4574 scmd->result = SAM_STAT_BUSY;
4575 else
4576 scmd->result = DID_SOFT_ERROR << 16;
4577 } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
4578 MPI2_SCSI_STATE_NO_SCSI_STATUS))
4579 scmd->result = DID_SOFT_ERROR << 16;
4580 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
4581 scmd->result = DID_RESET << 16;
4582 else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
4583 mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
4584 mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
4585 scmd->result = (DRIVER_SENSE << 24) |
4586 SAM_STAT_CHECK_CONDITION;
4587 scmd->sense_buffer[0] = 0x70;
4588 scmd->sense_buffer[2] = ILLEGAL_REQUEST;
4589 scmd->sense_buffer[12] = 0x20;
4590 scmd->sense_buffer[13] = 0;
4591 }
4592 break;
4593
4594 case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
4595 scsi_set_resid(scmd, 0);
4596 case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
4597 case MPI2_IOCSTATUS_SUCCESS:
4598 scmd->result = (DID_OK << 16) | scsi_status;
Kashyap, Desai9982f592009-09-23 17:23:07 +05304599 if (response_code ==
4600 MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
4601 (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
4602 MPI2_SCSI_STATE_NO_SCSI_STATUS)))
Eric Moore635374e2009-03-09 01:21:12 -06004603 scmd->result = DID_SOFT_ERROR << 16;
4604 else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
4605 scmd->result = DID_RESET << 16;
4606 break;
4607
Eric Moore3c621b32009-05-18 12:59:41 -06004608 case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
4609 case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
4610 case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
4611 _scsih_eedp_error_handling(scmd, ioc_status);
4612 break;
Eric Moore635374e2009-03-09 01:21:12 -06004613 case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
4614 case MPI2_IOCSTATUS_INVALID_FUNCTION:
4615 case MPI2_IOCSTATUS_INVALID_SGL:
4616 case MPI2_IOCSTATUS_INTERNAL_ERROR:
4617 case MPI2_IOCSTATUS_INVALID_FIELD:
4618 case MPI2_IOCSTATUS_INVALID_STATE:
4619 case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
4620 case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
4621 default:
4622 scmd->result = DID_SOFT_ERROR << 16;
4623 break;
4624
4625 }
4626
4627#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
4628 if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
4629 _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
4630#endif
4631
4632 out:
4633 scsi_dma_unmap(scmd);
4634 scmd->scsi_done(scmd);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05304635 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06004636}
4637
4638/**
Eric Moore635374e2009-03-09 01:21:12 -06004639 * _scsih_sas_host_refresh - refreshing sas host object contents
4640 * @ioc: per adapter object
Eric Moore635374e2009-03-09 01:21:12 -06004641 * Context: user
4642 *
4643 * During port enable, fw will send topology events for every device. Its
4644 * possible that the handles may change from the previous setting, so this
4645 * code keeping handles updating if changed.
4646 *
4647 * Return nothing.
4648 */
4649static void
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304650_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06004651{
4652 u16 sz;
4653 u16 ioc_status;
4654 int i;
4655 Mpi2ConfigReply_t mpi_reply;
4656 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304657 u16 attached_handle;
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304658 u8 link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06004659
4660 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
4661 "updating handles for sas_host(0x%016llx)\n",
4662 ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
4663
4664 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
4665 * sizeof(Mpi2SasIOUnit0PhyData_t));
4666 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
4667 if (!sas_iounit_pg0) {
4668 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4669 ioc->name, __FILE__, __LINE__, __func__);
4670 return;
4671 }
Eric Moore635374e2009-03-09 01:21:12 -06004672
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304673 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
4674 sas_iounit_pg0, sz)) != 0)
4675 goto out;
4676 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
4677 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
4678 goto out;
4679 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304680 link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304681 if (i == 0)
4682 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
4683 PhyData[0].ControllerDevHandle);
4684 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
4685 attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
4686 AttachedDevHandle);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304687 if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
4688 link_rate = MPI2_SAS_NEG_LINK_RATE_1_5;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304689 mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05304690 attached_handle, i, link_rate);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304691 }
Eric Moore635374e2009-03-09 01:21:12 -06004692 out:
4693 kfree(sas_iounit_pg0);
4694}
4695
4696/**
4697 * _scsih_sas_host_add - create sas host object
4698 * @ioc: per adapter object
4699 *
4700 * Creating host side data object, stored in ioc->sas_hba
4701 *
4702 * Return nothing.
4703 */
4704static void
4705_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
4706{
4707 int i;
4708 Mpi2ConfigReply_t mpi_reply;
4709 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
4710 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
4711 Mpi2SasPhyPage0_t phy_pg0;
4712 Mpi2SasDevicePage0_t sas_device_pg0;
4713 Mpi2SasEnclosurePage0_t enclosure_pg0;
4714 u16 ioc_status;
4715 u16 sz;
4716 u16 device_missing_delay;
4717
4718 mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
4719 if (!ioc->sas_hba.num_phys) {
4720 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4721 ioc->name, __FILE__, __LINE__, __func__);
4722 return;
4723 }
4724
4725 /* sas_iounit page 0 */
4726 sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
4727 sizeof(Mpi2SasIOUnit0PhyData_t));
4728 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
4729 if (!sas_iounit_pg0) {
4730 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4731 ioc->name, __FILE__, __LINE__, __func__);
4732 return;
4733 }
4734 if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
4735 sas_iounit_pg0, sz))) {
4736 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4737 ioc->name, __FILE__, __LINE__, __func__);
4738 goto out;
4739 }
4740 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4741 MPI2_IOCSTATUS_MASK;
4742 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4743 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4744 ioc->name, __FILE__, __LINE__, __func__);
4745 goto out;
4746 }
4747
4748 /* sas_iounit page 1 */
4749 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
4750 sizeof(Mpi2SasIOUnit1PhyData_t));
4751 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
4752 if (!sas_iounit_pg1) {
4753 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4754 ioc->name, __FILE__, __LINE__, __func__);
4755 goto out;
4756 }
4757 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
4758 sas_iounit_pg1, sz))) {
4759 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4760 ioc->name, __FILE__, __LINE__, __func__);
4761 goto out;
4762 }
4763 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4764 MPI2_IOCSTATUS_MASK;
4765 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4766 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4767 ioc->name, __FILE__, __LINE__, __func__);
4768 goto out;
4769 }
4770
4771 ioc->io_missing_delay =
4772 le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
4773 device_missing_delay =
4774 le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
4775 if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
4776 ioc->device_missing_delay = (device_missing_delay &
4777 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
4778 else
4779 ioc->device_missing_delay = device_missing_delay &
4780 MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
4781
4782 ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
4783 ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
4784 sizeof(struct _sas_phy), GFP_KERNEL);
4785 if (!ioc->sas_hba.phy) {
4786 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4787 ioc->name, __FILE__, __LINE__, __func__);
4788 goto out;
4789 }
4790 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
4791 if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
4792 i))) {
4793 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4794 ioc->name, __FILE__, __LINE__, __func__);
4795 goto out;
4796 }
4797 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4798 MPI2_IOCSTATUS_MASK;
4799 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4800 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4801 ioc->name, __FILE__, __LINE__, __func__);
4802 goto out;
4803 }
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304804
4805 if (i == 0)
4806 ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
4807 PhyData[0].ControllerDevHandle);
4808 ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
Eric Moore635374e2009-03-09 01:21:12 -06004809 ioc->sas_hba.phy[i].phy_id = i;
4810 mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
4811 phy_pg0, ioc->sas_hba.parent_dev);
4812 }
4813 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304814 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
Eric Moore635374e2009-03-09 01:21:12 -06004815 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4816 ioc->name, __FILE__, __LINE__, __func__);
4817 goto out;
4818 }
Eric Moore635374e2009-03-09 01:21:12 -06004819 ioc->sas_hba.enclosure_handle =
4820 le16_to_cpu(sas_device_pg0.EnclosureHandle);
4821 ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
4822 printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
4823 "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
4824 (unsigned long long) ioc->sas_hba.sas_address,
4825 ioc->sas_hba.num_phys) ;
4826
4827 if (ioc->sas_hba.enclosure_handle) {
4828 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
4829 &enclosure_pg0,
4830 MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4831 ioc->sas_hba.enclosure_handle))) {
4832 ioc->sas_hba.enclosure_logical_id =
4833 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
4834 }
4835 }
4836
4837 out:
4838 kfree(sas_iounit_pg1);
4839 kfree(sas_iounit_pg0);
4840}
4841
4842/**
4843 * _scsih_expander_add - creating expander object
4844 * @ioc: per adapter object
4845 * @handle: expander handle
4846 *
4847 * Creating expander object, stored in ioc->sas_expander_list.
4848 *
4849 * Return 0 for success, else error.
4850 */
4851static int
4852_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
4853{
4854 struct _sas_node *sas_expander;
4855 Mpi2ConfigReply_t mpi_reply;
4856 Mpi2ExpanderPage0_t expander_pg0;
4857 Mpi2ExpanderPage1_t expander_pg1;
4858 Mpi2SasEnclosurePage0_t enclosure_pg0;
4859 u32 ioc_status;
4860 u16 parent_handle;
Kashyap, Desaic97951e2011-06-14 10:54:56 +05304861 u64 sas_address, sas_address_parent = 0;
Eric Moore635374e2009-03-09 01:21:12 -06004862 int i;
4863 unsigned long flags;
Kashyap, Desai20f58952009-08-07 19:34:26 +05304864 struct _sas_port *mpt2sas_port = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06004865 int rc = 0;
4866
4867 if (!handle)
4868 return -1;
4869
Eric Moore3cb54692010-07-08 14:44:34 -06004870 if (ioc->shost_recovery || ioc->pci_error_recovery)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05304871 return -1;
4872
Eric Moore635374e2009-03-09 01:21:12 -06004873 if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
4874 MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
4875 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4876 ioc->name, __FILE__, __LINE__, __func__);
4877 return -1;
4878 }
4879
4880 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
4881 MPI2_IOCSTATUS_MASK;
4882 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
4883 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4884 ioc->name, __FILE__, __LINE__, __func__);
4885 return -1;
4886 }
4887
4888 /* handle out of order topology events */
4889 parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304890 if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
4891 != 0) {
4892 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4893 ioc->name, __FILE__, __LINE__, __func__);
4894 return -1;
4895 }
4896 if (sas_address_parent != ioc->sas_hba.sas_address) {
Eric Moore635374e2009-03-09 01:21:12 -06004897 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304898 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
4899 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004900 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4901 if (!sas_expander) {
4902 rc = _scsih_expander_add(ioc, parent_handle);
4903 if (rc != 0)
4904 return rc;
4905 }
4906 }
4907
Eric Moore635374e2009-03-09 01:21:12 -06004908 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05304909 sas_address = le64_to_cpu(expander_pg0.SASAddress);
Eric Moore635374e2009-03-09 01:21:12 -06004910 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
4911 sas_address);
4912 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
4913
4914 if (sas_expander)
4915 return 0;
4916
4917 sas_expander = kzalloc(sizeof(struct _sas_node),
4918 GFP_KERNEL);
4919 if (!sas_expander) {
4920 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4921 ioc->name, __FILE__, __LINE__, __func__);
4922 return -1;
4923 }
4924
4925 sas_expander->handle = handle;
4926 sas_expander->num_phys = expander_pg0.NumPhys;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304927 sas_expander->sas_address_parent = sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06004928 sas_expander->sas_address = sas_address;
4929
4930 printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
4931 " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304932 handle, parent_handle, (unsigned long long)
Eric Moore635374e2009-03-09 01:21:12 -06004933 sas_expander->sas_address, sas_expander->num_phys);
4934
4935 if (!sas_expander->num_phys)
4936 goto out_fail;
4937 sas_expander->phy = kcalloc(sas_expander->num_phys,
4938 sizeof(struct _sas_phy), GFP_KERNEL);
4939 if (!sas_expander->phy) {
4940 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4941 ioc->name, __FILE__, __LINE__, __func__);
4942 rc = -1;
4943 goto out_fail;
4944 }
4945
4946 INIT_LIST_HEAD(&sas_expander->sas_port_list);
4947 mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304948 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004949 if (!mpt2sas_port) {
4950 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4951 ioc->name, __FILE__, __LINE__, __func__);
4952 rc = -1;
4953 goto out_fail;
4954 }
4955 sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
4956
4957 for (i = 0 ; i < sas_expander->num_phys ; i++) {
4958 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
4959 &expander_pg1, i, handle))) {
4960 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4961 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai20f58952009-08-07 19:34:26 +05304962 rc = -1;
4963 goto out_fail;
Eric Moore635374e2009-03-09 01:21:12 -06004964 }
4965 sas_expander->phy[i].handle = handle;
4966 sas_expander->phy[i].phy_id = i;
Kashyap, Desai20f58952009-08-07 19:34:26 +05304967
4968 if ((mpt2sas_transport_add_expander_phy(ioc,
4969 &sas_expander->phy[i], expander_pg1,
4970 sas_expander->parent_dev))) {
4971 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
4972 ioc->name, __FILE__, __LINE__, __func__);
4973 rc = -1;
4974 goto out_fail;
4975 }
Eric Moore635374e2009-03-09 01:21:12 -06004976 }
4977
4978 if (sas_expander->enclosure_handle) {
4979 if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
4980 &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
4981 sas_expander->enclosure_handle))) {
4982 sas_expander->enclosure_logical_id =
4983 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
4984 }
4985 }
4986
4987 _scsih_expander_node_add(ioc, sas_expander);
4988 return 0;
4989
4990 out_fail:
4991
Kashyap, Desai20f58952009-08-07 19:34:26 +05304992 if (mpt2sas_port)
4993 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05304994 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06004995 kfree(sas_expander);
4996 return rc;
4997}
4998
4999/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05305000 * _scsih_done - scsih callback handler.
5001 * @ioc: per adapter object
5002 * @smid: system request message index
5003 * @msix_index: MSIX table index supplied by the OS
5004 * @reply: reply message frame(lower 32bit addr)
5005 *
5006 * Callback handler when sending internal generated message frames.
5007 * The callback index passed is `ioc->scsih_cb_idx`
5008 *
5009 * Return 1 meaning mf should be freed from _base_interrupt
5010 * 0 means the mf is freed from this function.
5011 */
5012static u8
5013_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
5014{
5015 MPI2DefaultReply_t *mpi_reply;
5016
5017 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
5018 if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
5019 return 1;
5020 if (ioc->scsih_cmds.smid != smid)
5021 return 1;
5022 ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
5023 if (mpi_reply) {
5024 memcpy(ioc->scsih_cmds.reply, mpi_reply,
5025 mpi_reply->MsgLength*4);
5026 ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
5027 }
5028 ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
5029 complete(&ioc->scsih_cmds.done);
5030 return 1;
5031}
5032
5033/**
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305034 * mpt2sas_expander_remove - removing expander object
Eric Moore635374e2009-03-09 01:21:12 -06005035 * @ioc: per adapter object
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305036 * @sas_address: expander sas_address
Eric Moore635374e2009-03-09 01:21:12 -06005037 *
5038 * Return nothing.
5039 */
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305040void
5041mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
Eric Moore635374e2009-03-09 01:21:12 -06005042{
5043 struct _sas_node *sas_expander;
5044 unsigned long flags;
5045
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305046 if (ioc->shost_recovery)
5047 return;
5048
Eric Moore635374e2009-03-09 01:21:12 -06005049 spin_lock_irqsave(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305050 sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
5051 sas_address);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305052 if (sas_expander)
5053 list_del(&sas_expander->list);
Eric Moore635374e2009-03-09 01:21:12 -06005054 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305055 if (sas_expander)
5056 _scsih_expander_node_remove(ioc, sas_expander);
Eric Moore635374e2009-03-09 01:21:12 -06005057}
5058
5059/**
Kashyap, Desaib4344272010-03-17 16:24:14 +05305060 * _scsih_check_access_status - check access flags
5061 * @ioc: per adapter object
5062 * @sas_address: sas address
5063 * @handle: sas device handle
5064 * @access_flags: errors returned during discovery of the device
5065 *
5066 * Return 0 for success, else failure
5067 */
5068static u8
5069_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
5070 u16 handle, u8 access_status)
5071{
5072 u8 rc = 1;
5073 char *desc = NULL;
5074
5075 switch (access_status) {
5076 case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS:
5077 case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION:
5078 rc = 0;
5079 break;
5080 case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED:
5081 desc = "sata capability failed";
5082 break;
5083 case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT:
5084 desc = "sata affiliation conflict";
5085 break;
5086 case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE:
5087 desc = "route not addressable";
5088 break;
5089 case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE:
5090 desc = "smp error not addressable";
5091 break;
5092 case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED:
5093 desc = "device blocked";
5094 break;
5095 case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED:
5096 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN:
5097 case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT:
5098 case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG:
5099 case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION:
5100 case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER:
5101 case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN:
5102 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN:
5103 case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN:
5104 case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION:
5105 case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE:
5106 case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX:
5107 desc = "sata initialization failed";
5108 break;
5109 default:
5110 desc = "unknown";
5111 break;
5112 }
5113
5114 if (!rc)
5115 return 0;
5116
5117 printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), "
5118 "handle(0x%04x)\n", ioc->name, desc,
5119 (unsigned long long)sas_address, handle);
5120 return rc;
5121}
5122
5123static void
5124_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
5125{
5126 Mpi2ConfigReply_t mpi_reply;
5127 Mpi2SasDevicePage0_t sas_device_pg0;
5128 struct _sas_device *sas_device;
5129 u32 ioc_status;
5130 unsigned long flags;
5131 u64 sas_address;
5132 struct scsi_target *starget;
5133 struct MPT2SAS_TARGET *sas_target_priv_data;
5134 u32 device_info;
5135
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305136
Kashyap, Desaib4344272010-03-17 16:24:14 +05305137 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
5138 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
5139 return;
5140
5141 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
5142 if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
5143 return;
5144
5145 /* check if this is end device */
5146 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5147 if (!(_scsih_is_end_device(device_info)))
5148 return;
5149
5150 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5151 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5152 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5153 sas_address);
5154
5155 if (!sas_device) {
5156 printk(MPT2SAS_ERR_FMT "device is not present "
5157 "handle(0x%04x), no sas_device!!!\n", ioc->name, handle);
5158 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5159 return;
5160 }
5161
5162 if (unlikely(sas_device->handle != handle)) {
5163 starget = sas_device->starget;
5164 sas_target_priv_data = starget->hostdata;
5165 starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)"
5166 " to (0x%04x)!!!\n", sas_device->handle, handle);
5167 sas_target_priv_data->handle = handle;
5168 sas_device->handle = handle;
5169 }
Kashyap, Desaib4344272010-03-17 16:24:14 +05305170
5171 /* check if device is present */
5172 if (!(le16_to_cpu(sas_device_pg0.Flags) &
5173 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
5174 printk(MPT2SAS_ERR_FMT "device is not present "
5175 "handle(0x%04x), flags!!!\n", ioc->name, handle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305176 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desaib4344272010-03-17 16:24:14 +05305177 return;
5178 }
5179
5180 /* check if there were any issues with discovery */
5181 if (_scsih_check_access_status(ioc, sas_address, handle,
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305182 sas_device_pg0.AccessStatus)) {
5183 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desaib4344272010-03-17 16:24:14 +05305184 return;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305185 }
5186 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desaib4344272010-03-17 16:24:14 +05305187 _scsih_ublock_io_device(ioc, handle);
5188
5189}
5190
5191/**
Eric Moore635374e2009-03-09 01:21:12 -06005192 * _scsih_add_device - creating sas device object
5193 * @ioc: per adapter object
5194 * @handle: sas device handle
5195 * @phy_num: phy number end device attached to
5196 * @is_pd: is this hidden raid component
5197 *
5198 * Creating end device object, stored in ioc->sas_device_list.
5199 *
5200 * Returns 0 for success, non-zero for failure.
5201 */
5202static int
5203_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
5204{
5205 Mpi2ConfigReply_t mpi_reply;
5206 Mpi2SasDevicePage0_t sas_device_pg0;
5207 Mpi2SasEnclosurePage0_t enclosure_pg0;
5208 struct _sas_device *sas_device;
5209 u32 ioc_status;
5210 __le64 sas_address;
5211 u32 device_info;
5212 unsigned long flags;
5213
5214 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
5215 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
5216 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5217 ioc->name, __FILE__, __LINE__, __func__);
5218 return -1;
5219 }
5220
5221 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
5222 MPI2_IOCSTATUS_MASK;
5223 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5224 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5225 ioc->name, __FILE__, __LINE__, __func__);
5226 return -1;
5227 }
5228
Kashyap, Desaib4344272010-03-17 16:24:14 +05305229 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
5230
Eric Moore635374e2009-03-09 01:21:12 -06005231 /* check if device is present */
5232 if (!(le16_to_cpu(sas_device_pg0.Flags) &
5233 MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
5234 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5235 ioc->name, __FILE__, __LINE__, __func__);
5236 printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
5237 ioc->name, le16_to_cpu(sas_device_pg0.Flags));
5238 return -1;
5239 }
5240
Kashyap, Desaib4344272010-03-17 16:24:14 +05305241 /* check if there were any issues with discovery */
5242 if (_scsih_check_access_status(ioc, sas_address, handle,
5243 sas_device_pg0.AccessStatus))
Eric Moore635374e2009-03-09 01:21:12 -06005244 return -1;
Eric Moore635374e2009-03-09 01:21:12 -06005245
5246 /* check if this is end device */
5247 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
5248 if (!(_scsih_is_end_device(device_info))) {
5249 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5250 ioc->name, __FILE__, __LINE__, __func__);
5251 return -1;
5252 }
5253
Eric Moore635374e2009-03-09 01:21:12 -06005254
5255 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5256 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5257 sas_address);
5258 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5259
Kashyap, Desaib4344272010-03-17 16:24:14 +05305260 if (sas_device)
Eric Moore635374e2009-03-09 01:21:12 -06005261 return 0;
Eric Moore635374e2009-03-09 01:21:12 -06005262
5263 sas_device = kzalloc(sizeof(struct _sas_device),
5264 GFP_KERNEL);
5265 if (!sas_device) {
5266 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5267 ioc->name, __FILE__, __LINE__, __func__);
5268 return -1;
5269 }
5270
5271 sas_device->handle = handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305272 if (_scsih_get_sas_address(ioc, le16_to_cpu
5273 (sas_device_pg0.ParentDevHandle),
5274 &sas_device->sas_address_parent) != 0)
5275 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
5276 ioc->name, __FILE__, __LINE__, __func__);
Eric Moore635374e2009-03-09 01:21:12 -06005277 sas_device->enclosure_handle =
5278 le16_to_cpu(sas_device_pg0.EnclosureHandle);
5279 sas_device->slot =
5280 le16_to_cpu(sas_device_pg0.Slot);
5281 sas_device->device_info = device_info;
5282 sas_device->sas_address = sas_address;
Kashyap, Desai7fbae672010-06-17 13:45:17 +05305283 sas_device->phy = sas_device_pg0.PhyNum;
Eric Moore635374e2009-03-09 01:21:12 -06005284
5285 /* get enclosure_logical_id */
Kashyap, Desai15052c92009-08-07 19:33:17 +05305286 if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
5287 ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
5288 sas_device->enclosure_handle)))
Eric Moore635374e2009-03-09 01:21:12 -06005289 sas_device->enclosure_logical_id =
5290 le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
Eric Moore635374e2009-03-09 01:21:12 -06005291
5292 /* get device name */
5293 sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
5294
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05305295 if (ioc->wait_for_discovery_to_complete)
Eric Moore635374e2009-03-09 01:21:12 -06005296 _scsih_sas_device_init_add(ioc, sas_device);
5297 else
5298 _scsih_sas_device_add(ioc, sas_device);
5299
5300 return 0;
5301}
5302
5303/**
Kashyap, Desai1278b112010-03-09 17:34:13 +05305304 * _scsih_remove_device - removing sas device object
5305 * @ioc: per adapter object
5306 * @sas_device_delete: the sas_device object
5307 *
5308 * Return nothing.
5309 */
5310static void
5311_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
5312 struct _sas_device *sas_device)
5313{
Kashyap, Desai1278b112010-03-09 17:34:13 +05305314 struct MPT2SAS_TARGET *sas_target_priv_data;
Kashyap, Desai34a03be2009-08-20 13:23:19 +05305315
Kashyap, Desai1278b112010-03-09 17:34:13 +05305316 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
5317 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305318 sas_device->handle, (unsigned long long)
5319 sas_device->sas_address));
Kashyap, Desai1278b112010-03-09 17:34:13 +05305320
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305321 if (sas_device->starget && sas_device->starget->hostdata) {
5322 sas_target_priv_data = sas_device->starget->hostdata;
Kashyap, Desai1278b112010-03-09 17:34:13 +05305323 sas_target_priv_data->deleted = 1;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305324 _scsih_ublock_io_device(ioc, sas_device->handle);
nagalakshmi.nandigama@lsi.com918134e2011-10-19 15:37:24 +05305325 sas_target_priv_data->handle =
5326 MPT2SAS_INVALID_DEVICE_HANDLE;
Kashyap, Desai1278b112010-03-09 17:34:13 +05305327 }
5328
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05305329 if (!ioc->hide_drives)
5330 mpt2sas_transport_port_remove(ioc,
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305331 sas_device->sas_address,
5332 sas_device->sas_address_parent);
Kashyap, Desai1278b112010-03-09 17:34:13 +05305333
5334 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305335 "(0x%016llx)\n", ioc->name, sas_device->handle,
5336 (unsigned long long) sas_device->sas_address);
Kashyap, Desai1278b112010-03-09 17:34:13 +05305337
5338 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
5339 "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305340 sas_device->handle, (unsigned long long)
5341 sas_device->sas_address));
5342 kfree(sas_device);
5343}
5344/**
5345 * _scsih_device_remove_by_handle - removing device object by handle
5346 * @ioc: per adapter object
5347 * @handle: device handle
5348 *
5349 * Return nothing.
5350 */
5351static void
5352_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
5353{
5354 struct _sas_device *sas_device;
5355 unsigned long flags;
5356
5357 if (ioc->shost_recovery)
5358 return;
5359
5360 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5361 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
5362 if (sas_device)
5363 list_del(&sas_device->list);
5364 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
5365 if (sas_device)
5366 _scsih_remove_device(ioc, sas_device);
Eric Moore635374e2009-03-09 01:21:12 -06005367}
5368
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305369/**
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305370 * mpt2sas_device_remove_by_sas_address - removing device object by sas address
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305371 * @ioc: per adapter object
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305372 * @sas_address: device sas_address
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305373 *
5374 * Return nothing.
5375 */
5376void
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305377mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
5378 u64 sas_address)
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305379{
5380 struct _sas_device *sas_device;
5381 unsigned long flags;
5382
5383 if (ioc->shost_recovery)
5384 return;
5385
5386 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5387 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5388 sas_address);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305389 if (sas_device)
5390 list_del(&sas_device->list);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305391 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305392 if (sas_device)
5393 _scsih_remove_device(ioc, sas_device);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305394}
Eric Moore635374e2009-03-09 01:21:12 -06005395#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5396/**
5397 * _scsih_sas_topology_change_event_debug - debug for topology event
5398 * @ioc: per adapter object
5399 * @event_data: event data payload
5400 * Context: user.
5401 */
5402static void
5403_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5404 Mpi2EventDataSasTopologyChangeList_t *event_data)
5405{
5406 int i;
5407 u16 handle;
5408 u16 reason_code;
5409 u8 phy_number;
5410 char *status_str = NULL;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305411 u8 link_rate, prev_link_rate;
Eric Moore635374e2009-03-09 01:21:12 -06005412
5413 switch (event_data->ExpStatus) {
5414 case MPI2_EVENT_SAS_TOPO_ES_ADDED:
5415 status_str = "add";
5416 break;
5417 case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
5418 status_str = "remove";
5419 break;
5420 case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305421 case 0:
Eric Moore635374e2009-03-09 01:21:12 -06005422 status_str = "responding";
5423 break;
5424 case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
5425 status_str = "remove delay";
5426 break;
5427 default:
5428 status_str = "unknown status";
5429 break;
5430 }
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305431 printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n",
Eric Moore635374e2009-03-09 01:21:12 -06005432 ioc->name, status_str);
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305433 printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) "
Eric Moore635374e2009-03-09 01:21:12 -06005434 "start_phy(%02d), count(%d)\n",
5435 le16_to_cpu(event_data->ExpanderDevHandle),
5436 le16_to_cpu(event_data->EnclosureHandle),
5437 event_data->StartPhyNum, event_data->NumEntries);
5438 for (i = 0; i < event_data->NumEntries; i++) {
5439 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
5440 if (!handle)
5441 continue;
5442 phy_number = event_data->StartPhyNum + i;
5443 reason_code = event_data->PHY[i].PhyStatus &
5444 MPI2_EVENT_SAS_TOPO_RC_MASK;
5445 switch (reason_code) {
5446 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305447 status_str = "target add";
Eric Moore635374e2009-03-09 01:21:12 -06005448 break;
5449 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305450 status_str = "target remove";
Eric Moore635374e2009-03-09 01:21:12 -06005451 break;
5452 case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305453 status_str = "delay target remove";
Eric Moore635374e2009-03-09 01:21:12 -06005454 break;
5455 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305456 status_str = "link rate change";
Eric Moore635374e2009-03-09 01:21:12 -06005457 break;
5458 case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305459 status_str = "target responding";
Eric Moore635374e2009-03-09 01:21:12 -06005460 break;
5461 default:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305462 status_str = "unknown";
Eric Moore635374e2009-03-09 01:21:12 -06005463 break;
5464 }
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305465 link_rate = event_data->PHY[i].LinkRate >> 4;
5466 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305467 printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:"
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305468 " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
5469 handle, status_str, link_rate, prev_link_rate);
5470
Eric Moore635374e2009-03-09 01:21:12 -06005471 }
5472}
5473#endif
5474
5475/**
5476 * _scsih_sas_topology_change_event - handle topology changes
5477 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305478 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005479 * Context: user.
5480 *
5481 */
5482static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305483_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
Eric Moore635374e2009-03-09 01:21:12 -06005484 struct fw_event_work *fw_event)
5485{
5486 int i;
5487 u16 parent_handle, handle;
5488 u16 reason_code;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305489 u8 phy_number, max_phys;
Eric Moore635374e2009-03-09 01:21:12 -06005490 struct _sas_node *sas_expander;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305491 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06005492 unsigned long flags;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305493 u8 link_rate, prev_link_rate;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305494 Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06005495
5496#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5497 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5498 _scsih_sas_topology_change_event_debug(ioc, event_data);
5499#endif
5500
nagalakshmi.nandigama@lsi.com918134e2011-10-19 15:37:24 +05305501 if (ioc->remove_host || ioc->pci_error_recovery)
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305502 return;
5503
Eric Moore635374e2009-03-09 01:21:12 -06005504 if (!ioc->sas_hba.num_phys)
5505 _scsih_sas_host_add(ioc);
5506 else
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305507 _scsih_sas_host_refresh(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005508
5509 if (fw_event->ignore) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305510 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander "
Eric Moore635374e2009-03-09 01:21:12 -06005511 "event\n", ioc->name));
5512 return;
5513 }
5514
5515 parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
5516
5517 /* handle expander add */
5518 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
5519 if (_scsih_expander_add(ioc, parent_handle) != 0)
5520 return;
5521
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305522 spin_lock_irqsave(&ioc->sas_node_lock, flags);
5523 sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
5524 parent_handle);
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305525 if (sas_expander) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305526 sas_address = sas_expander->sas_address;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305527 max_phys = sas_expander->num_phys;
5528 } else if (parent_handle < ioc->sas_hba.num_phys) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305529 sas_address = ioc->sas_hba.sas_address;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305530 max_phys = ioc->sas_hba.num_phys;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305531 } else {
5532 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305533 return;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305534 }
5535 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305536
Eric Moore635374e2009-03-09 01:21:12 -06005537 /* handle siblings events */
5538 for (i = 0; i < event_data->NumEntries; i++) {
5539 if (fw_event->ignore) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305540 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring "
Eric Moore635374e2009-03-09 01:21:12 -06005541 "expander event\n", ioc->name));
5542 return;
5543 }
Eric Moore3cb54692010-07-08 14:44:34 -06005544 if (ioc->shost_recovery || ioc->remove_host ||
5545 ioc->pci_error_recovery)
Kashyap, Desai155dd4c2009-08-20 13:22:00 +05305546 return;
Kashyap, Desai308609c2009-09-14 11:07:23 +05305547 phy_number = event_data->StartPhyNum + i;
Kashyap, Desaib41c09d2010-11-13 04:40:51 +05305548 if (phy_number >= max_phys)
5549 continue;
Kashyap, Desai308609c2009-09-14 11:07:23 +05305550 reason_code = event_data->PHY[i].PhyStatus &
5551 MPI2_EVENT_SAS_TOPO_RC_MASK;
5552 if ((event_data->PHY[i].PhyStatus &
5553 MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
5554 MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
Eric Moore635374e2009-03-09 01:21:12 -06005555 continue;
5556 handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
5557 if (!handle)
5558 continue;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305559 link_rate = event_data->PHY[i].LinkRate >> 4;
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305560 prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
Eric Moore635374e2009-03-09 01:21:12 -06005561 switch (reason_code) {
5562 case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305563
nagalakshmi.nandigama@lsi.com918134e2011-10-19 15:37:24 +05305564 if (ioc->shost_recovery)
5565 break;
5566
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305567 if (link_rate == prev_link_rate)
5568 break;
5569
5570 mpt2sas_transport_update_links(ioc, sas_address,
5571 handle, phy_number, link_rate);
5572
Kashyap, Desaib4344272010-03-17 16:24:14 +05305573 if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
5574 break;
5575
5576 _scsih_check_device(ioc, handle);
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305577 break;
Eric Moore635374e2009-03-09 01:21:12 -06005578 case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305579
nagalakshmi.nandigama@lsi.com918134e2011-10-19 15:37:24 +05305580 if (ioc->shost_recovery)
5581 break;
5582
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305583 mpt2sas_transport_update_links(ioc, sas_address,
5584 handle, phy_number, link_rate);
5585
Kashyap, Desaie7d59c12009-09-23 17:36:52 +05305586 _scsih_add_device(ioc, handle, phy_number, 0);
Eric Moore635374e2009-03-09 01:21:12 -06005587 break;
5588 case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305589
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305590 _scsih_device_remove_by_handle(ioc, handle);
Eric Moore635374e2009-03-09 01:21:12 -06005591 break;
5592 }
5593 }
5594
5595 /* handle expander removal */
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05305596 if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
5597 sas_expander)
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05305598 mpt2sas_expander_remove(ioc, sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06005599
5600}
5601
5602#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5603/**
5604 * _scsih_sas_device_status_change_event_debug - debug for device event
5605 * @event_data: event data payload
5606 * Context: user.
5607 *
5608 * Return nothing.
5609 */
5610static void
5611_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5612 Mpi2EventDataSasDeviceStatusChange_t *event_data)
5613{
5614 char *reason_str = NULL;
5615
5616 switch (event_data->ReasonCode) {
5617 case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
5618 reason_str = "smart data";
5619 break;
5620 case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
5621 reason_str = "unsupported device discovered";
5622 break;
5623 case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
5624 reason_str = "internal device reset";
5625 break;
5626 case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
5627 reason_str = "internal task abort";
5628 break;
5629 case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
5630 reason_str = "internal task abort set";
5631 break;
5632 case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
5633 reason_str = "internal clear task set";
5634 break;
5635 case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
5636 reason_str = "internal query task";
5637 break;
5638 case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
5639 reason_str = "sata init failure";
5640 break;
5641 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
5642 reason_str = "internal device reset complete";
5643 break;
5644 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
5645 reason_str = "internal task abort complete";
5646 break;
5647 case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
5648 reason_str = "internal async notification";
5649 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05305650 case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
5651 reason_str = "expander reduced functionality";
5652 break;
5653 case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
5654 reason_str = "expander reduced functionality complete";
5655 break;
Eric Moore635374e2009-03-09 01:21:12 -06005656 default:
5657 reason_str = "unknown reason";
5658 break;
5659 }
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305660 printk(MPT2SAS_INFO_FMT "device status change: (%s)\n"
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305661 "\thandle(0x%04x), sas address(0x%016llx), tag(%d)",
5662 ioc->name, reason_str, le16_to_cpu(event_data->DevHandle),
5663 (unsigned long long)le64_to_cpu(event_data->SASAddress),
5664 le16_to_cpu(event_data->TaskTag));
Eric Moore635374e2009-03-09 01:21:12 -06005665 if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305666 printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
Eric Moore635374e2009-03-09 01:21:12 -06005667 event_data->ASC, event_data->ASCQ);
5668 printk(KERN_INFO "\n");
5669}
5670#endif
5671
5672/**
5673 * _scsih_sas_device_status_change_event - handle device status change
5674 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305675 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005676 * Context: user.
5677 *
5678 * Return nothing.
5679 */
5680static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305681_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
5682 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005683{
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305684 struct MPT2SAS_TARGET *target_priv_data;
5685 struct _sas_device *sas_device;
Kashyap, Desaic97951e2011-06-14 10:54:56 +05305686 u64 sas_address;
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305687 unsigned long flags;
5688 Mpi2EventDataSasDeviceStatusChange_t *event_data =
5689 fw_event->event_data;
5690
Eric Moore635374e2009-03-09 01:21:12 -06005691#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5692 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305693 _scsih_sas_device_status_change_event_debug(ioc,
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305694 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005695#endif
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305696
Kashyap, Desaiefe82a12011-01-04 11:34:17 +05305697 /* In MPI Revision K (0xC), the internal device reset complete was
5698 * implemented, so avoid setting tm_busy flag for older firmware.
5699 */
5700 if ((ioc->facts.HeaderVersion >> 8) < 0xC)
5701 return;
5702
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05305703 if (event_data->ReasonCode !=
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305704 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
Kashyap, Desaif891dcf2010-03-17 16:22:21 +05305705 event_data->ReasonCode !=
5706 MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305707 return;
5708
5709 spin_lock_irqsave(&ioc->sas_device_lock, flags);
5710 sas_address = le64_to_cpu(event_data->SASAddress);
5711 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
5712 sas_address);
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305713
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305714 if (!sas_device || !sas_device->starget) {
5715 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305716 return;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305717 }
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305718
5719 target_priv_data = sas_device->starget->hostdata;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305720 if (!target_priv_data) {
5721 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305722 return;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305723 }
Kashyap, Desai8ffc4572009-09-23 17:35:41 +05305724
5725 if (event_data->ReasonCode ==
5726 MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
5727 target_priv_data->tm_busy = 1;
5728 else
5729 target_priv_data->tm_busy = 0;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05305730 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06005731}
5732
5733#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5734/**
5735 * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
5736 * @ioc: per adapter object
5737 * @event_data: event data payload
5738 * Context: user.
5739 *
5740 * Return nothing.
5741 */
5742static void
5743_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
5744 Mpi2EventDataSasEnclDevStatusChange_t *event_data)
5745{
5746 char *reason_str = NULL;
5747
5748 switch (event_data->ReasonCode) {
5749 case MPI2_EVENT_SAS_ENCL_RC_ADDED:
5750 reason_str = "enclosure add";
5751 break;
5752 case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
5753 reason_str = "enclosure remove";
5754 break;
5755 default:
5756 reason_str = "unknown reason";
5757 break;
5758 }
5759
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305760 printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n"
Eric Moore635374e2009-03-09 01:21:12 -06005761 "\thandle(0x%04x), enclosure logical id(0x%016llx)"
5762 " number slots(%d)\n", ioc->name, reason_str,
5763 le16_to_cpu(event_data->EnclosureHandle),
5764 (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
5765 le16_to_cpu(event_data->StartSlot));
5766}
5767#endif
5768
5769/**
5770 * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
5771 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305772 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005773 * Context: user.
5774 *
5775 * Return nothing.
5776 */
5777static void
5778_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305779 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005780{
5781#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5782 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
5783 _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305784 fw_event->event_data);
Eric Moore635374e2009-03-09 01:21:12 -06005785#endif
5786}
5787
5788/**
Andrew Mortona78e21d2012-02-08 12:52:22 -08005789 * _scsih_sas_broadcast_primitive_event - handle broadcast events
Eric Moore635374e2009-03-09 01:21:12 -06005790 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305791 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005792 * Context: user.
5793 *
5794 * Return nothing.
5795 */
5796static void
Andrew Mortona78e21d2012-02-08 12:52:22 -08005797_scsih_sas_broadcast_primitive_event(struct MPT2SAS_ADAPTER *ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305798 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005799{
5800 struct scsi_cmnd *scmd;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305801 struct scsi_device *sdev;
Eric Moore635374e2009-03-09 01:21:12 -06005802 u16 smid, handle;
5803 u32 lun;
5804 struct MPT2SAS_DEVICE *sas_device_priv_data;
5805 u32 termination_count;
5806 u32 query_count;
5807 Mpi2SCSITaskManagementReply_t *mpi_reply;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305808 Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
Kashyap, Desai463217b2009-10-05 15:53:06 +05305809 u16 ioc_status;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305810 unsigned long flags;
5811 int r;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305812 u8 max_retries = 0;
5813 u8 task_abort_retries;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305814
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305815 mutex_lock(&ioc->tm_cmds.mutex);
5816 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: phy number(%d), "
5817 "width(%d)\n", ioc->name, __func__, event_data->PhyNum,
5818 event_data->PortWidth));
5819
5820 _scsih_block_io_all_device(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06005821
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305822 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305823 mpi_reply = ioc->tm_cmds.reply;
5824broadcast_aen_retry:
5825
5826 /* sanity checks for retrying this loop */
5827 if (max_retries++ == 5) {
5828 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n",
5829 ioc->name, __func__));
5830 goto out;
5831 } else if (max_retries > 1)
5832 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n",
5833 ioc->name, __func__, max_retries - 1));
5834
Eric Moore635374e2009-03-09 01:21:12 -06005835 termination_count = 0;
5836 query_count = 0;
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05305837 for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05305838 if (ioc->shost_recovery)
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305839 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06005840 scmd = _scsih_scsi_lookup_get(ioc, smid);
5841 if (!scmd)
5842 continue;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305843 sdev = scmd->device;
5844 sas_device_priv_data = sdev->hostdata;
Eric Moore635374e2009-03-09 01:21:12 -06005845 if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
5846 continue;
5847 /* skip hidden raid components */
5848 if (sas_device_priv_data->sas_target->flags &
5849 MPT_TARGET_FLAGS_RAID_COMPONENT)
5850 continue;
5851 /* skip volumes */
5852 if (sas_device_priv_data->sas_target->flags &
5853 MPT_TARGET_FLAGS_VOLUME)
5854 continue;
5855
5856 handle = sas_device_priv_data->sas_target->handle;
5857 lun = sas_device_priv_data->lun;
5858 query_count++;
5859
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05305860 if (ioc->shost_recovery)
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305861 goto out;
5862
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305863 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305864 r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
5865 MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, 0,
5866 TM_MUTEX_OFF);
5867 if (r == FAILED) {
5868 sdev_printk(KERN_WARNING, sdev,
5869 "mpt2sas_scsih_issue_tm: FAILED when sending "
5870 "QUERY_TASK: scmd(%p)\n", scmd);
5871 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
5872 goto broadcast_aen_retry;
5873 }
Kashyap, Desai463217b2009-10-05 15:53:06 +05305874 ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
5875 & MPI2_IOCSTATUS_MASK;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305876 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
5877 sdev_printk(KERN_WARNING, sdev, "query task: FAILED "
5878 "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status,
5879 scmd);
5880 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
5881 goto broadcast_aen_retry;
5882 }
5883
5884 /* see if IO is still owned by IOC and target */
5885 if (mpi_reply->ResponseCode ==
Eric Moore635374e2009-03-09 01:21:12 -06005886 MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
5887 mpi_reply->ResponseCode ==
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305888 MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) {
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305889 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06005890 continue;
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305891 }
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305892 task_abort_retries = 0;
5893 tm_retry:
5894 if (task_abort_retries++ == 60) {
5895 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
5896 "%s: ABORT_TASK: giving up\n", ioc->name,
5897 __func__));
5898 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
5899 goto broadcast_aen_retry;
5900 }
5901
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05305902 if (ioc->shost_recovery)
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305903 goto out_no_lock;
5904
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305905 r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id,
5906 sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305907 scmd->serial_number, TM_MUTEX_OFF);
5908 if (r == FAILED) {
5909 sdev_printk(KERN_WARNING, sdev,
5910 "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : "
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305911 "scmd(%p)\n", scmd);
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305912 goto tm_retry;
5913 }
5914
5915 if (task_abort_retries > 1)
5916 sdev_printk(KERN_WARNING, sdev,
5917 "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):"
5918 " scmd(%p)\n",
5919 task_abort_retries - 1, scmd);
5920
Eric Moore635374e2009-03-09 01:21:12 -06005921 termination_count += le32_to_cpu(mpi_reply->TerminationCount);
Kashyap, Desaiec07a052011-01-05 17:54:32 +05305922 spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06005923 }
Eric Moore635374e2009-03-09 01:21:12 -06005924
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305925 if (ioc->broadcast_aen_pending) {
5926 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to"
5927 " pending AEN\n", ioc->name, __func__));
5928 ioc->broadcast_aen_pending = 0;
5929 goto broadcast_aen_retry;
5930 }
5931
5932 out:
5933 spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
5934 out_no_lock:
5935
5936 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
Eric Moore635374e2009-03-09 01:21:12 -06005937 "%s - exit, query_count = %d termination_count = %d\n",
5938 ioc->name, __func__, query_count, termination_count));
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305939
5940 ioc->broadcast_aen_busy = 0;
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05305941 if (!ioc->shost_recovery)
Kashyap, Desaif93213d2011-06-14 10:56:43 +05305942 _scsih_ublock_io_all_device(ioc);
5943 mutex_unlock(&ioc->tm_cmds.mutex);
Eric Moore635374e2009-03-09 01:21:12 -06005944}
5945
5946/**
5947 * _scsih_sas_discovery_event - handle discovery events
5948 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305949 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06005950 * Context: user.
5951 *
5952 * Return nothing.
5953 */
5954static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305955_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
5956 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06005957{
Kashyap, Desai7b936b02009-09-25 11:44:41 +05305958 Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
5959
Eric Moore635374e2009-03-09 01:21:12 -06005960#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
5961 if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05305962 printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name,
Eric Moore635374e2009-03-09 01:21:12 -06005963 (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
5964 "start" : "stop");
5965 if (event_data->DiscoveryStatus)
Kashyap, Desai595bb0b2009-09-14 11:02:48 +05305966 printk("discovery_status(0x%08x)",
5967 le32_to_cpu(event_data->DiscoveryStatus));
Eric Moore635374e2009-03-09 01:21:12 -06005968 printk("\n");
5969 }
5970#endif
5971
5972 if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
5973 !ioc->sas_hba.num_phys)
5974 _scsih_sas_host_add(ioc);
5975}
5976
5977/**
5978 * _scsih_reprobe_lun - reprobing lun
5979 * @sdev: scsi device struct
5980 * @no_uld_attach: sdev->no_uld_attach flag setting
5981 *
5982 **/
5983static void
5984_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
5985{
5986 int rc;
5987
5988 sdev->no_uld_attach = no_uld_attach ? 1 : 0;
5989 sdev_printk(KERN_INFO, sdev, "%s raid component\n",
5990 sdev->no_uld_attach ? "hidding" : "exposing");
5991 rc = scsi_device_reprobe(sdev);
5992}
5993
5994/**
Eric Moore635374e2009-03-09 01:21:12 -06005995 * _scsih_sas_volume_add - add new volume
5996 * @ioc: per adapter object
5997 * @element: IR config element data
5998 * Context: user.
5999 *
6000 * Return nothing.
6001 */
6002static void
6003_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
6004 Mpi2EventIrConfigElement_t *element)
6005{
6006 struct _raid_device *raid_device;
6007 unsigned long flags;
6008 u64 wwid;
6009 u16 handle = le16_to_cpu(element->VolDevHandle);
6010 int rc;
6011
Eric Moore635374e2009-03-09 01:21:12 -06006012 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
6013 if (!wwid) {
6014 printk(MPT2SAS_ERR_FMT
6015 "failure at %s:%d/%s()!\n", ioc->name,
6016 __FILE__, __LINE__, __func__);
6017 return;
6018 }
6019
6020 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6021 raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
6022 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6023
6024 if (raid_device)
6025 return;
6026
6027 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
6028 if (!raid_device) {
6029 printk(MPT2SAS_ERR_FMT
6030 "failure at %s:%d/%s()!\n", ioc->name,
6031 __FILE__, __LINE__, __func__);
6032 return;
6033 }
6034
6035 raid_device->id = ioc->sas_id++;
6036 raid_device->channel = RAID_CHANNEL;
6037 raid_device->handle = handle;
6038 raid_device->wwid = wwid;
6039 _scsih_raid_device_add(ioc, raid_device);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306040 if (!ioc->wait_for_discovery_to_complete) {
Eric Moore635374e2009-03-09 01:21:12 -06006041 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6042 raid_device->id, 0);
6043 if (rc)
6044 _scsih_raid_device_remove(ioc, raid_device);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306045 } else {
6046 spin_lock_irqsave(&ioc->raid_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06006047 _scsih_determine_boot_device(ioc, raid_device, 1);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306048 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6049 }
Eric Moore635374e2009-03-09 01:21:12 -06006050}
6051
6052/**
6053 * _scsih_sas_volume_delete - delete volume
6054 * @ioc: per adapter object
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306055 * @handle: volume device handle
Eric Moore635374e2009-03-09 01:21:12 -06006056 * Context: user.
6057 *
6058 * Return nothing.
6059 */
6060static void
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306061_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
Eric Moore635374e2009-03-09 01:21:12 -06006062{
6063 struct _raid_device *raid_device;
Eric Moore635374e2009-03-09 01:21:12 -06006064 unsigned long flags;
6065 struct MPT2SAS_TARGET *sas_target_priv_data;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306066 struct scsi_target *starget = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06006067
Eric Moore635374e2009-03-09 01:21:12 -06006068 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6069 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306070 if (raid_device) {
6071 if (raid_device->starget) {
6072 starget = raid_device->starget;
6073 sas_target_priv_data = starget->hostdata;
6074 sas_target_priv_data->deleted = 1;
6075 }
6076 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
6077 "(0x%016llx)\n", ioc->name, raid_device->handle,
6078 (unsigned long long) raid_device->wwid);
6079 list_del(&raid_device->list);
6080 kfree(raid_device);
Eric Moore635374e2009-03-09 01:21:12 -06006081 }
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306082 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6083 if (starget)
6084 scsi_remove_target(&starget->dev);
Eric Moore635374e2009-03-09 01:21:12 -06006085}
6086
6087/**
6088 * _scsih_sas_pd_expose - expose pd component to /dev/sdX
6089 * @ioc: per adapter object
6090 * @element: IR config element data
6091 * Context: user.
6092 *
6093 * Return nothing.
6094 */
6095static void
6096_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
6097 Mpi2EventIrConfigElement_t *element)
6098{
6099 struct _sas_device *sas_device;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306100 struct scsi_target *starget = NULL;
6101 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06006102 unsigned long flags;
6103 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
6104
6105 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6106 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306107 if (sas_device) {
6108 sas_device->volume_handle = 0;
6109 sas_device->volume_wwid = 0;
6110 clear_bit(handle, ioc->pd_handles);
6111 if (sas_device->starget && sas_device->starget->hostdata) {
6112 starget = sas_device->starget;
6113 sas_target_priv_data = starget->hostdata;
6114 sas_target_priv_data->flags &=
6115 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
6116 }
6117 }
Eric Moore635374e2009-03-09 01:21:12 -06006118 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6119 if (!sas_device)
6120 return;
6121
6122 /* exposing raid component */
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306123 if (starget)
6124 starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
Eric Moore635374e2009-03-09 01:21:12 -06006125}
6126
6127/**
6128 * _scsih_sas_pd_hide - hide pd component from /dev/sdX
6129 * @ioc: per adapter object
6130 * @element: IR config element data
6131 * Context: user.
6132 *
6133 * Return nothing.
6134 */
6135static void
6136_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
6137 Mpi2EventIrConfigElement_t *element)
6138{
6139 struct _sas_device *sas_device;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306140 struct scsi_target *starget = NULL;
6141 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06006142 unsigned long flags;
6143 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306144 u16 volume_handle = 0;
6145 u64 volume_wwid = 0;
6146
6147 mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle);
6148 if (volume_handle)
6149 mpt2sas_config_get_volume_wwid(ioc, volume_handle,
6150 &volume_wwid);
Eric Moore635374e2009-03-09 01:21:12 -06006151
6152 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6153 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306154 if (sas_device) {
6155 set_bit(handle, ioc->pd_handles);
6156 if (sas_device->starget && sas_device->starget->hostdata) {
6157 starget = sas_device->starget;
6158 sas_target_priv_data = starget->hostdata;
6159 sas_target_priv_data->flags |=
6160 MPT_TARGET_FLAGS_RAID_COMPONENT;
6161 sas_device->volume_handle = volume_handle;
6162 sas_device->volume_wwid = volume_wwid;
6163 }
6164 }
Eric Moore635374e2009-03-09 01:21:12 -06006165 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6166 if (!sas_device)
6167 return;
6168
6169 /* hiding raid component */
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306170 if (starget)
6171 starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
Eric Moore635374e2009-03-09 01:21:12 -06006172}
6173
6174/**
6175 * _scsih_sas_pd_delete - delete pd component
6176 * @ioc: per adapter object
6177 * @element: IR config element data
6178 * Context: user.
6179 *
6180 * Return nothing.
6181 */
6182static void
6183_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
6184 Mpi2EventIrConfigElement_t *element)
6185{
Eric Moore635374e2009-03-09 01:21:12 -06006186 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
6187
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306188 _scsih_device_remove_by_handle(ioc, handle);
Eric Moore635374e2009-03-09 01:21:12 -06006189}
6190
6191/**
6192 * _scsih_sas_pd_add - remove pd component
6193 * @ioc: per adapter object
6194 * @element: IR config element data
6195 * Context: user.
6196 *
6197 * Return nothing.
6198 */
6199static void
6200_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
6201 Mpi2EventIrConfigElement_t *element)
6202{
6203 struct _sas_device *sas_device;
6204 unsigned long flags;
6205 u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Kashyap, Desai62727a72009-08-07 19:35:18 +05306206 Mpi2ConfigReply_t mpi_reply;
6207 Mpi2SasDevicePage0_t sas_device_pg0;
6208 u32 ioc_status;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306209 u64 sas_address;
6210 u16 parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06006211
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306212 set_bit(handle, ioc->pd_handles);
6213
Eric Moore635374e2009-03-09 01:21:12 -06006214 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6215 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
6216 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306217 if (sas_device)
Kashyap, Desai62727a72009-08-07 19:35:18 +05306218 return;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306219
6220 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
6221 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
6222 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6223 ioc->name, __FILE__, __LINE__, __func__);
6224 return;
6225 }
6226
6227 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6228 MPI2_IOCSTATUS_MASK;
6229 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
6230 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6231 ioc->name, __FILE__, __LINE__, __func__);
6232 return;
6233 }
6234
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306235 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
6236 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
6237 mpt2sas_transport_update_links(ioc, sas_address, handle,
6238 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05306239
6240 _scsih_add_device(ioc, handle, 0, 1);
Eric Moore635374e2009-03-09 01:21:12 -06006241}
6242
6243#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
6244/**
6245 * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
6246 * @ioc: per adapter object
6247 * @event_data: event data payload
6248 * Context: user.
6249 *
6250 * Return nothing.
6251 */
6252static void
6253_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
6254 Mpi2EventDataIrConfigChangeList_t *event_data)
6255{
6256 Mpi2EventIrConfigElement_t *element;
6257 u8 element_type;
6258 int i;
6259 char *reason_str = NULL, *element_str = NULL;
6260
6261 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
6262
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306263 printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n",
Eric Moore635374e2009-03-09 01:21:12 -06006264 ioc->name, (le32_to_cpu(event_data->Flags) &
6265 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
6266 "foreign" : "native", event_data->NumElements);
6267 for (i = 0; i < event_data->NumElements; i++, element++) {
6268 switch (element->ReasonCode) {
6269 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
6270 reason_str = "add";
6271 break;
6272 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
6273 reason_str = "remove";
6274 break;
6275 case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
6276 reason_str = "no change";
6277 break;
6278 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
6279 reason_str = "hide";
6280 break;
6281 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
6282 reason_str = "unhide";
6283 break;
6284 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
6285 reason_str = "volume_created";
6286 break;
6287 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
6288 reason_str = "volume_deleted";
6289 break;
6290 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
6291 reason_str = "pd_created";
6292 break;
6293 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
6294 reason_str = "pd_deleted";
6295 break;
6296 default:
6297 reason_str = "unknown reason";
6298 break;
6299 }
6300 element_type = le16_to_cpu(element->ElementFlags) &
6301 MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
6302 switch (element_type) {
6303 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
6304 element_str = "volume";
6305 break;
6306 case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
6307 element_str = "phys disk";
6308 break;
6309 case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
6310 element_str = "hot spare";
6311 break;
6312 default:
6313 element_str = "unknown element";
6314 break;
6315 }
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05306316 printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), "
Eric Moore635374e2009-03-09 01:21:12 -06006317 "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
6318 reason_str, le16_to_cpu(element->VolDevHandle),
6319 le16_to_cpu(element->PhysDiskDevHandle),
6320 element->PhysDiskNum);
6321 }
6322}
6323#endif
6324
6325/**
6326 * _scsih_sas_ir_config_change_event - handle ir configuration change events
6327 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306328 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006329 * Context: user.
6330 *
6331 * Return nothing.
6332 */
6333static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306334_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
6335 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006336{
6337 Mpi2EventIrConfigElement_t *element;
6338 int i;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306339 u8 foreign_config;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306340 Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06006341
6342#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306343 if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
6344 && !ioc->hide_ir_msg)
Eric Moore635374e2009-03-09 01:21:12 -06006345 _scsih_sas_ir_config_change_event_debug(ioc, event_data);
6346
6347#endif
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306348
6349 if (ioc->shost_recovery)
6350 return;
6351
Kashyap, Desai62727a72009-08-07 19:35:18 +05306352 foreign_config = (le32_to_cpu(event_data->Flags) &
6353 MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
Eric Moore635374e2009-03-09 01:21:12 -06006354
6355 element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
6356 for (i = 0; i < event_data->NumElements; i++, element++) {
6357
6358 switch (element->ReasonCode) {
6359 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
6360 case MPI2_EVENT_IR_CHANGE_RC_ADDED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05306361 if (!foreign_config)
6362 _scsih_sas_volume_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006363 break;
6364 case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
6365 case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
Kashyap, Desai62727a72009-08-07 19:35:18 +05306366 if (!foreign_config)
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306367 _scsih_sas_volume_delete(ioc,
6368 le16_to_cpu(element->VolDevHandle));
Eric Moore635374e2009-03-09 01:21:12 -06006369 break;
6370 case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306371 if (!ioc->is_warpdrive)
6372 _scsih_sas_pd_hide(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006373 break;
6374 case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306375 if (!ioc->is_warpdrive)
6376 _scsih_sas_pd_expose(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006377 break;
6378 case MPI2_EVENT_IR_CHANGE_RC_HIDE:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306379 if (!ioc->is_warpdrive)
6380 _scsih_sas_pd_add(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006381 break;
6382 case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306383 if (!ioc->is_warpdrive)
6384 _scsih_sas_pd_delete(ioc, element);
Eric Moore635374e2009-03-09 01:21:12 -06006385 break;
6386 }
6387 }
6388}
6389
6390/**
6391 * _scsih_sas_ir_volume_event - IR volume event
6392 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306393 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006394 * Context: user.
6395 *
6396 * Return nothing.
6397 */
6398static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306399_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
6400 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006401{
6402 u64 wwid;
6403 unsigned long flags;
6404 struct _raid_device *raid_device;
6405 u16 handle;
6406 u32 state;
6407 int rc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306408 Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
Eric Moore635374e2009-03-09 01:21:12 -06006409
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306410 if (ioc->shost_recovery)
6411 return;
6412
Eric Moore635374e2009-03-09 01:21:12 -06006413 if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
6414 return;
6415
6416 handle = le16_to_cpu(event_data->VolDevHandle);
6417 state = le32_to_cpu(event_data->NewValue);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306418 if (!ioc->hide_ir_msg)
6419 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
6420 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
6421 le32_to_cpu(event_data->PreviousValue), state));
Eric Moore635374e2009-03-09 01:21:12 -06006422
Eric Moore635374e2009-03-09 01:21:12 -06006423 switch (state) {
6424 case MPI2_RAID_VOL_STATE_MISSING:
6425 case MPI2_RAID_VOL_STATE_FAILED:
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306426 _scsih_sas_volume_delete(ioc, handle);
Eric Moore635374e2009-03-09 01:21:12 -06006427 break;
6428
6429 case MPI2_RAID_VOL_STATE_ONLINE:
6430 case MPI2_RAID_VOL_STATE_DEGRADED:
6431 case MPI2_RAID_VOL_STATE_OPTIMAL:
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306432
6433 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6434 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
6435 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6436
Eric Moore635374e2009-03-09 01:21:12 -06006437 if (raid_device)
6438 break;
6439
6440 mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
6441 if (!wwid) {
6442 printk(MPT2SAS_ERR_FMT
6443 "failure at %s:%d/%s()!\n", ioc->name,
6444 __FILE__, __LINE__, __func__);
6445 break;
6446 }
6447
6448 raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
6449 if (!raid_device) {
6450 printk(MPT2SAS_ERR_FMT
6451 "failure at %s:%d/%s()!\n", ioc->name,
6452 __FILE__, __LINE__, __func__);
6453 break;
6454 }
6455
6456 raid_device->id = ioc->sas_id++;
6457 raid_device->channel = RAID_CHANNEL;
6458 raid_device->handle = handle;
6459 raid_device->wwid = wwid;
6460 _scsih_raid_device_add(ioc, raid_device);
6461 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
6462 raid_device->id, 0);
6463 if (rc)
6464 _scsih_raid_device_remove(ioc, raid_device);
6465 break;
6466
6467 case MPI2_RAID_VOL_STATE_INITIALIZING:
6468 default:
6469 break;
6470 }
6471}
6472
6473/**
6474 * _scsih_sas_ir_physical_disk_event - PD event
6475 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306476 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006477 * Context: user.
6478 *
6479 * Return nothing.
6480 */
6481static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306482_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
6483 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006484{
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306485 u16 handle, parent_handle;
Eric Moore635374e2009-03-09 01:21:12 -06006486 u32 state;
6487 struct _sas_device *sas_device;
6488 unsigned long flags;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306489 Mpi2ConfigReply_t mpi_reply;
6490 Mpi2SasDevicePage0_t sas_device_pg0;
6491 u32 ioc_status;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306492 Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306493 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06006494
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306495 if (ioc->shost_recovery)
6496 return;
6497
Eric Moore635374e2009-03-09 01:21:12 -06006498 if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
6499 return;
6500
6501 handle = le16_to_cpu(event_data->PhysDiskDevHandle);
6502 state = le32_to_cpu(event_data->NewValue);
6503
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306504 if (!ioc->hide_ir_msg)
6505 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
6506 "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
6507 le32_to_cpu(event_data->PreviousValue), state));
Eric Moore635374e2009-03-09 01:21:12 -06006508
Eric Moore635374e2009-03-09 01:21:12 -06006509 switch (state) {
Eric Moore635374e2009-03-09 01:21:12 -06006510 case MPI2_RAID_PD_STATE_ONLINE:
6511 case MPI2_RAID_PD_STATE_DEGRADED:
6512 case MPI2_RAID_PD_STATE_REBUILDING:
6513 case MPI2_RAID_PD_STATE_OPTIMAL:
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306514 case MPI2_RAID_PD_STATE_HOT_SPARE:
6515
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306516 if (!ioc->is_warpdrive)
6517 set_bit(handle, ioc->pd_handles);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306518
6519 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6520 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
6521 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6522
6523 if (sas_device)
Kashyap, Desai62727a72009-08-07 19:35:18 +05306524 return;
Kashyap, Desai62727a72009-08-07 19:35:18 +05306525
6526 if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
6527 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
6528 handle))) {
6529 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6530 ioc->name, __FILE__, __LINE__, __func__);
6531 return;
6532 }
6533
6534 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6535 MPI2_IOCSTATUS_MASK;
6536 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
6537 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
6538 ioc->name, __FILE__, __LINE__, __func__);
6539 return;
6540 }
6541
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306542 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
6543 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
6544 mpt2sas_transport_update_links(ioc, sas_address, handle,
6545 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
Kashyap, Desai62727a72009-08-07 19:35:18 +05306546
6547 _scsih_add_device(ioc, handle, 0, 1);
6548
Eric Moore635374e2009-03-09 01:21:12 -06006549 break;
6550
Kashyap, Desai62727a72009-08-07 19:35:18 +05306551 case MPI2_RAID_PD_STATE_OFFLINE:
Eric Moore635374e2009-03-09 01:21:12 -06006552 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
6553 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
Eric Moore635374e2009-03-09 01:21:12 -06006554 default:
6555 break;
6556 }
6557}
6558
6559#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
6560/**
6561 * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
6562 * @ioc: per adapter object
6563 * @event_data: event data payload
6564 * Context: user.
6565 *
6566 * Return nothing.
6567 */
6568static void
6569_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
6570 Mpi2EventDataIrOperationStatus_t *event_data)
6571{
6572 char *reason_str = NULL;
6573
6574 switch (event_data->RAIDOperation) {
6575 case MPI2_EVENT_IR_RAIDOP_RESYNC:
6576 reason_str = "resync";
6577 break;
6578 case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
6579 reason_str = "online capacity expansion";
6580 break;
6581 case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
6582 reason_str = "consistency check";
6583 break;
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05306584 case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
6585 reason_str = "background init";
6586 break;
6587 case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
6588 reason_str = "make data consistent";
Eric Moore635374e2009-03-09 01:21:12 -06006589 break;
6590 }
6591
Kashyap, Desaiec6c2b42009-09-23 17:31:01 +05306592 if (!reason_str)
6593 return;
6594
Eric Moore635374e2009-03-09 01:21:12 -06006595 printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
6596 "\thandle(0x%04x), percent complete(%d)\n",
6597 ioc->name, reason_str,
6598 le16_to_cpu(event_data->VolDevHandle),
6599 event_data->PercentComplete);
6600}
6601#endif
6602
6603/**
6604 * _scsih_sas_ir_operation_status_event - handle RAID operation events
6605 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306606 * @fw_event: The fw_event_work object
Eric Moore635374e2009-03-09 01:21:12 -06006607 * Context: user.
6608 *
6609 * Return nothing.
6610 */
6611static void
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306612_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
6613 struct fw_event_work *fw_event)
Eric Moore635374e2009-03-09 01:21:12 -06006614{
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306615 Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data;
6616 static struct _raid_device *raid_device;
6617 unsigned long flags;
6618 u16 handle;
6619
Eric Moore635374e2009-03-09 01:21:12 -06006620#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306621 if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
6622 && !ioc->hide_ir_msg)
Kashyap, Desai7b936b02009-09-25 11:44:41 +05306623 _scsih_sas_ir_operation_status_event_debug(ioc,
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306624 event_data);
Eric Moore635374e2009-03-09 01:21:12 -06006625#endif
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306626
6627 /* code added for raid transport support */
6628 if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
6629
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306630 spin_lock_irqsave(&ioc->raid_device_lock, flags);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306631 handle = le16_to_cpu(event_data->VolDevHandle);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306632 raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306633 if (raid_device)
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306634 raid_device->percent_complete =
6635 event_data->PercentComplete;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306636 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05306637 }
Eric Moore635374e2009-03-09 01:21:12 -06006638}
6639
6640/**
Kashyap, Desai14695852010-03-30 10:52:44 +05306641 * _scsih_prep_device_scan - initialize parameters prior to device scan
6642 * @ioc: per adapter object
6643 *
6644 * Set the deleted flag prior to device scan. If the device is found during
6645 * the scan, then we clear the deleted flag.
6646 */
6647static void
6648_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc)
6649{
6650 struct MPT2SAS_DEVICE *sas_device_priv_data;
6651 struct scsi_device *sdev;
6652
6653 shost_for_each_device(sdev, ioc->shost) {
6654 sas_device_priv_data = sdev->hostdata;
6655 if (sas_device_priv_data && sas_device_priv_data->sas_target)
6656 sas_device_priv_data->sas_target->deleted = 1;
6657 }
6658}
6659
6660/**
Eric Moore635374e2009-03-09 01:21:12 -06006661 * _scsih_mark_responding_sas_device - mark a sas_devices as responding
6662 * @ioc: per adapter object
6663 * @sas_address: sas address
6664 * @slot: enclosure slot id
6665 * @handle: device handle
6666 *
6667 * After host reset, find out whether devices are still responding.
6668 * Used in _scsi_remove_unresponsive_sas_devices.
6669 *
6670 * Return nothing.
6671 */
6672static void
6673_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
6674 u16 slot, u16 handle)
6675{
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306676 struct MPT2SAS_TARGET *sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06006677 struct scsi_target *starget;
6678 struct _sas_device *sas_device;
6679 unsigned long flags;
6680
6681 spin_lock_irqsave(&ioc->sas_device_lock, flags);
6682 list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
6683 if (sas_device->sas_address == sas_address &&
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306684 sas_device->slot == slot) {
Eric Moore635374e2009-03-09 01:21:12 -06006685 sas_device->responding = 1;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05306686 starget = sas_device->starget;
Kashyap, Desai14695852010-03-30 10:52:44 +05306687 if (starget && starget->hostdata) {
6688 sas_target_priv_data = starget->hostdata;
6689 sas_target_priv_data->tm_busy = 0;
6690 sas_target_priv_data->deleted = 0;
6691 } else
6692 sas_target_priv_data = NULL;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306693 if (starget)
6694 starget_printk(KERN_INFO, starget,
6695 "handle(0x%04x), sas_addr(0x%016llx), "
6696 "enclosure logical id(0x%016llx), "
6697 "slot(%d)\n", handle,
6698 (unsigned long long)sas_device->sas_address,
6699 (unsigned long long)
6700 sas_device->enclosure_logical_id,
6701 sas_device->slot);
Eric Moore635374e2009-03-09 01:21:12 -06006702 if (sas_device->handle == handle)
6703 goto out;
6704 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
6705 sas_device->handle);
6706 sas_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05306707 if (sas_target_priv_data)
6708 sas_target_priv_data->handle = handle;
Eric Moore635374e2009-03-09 01:21:12 -06006709 goto out;
6710 }
6711 }
6712 out:
6713 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
6714}
6715
6716/**
6717 * _scsih_search_responding_sas_devices -
6718 * @ioc: per adapter object
6719 *
6720 * After host reset, find out whether devices are still responding.
6721 * If not remove.
6722 *
6723 * Return nothing.
6724 */
6725static void
6726_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
6727{
6728 Mpi2SasDevicePage0_t sas_device_pg0;
6729 Mpi2ConfigReply_t mpi_reply;
6730 u16 ioc_status;
6731 __le64 sas_address;
6732 u16 handle;
6733 u32 device_info;
6734 u16 slot;
6735
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306736 printk(MPT2SAS_INFO_FMT "search for end-devices: start\n", ioc->name);
Eric Moore635374e2009-03-09 01:21:12 -06006737
6738 if (list_empty(&ioc->sas_device_list))
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306739 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06006740
6741 handle = 0xFFFF;
6742 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
6743 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
6744 handle))) {
6745 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6746 MPI2_IOCSTATUS_MASK;
6747 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6748 break;
6749 handle = le16_to_cpu(sas_device_pg0.DevHandle);
6750 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
6751 if (!(_scsih_is_end_device(device_info)))
6752 continue;
6753 sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
6754 slot = le16_to_cpu(sas_device_pg0.Slot);
6755 _scsih_mark_responding_sas_device(ioc, sas_address, slot,
6756 handle);
6757 }
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306758out:
6759 printk(MPT2SAS_INFO_FMT "search for end-devices: complete\n",
6760 ioc->name);
Eric Moore635374e2009-03-09 01:21:12 -06006761}
6762
6763/**
6764 * _scsih_mark_responding_raid_device - mark a raid_device as responding
6765 * @ioc: per adapter object
6766 * @wwid: world wide identifier for raid volume
6767 * @handle: device handle
6768 *
6769 * After host reset, find out whether devices are still responding.
6770 * Used in _scsi_remove_unresponsive_raid_devices.
6771 *
6772 * Return nothing.
6773 */
6774static void
6775_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
6776 u16 handle)
6777{
6778 struct MPT2SAS_TARGET *sas_target_priv_data;
6779 struct scsi_target *starget;
6780 struct _raid_device *raid_device;
6781 unsigned long flags;
6782
6783 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6784 list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
6785 if (raid_device->wwid == wwid && raid_device->starget) {
Kashyap, Desai14695852010-03-30 10:52:44 +05306786 starget = raid_device->starget;
6787 if (starget && starget->hostdata) {
6788 sas_target_priv_data = starget->hostdata;
6789 sas_target_priv_data->deleted = 0;
6790 } else
6791 sas_target_priv_data = NULL;
Eric Moore635374e2009-03-09 01:21:12 -06006792 raid_device->responding = 1;
nagalakshmi.nandigama@lsi.com30c43282011-12-01 07:52:56 +05306793 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06006794 starget_printk(KERN_INFO, raid_device->starget,
6795 "handle(0x%04x), wwid(0x%016llx)\n", handle,
6796 (unsigned long long)raid_device->wwid);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306797 /*
6798 * WARPDRIVE: The handles of the PDs might have changed
6799 * across the host reset so re-initialize the
6800 * required data for Direct IO
6801 */
6802 _scsih_init_warpdrive_properties(ioc, raid_device);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306803 spin_lock_irqsave(&ioc->raid_device_lock, flags);
6804 if (raid_device->handle == handle) {
6805 spin_unlock_irqrestore(&ioc->raid_device_lock,
6806 flags);
nagalakshmi.nandigama@lsi.com30c43282011-12-01 07:52:56 +05306807 return;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306808 }
Eric Moore635374e2009-03-09 01:21:12 -06006809 printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
6810 raid_device->handle);
6811 raid_device->handle = handle;
Kashyap, Desai14695852010-03-30 10:52:44 +05306812 if (sas_target_priv_data)
6813 sas_target_priv_data->handle = handle;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306814 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
nagalakshmi.nandigama@lsi.com30c43282011-12-01 07:52:56 +05306815 return;
Eric Moore635374e2009-03-09 01:21:12 -06006816 }
6817 }
nagalakshmi.nandigama@lsi.com30c43282011-12-01 07:52:56 +05306818
Eric Moore635374e2009-03-09 01:21:12 -06006819 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
6820}
6821
6822/**
6823 * _scsih_search_responding_raid_devices -
6824 * @ioc: per adapter object
6825 *
6826 * After host reset, find out whether devices are still responding.
6827 * If not remove.
6828 *
6829 * Return nothing.
6830 */
6831static void
6832_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
6833{
6834 Mpi2RaidVolPage1_t volume_pg1;
Kashyap, Desaid417d1c2010-06-17 13:48:10 +05306835 Mpi2RaidVolPage0_t volume_pg0;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306836 Mpi2RaidPhysDiskPage0_t pd_pg0;
Eric Moore635374e2009-03-09 01:21:12 -06006837 Mpi2ConfigReply_t mpi_reply;
6838 u16 ioc_status;
6839 u16 handle;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306840 u8 phys_disk_num;
Eric Moore635374e2009-03-09 01:21:12 -06006841
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306842 if (!ioc->ir_firmware)
6843 return;
6844
6845 printk(MPT2SAS_INFO_FMT "search for raid volumes: start\n",
6846 ioc->name);
Eric Moore635374e2009-03-09 01:21:12 -06006847
6848 if (list_empty(&ioc->raid_device_list))
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306849 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06006850
6851 handle = 0xFFFF;
6852 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
6853 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
6854 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6855 MPI2_IOCSTATUS_MASK;
6856 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6857 break;
6858 handle = le16_to_cpu(volume_pg1.DevHandle);
Kashyap, Desaid417d1c2010-06-17 13:48:10 +05306859
6860 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
6861 &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
6862 sizeof(Mpi2RaidVolPage0_t)))
6863 continue;
6864
6865 if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
6866 volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
6867 volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED)
6868 _scsih_mark_responding_raid_device(ioc,
6869 le64_to_cpu(volume_pg1.WWID), handle);
Eric Moore635374e2009-03-09 01:21:12 -06006870 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306871
6872 /* refresh the pd_handles */
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05306873 if (!ioc->is_warpdrive) {
6874 phys_disk_num = 0xFF;
6875 memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
6876 while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
6877 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
6878 phys_disk_num))) {
6879 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6880 MPI2_IOCSTATUS_MASK;
6881 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6882 break;
6883 phys_disk_num = pd_pg0.PhysDiskNum;
6884 handle = le16_to_cpu(pd_pg0.DevHandle);
6885 set_bit(handle, ioc->pd_handles);
6886 }
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05306887 }
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306888out:
6889 printk(MPT2SAS_INFO_FMT "search for responding raid volumes: "
6890 "complete\n", ioc->name);
Eric Moore635374e2009-03-09 01:21:12 -06006891}
6892
6893/**
6894 * _scsih_mark_responding_expander - mark a expander as responding
6895 * @ioc: per adapter object
6896 * @sas_address: sas address
6897 * @handle:
6898 *
6899 * After host reset, find out whether devices are still responding.
6900 * Used in _scsi_remove_unresponsive_expanders.
6901 *
6902 * Return nothing.
6903 */
6904static void
6905_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
6906 u16 handle)
6907{
6908 struct _sas_node *sas_expander;
6909 unsigned long flags;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306910 int i;
Eric Moore635374e2009-03-09 01:21:12 -06006911
6912 spin_lock_irqsave(&ioc->sas_node_lock, flags);
6913 list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306914 if (sas_expander->sas_address != sas_address)
6915 continue;
6916 sas_expander->responding = 1;
6917 if (sas_expander->handle == handle)
Eric Moore635374e2009-03-09 01:21:12 -06006918 goto out;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05306919 printk(KERN_INFO "\texpander(0x%016llx): handle changed"
6920 " from(0x%04x) to (0x%04x)!!!\n",
6921 (unsigned long long)sas_expander->sas_address,
6922 sas_expander->handle, handle);
6923 sas_expander->handle = handle;
6924 for (i = 0 ; i < sas_expander->num_phys ; i++)
6925 sas_expander->phy[i].handle = handle;
6926 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06006927 }
6928 out:
6929 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
6930}
6931
6932/**
6933 * _scsih_search_responding_expanders -
6934 * @ioc: per adapter object
6935 *
6936 * After host reset, find out whether devices are still responding.
6937 * If not remove.
6938 *
6939 * Return nothing.
6940 */
6941static void
6942_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
6943{
6944 Mpi2ExpanderPage0_t expander_pg0;
6945 Mpi2ConfigReply_t mpi_reply;
6946 u16 ioc_status;
Kashyap, Desaic97951e2011-06-14 10:54:56 +05306947 u64 sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06006948 u16 handle;
6949
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306950 printk(MPT2SAS_INFO_FMT "search for expanders: start\n", ioc->name);
Eric Moore635374e2009-03-09 01:21:12 -06006951
6952 if (list_empty(&ioc->sas_expander_list))
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306953 goto out;
Eric Moore635374e2009-03-09 01:21:12 -06006954
6955 handle = 0xFFFF;
6956 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
6957 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
6958
6959 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
6960 MPI2_IOCSTATUS_MASK;
6961 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
6962 break;
6963
6964 handle = le16_to_cpu(expander_pg0.DevHandle);
6965 sas_address = le64_to_cpu(expander_pg0.SASAddress);
6966 printk(KERN_INFO "\texpander present: handle(0x%04x), "
6967 "sas_addr(0x%016llx)\n", handle,
6968 (unsigned long long)sas_address);
6969 _scsih_mark_responding_expander(ioc, sas_address, handle);
6970 }
6971
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306972 out:
6973 printk(MPT2SAS_INFO_FMT "search for expanders: complete\n", ioc->name);
Eric Moore635374e2009-03-09 01:21:12 -06006974}
6975
6976/**
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306977 * _scsih_remove_unresponding_sas_devices - removing unresponding devices
Eric Moore635374e2009-03-09 01:21:12 -06006978 * @ioc: per adapter object
6979 *
6980 * Return nothing.
6981 */
6982static void
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05306983_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
Eric Moore635374e2009-03-09 01:21:12 -06006984{
6985 struct _sas_device *sas_device, *sas_device_next;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306986 struct _sas_node *sas_expander, *sas_expander_next;
Eric Moore635374e2009-03-09 01:21:12 -06006987 struct _raid_device *raid_device, *raid_device_next;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306988 struct list_head tmp_list;
6989 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06006990
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05306991 printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n",
6992 ioc->name);
Eric Moore635374e2009-03-09 01:21:12 -06006993
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306994 /* removing unresponding end devices */
6995 printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n",
6996 ioc->name);
Eric Moore635374e2009-03-09 01:21:12 -06006997 list_for_each_entry_safe(sas_device, sas_device_next,
6998 &ioc->sas_device_list, list) {
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05306999 if (!sas_device->responding)
7000 _scsih_device_remove_by_handle(ioc,
7001 sas_device->handle);
7002 else
Eric Moore635374e2009-03-09 01:21:12 -06007003 sas_device->responding = 0;
Eric Moore635374e2009-03-09 01:21:12 -06007004 }
7005
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307006 /* removing unresponding volumes */
7007 if (ioc->ir_firmware) {
7008 printk(MPT2SAS_INFO_FMT "removing unresponding devices: "
7009 "volumes\n", ioc->name);
7010 list_for_each_entry_safe(raid_device, raid_device_next,
7011 &ioc->raid_device_list, list) {
7012 if (!raid_device->responding)
7013 _scsih_sas_volume_delete(ioc,
7014 raid_device->handle);
7015 else
7016 raid_device->responding = 0;
Eric Moore635374e2009-03-09 01:21:12 -06007017 }
Eric Moore635374e2009-03-09 01:21:12 -06007018 }
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307019 /* removing unresponding expanders */
7020 printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n",
7021 ioc->name);
7022 spin_lock_irqsave(&ioc->sas_node_lock, flags);
7023 INIT_LIST_HEAD(&tmp_list);
7024 list_for_each_entry_safe(sas_expander, sas_expander_next,
7025 &ioc->sas_expander_list, list) {
7026 if (!sas_expander->responding)
7027 list_move_tail(&sas_expander->list, &tmp_list);
7028 else
Eric Moore635374e2009-03-09 01:21:12 -06007029 sas_expander->responding = 0;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307030 }
7031 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
7032 list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list,
7033 list) {
7034 list_del(&sas_expander->list);
7035 _scsih_expander_node_remove(ioc, sas_expander);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307036 }
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307037 printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n",
7038 ioc->name);
7039 /* unblock devices */
7040 _scsih_ublock_io_all_device(ioc);
7041}
7042
7043static void
7044_scsih_refresh_expander_links(struct MPT2SAS_ADAPTER *ioc,
7045 struct _sas_node *sas_expander, u16 handle)
7046{
7047 Mpi2ExpanderPage1_t expander_pg1;
7048 Mpi2ConfigReply_t mpi_reply;
7049 int i;
7050
7051 for (i = 0 ; i < sas_expander->num_phys ; i++) {
7052 if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
7053 &expander_pg1, i, handle))) {
7054 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7055 ioc->name, __FILE__, __LINE__, __func__);
7056 return;
7057 }
7058
7059 mpt2sas_transport_update_links(ioc, sas_expander->sas_address,
7060 le16_to_cpu(expander_pg1.AttachedDevHandle), i,
7061 expander_pg1.NegotiatedLinkRate >> 4);
7062 }
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307063}
7064
7065/**
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307066 * _scsih_scan_for_devices_after_reset - scan for devices after host reset
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307067 * @ioc: per adapter object
7068 *
7069 * Return nothing.
7070 */
7071static void
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307072_scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307073{
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307074 Mpi2ExpanderPage0_t expander_pg0;
7075 Mpi2SasDevicePage0_t sas_device_pg0;
7076 Mpi2RaidVolPage1_t volume_pg1;
7077 Mpi2RaidVolPage0_t volume_pg0;
7078 Mpi2RaidPhysDiskPage0_t pd_pg0;
7079 Mpi2EventIrConfigElement_t element;
7080 Mpi2ConfigReply_t mpi_reply;
7081 u8 phys_disk_num;
7082 u16 ioc_status;
7083 u16 handle, parent_handle;
7084 u64 sas_address;
7085 struct _sas_device *sas_device;
7086 struct _sas_node *expander_device;
7087 static struct _raid_device *raid_device;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307088 unsigned long flags;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307089
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307090 printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307091
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307092 _scsih_sas_host_refresh(ioc);
7093
7094 /* expanders */
7095 handle = 0xFFFF;
7096 while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
7097 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
7098 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
7099 MPI2_IOCSTATUS_MASK;
7100 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
7101 break;
7102 handle = le16_to_cpu(expander_pg0.DevHandle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307103 spin_lock_irqsave(&ioc->sas_node_lock, flags);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307104 expander_device = mpt2sas_scsih_expander_find_by_sas_address(
7105 ioc, le64_to_cpu(expander_pg0.SASAddress));
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307106 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307107 if (expander_device)
7108 _scsih_refresh_expander_links(ioc, expander_device,
7109 handle);
7110 else
7111 _scsih_expander_add(ioc, handle);
7112 }
7113
7114 if (!ioc->ir_firmware)
7115 goto skip_to_sas;
7116
7117 /* phys disk */
7118 phys_disk_num = 0xFF;
7119 while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
7120 &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
7121 phys_disk_num))) {
7122 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
7123 MPI2_IOCSTATUS_MASK;
7124 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
7125 break;
7126 phys_disk_num = pd_pg0.PhysDiskNum;
7127 handle = le16_to_cpu(pd_pg0.DevHandle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307128 spin_lock_irqsave(&ioc->sas_device_lock, flags);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307129 sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307130 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307131 if (sas_device)
7132 continue;
7133 if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
7134 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
7135 handle) != 0)
7136 continue;
7137 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
7138 if (!_scsih_get_sas_address(ioc, parent_handle,
7139 &sas_address)) {
7140 mpt2sas_transport_update_links(ioc, sas_address,
7141 handle, sas_device_pg0.PhyNum,
7142 MPI2_SAS_NEG_LINK_RATE_1_5);
7143 set_bit(handle, ioc->pd_handles);
7144 _scsih_add_device(ioc, handle, 0, 1);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307145 }
7146 }
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307147
7148 /* volumes */
7149 handle = 0xFFFF;
7150 while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
7151 &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
7152 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
7153 MPI2_IOCSTATUS_MASK;
7154 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
7155 break;
7156 handle = le16_to_cpu(volume_pg1.DevHandle);
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307157 spin_lock_irqsave(&ioc->raid_device_lock, flags);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307158 raid_device = _scsih_raid_device_find_by_wwid(ioc,
7159 le64_to_cpu(volume_pg1.WWID));
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307160 spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307161 if (raid_device)
7162 continue;
7163 if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
7164 &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
7165 sizeof(Mpi2RaidVolPage0_t)))
7166 continue;
7167 if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
7168 volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
7169 volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) {
7170 memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t));
7171 element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED;
7172 element.VolDevHandle = volume_pg1.DevHandle;
7173 _scsih_sas_volume_add(ioc, &element);
7174 }
7175 }
7176
7177 skip_to_sas:
7178
7179 /* sas devices */
7180 handle = 0xFFFF;
7181 while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
7182 &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
7183 handle))) {
7184 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
7185 MPI2_IOCSTATUS_MASK;
7186 if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
7187 break;
7188 handle = le16_to_cpu(sas_device_pg0.DevHandle);
7189 if (!(_scsih_is_end_device(
7190 le32_to_cpu(sas_device_pg0.DeviceInfo))))
7191 continue;
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307192 spin_lock_irqsave(&ioc->sas_device_lock, flags);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307193 sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
7194 le64_to_cpu(sas_device_pg0.SASAddress));
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307195 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307196 if (sas_device)
7197 continue;
7198 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
7199 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) {
7200 mpt2sas_transport_update_links(ioc, sas_address, handle,
7201 sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
7202 _scsih_add_device(ioc, handle, 0, 0);
7203 }
7204 }
7205
7206 printk(MPT2SAS_INFO_FMT "scan devices: complete\n", ioc->name);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307207}
7208
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307209
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307210/**
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307211 * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
7212 * @ioc: per adapter object
7213 * @reset_phase: phase
7214 *
7215 * The handler for doing any required cleanup or initialization.
7216 *
7217 * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
7218 * MPT2_IOC_DONE_RESET
7219 *
7220 * Return nothing.
7221 */
7222void
7223mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
7224{
7225 switch (reset_phase) {
7226 case MPT2_IOC_PRE_RESET:
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05307227 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307228 "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307229 break;
7230 case MPT2_IOC_AFTER_RESET:
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05307231 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307232 "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05307233 if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
7234 ioc->scsih_cmds.status |= MPT2_CMD_RESET;
7235 mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
7236 complete(&ioc->scsih_cmds.done);
7237 }
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307238 if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
7239 ioc->tm_cmds.status |= MPT2_CMD_RESET;
7240 mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
7241 complete(&ioc->tm_cmds.done);
7242 }
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05307243 _scsih_fw_event_cleanup_queue(ioc);
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307244 _scsih_flush_running_cmds(ioc);
7245 break;
7246 case MPT2_IOC_DONE_RESET:
Kashyap, Desaieabb08a2010-06-17 13:43:57 +05307247 dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307248 "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307249 _scsih_sas_host_refresh(ioc);
Kashyap, Desai14695852010-03-30 10:52:44 +05307250 _scsih_prep_device_scan(ioc);
7251 _scsih_search_responding_sas_devices(ioc);
7252 _scsih_search_responding_raid_devices(ioc);
7253 _scsih_search_responding_expanders(ioc);
nagalakshmi.nandigama@lsi.com918134e2011-10-19 15:37:24 +05307254 if (!ioc->is_driver_loading) {
7255 _scsih_prep_device_scan(ioc);
7256 _scsih_search_responding_sas_devices(ioc);
7257 _scsih_search_responding_raid_devices(ioc);
7258 _scsih_search_responding_expanders(ioc);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307259 _scsih_error_recovery_delete_devices(ioc);
nagalakshmi.nandigama@lsi.com918134e2011-10-19 15:37:24 +05307260 }
Kashyap, Desaicd4e12e2009-08-20 13:20:54 +05307261 break;
Eric Moore635374e2009-03-09 01:21:12 -06007262 }
7263}
7264
7265/**
7266 * _firmware_event_work - delayed task for processing firmware events
7267 * @ioc: per adapter object
7268 * @work: equal to the fw_event_work object
7269 * Context: user.
7270 *
7271 * Return nothing.
7272 */
7273static void
7274_firmware_event_work(struct work_struct *work)
7275{
7276 struct fw_event_work *fw_event = container_of(work,
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05307277 struct fw_event_work, delayed_work.work);
Eric Moore635374e2009-03-09 01:21:12 -06007278 struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
7279
Eric Moore635374e2009-03-09 01:21:12 -06007280 /* the queue is being flushed so ignore this event */
Eric Moore3cb54692010-07-08 14:44:34 -06007281 if (ioc->remove_host || fw_event->cancel_pending_work ||
7282 ioc->pci_error_recovery) {
Eric Moore635374e2009-03-09 01:21:12 -06007283 _scsih_fw_event_free(ioc, fw_event);
7284 return;
7285 }
Eric Moore635374e2009-03-09 01:21:12 -06007286
Eric Moore635374e2009-03-09 01:21:12 -06007287 switch (fw_event->event) {
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307288 case MPT2SAS_REMOVE_UNRESPONDING_DEVICES:
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307289 while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery)
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307290 ssleep(1);
7291 _scsih_remove_unresponding_sas_devices(ioc);
7292 _scsih_scan_for_devices_after_reset(ioc);
7293 break;
7294 case MPT2SAS_PORT_ENABLE_COMPLETE:
nagalakshmi.nandigama@lsi.com918134e2011-10-19 15:37:24 +05307295 ioc->start_scan = 0;
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307296
7297
7298
7299 dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "port enable: complete "
7300 "from worker thread\n", ioc->name));
7301 break;
Kashyap, Desai3ace8e02011-05-04 16:35:58 +05307302 case MPT2SAS_TURN_ON_FAULT_LED:
7303 _scsih_turn_on_fault_led(ioc, fw_event->device_handle);
7304 break;
Eric Moore635374e2009-03-09 01:21:12 -06007305 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307306 _scsih_sas_topology_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06007307 break;
7308 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307309 _scsih_sas_device_status_change_event(ioc,
7310 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06007311 break;
7312 case MPI2_EVENT_SAS_DISCOVERY:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307313 _scsih_sas_discovery_event(ioc,
7314 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06007315 break;
7316 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
Andrew Mortona78e21d2012-02-08 12:52:22 -08007317 _scsih_sas_broadcast_primitive_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307318 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06007319 break;
7320 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
7321 _scsih_sas_enclosure_dev_status_change_event(ioc,
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307322 fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06007323 break;
7324 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307325 _scsih_sas_ir_config_change_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06007326 break;
7327 case MPI2_EVENT_IR_VOLUME:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307328 _scsih_sas_ir_volume_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06007329 break;
7330 case MPI2_EVENT_IR_PHYSICAL_DISK:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307331 _scsih_sas_ir_physical_disk_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06007332 break;
7333 case MPI2_EVENT_IR_OPERATION_STATUS:
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307334 _scsih_sas_ir_operation_status_event(ioc, fw_event);
Eric Moore635374e2009-03-09 01:21:12 -06007335 break;
Eric Moore635374e2009-03-09 01:21:12 -06007336 }
7337 _scsih_fw_event_free(ioc, fw_event);
7338}
7339
7340/**
7341 * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
7342 * @ioc: per adapter object
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307343 * @msix_index: MSIX table index supplied by the OS
Eric Moore635374e2009-03-09 01:21:12 -06007344 * @reply: reply message frame(lower 32bit addr)
7345 * Context: interrupt.
7346 *
7347 * This function merely adds a new work task into ioc->firmware_event_thread.
7348 * The tasks are worked from _firmware_event_work in user context.
7349 *
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307350 * Return 1 meaning mf should be freed from _base_interrupt
7351 * 0 means the mf is freed from this function.
Eric Moore635374e2009-03-09 01:21:12 -06007352 */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307353u8
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307354mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
7355 u32 reply)
Eric Moore635374e2009-03-09 01:21:12 -06007356{
7357 struct fw_event_work *fw_event;
7358 Mpi2EventNotificationReply_t *mpi_reply;
Eric Moore635374e2009-03-09 01:21:12 -06007359 u16 event;
Kashyap, Desaie94f6742010-03-17 16:24:52 +05307360 u16 sz;
Eric Moore635374e2009-03-09 01:21:12 -06007361
7362 /* events turned off due to host reset or driver unloading */
Eric Moore3cb54692010-07-08 14:44:34 -06007363 if (ioc->remove_host || ioc->pci_error_recovery)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307364 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06007365
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307366 mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
nagalakshmi.nandigama@lsi.com298c7942012-03-20 12:07:17 +05307367
7368 if (unlikely(!mpi_reply)) {
7369 printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
7370 ioc->name, __FILE__, __LINE__, __func__);
7371 return 1;
7372 }
7373
Eric Moore635374e2009-03-09 01:21:12 -06007374 event = le16_to_cpu(mpi_reply->Event);
7375
7376 switch (event) {
7377 /* handle these */
7378 case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
7379 {
7380 Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
7381 (Mpi2EventDataSasBroadcastPrimitive_t *)
7382 mpi_reply->EventData;
7383
7384 if (baen_data->Primitive !=
Kashyap, Desaif93213d2011-06-14 10:56:43 +05307385 MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307386 return 1;
Kashyap, Desaif93213d2011-06-14 10:56:43 +05307387
7388 if (ioc->broadcast_aen_busy) {
7389 ioc->broadcast_aen_pending++;
7390 return 1;
7391 } else
7392 ioc->broadcast_aen_busy = 1;
Eric Moore635374e2009-03-09 01:21:12 -06007393 break;
7394 }
7395
7396 case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
7397 _scsih_check_topo_delete_events(ioc,
7398 (Mpi2EventDataSasTopologyChangeList_t *)
7399 mpi_reply->EventData);
7400 break;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05307401 case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
7402 _scsih_check_ir_config_unhide_events(ioc,
7403 (Mpi2EventDataIrConfigChangeList_t *)
7404 mpi_reply->EventData);
7405 break;
7406 case MPI2_EVENT_IR_VOLUME:
7407 _scsih_check_volume_delete_events(ioc,
7408 (Mpi2EventDataIrVolume_t *)
7409 mpi_reply->EventData);
7410 break;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307411 case MPI2_EVENT_LOG_ENTRY_ADDED:
7412 {
7413 Mpi2EventDataLogEntryAdded_t *log_entry;
7414 u32 *log_code;
7415
7416 if (!ioc->is_warpdrive)
7417 break;
7418
7419 log_entry = (Mpi2EventDataLogEntryAdded_t *)
7420 mpi_reply->EventData;
7421 log_code = (u32 *)log_entry->LogData;
7422
7423 if (le16_to_cpu(log_entry->LogEntryQualifier)
7424 != MPT2_WARPDRIVE_LOGENTRY)
7425 break;
7426
7427 switch (le32_to_cpu(*log_code)) {
7428 case MPT2_WARPDRIVE_LC_SSDT:
7429 printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
7430 "IO Throttling has occurred in the WarpDrive "
7431 "subsystem. Check WarpDrive documentation for "
7432 "additional details.\n", ioc->name);
7433 break;
7434 case MPT2_WARPDRIVE_LC_SSDLW:
7435 printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
7436 "Program/Erase Cycles for the WarpDrive subsystem "
7437 "in degraded range. Check WarpDrive documentation "
7438 "for additional details.\n", ioc->name);
7439 break;
7440 case MPT2_WARPDRIVE_LC_SSDLF:
7441 printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
7442 "There are no Program/Erase Cycles for the "
7443 "WarpDrive subsystem. The storage device will be "
7444 "in read-only mode. Check WarpDrive documentation "
7445 "for additional details.\n", ioc->name);
7446 break;
7447 case MPT2_WARPDRIVE_LC_BRMF:
7448 printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
7449 "The Backup Rail Monitor has failed on the "
7450 "WarpDrive subsystem. Check WarpDrive "
7451 "documentation for additional details.\n",
7452 ioc->name);
7453 break;
7454 }
7455
7456 break;
7457 }
Eric Moore635374e2009-03-09 01:21:12 -06007458 case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
7459 case MPI2_EVENT_IR_OPERATION_STATUS:
7460 case MPI2_EVENT_SAS_DISCOVERY:
7461 case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
Eric Moore635374e2009-03-09 01:21:12 -06007462 case MPI2_EVENT_IR_PHYSICAL_DISK:
Eric Moore635374e2009-03-09 01:21:12 -06007463 break;
7464
7465 default: /* ignore the rest */
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307466 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06007467 }
7468
7469 fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
7470 if (!fw_event) {
7471 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7472 ioc->name, __FILE__, __LINE__, __func__);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307473 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06007474 }
Kashyap, Desaie94f6742010-03-17 16:24:52 +05307475 sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
7476 fw_event->event_data = kzalloc(sz, GFP_ATOMIC);
Eric Moore635374e2009-03-09 01:21:12 -06007477 if (!fw_event->event_data) {
7478 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
7479 ioc->name, __FILE__, __LINE__, __func__);
7480 kfree(fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307481 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06007482 }
7483
7484 memcpy(fw_event->event_data, mpi_reply->EventData,
Kashyap, Desaie94f6742010-03-17 16:24:52 +05307485 sz);
Eric Moore635374e2009-03-09 01:21:12 -06007486 fw_event->ioc = ioc;
Kashyap, Desai7b936b02009-09-25 11:44:41 +05307487 fw_event->VF_ID = mpi_reply->VF_ID;
7488 fw_event->VP_ID = mpi_reply->VP_ID;
Eric Moore635374e2009-03-09 01:21:12 -06007489 fw_event->event = event;
7490 _scsih_fw_event_add(ioc, fw_event);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307491 return 1;
Eric Moore635374e2009-03-09 01:21:12 -06007492}
7493
7494/* shost template */
7495static struct scsi_host_template scsih_driver_template = {
7496 .module = THIS_MODULE,
7497 .name = "Fusion MPT SAS Host",
7498 .proc_name = MPT2SAS_DRIVER_NAME,
Eric Moored5d135b2009-05-18 13:02:08 -06007499 .queuecommand = _scsih_qcmd,
7500 .target_alloc = _scsih_target_alloc,
7501 .slave_alloc = _scsih_slave_alloc,
7502 .slave_configure = _scsih_slave_configure,
7503 .target_destroy = _scsih_target_destroy,
7504 .slave_destroy = _scsih_slave_destroy,
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307505 .scan_finished = _scsih_scan_finished,
7506 .scan_start = _scsih_scan_start,
Eric Moored5d135b2009-05-18 13:02:08 -06007507 .change_queue_depth = _scsih_change_queue_depth,
7508 .change_queue_type = _scsih_change_queue_type,
7509 .eh_abort_handler = _scsih_abort,
7510 .eh_device_reset_handler = _scsih_dev_reset,
7511 .eh_target_reset_handler = _scsih_target_reset,
7512 .eh_host_reset_handler = _scsih_host_reset,
7513 .bios_param = _scsih_bios_param,
Eric Moore635374e2009-03-09 01:21:12 -06007514 .can_queue = 1,
7515 .this_id = -1,
7516 .sg_tablesize = MPT2SAS_SG_DEPTH,
nagalakshmi.nandigama@lsi.com9ac49d32011-12-01 07:52:08 +05307517 .max_sectors = 32767,
Eric Moore635374e2009-03-09 01:21:12 -06007518 .cmd_per_lun = 7,
7519 .use_clustering = ENABLE_CLUSTERING,
7520 .shost_attrs = mpt2sas_host_attrs,
7521 .sdev_attrs = mpt2sas_dev_attrs,
7522};
7523
7524/**
7525 * _scsih_expander_node_remove - removing expander device from list.
7526 * @ioc: per adapter object
7527 * @sas_expander: the sas_device object
7528 * Context: Calling function should acquire ioc->sas_node_lock.
7529 *
7530 * Removing object and freeing associated memory from the
7531 * ioc->sas_expander_list.
7532 *
7533 * Return nothing.
7534 */
7535static void
7536_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
7537 struct _sas_node *sas_expander)
7538{
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307539 struct _sas_port *mpt2sas_port, *next;
Eric Moore635374e2009-03-09 01:21:12 -06007540
7541 /* remove sibling ports attached to this expander */
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307542 list_for_each_entry_safe(mpt2sas_port, next,
Eric Moore635374e2009-03-09 01:21:12 -06007543 &sas_expander->sas_port_list, port_list) {
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307544 if (ioc->shost_recovery)
7545 return;
Eric Moore635374e2009-03-09 01:21:12 -06007546 if (mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307547 SAS_END_DEVICE)
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307548 mpt2sas_device_remove_by_sas_address(ioc,
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307549 mpt2sas_port->remote_identify.sas_address);
7550 else if (mpt2sas_port->remote_identify.device_type ==
7551 SAS_EDGE_EXPANDER_DEVICE ||
Eric Moore635374e2009-03-09 01:21:12 -06007552 mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307553 SAS_FANOUT_EXPANDER_DEVICE)
7554 mpt2sas_expander_remove(ioc,
7555 mpt2sas_port->remote_identify.sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06007556 }
7557
7558 mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307559 sas_expander->sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06007560
7561 printk(MPT2SAS_INFO_FMT "expander_remove: handle"
7562 "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
7563 sas_expander->handle, (unsigned long long)
7564 sas_expander->sas_address);
7565
Eric Moore635374e2009-03-09 01:21:12 -06007566 kfree(sas_expander->phy);
7567 kfree(sas_expander);
7568}
7569
7570/**
Kashyap, Desai744090d2009-10-05 15:56:56 +05307571 * _scsih_ir_shutdown - IR shutdown notification
7572 * @ioc: per adapter object
7573 *
7574 * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
7575 * the host system is shutting down.
7576 *
7577 * Return nothing.
7578 */
7579static void
7580_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
7581{
7582 Mpi2RaidActionRequest_t *mpi_request;
7583 Mpi2RaidActionReply_t *mpi_reply;
7584 u16 smid;
7585
7586 /* is IR firmware build loaded ? */
7587 if (!ioc->ir_firmware)
7588 return;
7589
7590 /* are there any volumes ? */
7591 if (list_empty(&ioc->raid_device_list))
7592 return;
7593
7594 mutex_lock(&ioc->scsih_cmds.mutex);
7595
7596 if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
7597 printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
7598 ioc->name, __func__);
7599 goto out;
7600 }
7601 ioc->scsih_cmds.status = MPT2_CMD_PENDING;
7602
7603 smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
7604 if (!smid) {
7605 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
7606 ioc->name, __func__);
7607 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
7608 goto out;
7609 }
7610
7611 mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
7612 ioc->scsih_cmds.smid = smid;
7613 memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
7614
7615 mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
7616 mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
7617
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307618 if (!ioc->hide_ir_msg)
7619 printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
Kashyap, Desai744090d2009-10-05 15:56:56 +05307620 init_completion(&ioc->scsih_cmds.done);
7621 mpt2sas_base_put_smid_default(ioc, smid);
7622 wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
7623
7624 if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
7625 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
7626 ioc->name, __func__);
7627 goto out;
7628 }
7629
7630 if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
7631 mpi_reply = ioc->scsih_cmds.reply;
7632
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307633 if (!ioc->hide_ir_msg)
7634 printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
7635 "ioc_status(0x%04x), loginfo(0x%08x)\n",
7636 ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
7637 le32_to_cpu(mpi_reply->IOCLogInfo));
Kashyap, Desai744090d2009-10-05 15:56:56 +05307638 }
7639
7640 out:
7641 ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
7642 mutex_unlock(&ioc->scsih_cmds.mutex);
7643}
7644
7645/**
7646 * _scsih_shutdown - routine call during system shutdown
7647 * @pdev: PCI device struct
7648 *
7649 * Return nothing.
7650 */
7651static void
7652_scsih_shutdown(struct pci_dev *pdev)
7653{
7654 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7655 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05307656 struct workqueue_struct *wq;
7657 unsigned long flags;
7658
7659 ioc->remove_host = 1;
7660 _scsih_fw_event_cleanup_queue(ioc);
7661
7662 spin_lock_irqsave(&ioc->fw_event_lock, flags);
7663 wq = ioc->firmware_event_thread;
7664 ioc->firmware_event_thread = NULL;
7665 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
7666 if (wq)
7667 destroy_workqueue(wq);
Kashyap, Desai744090d2009-10-05 15:56:56 +05307668
7669 _scsih_ir_shutdown(ioc);
7670 mpt2sas_base_detach(ioc);
7671}
7672
7673/**
Eric Moored5d135b2009-05-18 13:02:08 -06007674 * _scsih_remove - detach and remove add host
Eric Moore635374e2009-03-09 01:21:12 -06007675 * @pdev: PCI device struct
7676 *
Kashyap, Desai744090d2009-10-05 15:56:56 +05307677 * Routine called when unloading the driver.
Eric Moore635374e2009-03-09 01:21:12 -06007678 * Return nothing.
7679 */
7680static void __devexit
Eric Moored5d135b2009-05-18 13:02:08 -06007681_scsih_remove(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06007682{
7683 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7684 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307685 struct _sas_port *mpt2sas_port, *next_port;
Kashyap, Desaid7384b22009-12-16 18:50:06 +05307686 struct _raid_device *raid_device, *next;
7687 struct MPT2SAS_TARGET *sas_target_priv_data;
Eric Moore635374e2009-03-09 01:21:12 -06007688 struct workqueue_struct *wq;
7689 unsigned long flags;
7690
7691 ioc->remove_host = 1;
Kashyap, Desaif1c35e62010-03-09 16:31:43 +05307692 _scsih_fw_event_cleanup_queue(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007693
7694 spin_lock_irqsave(&ioc->fw_event_lock, flags);
7695 wq = ioc->firmware_event_thread;
7696 ioc->firmware_event_thread = NULL;
7697 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
7698 if (wq)
7699 destroy_workqueue(wq);
7700
Kashyap, Desaid7384b22009-12-16 18:50:06 +05307701 /* release all the volumes */
Kashyap, Desai3a9c9132011-01-04 11:40:23 +05307702 _scsih_ir_shutdown(ioc);
Kashyap, Desaid7384b22009-12-16 18:50:06 +05307703 list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
7704 list) {
7705 if (raid_device->starget) {
7706 sas_target_priv_data =
7707 raid_device->starget->hostdata;
7708 sas_target_priv_data->deleted = 1;
7709 scsi_remove_target(&raid_device->starget->dev);
7710 }
7711 printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
7712 "(0x%016llx)\n", ioc->name, raid_device->handle,
7713 (unsigned long long) raid_device->wwid);
7714 _scsih_raid_device_remove(ioc, raid_device);
7715 }
7716
Eric Moore635374e2009-03-09 01:21:12 -06007717 /* free ports attached to the sas_host */
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307718 list_for_each_entry_safe(mpt2sas_port, next_port,
Eric Moore635374e2009-03-09 01:21:12 -06007719 &ioc->sas_hba.sas_port_list, port_list) {
7720 if (mpt2sas_port->remote_identify.device_type ==
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307721 SAS_END_DEVICE)
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307722 mpt2sas_device_remove_by_sas_address(ioc,
Eric Moore635374e2009-03-09 01:21:12 -06007723 mpt2sas_port->remote_identify.sas_address);
Kashyap, Desai7f6f7942010-11-13 04:35:30 +05307724 else if (mpt2sas_port->remote_identify.device_type ==
7725 SAS_EDGE_EXPANDER_DEVICE ||
7726 mpt2sas_port->remote_identify.device_type ==
7727 SAS_FANOUT_EXPANDER_DEVICE)
7728 mpt2sas_expander_remove(ioc,
7729 mpt2sas_port->remote_identify.sas_address);
Eric Moore635374e2009-03-09 01:21:12 -06007730 }
7731
7732 /* free phys attached to the sas_host */
7733 if (ioc->sas_hba.num_phys) {
7734 kfree(ioc->sas_hba.phy);
7735 ioc->sas_hba.phy = NULL;
7736 ioc->sas_hba.num_phys = 0;
7737 }
7738
7739 sas_remove_host(shost);
kashyap.desai@lsi.com9ae89b02011-08-04 16:47:50 +05307740 mpt2sas_base_detach(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007741 list_del(&ioc->list);
7742 scsi_remove_host(shost);
7743 scsi_host_put(shost);
7744}
7745
7746/**
7747 * _scsih_probe_boot_devices - reports 1st device
7748 * @ioc: per adapter object
7749 *
7750 * If specified in bios page 2, this routine reports the 1st
7751 * device scsi-ml or sas transport for persistent boot device
7752 * purposes. Please refer to function _scsih_determine_boot_device()
7753 */
7754static void
7755_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
7756{
7757 u8 is_raid;
7758 void *device;
7759 struct _sas_device *sas_device;
7760 struct _raid_device *raid_device;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307761 u16 handle;
7762 u64 sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06007763 u64 sas_address;
7764 unsigned long flags;
7765 int rc;
7766
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307767 /* no Bios, return immediately */
7768 if (!ioc->bios_pg3.BiosVersion)
7769 return;
7770
Eric Moore635374e2009-03-09 01:21:12 -06007771 device = NULL;
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307772 is_raid = 0;
Eric Moore635374e2009-03-09 01:21:12 -06007773 if (ioc->req_boot_device.device) {
7774 device = ioc->req_boot_device.device;
7775 is_raid = ioc->req_boot_device.is_raid;
7776 } else if (ioc->req_alt_boot_device.device) {
7777 device = ioc->req_alt_boot_device.device;
7778 is_raid = ioc->req_alt_boot_device.is_raid;
7779 } else if (ioc->current_boot_device.device) {
7780 device = ioc->current_boot_device.device;
7781 is_raid = ioc->current_boot_device.is_raid;
7782 }
7783
7784 if (!device)
7785 return;
7786
7787 if (is_raid) {
7788 raid_device = device;
7789 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
7790 raid_device->id, 0);
7791 if (rc)
7792 _scsih_raid_device_remove(ioc, raid_device);
7793 } else {
nagalakshmi.nandigama@lsi.com09da0b32012-03-20 12:06:50 +05307794 spin_lock_irqsave(&ioc->sas_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06007795 sas_device = device;
7796 handle = sas_device->handle;
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307797 sas_address_parent = sas_device->sas_address_parent;
Eric Moore635374e2009-03-09 01:21:12 -06007798 sas_address = sas_device->sas_address;
Eric Moore635374e2009-03-09 01:21:12 -06007799 list_move_tail(&sas_device->list, &ioc->sas_device_list);
7800 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307801
7802 if (ioc->hide_drives)
7803 return;
Eric Moore635374e2009-03-09 01:21:12 -06007804 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307805 sas_device->sas_address_parent)) {
Eric Moore635374e2009-03-09 01:21:12 -06007806 _scsih_sas_device_remove(ioc, sas_device);
7807 } else if (!sas_device->starget) {
nagalakshmi.nandigama@lsi.com35116db2011-10-21 10:08:07 +05307808 if (!ioc->is_driver_loading)
7809 mpt2sas_transport_port_remove(ioc, sas_address,
7810 sas_address_parent);
Eric Moore635374e2009-03-09 01:21:12 -06007811 _scsih_sas_device_remove(ioc, sas_device);
7812 }
7813 }
7814}
7815
7816/**
7817 * _scsih_probe_raid - reporting raid volumes to scsi-ml
7818 * @ioc: per adapter object
7819 *
7820 * Called during initial loading of the driver.
7821 */
7822static void
7823_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
7824{
7825 struct _raid_device *raid_device, *raid_next;
7826 int rc;
7827
7828 list_for_each_entry_safe(raid_device, raid_next,
7829 &ioc->raid_device_list, list) {
7830 if (raid_device->starget)
7831 continue;
7832 rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
7833 raid_device->id, 0);
7834 if (rc)
7835 _scsih_raid_device_remove(ioc, raid_device);
7836 }
7837}
7838
7839/**
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05307840 * _scsih_probe_sas - reporting sas devices to sas transport
Eric Moore635374e2009-03-09 01:21:12 -06007841 * @ioc: per adapter object
7842 *
7843 * Called during initial loading of the driver.
7844 */
7845static void
7846_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
7847{
7848 struct _sas_device *sas_device, *next;
7849 unsigned long flags;
Eric Moore635374e2009-03-09 01:21:12 -06007850
7851 /* SAS Device List */
7852 list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
7853 list) {
Eric Moore635374e2009-03-09 01:21:12 -06007854
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05307855 if (ioc->hide_drives)
7856 continue;
7857
Kashyap, Desaic5e039b2009-09-23 17:21:29 +05307858 if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
7859 sas_device->sas_address_parent)) {
nagalakshmi.nandigama@lsi.com0167ac62011-10-21 10:06:33 +05307860 list_del(&sas_device->list);
7861 kfree(sas_device);
7862 continue;
Eric Moore635374e2009-03-09 01:21:12 -06007863 } else if (!sas_device->starget) {
nagalakshmi.nandigama@lsi.com35116db2011-10-21 10:08:07 +05307864 if (!ioc->is_driver_loading)
7865 mpt2sas_transport_port_remove(ioc,
7866 sas_device->sas_address,
7867 sas_device->sas_address_parent);
nagalakshmi.nandigama@lsi.com0167ac62011-10-21 10:06:33 +05307868 list_del(&sas_device->list);
7869 kfree(sas_device);
7870 continue;
7871
Eric Moore635374e2009-03-09 01:21:12 -06007872 }
nagalakshmi.nandigama@lsi.com0167ac62011-10-21 10:06:33 +05307873 spin_lock_irqsave(&ioc->sas_device_lock, flags);
7874 list_move_tail(&sas_device->list, &ioc->sas_device_list);
7875 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
Eric Moore635374e2009-03-09 01:21:12 -06007876 }
7877}
7878
7879/**
7880 * _scsih_probe_devices - probing for devices
7881 * @ioc: per adapter object
7882 *
7883 * Called during initial loading of the driver.
7884 */
7885static void
7886_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
7887{
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307888 u16 volume_mapping_flags;
Eric Moore635374e2009-03-09 01:21:12 -06007889
7890 if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
7891 return; /* return when IOC doesn't support initiator mode */
7892
7893 _scsih_probe_boot_devices(ioc);
7894
7895 if (ioc->ir_firmware) {
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307896 volume_mapping_flags =
7897 le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
7898 MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
7899 if (volume_mapping_flags ==
7900 MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
Eric Moore635374e2009-03-09 01:21:12 -06007901 _scsih_probe_raid(ioc);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307902 _scsih_probe_sas(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007903 } else {
Eric Moore635374e2009-03-09 01:21:12 -06007904 _scsih_probe_sas(ioc);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307905 _scsih_probe_raid(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06007906 }
7907 } else
7908 _scsih_probe_sas(ioc);
7909}
7910
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05307911
7912/**
7913 * _scsih_scan_start - scsi lld callback for .scan_start
7914 * @shost: SCSI host pointer
7915 *
7916 * The shost has the ability to discover targets on its own instead
7917 * of scanning the entire bus. In our implemention, we will kick off
7918 * firmware discovery.
7919 */
7920static void
7921_scsih_scan_start(struct Scsi_Host *shost)
7922{
7923 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7924 int rc;
7925
7926 if (diag_buffer_enable != -1 && diag_buffer_enable != 0)
7927 mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
7928
7929 ioc->start_scan = 1;
7930 rc = mpt2sas_port_enable(ioc);
7931
7932 if (rc != 0)
7933 printk(MPT2SAS_INFO_FMT "port enable: FAILED\n", ioc->name);
7934}
7935
7936/**
7937 * _scsih_scan_finished - scsi lld callback for .scan_finished
7938 * @shost: SCSI host pointer
7939 * @time: elapsed time of the scan in jiffies
7940 *
7941 * This function will be called periodically until it returns 1 with the
7942 * scsi_host and the elapsed time of the scan in jiffies. In our implemention,
7943 * we wait for firmware discovery to complete, then return 1.
7944 */
7945static int
7946_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
7947{
7948 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
7949
7950 if (time >= (300 * HZ)) {
7951 ioc->base_cmds.status = MPT2_CMD_NOT_USED;
7952 printk(MPT2SAS_INFO_FMT "port enable: FAILED with timeout "
7953 "(timeout=300s)\n", ioc->name);
7954 ioc->is_driver_loading = 0;
7955 return 1;
7956 }
7957
7958 if (ioc->start_scan)
7959 return 0;
7960
7961 if (ioc->start_scan_failed) {
7962 printk(MPT2SAS_INFO_FMT "port enable: FAILED with "
7963 "(ioc_status=0x%08x)\n", ioc->name, ioc->start_scan_failed);
7964 ioc->is_driver_loading = 0;
7965 ioc->wait_for_discovery_to_complete = 0;
7966 ioc->remove_host = 1;
7967 return 1;
7968 }
7969
7970 printk(MPT2SAS_INFO_FMT "port enable: SUCCESS\n", ioc->name);
7971 ioc->base_cmds.status = MPT2_CMD_NOT_USED;
7972
7973 if (ioc->wait_for_discovery_to_complete) {
7974 ioc->wait_for_discovery_to_complete = 0;
7975 _scsih_probe_devices(ioc);
7976 }
7977 mpt2sas_base_start_watchdog(ioc);
7978 ioc->is_driver_loading = 0;
7979 return 1;
7980}
7981
7982
Eric Moore635374e2009-03-09 01:21:12 -06007983/**
Eric Moored5d135b2009-05-18 13:02:08 -06007984 * _scsih_probe - attach and add scsi host
Eric Moore635374e2009-03-09 01:21:12 -06007985 * @pdev: PCI device struct
7986 * @id: pci device id
7987 *
7988 * Returns 0 success, anything else error.
7989 */
7990static int
Eric Moored5d135b2009-05-18 13:02:08 -06007991_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Eric Moore635374e2009-03-09 01:21:12 -06007992{
7993 struct MPT2SAS_ADAPTER *ioc;
7994 struct Scsi_Host *shost;
7995
7996 shost = scsi_host_alloc(&scsih_driver_template,
7997 sizeof(struct MPT2SAS_ADAPTER));
7998 if (!shost)
7999 return -ENODEV;
8000
8001 /* init local params */
8002 ioc = shost_priv(shost);
8003 memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
8004 INIT_LIST_HEAD(&ioc->list);
Eric Mooreba33fad2009-03-15 21:37:18 -06008005 list_add_tail(&ioc->list, &mpt2sas_ioc_list);
Eric Moore635374e2009-03-09 01:21:12 -06008006 ioc->shost = shost;
8007 ioc->id = mpt_ids++;
8008 sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
8009 ioc->pdev = pdev;
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05308010 if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) {
8011 ioc->is_warpdrive = 1;
8012 ioc->hide_ir_msg = 1;
8013 } else
8014 ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
Eric Moore635374e2009-03-09 01:21:12 -06008015 ioc->scsi_io_cb_idx = scsi_io_cb_idx;
8016 ioc->tm_cb_idx = tm_cb_idx;
8017 ioc->ctl_cb_idx = ctl_cb_idx;
8018 ioc->base_cb_idx = base_cb_idx;
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05308019 ioc->port_enable_cb_idx = port_enable_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06008020 ioc->transport_cb_idx = transport_cb_idx;
Kashyap, Desai744090d2009-10-05 15:56:56 +05308021 ioc->scsih_cb_idx = scsih_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06008022 ioc->config_cb_idx = config_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05308023 ioc->tm_tr_cb_idx = tm_tr_cb_idx;
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05308024 ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx;
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05308025 ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
Eric Moore635374e2009-03-09 01:21:12 -06008026 ioc->logging_level = logging_level;
nagalakshmi.nandigama@lsi.com845a0e42011-12-01 07:42:04 +05308027 ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds;
Eric Moore635374e2009-03-09 01:21:12 -06008028 /* misc semaphores and spin locks */
Kashyap, Desaid2742132010-06-17 13:28:55 +05308029 mutex_init(&ioc->reset_in_progress_mutex);
Eric Moore635374e2009-03-09 01:21:12 -06008030 spin_lock_init(&ioc->ioc_reset_in_progress_lock);
8031 spin_lock_init(&ioc->scsi_lookup_lock);
8032 spin_lock_init(&ioc->sas_device_lock);
8033 spin_lock_init(&ioc->sas_node_lock);
8034 spin_lock_init(&ioc->fw_event_lock);
8035 spin_lock_init(&ioc->raid_device_lock);
8036
8037 INIT_LIST_HEAD(&ioc->sas_device_list);
8038 INIT_LIST_HEAD(&ioc->sas_device_init_list);
8039 INIT_LIST_HEAD(&ioc->sas_expander_list);
8040 INIT_LIST_HEAD(&ioc->fw_event_list);
8041 INIT_LIST_HEAD(&ioc->raid_device_list);
8042 INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05308043 INIT_LIST_HEAD(&ioc->delayed_tr_list);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05308044 INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
Eric Moore635374e2009-03-09 01:21:12 -06008045
8046 /* init shost parameters */
Eric Moored334aa72010-04-22 10:47:40 -06008047 shost->max_cmd_len = 32;
Eric Moore635374e2009-03-09 01:21:12 -06008048 shost->max_lun = max_lun;
8049 shost->transportt = mpt2sas_transport_template;
8050 shost->unique_id = ioc->id;
8051
Kashyap, Desaia3e1e552011-06-14 10:56:12 +05308052 if (max_sectors != 0xFFFF) {
8053 if (max_sectors < 64) {
8054 shost->max_sectors = 64;
8055 printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
8056 "for max_sectors, range is 64 to 8192. Assigning "
8057 "value of 64.\n", ioc->name, max_sectors);
nagalakshmi.nandigama@lsi.com9ac49d32011-12-01 07:52:08 +05308058 } else if (max_sectors > 32767) {
8059 shost->max_sectors = 32767;
Kashyap, Desaia3e1e552011-06-14 10:56:12 +05308060 printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
8061 "for max_sectors, range is 64 to 8192. Assigning "
nagalakshmi.nandigama@lsi.com9ac49d32011-12-01 07:52:08 +05308062 "default value of 32767.\n", ioc->name,
Kashyap, Desaia3e1e552011-06-14 10:56:12 +05308063 max_sectors);
8064 } else {
8065 shost->max_sectors = max_sectors & 0xFFFE;
8066 printk(MPT2SAS_INFO_FMT "The max_sectors value is "
8067 "set to %d\n", ioc->name, shost->max_sectors);
8068 }
8069 }
8070
Eric Moore635374e2009-03-09 01:21:12 -06008071 if ((scsi_add_host(shost, &pdev->dev))) {
8072 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
8073 ioc->name, __FILE__, __LINE__, __func__);
8074 list_del(&ioc->list);
8075 goto out_add_shost_fail;
8076 }
8077
Eric Moore3c621b32009-05-18 12:59:41 -06008078 scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
Eric Moored334aa72010-04-22 10:47:40 -06008079 | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05308080 scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
Eric Moore3c621b32009-05-18 12:59:41 -06008081
Eric Moore635374e2009-03-09 01:21:12 -06008082 /* event thread */
8083 snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
8084 "fw_event%d", ioc->id);
8085 ioc->firmware_event_thread = create_singlethread_workqueue(
8086 ioc->firmware_event_name);
8087 if (!ioc->firmware_event_thread) {
8088 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
8089 ioc->name, __FILE__, __LINE__, __func__);
8090 goto out_thread_fail;
8091 }
8092
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05308093 ioc->is_driver_loading = 1;
Eric Moore635374e2009-03-09 01:21:12 -06008094 if ((mpt2sas_base_attach(ioc))) {
8095 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
8096 ioc->name, __FILE__, __LINE__, __func__);
8097 goto out_attach_fail;
8098 }
8099
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05308100 if (ioc->is_warpdrive) {
8101 if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS)
8102 ioc->hide_drives = 0;
8103 else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS)
8104 ioc->hide_drives = 1;
8105 else {
8106 if (_scsih_get_num_volumes(ioc))
8107 ioc->hide_drives = 1;
8108 else
8109 ioc->hide_drives = 0;
8110 }
8111 } else
8112 ioc->hide_drives = 0;
nagalakshmi.nandigama@lsi.com2cb6fc82011-12-13 09:29:15 +05308113 scsi_scan_host(shost);
Kashyap, Desai0bdccdb2011-04-07 12:32:49 +05308114
Eric Moore635374e2009-03-09 01:21:12 -06008115 return 0;
8116
8117 out_attach_fail:
8118 destroy_workqueue(ioc->firmware_event_thread);
8119 out_thread_fail:
8120 list_del(&ioc->list);
8121 scsi_remove_host(shost);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05308122 scsi_host_put(shost);
Eric Moore635374e2009-03-09 01:21:12 -06008123 out_add_shost_fail:
8124 return -ENODEV;
8125}
8126
8127#ifdef CONFIG_PM
8128/**
Eric Moored5d135b2009-05-18 13:02:08 -06008129 * _scsih_suspend - power management suspend main entry point
Eric Moore635374e2009-03-09 01:21:12 -06008130 * @pdev: PCI device struct
8131 * @state: PM state change to (usually PCI_D3)
8132 *
8133 * Returns 0 success, anything else error.
8134 */
8135static int
Eric Moored5d135b2009-05-18 13:02:08 -06008136_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
Eric Moore635374e2009-03-09 01:21:12 -06008137{
8138 struct Scsi_Host *shost = pci_get_drvdata(pdev);
8139 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaic97951e2011-06-14 10:54:56 +05308140 pci_power_t device_state;
Eric Moore635374e2009-03-09 01:21:12 -06008141
Kashyap, Desaie4750c92009-08-07 19:37:59 +05308142 mpt2sas_base_stop_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06008143 scsi_block_requests(shost);
8144 device_state = pci_choose_state(pdev, state);
8145 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
8146 "operating state [D%d]\n", ioc->name, pdev,
8147 pci_name(pdev), device_state);
8148
8149 mpt2sas_base_free_resources(ioc);
8150 pci_save_state(pdev);
8151 pci_disable_device(pdev);
8152 pci_set_power_state(pdev, device_state);
8153 return 0;
8154}
8155
8156/**
Eric Moored5d135b2009-05-18 13:02:08 -06008157 * _scsih_resume - power management resume main entry point
Eric Moore635374e2009-03-09 01:21:12 -06008158 * @pdev: PCI device struct
8159 *
8160 * Returns 0 success, anything else error.
8161 */
8162static int
Eric Moored5d135b2009-05-18 13:02:08 -06008163_scsih_resume(struct pci_dev *pdev)
Eric Moore635374e2009-03-09 01:21:12 -06008164{
8165 struct Scsi_Host *shost = pci_get_drvdata(pdev);
8166 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Kashyap, Desaic97951e2011-06-14 10:54:56 +05308167 pci_power_t device_state = pdev->current_state;
Eric Moore635374e2009-03-09 01:21:12 -06008168 int r;
8169
8170 printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
8171 "operating state [D%d]\n", ioc->name, pdev,
8172 pci_name(pdev), device_state);
8173
8174 pci_set_power_state(pdev, PCI_D0);
8175 pci_enable_wake(pdev, PCI_D0, 0);
8176 pci_restore_state(pdev);
8177 ioc->pdev = pdev;
8178 r = mpt2sas_base_map_resources(ioc);
8179 if (r)
8180 return r;
8181
8182 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
8183 scsi_unblock_requests(shost);
Kashyap, Desaie4750c92009-08-07 19:37:59 +05308184 mpt2sas_base_start_watchdog(ioc);
Eric Moore635374e2009-03-09 01:21:12 -06008185 return 0;
8186}
8187#endif /* CONFIG_PM */
8188
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05308189/**
8190 * _scsih_pci_error_detected - Called when a PCI error is detected.
8191 * @pdev: PCI device struct
8192 * @state: PCI channel state
8193 *
8194 * Description: Called when a PCI error is detected.
8195 *
8196 * Return value:
8197 * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
8198 */
8199static pci_ers_result_t
8200_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
8201{
8202 struct Scsi_Host *shost = pci_get_drvdata(pdev);
8203 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
8204
8205 printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n",
8206 ioc->name, state);
8207
8208 switch (state) {
8209 case pci_channel_io_normal:
8210 return PCI_ERS_RESULT_CAN_RECOVER;
8211 case pci_channel_io_frozen:
Eric Moore3cb54692010-07-08 14:44:34 -06008212 /* Fatal error, prepare for slot reset */
8213 ioc->pci_error_recovery = 1;
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05308214 scsi_block_requests(ioc->shost);
8215 mpt2sas_base_stop_watchdog(ioc);
8216 mpt2sas_base_free_resources(ioc);
8217 return PCI_ERS_RESULT_NEED_RESET;
8218 case pci_channel_io_perm_failure:
Eric Moore3cb54692010-07-08 14:44:34 -06008219 /* Permanent error, prepare for device removal */
8220 ioc->pci_error_recovery = 1;
8221 mpt2sas_base_stop_watchdog(ioc);
8222 _scsih_flush_running_cmds(ioc);
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05308223 return PCI_ERS_RESULT_DISCONNECT;
8224 }
8225 return PCI_ERS_RESULT_NEED_RESET;
8226}
8227
8228/**
8229 * _scsih_pci_slot_reset - Called when PCI slot has been reset.
8230 * @pdev: PCI device struct
8231 *
8232 * Description: This routine is called by the pci error recovery
8233 * code after the PCI slot has been reset, just before we
8234 * should resume normal operations.
8235 */
8236static pci_ers_result_t
8237_scsih_pci_slot_reset(struct pci_dev *pdev)
8238{
8239 struct Scsi_Host *shost = pci_get_drvdata(pdev);
8240 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
8241 int rc;
8242
8243 printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
8244 ioc->name);
8245
Eric Moore3cb54692010-07-08 14:44:34 -06008246 ioc->pci_error_recovery = 0;
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05308247 ioc->pdev = pdev;
Eric Moore3cb54692010-07-08 14:44:34 -06008248 pci_restore_state(pdev);
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05308249 rc = mpt2sas_base_map_resources(ioc);
8250 if (rc)
8251 return PCI_ERS_RESULT_DISCONNECT;
8252
8253
8254 rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
8255 FORCE_BIG_HAMMER);
8256
8257 printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name,
8258 (rc == 0) ? "success" : "failed");
8259
8260 if (!rc)
8261 return PCI_ERS_RESULT_RECOVERED;
8262 else
8263 return PCI_ERS_RESULT_DISCONNECT;
8264}
8265
8266/**
8267 * _scsih_pci_resume() - resume normal ops after PCI reset
8268 * @pdev: pointer to PCI device
8269 *
8270 * Called when the error recovery driver tells us that its
8271 * OK to resume normal operation. Use completion to allow
8272 * halted scsi ops to resume.
8273 */
8274static void
8275_scsih_pci_resume(struct pci_dev *pdev)
8276{
8277 struct Scsi_Host *shost = pci_get_drvdata(pdev);
8278 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
8279
8280 printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name);
8281
8282 pci_cleanup_aer_uncorrect_error_status(pdev);
8283 mpt2sas_base_start_watchdog(ioc);
8284 scsi_unblock_requests(ioc->shost);
8285}
8286
8287/**
8288 * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
8289 * @pdev: pointer to PCI device
8290 */
8291static pci_ers_result_t
8292_scsih_pci_mmio_enabled(struct pci_dev *pdev)
8293{
8294 struct Scsi_Host *shost = pci_get_drvdata(pdev);
8295 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
8296
8297 printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n",
8298 ioc->name);
8299
8300 /* TODO - dump whatever for debugging purposes */
8301
8302 /* Request a slot reset. */
8303 return PCI_ERS_RESULT_NEED_RESET;
8304}
8305
8306static struct pci_error_handlers _scsih_err_handler = {
8307 .error_detected = _scsih_pci_error_detected,
8308 .mmio_enabled = _scsih_pci_mmio_enabled,
8309 .slot_reset = _scsih_pci_slot_reset,
8310 .resume = _scsih_pci_resume,
8311};
Eric Moore635374e2009-03-09 01:21:12 -06008312
8313static struct pci_driver scsih_driver = {
8314 .name = MPT2SAS_DRIVER_NAME,
8315 .id_table = scsih_pci_table,
Eric Moored5d135b2009-05-18 13:02:08 -06008316 .probe = _scsih_probe,
8317 .remove = __devexit_p(_scsih_remove),
Kashyap, Desai744090d2009-10-05 15:56:56 +05308318 .shutdown = _scsih_shutdown,
Kashyap, Desaief7c80c2010-04-05 14:20:07 +05308319 .err_handler = &_scsih_err_handler,
Eric Moore635374e2009-03-09 01:21:12 -06008320#ifdef CONFIG_PM
Eric Moored5d135b2009-05-18 13:02:08 -06008321 .suspend = _scsih_suspend,
8322 .resume = _scsih_resume,
Eric Moore635374e2009-03-09 01:21:12 -06008323#endif
8324};
8325
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05308326/* raid transport support */
8327static struct raid_function_template mpt2sas_raid_functions = {
8328 .cookie = &scsih_driver_template,
8329 .is_raid = _scsih_is_raid,
8330 .get_resync = _scsih_get_resync,
8331 .get_state = _scsih_get_state,
8332};
Eric Moore635374e2009-03-09 01:21:12 -06008333
8334/**
Eric Moored5d135b2009-05-18 13:02:08 -06008335 * _scsih_init - main entry point for this driver.
Eric Moore635374e2009-03-09 01:21:12 -06008336 *
8337 * Returns 0 success, anything else error.
8338 */
8339static int __init
Eric Moored5d135b2009-05-18 13:02:08 -06008340_scsih_init(void)
Eric Moore635374e2009-03-09 01:21:12 -06008341{
8342 int error;
8343
8344 mpt_ids = 0;
8345 printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
8346 MPT2SAS_DRIVER_VERSION);
8347
8348 mpt2sas_transport_template =
8349 sas_attach_transport(&mpt2sas_transport_functions);
8350 if (!mpt2sas_transport_template)
8351 return -ENODEV;
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05308352 /* raid transport support */
8353 mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
8354 if (!mpt2sas_raid_template) {
8355 sas_release_transport(mpt2sas_transport_template);
8356 return -ENODEV;
8357 }
Eric Moore635374e2009-03-09 01:21:12 -06008358
8359 mpt2sas_base_initialize_callback_handler();
8360
8361 /* queuecommand callback hander */
Eric Moored5d135b2009-05-18 13:02:08 -06008362 scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
Eric Moore635374e2009-03-09 01:21:12 -06008363
Uwe Kleine-König65155b32010-06-11 12:17:01 +02008364 /* task management callback handler */
Eric Moored5d135b2009-05-18 13:02:08 -06008365 tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
Eric Moore635374e2009-03-09 01:21:12 -06008366
8367 /* base internal commands callback handler */
8368 base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05308369 port_enable_cb_idx = mpt2sas_base_register_callback_handler(
8370 mpt2sas_port_enable_done);
Eric Moore635374e2009-03-09 01:21:12 -06008371
8372 /* transport internal commands callback handler */
8373 transport_cb_idx = mpt2sas_base_register_callback_handler(
8374 mpt2sas_transport_done);
8375
Kashyap, Desai744090d2009-10-05 15:56:56 +05308376 /* scsih internal commands callback handler */
8377 scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
8378
Eric Moore635374e2009-03-09 01:21:12 -06008379 /* configuration page API internal commands callback handler */
8380 config_cb_idx = mpt2sas_base_register_callback_handler(
8381 mpt2sas_config_done);
8382
8383 /* ctl module callback handler */
8384 ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
8385
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05308386 tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
8387 _scsih_tm_tr_complete);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05308388
8389 tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler(
8390 _scsih_tm_volume_tr_complete);
8391
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05308392 tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
8393 _scsih_sas_control_complete);
8394
Eric Moore635374e2009-03-09 01:21:12 -06008395 mpt2sas_ctl_init();
8396
8397 error = pci_register_driver(&scsih_driver);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05308398 if (error) {
8399 /* raid transport support */
8400 raid_class_release(mpt2sas_raid_template);
Eric Moore635374e2009-03-09 01:21:12 -06008401 sas_release_transport(mpt2sas_transport_template);
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05308402 }
Eric Moore635374e2009-03-09 01:21:12 -06008403
8404 return error;
8405}
8406
8407/**
Eric Moored5d135b2009-05-18 13:02:08 -06008408 * _scsih_exit - exit point for this driver (when it is a module).
Eric Moore635374e2009-03-09 01:21:12 -06008409 *
8410 * Returns 0 success, anything else error.
8411 */
8412static void __exit
Eric Moored5d135b2009-05-18 13:02:08 -06008413_scsih_exit(void)
Eric Moore635374e2009-03-09 01:21:12 -06008414{
8415 printk(KERN_INFO "mpt2sas version %s unloading\n",
8416 MPT2SAS_DRIVER_VERSION);
8417
8418 pci_unregister_driver(&scsih_driver);
8419
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05308420 mpt2sas_ctl_exit();
8421
Eric Moore635374e2009-03-09 01:21:12 -06008422 mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
8423 mpt2sas_base_release_callback_handler(tm_cb_idx);
8424 mpt2sas_base_release_callback_handler(base_cb_idx);
nagalakshmi.nandigama@lsi.com921cd802011-10-19 15:36:26 +05308425 mpt2sas_base_release_callback_handler(port_enable_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06008426 mpt2sas_base_release_callback_handler(transport_cb_idx);
Kashyap, Desai744090d2009-10-05 15:56:56 +05308427 mpt2sas_base_release_callback_handler(scsih_cb_idx);
Eric Moore635374e2009-03-09 01:21:12 -06008428 mpt2sas_base_release_callback_handler(config_cb_idx);
8429 mpt2sas_base_release_callback_handler(ctl_cb_idx);
8430
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05308431 mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
Kashyap, Desaif3eedd62010-06-17 13:46:13 +05308432 mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx);
Kashyap, Desai77e63ed2009-09-14 11:04:23 +05308433 mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
8434
Kashyap, Desaif7c95ef2009-12-16 18:54:42 +05308435 /* raid transport support */
8436 raid_class_release(mpt2sas_raid_template);
8437 sas_release_transport(mpt2sas_transport_template);
8438
Eric Moore635374e2009-03-09 01:21:12 -06008439}
8440
Eric Moored5d135b2009-05-18 13:02:08 -06008441module_init(_scsih_init);
8442module_exit(_scsih_exit);