diff options
author | Arun Easi <arun.easi@qlogic.com> | 2011-08-16 14:29:22 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-08-27 09:55:46 -0400 |
commit | 8cb2049c744809193ed3707a37c09676a24599ee (patch) | |
tree | b9523a9a1be8f2610547036d849880d588f0a694 /drivers/scsi/qla2xxx/qla_isr.c | |
parent | 01350d05539d1c95ef3568d062d864ab76ae7670 (diff) |
[SCSI] qla2xxx: T10 DIF - Handle uninitalized sectors.
Driver needs to update protection bytes for uninitialized sectors as they are
not DMA-d.
Signed-off-by: Arun Easi <arun.easi@qlogic.com>
Reviewed-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_isr.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 90 |
1 files changed, 75 insertions, 15 deletions
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b16b7725dee0..53339f10a598 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c | |||
@@ -1435,25 +1435,27 @@ struct scsi_dif_tuple { | |||
1435 | * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST | 1435 | * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST |
1436 | * to indicate to the kernel that the HBA detected error. | 1436 | * to indicate to the kernel that the HBA detected error. |
1437 | */ | 1437 | */ |
1438 | static inline void | 1438 | static inline int |
1439 | qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) | 1439 | qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) |
1440 | { | 1440 | { |
1441 | struct scsi_qla_host *vha = sp->fcport->vha; | 1441 | struct scsi_qla_host *vha = sp->fcport->vha; |
1442 | struct scsi_cmnd *cmd = sp->cmd; | 1442 | struct scsi_cmnd *cmd = sp->cmd; |
1443 | struct scsi_dif_tuple *ep = | 1443 | uint8_t *ap = &sts24->data[12]; |
1444 | (struct scsi_dif_tuple *)&sts24->data[20]; | 1444 | uint8_t *ep = &sts24->data[20]; |
1445 | struct scsi_dif_tuple *ap = | ||
1446 | (struct scsi_dif_tuple *)&sts24->data[12]; | ||
1447 | uint32_t e_ref_tag, a_ref_tag; | 1445 | uint32_t e_ref_tag, a_ref_tag; |
1448 | uint16_t e_app_tag, a_app_tag; | 1446 | uint16_t e_app_tag, a_app_tag; |
1449 | uint16_t e_guard, a_guard; | 1447 | uint16_t e_guard, a_guard; |
1450 | 1448 | ||
1451 | e_ref_tag = be32_to_cpu(ep->ref_tag); | 1449 | /* |
1452 | a_ref_tag = be32_to_cpu(ap->ref_tag); | 1450 | * swab32 of the "data" field in the beginning of qla2x00_status_entry() |
1453 | e_app_tag = be16_to_cpu(ep->app_tag); | 1451 | * would make guard field appear at offset 2 |
1454 | a_app_tag = be16_to_cpu(ap->app_tag); | 1452 | */ |
1455 | e_guard = be16_to_cpu(ep->guard); | 1453 | a_guard = le16_to_cpu(*(uint16_t *)(ap + 2)); |
1456 | a_guard = be16_to_cpu(ap->guard); | 1454 | a_app_tag = le16_to_cpu(*(uint16_t *)(ap + 0)); |
1455 | a_ref_tag = le32_to_cpu(*(uint32_t *)(ap + 4)); | ||
1456 | e_guard = le16_to_cpu(*(uint16_t *)(ep + 2)); | ||
1457 | e_app_tag = le16_to_cpu(*(uint16_t *)(ep + 0)); | ||
1458 | e_ref_tag = le32_to_cpu(*(uint32_t *)(ep + 4)); | ||
1457 | 1459 | ||
1458 | ql_dbg(ql_dbg_io, vha, 0x3023, | 1460 | ql_dbg(ql_dbg_io, vha, 0x3023, |
1459 | "iocb(s) %p Returned STATUS.\n", sts24); | 1461 | "iocb(s) %p Returned STATUS.\n", sts24); |
@@ -1465,6 +1467,63 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) | |||
1465 | cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag, | 1467 | cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag, |
1466 | a_app_tag, e_app_tag, a_guard, e_guard); | 1468 | a_app_tag, e_app_tag, a_guard, e_guard); |
1467 | 1469 | ||
1470 | /* | ||
1471 | * Ignore sector if: | ||
1472 | * For type 3: ref & app tag is all 'f's | ||
1473 | * For type 0,1,2: app tag is all 'f's | ||
1474 | */ | ||
1475 | if ((a_app_tag == 0xffff) && | ||
1476 | ((scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3) || | ||
1477 | (a_ref_tag == 0xffffffff))) { | ||
1478 | uint32_t blocks_done, resid; | ||
1479 | sector_t lba_s = scsi_get_lba(cmd); | ||
1480 | |||
1481 | /* 2TB boundary case covered automatically with this */ | ||
1482 | blocks_done = e_ref_tag - (uint32_t)lba_s + 1; | ||
1483 | |||
1484 | resid = scsi_bufflen(cmd) - (blocks_done * | ||
1485 | cmd->device->sector_size); | ||
1486 | |||
1487 | scsi_set_resid(cmd, resid); | ||
1488 | cmd->result = DID_OK << 16; | ||
1489 | |||
1490 | /* Update protection tag */ | ||
1491 | if (scsi_prot_sg_count(cmd)) { | ||
1492 | uint32_t i, j = 0, k = 0, num_ent; | ||
1493 | struct scatterlist *sg; | ||
1494 | struct sd_dif_tuple *spt; | ||
1495 | |||
1496 | /* Patch the corresponding protection tags */ | ||
1497 | scsi_for_each_prot_sg(cmd, sg, | ||
1498 | scsi_prot_sg_count(cmd), i) { | ||
1499 | num_ent = sg_dma_len(sg) / 8; | ||
1500 | if (k + num_ent < blocks_done) { | ||
1501 | k += num_ent; | ||
1502 | continue; | ||
1503 | } | ||
1504 | j = blocks_done - k - 1; | ||
1505 | k = blocks_done; | ||
1506 | break; | ||
1507 | } | ||
1508 | |||
1509 | if (k != blocks_done) { | ||
1510 | qla_printk(KERN_WARNING, sp->fcport->vha->hw, | ||
1511 | "unexpected tag values tag:lba=%x:%lx)\n", | ||
1512 | e_ref_tag, lba_s); | ||
1513 | return 1; | ||
1514 | } | ||
1515 | |||
1516 | spt = page_address(sg_page(sg)) + sg->offset; | ||
1517 | spt += j; | ||
1518 | |||
1519 | spt->app_tag = 0xffff; | ||
1520 | if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3) | ||
1521 | spt->ref_tag = 0xffffffff; | ||
1522 | } | ||
1523 | |||
1524 | return 0; | ||
1525 | } | ||
1526 | |||
1468 | /* check guard */ | 1527 | /* check guard */ |
1469 | if (e_guard != a_guard) { | 1528 | if (e_guard != a_guard) { |
1470 | scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, | 1529 | scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, |
@@ -1472,7 +1531,7 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) | |||
1472 | set_driver_byte(cmd, DRIVER_SENSE); | 1531 | set_driver_byte(cmd, DRIVER_SENSE); |
1473 | set_host_byte(cmd, DID_ABORT); | 1532 | set_host_byte(cmd, DID_ABORT); |
1474 | cmd->result |= SAM_STAT_CHECK_CONDITION << 1; | 1533 | cmd->result |= SAM_STAT_CHECK_CONDITION << 1; |
1475 | return; | 1534 | return 1; |
1476 | } | 1535 | } |
1477 | 1536 | ||
1478 | /* check appl tag */ | 1537 | /* check appl tag */ |
@@ -1482,7 +1541,7 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) | |||
1482 | set_driver_byte(cmd, DRIVER_SENSE); | 1541 | set_driver_byte(cmd, DRIVER_SENSE); |
1483 | set_host_byte(cmd, DID_ABORT); | 1542 | set_host_byte(cmd, DID_ABORT); |
1484 | cmd->result |= SAM_STAT_CHECK_CONDITION << 1; | 1543 | cmd->result |= SAM_STAT_CHECK_CONDITION << 1; |
1485 | return; | 1544 | return 1; |
1486 | } | 1545 | } |
1487 | 1546 | ||
1488 | /* check ref tag */ | 1547 | /* check ref tag */ |
@@ -1492,8 +1551,9 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) | |||
1492 | set_driver_byte(cmd, DRIVER_SENSE); | 1551 | set_driver_byte(cmd, DRIVER_SENSE); |
1493 | set_host_byte(cmd, DID_ABORT); | 1552 | set_host_byte(cmd, DID_ABORT); |
1494 | cmd->result |= SAM_STAT_CHECK_CONDITION << 1; | 1553 | cmd->result |= SAM_STAT_CHECK_CONDITION << 1; |
1495 | return; | 1554 | return 1; |
1496 | } | 1555 | } |
1556 | return 1; | ||
1497 | } | 1557 | } |
1498 | 1558 | ||
1499 | /** | 1559 | /** |
@@ -1767,7 +1827,7 @@ check_scsi_status: | |||
1767 | break; | 1827 | break; |
1768 | 1828 | ||
1769 | case CS_DIF_ERROR: | 1829 | case CS_DIF_ERROR: |
1770 | qla2x00_handle_dif_error(sp, sts24); | 1830 | logit = qla2x00_handle_dif_error(sp, sts24); |
1771 | break; | 1831 | break; |
1772 | default: | 1832 | default: |
1773 | cp->result = DID_ERROR << 16; | 1833 | cp->result = DID_ERROR << 16; |