diff options
author | Lalit Chandivade <lalit.chandivade@qlogic.com> | 2009-10-13 18:16:52 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-04 13:00:14 -0500 |
commit | 0f00a206ccb1dc644b6770ef25f185610fee6962 (patch) | |
tree | ccf60cbb85f59d65b0a876f32ad5799d389482f0 /drivers/scsi | |
parent | 531a82d1bd73152130b9e3b1f3e2e875c6cff7cd (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/scsi')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 120 |
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 | ||