aboutsummaryrefslogtreecommitdiff
path: root/drivers/message/fusion/mptscsih.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/message/fusion/mptscsih.c')
-rw-r--r--drivers/message/fusion/mptscsih.c197
1 files changed, 75 insertions, 122 deletions
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 5c53624e0e8..2a1c6f21af2 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -664,6 +664,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
u32 log_info;
status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+
scsi_state = pScsiReply->SCSIState;
scsi_status = pScsiReply->SCSIStatus;
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
@@ -738,13 +739,36 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
if ( ioc->bus_type == SAS ) {
- u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
- if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
- if ((log_info & SAS_LOGINFO_MASK)
- == SAS_LOGINFO_NEXUS_LOSS) {
- sc->result = (DID_BUS_BUSY << 16);
- break;
- }
+ u16 ioc_status =
+ le16_to_cpu(pScsiReply->IOCStatus);
+ if ((ioc_status &
+ MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
+ &&
+ ((log_info & SAS_LOGINFO_MASK) ==
+ SAS_LOGINFO_NEXUS_LOSS)) {
+ VirtDevice *vdevice =
+ sc->device->hostdata;
+
+ /* flag the device as being in
+ * device removal delay so we can
+ * notify the midlayer to hold off
+ * on timeout eh */
+ if (vdevice && vdevice->
+ vtarget &&
+ vdevice->vtarget->
+ raidVolume)
+ printk(KERN_INFO
+ "Skipping Raid Volume"
+ "for inDMD\n");
+ else if (vdevice &&
+ vdevice->vtarget)
+ vdevice->vtarget->
+ inDMD = 1;
+
+ sc->result =
+ (DID_TRANSPORT_DISRUPTED
+ << 16);
+ break;
}
} else if (ioc->bus_type == FC) {
/*
@@ -768,6 +792,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
* than an unsolicited DID_ABORT.
*/
sc->result = DID_RESET << 16;
+ break;
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
if (ioc->bus_type == FC)
@@ -803,10 +828,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
* DID_SOFT_ERROR is set.
*/
if (ioc->bus_type == SPI) {
- if (pScsiReq->CDB[0] == READ_6 ||
+ if ((pScsiReq->CDB[0] == READ_6 && ((pScsiReq->CDB[1] & 0x02) == 0)) ||
pScsiReq->CDB[0] == READ_10 ||
pScsiReq->CDB[0] == READ_12 ||
- pScsiReq->CDB[0] == READ_16 ||
+ (pScsiReq->CDB[0] == READ_16 &&
+ ((pScsiReq->CDB[1] & 0x02) == 0)) ||
pScsiReq->CDB[0] == VERIFY ||
pScsiReq->CDB[0] == VERIFY_16) {
if (scsi_bufflen(sc) !=
@@ -1000,7 +1026,7 @@ out:
*
* Must be called while new I/Os are being queued.
*/
-static void
+void
mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
{
MPT_ADAPTER *ioc = hd->ioc;
@@ -1031,6 +1057,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
sc->scsi_done(sc);
}
}
+EXPORT_SYMBOL(mptscsih_flush_running_cmds);
/*
* mptscsih_search_running_cmds - Delete any commands associated
@@ -1257,101 +1284,17 @@ mptscsih_info(struct Scsi_Host *SChost)
return h->info_kbuf;
}
-struct info_str {
- char *buffer;
- int length;
- int offset;
- int pos;
-};
-
-static void
-mptscsih_copy_mem_info(struct info_str *info, char *data, int len)
-{
- if (info->pos + len > info->length)
- len = info->length - info->pos;
-
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
-
- if (info->pos < info->offset) {
- data += (info->offset - info->pos);
- len -= (info->offset - info->pos);
- }
-
- if (len > 0) {
- memcpy(info->buffer + info->pos, data, len);
- info->pos += len;
- }
-}
-
-static int
-mptscsih_copy_info(struct info_str *info, char *fmt, ...)
-{
- va_list args;
- char buf[81];
- int len;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- mptscsih_copy_mem_info(info, buf, len);
- return len;
-}
-
-static int
-mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len)
-{
- struct info_str info;
-
- info.buffer = pbuf;
- info.length = len;
- info.offset = offset;
- info.pos = 0;
-
- mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name);
- mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
- mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts);
- mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth);
-
- return ((info.pos > info.offset) ? info.pos - info.offset : 0);
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/**
- * mptscsih_proc_info - Return information about MPT adapter
- * @host: scsi host struct
- * @buffer: if write, user data; if read, buffer for user
- * @start: returns the buffer address
- * @offset: if write, 0; if read, the current offset into the buffer from
- * the previous read.
- * @length: if write, return length;
- * @func: write = 1; read = 0
- *
- * (linux scsi_host_template.info routine)
- */
-int
-mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int func)
+int mptscsih_show_info(struct seq_file *m, struct Scsi_Host *host)
{
MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
- int size = 0;
- if (func) {
- /*
- * write is not supported
- */
- } else {
- if (start)
- *start = buffer;
-
- size = mptscsih_host_info(ioc, buffer, offset, length);
- }
+ seq_printf(m, "%s: %s, ", ioc->name, ioc->prod_name);
+ seq_printf(m, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word);
+ seq_printf(m, "Ports=%d, ", ioc->facts.NumberOfPorts);
+ seq_printf(m, "MaxQ=%d\n", ioc->req_depth);
- return size;
+ return 0;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1361,7 +1304,6 @@ mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t off
/**
* mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine.
* @SCpnt: Pointer to scsi_cmnd structure
- * @done: Pointer SCSI mid-layer IO completion function
*
* (linux scsi_host_template.queuecommand routine)
* This is the primary SCSI IO start routine. Create a MPI SCSIIORequest
@@ -1370,7 +1312,7 @@ mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t off
* Returns 0. (rtn value discarded by linux scsi mid-layer)
*/
int
-mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptscsih_qcmd(struct scsi_cmnd *SCpnt)
{
MPT_SCSI_HOST *hd;
MPT_FRAME_HDR *mf;
@@ -1386,16 +1328,12 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
hd = shost_priv(SCpnt->device->host);
ioc = hd->ioc;
- SCpnt->scsi_done = done;
- dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
- ioc->name, SCpnt, done));
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p\n",
+ ioc->name, SCpnt));
- if (ioc->taskmgmt_quiesce_io) {
- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
- ioc->name, SCpnt));
+ if (ioc->taskmgmt_quiesce_io)
return SCSI_MLQUEUE_HOST_BUSY;
- }
/*
* Put together a MPT SCSI request...
@@ -1608,7 +1546,13 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
return 0;
}
- if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
+ /* DOORBELL ACTIVE check is not required if
+ * MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q is supported.
+ */
+
+ if (!((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q)
+ && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) &&
+ (ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
printk(MYIOC_s_WARN_FMT
"TaskMgmt type=%x: ioc_state: "
"DOORBELL_ACTIVE (0x%x)!\n",
@@ -1704,9 +1648,12 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
if (issue_hard_reset) {
- printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
- ioc->name, __func__);
- retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
+ printk(MYIOC_s_WARN_FMT
+ "Issuing Reset from %s!! doorbell=0x%08x\n",
+ ioc->name, __func__, mpt_GetIocState(ioc, 0));
+ retval = (ioc->bus_type == SAS) ?
+ mpt_HardResetHandler(ioc, CAN_SLEEP) :
+ mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
mpt_free_msg_frame(ioc, mf);
}
@@ -1748,7 +1695,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
int scpnt_idx;
int retval;
VirtDevice *vdevice;
- ulong sn = SCpnt->serial_number;
MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
@@ -1834,8 +1780,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdevice->vtarget->id, vdevice->lun,
ctx2abort, mptscsih_get_tm_timeout(ioc));
- if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
- SCpnt->serial_number == sn) {
+ if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) {
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"task abort: command still in active list! (sc=%p)\n",
ioc->name, SCpnt));
@@ -1848,8 +1793,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
}
out:
- printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
- ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt);
+ printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n",
+ ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
+ SCpnt);
return retval;
}
@@ -1886,7 +1832,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
vdevice = SCpnt->device->hostdata;
if (!vdevice || !vdevice->vtarget) {
- retval = SUCCESS;
+ retval = 0;
goto out;
}
@@ -2132,6 +2078,8 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
mpt_clear_taskmgmt_in_progress_flag(ioc);
ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->taskmgmt_cmds.done);
+ if (ioc->bus_type == SAS)
+ ioc->schedule_target_reset(ioc);
return 1;
}
return 0;
@@ -2459,6 +2407,8 @@ mptscsih_slave_configure(struct scsi_device *sdev)
ioc->name,sdev->tagged_supported, sdev->simple_tags,
sdev->ordered_tags));
+ blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
+
return 0;
}
@@ -3045,8 +2995,11 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
goto out;
}
if (!timeleft) {
- printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
- ioc->name, __func__);
+ printk(MYIOC_s_WARN_FMT
+ "Issuing Reset from %s!! doorbell=0x%08xh"
+ " cmd=0x%02x\n",
+ ioc->name, __func__, mpt_GetIocState(ioc, 0),
+ cmd);
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
mpt_free_msg_frame(ioc, mf);
}
@@ -3309,7 +3262,7 @@ EXPORT_SYMBOL(mptscsih_shutdown);
EXPORT_SYMBOL(mptscsih_suspend);
EXPORT_SYMBOL(mptscsih_resume);
#endif
-EXPORT_SYMBOL(mptscsih_proc_info);
+EXPORT_SYMBOL(mptscsih_show_info);
EXPORT_SYMBOL(mptscsih_info);
EXPORT_SYMBOL(mptscsih_qcmd);
EXPORT_SYMBOL(mptscsih_slave_destroy);