aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLalit Chandivade <lalit.chandivade@qlogic.com>2009-10-13 18:16:52 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 13:00:14 -0500
commit0f00a206ccb1dc644b6770ef25f185610fee6962 (patch)
treeccf60cbb85f59d65b0a876f32ad5799d389482f0 /drivers
parent531a82d1bd73152130b9e3b1f3e2e875c6cff7cd (diff)
[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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c120
1 files changed, 57 insertions, 63 deletions
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 4d758d29523c..804987397b77 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1353,16 +1353,22 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
1353 1353
1354 sense_len = rsp_info_len = resid_len = fw_resid_len = 0; 1354 sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
1355 if (IS_FWI2_CAPABLE(ha)) { 1355 if (IS_FWI2_CAPABLE(ha)) {
1356 sense_len = le32_to_cpu(sts24->sense_len); 1356 if (scsi_status & SS_SENSE_LEN_VALID)
1357 rsp_info_len = le32_to_cpu(sts24->rsp_data_len); 1357 sense_len = le32_to_cpu(sts24->sense_len);
1358 resid_len = le32_to_cpu(sts24->rsp_residual_count); 1358 if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
1359 fw_resid_len = le32_to_cpu(sts24->residual_len); 1359 rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
1360 if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
1361 resid_len = le32_to_cpu(sts24->rsp_residual_count);
1362 if (comp_status == CS_DATA_UNDERRUN)
1363 fw_resid_len = le32_to_cpu(sts24->residual_len);
1360 rsp_info = sts24->data; 1364 rsp_info = sts24->data;
1361 sense_data = sts24->data; 1365 sense_data = sts24->data;
1362 host_to_fcp_swap(sts24->data, sizeof(sts24->data)); 1366 host_to_fcp_swap(sts24->data, sizeof(sts24->data));
1363 } else { 1367 } else {
1364 sense_len = le16_to_cpu(sts->req_sense_length); 1368 if (scsi_status & SS_SENSE_LEN_VALID)
1365 rsp_info_len = le16_to_cpu(sts->rsp_info_len); 1369 sense_len = le16_to_cpu(sts->req_sense_length);
1370 if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
1371 rsp_info_len = le16_to_cpu(sts->rsp_info_len);
1366 resid_len = le32_to_cpu(sts->residual_length); 1372 resid_len = le32_to_cpu(sts->residual_length);
1367 rsp_info = sts->rsp_info; 1373 rsp_info = sts->rsp_info;
1368 sense_data = sts->req_sense_data; 1374 sense_data = sts->req_sense_data;
@@ -1449,38 +1455,62 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
1449 break; 1455 break;
1450 1456
1451 case CS_DATA_UNDERRUN: 1457 case CS_DATA_UNDERRUN:
1452 resid = resid_len; 1458 DEBUG2(printk(KERN_INFO
1459 "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x. "
1460 "resid=0x%x fw_resid=0x%x cdb=0x%x os_underflow=0x%x\n",
1461 vha->host_no, cp->device->id, cp->device->lun, comp_status,
1462 scsi_status, resid_len, fw_resid_len, cp->cmnd[0],
1463 cp->underflow));
1464
1453 /* Use F/W calculated residual length. */ 1465 /* Use F/W calculated residual length. */
1454 if (IS_FWI2_CAPABLE(ha)) { 1466 resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
1455 if (!(scsi_status & SS_RESIDUAL_UNDER)) { 1467 scsi_set_resid(cp, resid);
1456 lscsi_status = 0; 1468 if (scsi_status & SS_RESIDUAL_UNDER) {
1457 } else if (resid != fw_resid_len) { 1469 if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
1458 scsi_status &= ~SS_RESIDUAL_UNDER; 1470 DEBUG2(printk(
1459 lscsi_status = 0; 1471 "scsi(%ld:%d:%d:%d) Dropped frame(s) "
1472 "detected (%x of %x bytes)...residual "
1473 "length mismatch...retrying command.\n",
1474 vha->host_no, cp->device->channel,
1475 cp->device->id, cp->device->lun, resid,
1476 scsi_bufflen(cp)));
1477
1478 cp->result = DID_ERROR << 16 | lscsi_status;
1479 break;
1460 } 1480 }
1461 resid = fw_resid_len;
1462 }
1463 1481
1464 if (scsi_status & SS_RESIDUAL_UNDER) { 1482 if (!lscsi_status &&
1465 scsi_set_resid(cp, resid); 1483 ((unsigned)(scsi_bufflen(cp) - resid) <
1466 } else { 1484 cp->underflow)) {
1467 DEBUG2(printk(KERN_INFO 1485 qla_printk(KERN_INFO, ha,
1468 "scsi(%ld:%d:%d) UNDERRUN status detected " 1486 "scsi(%ld:%d:%d:%d): Mid-layer underflow "
1469 "0x%x-0x%x. resid=0x%x fw_resid=0x%x cdb=0x%x " 1487 "detected (%x of %x bytes)...returning "
1470 "os_underflow=0x%x\n", vha->host_no, 1488 "error status.\n", vha->host_no,
1471 cp->device->id, cp->device->lun, comp_status, 1489 cp->device->channel, cp->device->id,
1472 scsi_status, resid_len, resid, cp->cmnd[0], 1490 cp->device->lun, resid, scsi_bufflen(cp));
1473 cp->underflow));
1474 1491
1492 cp->result = DID_ERROR << 16;
1493 break;
1494 }
1495 } else if (!lscsi_status) {
1496 DEBUG2(printk(
1497 "scsi(%ld:%d:%d:%d) Dropped frame(s) detected "
1498 "(%x of %x bytes)...firmware reported underrun..."
1499 "retrying command.\n", vha->host_no,
1500 cp->device->channel, cp->device->id,
1501 cp->device->lun, resid, scsi_bufflen(cp)));
1502
1503 cp->result = DID_ERROR << 16;
1504 break;
1475 } 1505 }
1476 1506
1507 cp->result = DID_OK << 16 | lscsi_status;
1508
1477 /* 1509 /*
1478 * Check to see if SCSI Status is non zero. If so report SCSI 1510 * Check to see if SCSI Status is non zero. If so report SCSI
1479 * Status. 1511 * Status.
1480 */ 1512 */
1481 if (lscsi_status != 0) { 1513 if (lscsi_status != 0) {
1482 cp->result = DID_OK << 16 | lscsi_status;
1483
1484 if (lscsi_status == SAM_STAT_TASK_SET_FULL) { 1514 if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
1485 DEBUG2(printk(KERN_INFO 1515 DEBUG2(printk(KERN_INFO
1486 "scsi(%ld): QUEUE FULL status detected " 1516 "scsi(%ld): QUEUE FULL status detected "
@@ -1507,42 +1537,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
1507 break; 1537 break;
1508 1538
1509 qla2x00_handle_sense(sp, sense_data, sense_len, rsp); 1539 qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
1510 } else {
1511 /*
1512 * If RISC reports underrun and target does not report
1513 * it then we must have a lost frame, so tell upper
1514 * layer to retry it by reporting an error.
1515 */
1516 if (!(scsi_status & SS_RESIDUAL_UNDER)) {
1517 DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
1518 "frame(s) detected (%x of %x bytes)..."
1519 "retrying command.\n",
1520 vha->host_no, cp->device->channel,
1521 cp->device->id, cp->device->lun, resid,
1522 scsi_bufflen(cp)));
1523
1524 scsi_set_resid(cp, resid);
1525 cp->result = DID_ERROR << 16;
1526 break;
1527 }
1528
1529 /* Handle mid-layer underflow */
1530 if ((unsigned)(scsi_bufflen(cp) - resid) <
1531 cp->underflow) {
1532 qla_printk(KERN_INFO, ha,
1533 "scsi(%ld:%d:%d:%d): Mid-layer underflow "
1534 "detected (%x of %x bytes)...returning "
1535 "error status.\n", vha->host_no,
1536 cp->device->channel, cp->device->id,
1537 cp->device->lun, resid,
1538 scsi_bufflen(cp));
1539
1540 cp->result = DID_ERROR << 16;
1541 break;
1542 }
1543
1544 /* Everybody online, looking good... */
1545 cp->result = DID_OK << 16;
1546 } 1540 }
1547 break; 1541 break;
1548 1542