mirror of https://gitee.com/openkylin/linux.git
[SCSI] qla2xxx: Properly handle UNDERRUN completion statuses.
Correct issues where the lower scsi-status would be improperly cleared, instead, allow the midlayer to process the status after the proper residual-count checks are performed. Finally, validate firmware status flags prior to assigning values from the FCP_RSP frame. Signed-off-by: Lalit Chandivade <lalit.chandivade@qlogic.com> Signed-off-by: Michael Hernandez <michael.hernandez@qlogic.com> Signed-off-by: Ravi Anand <ravi.anand@qlogic.com> Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
parent
531a82d1bd
commit
0f00a206cc
|
@ -1353,16 +1353,22 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
|
|||
|
||||
sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
|
||||
if (IS_FWI2_CAPABLE(ha)) {
|
||||
sense_len = le32_to_cpu(sts24->sense_len);
|
||||
rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
|
||||
resid_len = le32_to_cpu(sts24->rsp_residual_count);
|
||||
fw_resid_len = le32_to_cpu(sts24->residual_len);
|
||||
if (scsi_status & SS_SENSE_LEN_VALID)
|
||||
sense_len = le32_to_cpu(sts24->sense_len);
|
||||
if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
|
||||
rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
|
||||
if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
|
||||
resid_len = le32_to_cpu(sts24->rsp_residual_count);
|
||||
if (comp_status == CS_DATA_UNDERRUN)
|
||||
fw_resid_len = le32_to_cpu(sts24->residual_len);
|
||||
rsp_info = sts24->data;
|
||||
sense_data = sts24->data;
|
||||
host_to_fcp_swap(sts24->data, sizeof(sts24->data));
|
||||
} else {
|
||||
sense_len = le16_to_cpu(sts->req_sense_length);
|
||||
rsp_info_len = le16_to_cpu(sts->rsp_info_len);
|
||||
if (scsi_status & SS_SENSE_LEN_VALID)
|
||||
sense_len = le16_to_cpu(sts->req_sense_length);
|
||||
if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
|
||||
rsp_info_len = le16_to_cpu(sts->rsp_info_len);
|
||||
resid_len = le32_to_cpu(sts->residual_length);
|
||||
rsp_info = sts->rsp_info;
|
||||
sense_data = sts->req_sense_data;
|
||||
|
@ -1449,38 +1455,62 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
|
|||
break;
|
||||
|
||||
case CS_DATA_UNDERRUN:
|
||||
resid = resid_len;
|
||||
DEBUG2(printk(KERN_INFO
|
||||
"scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x. "
|
||||
"resid=0x%x fw_resid=0x%x cdb=0x%x os_underflow=0x%x\n",
|
||||
vha->host_no, cp->device->id, cp->device->lun, comp_status,
|
||||
scsi_status, resid_len, fw_resid_len, cp->cmnd[0],
|
||||
cp->underflow));
|
||||
|
||||
/* Use F/W calculated residual length. */
|
||||
if (IS_FWI2_CAPABLE(ha)) {
|
||||
if (!(scsi_status & SS_RESIDUAL_UNDER)) {
|
||||
lscsi_status = 0;
|
||||
} else if (resid != fw_resid_len) {
|
||||
scsi_status &= ~SS_RESIDUAL_UNDER;
|
||||
lscsi_status = 0;
|
||||
}
|
||||
resid = fw_resid_len;
|
||||
}
|
||||
|
||||
resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
|
||||
scsi_set_resid(cp, resid);
|
||||
if (scsi_status & SS_RESIDUAL_UNDER) {
|
||||
scsi_set_resid(cp, resid);
|
||||
} else {
|
||||
DEBUG2(printk(KERN_INFO
|
||||
"scsi(%ld:%d:%d) UNDERRUN status detected "
|
||||
"0x%x-0x%x. resid=0x%x fw_resid=0x%x cdb=0x%x "
|
||||
"os_underflow=0x%x\n", vha->host_no,
|
||||
cp->device->id, cp->device->lun, comp_status,
|
||||
scsi_status, resid_len, resid, cp->cmnd[0],
|
||||
cp->underflow));
|
||||
if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
|
||||
DEBUG2(printk(
|
||||
"scsi(%ld:%d:%d:%d) Dropped frame(s) "
|
||||
"detected (%x of %x bytes)...residual "
|
||||
"length mismatch...retrying command.\n",
|
||||
vha->host_no, cp->device->channel,
|
||||
cp->device->id, cp->device->lun, resid,
|
||||
scsi_bufflen(cp)));
|
||||
|
||||
cp->result = DID_ERROR << 16 | lscsi_status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!lscsi_status &&
|
||||
((unsigned)(scsi_bufflen(cp) - resid) <
|
||||
cp->underflow)) {
|
||||
qla_printk(KERN_INFO, ha,
|
||||
"scsi(%ld:%d:%d:%d): Mid-layer underflow "
|
||||
"detected (%x of %x bytes)...returning "
|
||||
"error status.\n", vha->host_no,
|
||||
cp->device->channel, cp->device->id,
|
||||
cp->device->lun, resid, scsi_bufflen(cp));
|
||||
|
||||
cp->result = DID_ERROR << 16;
|
||||
break;
|
||||
}
|
||||
} else if (!lscsi_status) {
|
||||
DEBUG2(printk(
|
||||
"scsi(%ld:%d:%d:%d) Dropped frame(s) detected "
|
||||
"(%x of %x bytes)...firmware reported underrun..."
|
||||
"retrying command.\n", vha->host_no,
|
||||
cp->device->channel, cp->device->id,
|
||||
cp->device->lun, resid, scsi_bufflen(cp)));
|
||||
|
||||
cp->result = DID_ERROR << 16;
|
||||
break;
|
||||
}
|
||||
|
||||
cp->result = DID_OK << 16 | lscsi_status;
|
||||
|
||||
/*
|
||||
* Check to see if SCSI Status is non zero. If so report SCSI
|
||||
* Status.
|
||||
*/
|
||||
if (lscsi_status != 0) {
|
||||
cp->result = DID_OK << 16 | lscsi_status;
|
||||
|
||||
if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
|
||||
DEBUG2(printk(KERN_INFO
|
||||
"scsi(%ld): QUEUE FULL status detected "
|
||||
|
@ -1507,42 +1537,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
|
|||
break;
|
||||
|
||||
qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
|
||||
} 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 an error.
|
||||
*/
|
||||
if (!(scsi_status & SS_RESIDUAL_UNDER)) {
|
||||
DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
|
||||
"frame(s) detected (%x of %x bytes)..."
|
||||
"retrying command.\n",
|
||||
vha->host_no, cp->device->channel,
|
||||
cp->device->id, cp->device->lun, resid,
|
||||
scsi_bufflen(cp)));
|
||||
|
||||
scsi_set_resid(cp, resid);
|
||||
cp->result = DID_ERROR << 16;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle mid-layer underflow */
|
||||
if ((unsigned)(scsi_bufflen(cp) - resid) <
|
||||
cp->underflow) {
|
||||
qla_printk(KERN_INFO, ha,
|
||||
"scsi(%ld:%d:%d:%d): Mid-layer underflow "
|
||||
"detected (%x of %x bytes)...returning "
|
||||
"error status.\n", vha->host_no,
|
||||
cp->device->channel, cp->device->id,
|
||||
cp->device->lun, resid,
|
||||
scsi_bufflen(cp));
|
||||
|
||||
cp->result = DID_ERROR << 16;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Everybody online, looking good... */
|
||||
cp->result = DID_OK << 16;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in New Issue