diff options
author | Lalit Chandivade <lalit.chandivade@qlogic.com> | 2012-08-07 07:57:16 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-09-14 17:59:21 +0100 |
commit | 24c14200947d0c2ca6943fe0353438c3ac9c1c2a (patch) | |
tree | 361cd82ef814fb5412114aed9ed5c68ad4f1c487 /drivers | |
parent | 80c53e649d23c3eedb5047c4dcbe8a70b9f99202 (diff) | |
download | linux-stable-24c14200947d0c2ca6943fe0353438c3ac9c1c2a.tar.gz linux-stable-24c14200947d0c2ca6943fe0353438c3ac9c1c2a.tar.bz2 linux-stable-24c14200947d0c2ca6943fe0353438c3ac9c1c2a.zip |
[SCSI] qla4xxx: Properly handle SCSI underrun while processing status IOCBs.
The current code would incorrectly return a DID_OK for a
CHECK CONDITION with Recovered error sense key causing incorrect
completion of a command when there is a dropped frame.
Signed-off-by: Lalit Chandivade <lalit.chandivade@qlogic.com>
Signed-off-by: Tej Parkash <tej.parkash@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_isr.c | 102 |
1 files changed, 59 insertions, 43 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index fc542a9bb106..db8c8e5fe259 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -243,56 +243,72 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, scsi_set_resid(cmd, residual); - /* - * If there is scsi_status, it takes precedense over - * underflow condition. - */ - if (scsi_status != 0) { - cmd->result = DID_OK << 16 | scsi_status; + if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) { + + /* Both the firmware and target reported UNDERRUN: + * + * MID-LAYER UNDERFLOW case: + * Some kernels do not properly detect midlayer + * underflow, so we manually check it and return + * ERROR if the minimum required data was not + * received. + * + * ALL OTHER cases: + * Fall thru to check scsi_status + */ + if (!scsi_status && (scsi_bufflen(cmd) - residual) < + cmd->underflow) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld:%d:%d:%d: %s: Mid-layer Data underrun, xferlen = 0x%x,residual = 0x%x\n", + ha->host_no, + cmd->device->channel, + cmd->device->id, + cmd->device->lun, __func__, + scsi_bufflen(cmd), + residual)); - if (scsi_status != SCSI_CHECK_CONDITION) + cmd->result = DID_ERROR << 16; break; + } + + } else if (scsi_status != SAM_STAT_TASK_SET_FULL && + scsi_status != SAM_STAT_BUSY) { - /* Copy Sense Data into sense buffer. */ - qla4xxx_copy_sense(ha, sts_entry, srb); - } else { /* - * If RISC reports underrun and target does not - * report it then we must have a lost frame, so - * tell upper layer to retry it by reporting a - * bus busy. + * The firmware reports UNDERRUN, but the target does + * not report it: + * + * scsi_status | host_byte device_byte + * | (19:16) (7:0) + * ============= | ========= =========== + * TASK_SET_FULL | DID_OK scsi_status + * BUSY | DID_OK scsi_status + * ALL OTHERS | DID_ERROR scsi_status + * + * Note: If scsi_status is task set full or busy, + * then this else if would fall thru to check the + * scsi_status and return DID_OK. */ - if ((sts_entry->iscsiFlags & - ISCSI_FLAG_RESIDUAL_UNDER) == 0) { - cmd->result = DID_BUS_BUSY << 16; - } else if ((scsi_bufflen(cmd) - residual) < - cmd->underflow) { - /* - * Handle mid-layer underflow??? - * - * For kernels less than 2.4, the driver must - * return an error if an underflow is detected. - * For kernels equal-to and above 2.4, the - * mid-layer will appearantly handle the - * underflow by detecting the residual count -- - * unfortunately, we do not see where this is - * actually being done. In the interim, we - * will return DID_ERROR. - */ - DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " - "Mid-layer Data underrun1, " - "xferlen = 0x%x, " - "residual = 0x%x\n", ha->host_no, - cmd->device->channel, - cmd->device->id, - cmd->device->lun, __func__, - scsi_bufflen(cmd), residual)); - cmd->result = DID_ERROR << 16; - } else { - cmd->result = DID_OK << 16; - } + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld:%d:%d:%d: %s: Dropped frame(s) detected (0x%x of 0x%x bytes).\n", + ha->host_no, + cmd->device->channel, + cmd->device->id, + cmd->device->lun, __func__, + residual, + scsi_bufflen(cmd))); + + cmd->result = DID_ERROR << 16 | scsi_status; + goto check_scsi_status; } + + cmd->result = DID_OK << 16 | scsi_status; + +check_scsi_status: + if (scsi_status == SAM_STAT_CHECK_CONDITION) + qla4xxx_copy_sense(ha, sts_entry, srb); + break; case SCS_DEVICE_LOGGED_OUT: |