diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2009-01-04 03:08:19 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-03-12 13:57:55 -0400 |
commit | c6a44287417de1625a59f1d4ae52d033c03b9dab (patch) | |
tree | 380e7fdb6f689196a648c7c8bc3cf41c5cd58fcc /drivers/scsi/scsi_debug.c | |
parent | 59d3270326fcba29226c28df27cb43fefd8c58d0 (diff) |
[SCSI] scsi_debug: DIF/DIX support
This patch adds support for DIX and DIF in scsi_debug. A separate
buffer is allocated for the protection information.
- The dix parameter indicates whether the controller supports DIX
(protection information DMA)
- The dif parameter indicates whether the simulated storage device
supports DIF
- The guard parameter switches between T10 CRC(0) and IP checksum(1)
- The ato parameter indicates whether the application tag is owned by
the disk(0) or the OS(1)
- DIF and DIX errors can be triggered using the scsi_debug_opts mask
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Acked-by: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 443 |
1 files changed, 436 insertions, 7 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 6eebd0bbe8a8..213123b0486b 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -40,6 +40,9 @@ | |||
40 | #include <linux/moduleparam.h> | 40 | #include <linux/moduleparam.h> |
41 | #include <linux/scatterlist.h> | 41 | #include <linux/scatterlist.h> |
42 | #include <linux/blkdev.h> | 42 | #include <linux/blkdev.h> |
43 | #include <linux/crc-t10dif.h> | ||
44 | |||
45 | #include <net/checksum.h> | ||
43 | 46 | ||
44 | #include <scsi/scsi.h> | 47 | #include <scsi/scsi.h> |
45 | #include <scsi/scsi_cmnd.h> | 48 | #include <scsi/scsi_cmnd.h> |
@@ -48,8 +51,7 @@ | |||
48 | #include <scsi/scsicam.h> | 51 | #include <scsi/scsicam.h> |
49 | #include <scsi/scsi_eh.h> | 52 | #include <scsi/scsi_eh.h> |
50 | 53 | ||
51 | #include <linux/stat.h> | 54 | #include "sd.h" |
52 | |||
53 | #include "scsi_logging.h" | 55 | #include "scsi_logging.h" |
54 | 56 | ||
55 | #define SCSI_DEBUG_VERSION "1.81" | 57 | #define SCSI_DEBUG_VERSION "1.81" |
@@ -95,6 +97,10 @@ static const char * scsi_debug_version_date = "20070104"; | |||
95 | #define DEF_FAKE_RW 0 | 97 | #define DEF_FAKE_RW 0 |
96 | #define DEF_VPD_USE_HOSTNO 1 | 98 | #define DEF_VPD_USE_HOSTNO 1 |
97 | #define DEF_SECTOR_SIZE 512 | 99 | #define DEF_SECTOR_SIZE 512 |
100 | #define DEF_DIX 0 | ||
101 | #define DEF_DIF 0 | ||
102 | #define DEF_GUARD 0 | ||
103 | #define DEF_ATO 1 | ||
98 | 104 | ||
99 | /* bit mask values for scsi_debug_opts */ | 105 | /* bit mask values for scsi_debug_opts */ |
100 | #define SCSI_DEBUG_OPT_NOISE 1 | 106 | #define SCSI_DEBUG_OPT_NOISE 1 |
@@ -102,6 +108,8 @@ static const char * scsi_debug_version_date = "20070104"; | |||
102 | #define SCSI_DEBUG_OPT_TIMEOUT 4 | 108 | #define SCSI_DEBUG_OPT_TIMEOUT 4 |
103 | #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 | 109 | #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 |
104 | #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 | 110 | #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 |
111 | #define SCSI_DEBUG_OPT_DIF_ERR 32 | ||
112 | #define SCSI_DEBUG_OPT_DIX_ERR 64 | ||
105 | /* When "every_nth" > 0 then modulo "every_nth" commands: | 113 | /* When "every_nth" > 0 then modulo "every_nth" commands: |
106 | * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set | 114 | * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set |
107 | * - a RECOVERED_ERROR is simulated on successful read and write | 115 | * - a RECOVERED_ERROR is simulated on successful read and write |
@@ -144,6 +152,10 @@ static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; | |||
144 | static int scsi_debug_fake_rw = DEF_FAKE_RW; | 152 | static int scsi_debug_fake_rw = DEF_FAKE_RW; |
145 | static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; | 153 | static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; |
146 | static int scsi_debug_sector_size = DEF_SECTOR_SIZE; | 154 | static int scsi_debug_sector_size = DEF_SECTOR_SIZE; |
155 | static int scsi_debug_dix = DEF_DIX; | ||
156 | static int scsi_debug_dif = DEF_DIF; | ||
157 | static int scsi_debug_guard = DEF_GUARD; | ||
158 | static int scsi_debug_ato = DEF_ATO; | ||
147 | 159 | ||
148 | static int scsi_debug_cmnd_count = 0; | 160 | static int scsi_debug_cmnd_count = 0; |
149 | 161 | ||
@@ -204,11 +216,15 @@ struct sdebug_queued_cmd { | |||
204 | static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; | 216 | static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; |
205 | 217 | ||
206 | static unsigned char * fake_storep; /* ramdisk storage */ | 218 | static unsigned char * fake_storep; /* ramdisk storage */ |
219 | static unsigned char *dif_storep; /* protection info */ | ||
207 | 220 | ||
208 | static int num_aborts = 0; | 221 | static int num_aborts = 0; |
209 | static int num_dev_resets = 0; | 222 | static int num_dev_resets = 0; |
210 | static int num_bus_resets = 0; | 223 | static int num_bus_resets = 0; |
211 | static int num_host_resets = 0; | 224 | static int num_host_resets = 0; |
225 | static int dix_writes; | ||
226 | static int dix_reads; | ||
227 | static int dif_errors; | ||
212 | 228 | ||
213 | static DEFINE_SPINLOCK(queued_arr_lock); | 229 | static DEFINE_SPINLOCK(queued_arr_lock); |
214 | static DEFINE_RWLOCK(atomic_rw); | 230 | static DEFINE_RWLOCK(atomic_rw); |
@@ -217,6 +233,11 @@ static char sdebug_proc_name[] = "scsi_debug"; | |||
217 | 233 | ||
218 | static struct bus_type pseudo_lld_bus; | 234 | static struct bus_type pseudo_lld_bus; |
219 | 235 | ||
236 | static inline sector_t dif_offset(sector_t sector) | ||
237 | { | ||
238 | return sector << 3; | ||
239 | } | ||
240 | |||
220 | static struct device_driver sdebug_driverfs_driver = { | 241 | static struct device_driver sdebug_driverfs_driver = { |
221 | .name = sdebug_proc_name, | 242 | .name = sdebug_proc_name, |
222 | .bus = &pseudo_lld_bus, | 243 | .bus = &pseudo_lld_bus, |
@@ -225,6 +246,9 @@ static struct device_driver sdebug_driverfs_driver = { | |||
225 | static const int check_condition_result = | 246 | static const int check_condition_result = |
226 | (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; | 247 | (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; |
227 | 248 | ||
249 | static const int illegal_condition_result = | ||
250 | (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; | ||
251 | |||
228 | static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, | 252 | static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, |
229 | 0, 0, 0x2, 0x4b}; | 253 | 0, 0, 0x2, 0x4b}; |
230 | static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, | 254 | static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, |
@@ -726,7 +750,12 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
726 | } else if (0x86 == cmd[2]) { /* extended inquiry */ | 750 | } else if (0x86 == cmd[2]) { /* extended inquiry */ |
727 | arr[1] = cmd[2]; /*sanity */ | 751 | arr[1] = cmd[2]; /*sanity */ |
728 | arr[3] = 0x3c; /* number of following entries */ | 752 | arr[3] = 0x3c; /* number of following entries */ |
729 | arr[4] = 0x0; /* no protection stuff */ | 753 | if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) |
754 | arr[4] = 0x4; /* SPT: GRD_CHK:1 */ | ||
755 | else if (scsi_debug_dif) | ||
756 | arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ | ||
757 | else | ||
758 | arr[4] = 0x0; /* no protection stuff */ | ||
730 | arr[5] = 0x7; /* head of q, ordered + simple q's */ | 759 | arr[5] = 0x7; /* head of q, ordered + simple q's */ |
731 | } else if (0x87 == cmd[2]) { /* mode page policy */ | 760 | } else if (0x87 == cmd[2]) { /* mode page policy */ |
732 | arr[1] = cmd[2]; /*sanity */ | 761 | arr[1] = cmd[2]; /*sanity */ |
@@ -767,6 +796,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
767 | arr[2] = scsi_debug_scsi_level; | 796 | arr[2] = scsi_debug_scsi_level; |
768 | arr[3] = 2; /* response_data_format==2 */ | 797 | arr[3] = 2; /* response_data_format==2 */ |
769 | arr[4] = SDEBUG_LONG_INQ_SZ - 5; | 798 | arr[4] = SDEBUG_LONG_INQ_SZ - 5; |
799 | arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */ | ||
770 | if (0 == scsi_debug_vpd_use_hostno) | 800 | if (0 == scsi_debug_vpd_use_hostno) |
771 | arr[5] = 0x10; /* claim: implicit TGPS */ | 801 | arr[5] = 0x10; /* claim: implicit TGPS */ |
772 | arr[6] = 0x10; /* claim: MultiP */ | 802 | arr[6] = 0x10; /* claim: MultiP */ |
@@ -915,6 +945,12 @@ static int resp_readcap16(struct scsi_cmnd * scp, | |||
915 | arr[9] = (scsi_debug_sector_size >> 16) & 0xff; | 945 | arr[9] = (scsi_debug_sector_size >> 16) & 0xff; |
916 | arr[10] = (scsi_debug_sector_size >> 8) & 0xff; | 946 | arr[10] = (scsi_debug_sector_size >> 8) & 0xff; |
917 | arr[11] = scsi_debug_sector_size & 0xff; | 947 | arr[11] = scsi_debug_sector_size & 0xff; |
948 | |||
949 | if (scsi_debug_dif) { | ||
950 | arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */ | ||
951 | arr[12] |= 1; /* PROT_EN */ | ||
952 | } | ||
953 | |||
918 | return fill_from_dev_buffer(scp, arr, | 954 | return fill_from_dev_buffer(scp, arr, |
919 | min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); | 955 | min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); |
920 | } | 956 | } |
@@ -1066,6 +1102,10 @@ static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) | |||
1066 | ctrl_m_pg[2] |= 0x4; | 1102 | ctrl_m_pg[2] |= 0x4; |
1067 | else | 1103 | else |
1068 | ctrl_m_pg[2] &= ~0x4; | 1104 | ctrl_m_pg[2] &= ~0x4; |
1105 | |||
1106 | if (scsi_debug_ato) | ||
1107 | ctrl_m_pg[5] |= 0x80; /* ATO=1 */ | ||
1108 | |||
1069 | memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); | 1109 | memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); |
1070 | if (1 == pcontrol) | 1110 | if (1 == pcontrol) |
1071 | memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); | 1111 | memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); |
@@ -1536,6 +1576,87 @@ static int do_device_access(struct scsi_cmnd *scmd, | |||
1536 | return ret; | 1576 | return ret; |
1537 | } | 1577 | } |
1538 | 1578 | ||
1579 | static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, | ||
1580 | unsigned int sectors) | ||
1581 | { | ||
1582 | unsigned int i, resid; | ||
1583 | struct scatterlist *psgl; | ||
1584 | struct sd_dif_tuple *sdt; | ||
1585 | sector_t sector; | ||
1586 | sector_t tmp_sec = start_sec; | ||
1587 | void *paddr; | ||
1588 | |||
1589 | start_sec = do_div(tmp_sec, sdebug_store_sectors); | ||
1590 | |||
1591 | sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec)); | ||
1592 | |||
1593 | for (i = 0 ; i < sectors ; i++) { | ||
1594 | u16 csum; | ||
1595 | |||
1596 | if (sdt[i].app_tag == 0xffff) | ||
1597 | continue; | ||
1598 | |||
1599 | sector = start_sec + i; | ||
1600 | |||
1601 | switch (scsi_debug_guard) { | ||
1602 | case 1: | ||
1603 | csum = ip_compute_csum(fake_storep + | ||
1604 | sector * scsi_debug_sector_size, | ||
1605 | scsi_debug_sector_size); | ||
1606 | break; | ||
1607 | case 0: | ||
1608 | csum = crc_t10dif(fake_storep + | ||
1609 | sector * scsi_debug_sector_size, | ||
1610 | scsi_debug_sector_size); | ||
1611 | csum = cpu_to_be16(csum); | ||
1612 | break; | ||
1613 | default: | ||
1614 | BUG(); | ||
1615 | } | ||
1616 | |||
1617 | if (sdt[i].guard_tag != csum) { | ||
1618 | printk(KERN_ERR "%s: GUARD check failed on sector %lu" \ | ||
1619 | " rcvd 0x%04x, data 0x%04x\n", __func__, | ||
1620 | (unsigned long)sector, | ||
1621 | be16_to_cpu(sdt[i].guard_tag), | ||
1622 | be16_to_cpu(csum)); | ||
1623 | dif_errors++; | ||
1624 | return 0x01; | ||
1625 | } | ||
1626 | |||
1627 | if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && | ||
1628 | be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { | ||
1629 | printk(KERN_ERR "%s: REF check failed on sector %lu\n", | ||
1630 | __func__, (unsigned long)sector); | ||
1631 | dif_errors++; | ||
1632 | return 0x03; | ||
1633 | } | ||
1634 | } | ||
1635 | |||
1636 | resid = sectors * 8; /* Bytes of protection data to copy into sgl */ | ||
1637 | sector = start_sec; | ||
1638 | |||
1639 | scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { | ||
1640 | int len = min(psgl->length, resid); | ||
1641 | |||
1642 | paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset; | ||
1643 | memcpy(paddr, dif_storep + dif_offset(sector), len); | ||
1644 | |||
1645 | sector += len >> 3; | ||
1646 | if (sector >= sdebug_store_sectors) { | ||
1647 | /* Force wrap */ | ||
1648 | tmp_sec = sector; | ||
1649 | sector = do_div(tmp_sec, sdebug_store_sectors); | ||
1650 | } | ||
1651 | resid -= len; | ||
1652 | kunmap_atomic(paddr, KM_IRQ0); | ||
1653 | } | ||
1654 | |||
1655 | dix_reads++; | ||
1656 | |||
1657 | return 0; | ||
1658 | } | ||
1659 | |||
1539 | static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, | 1660 | static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, |
1540 | unsigned int num, struct sdebug_dev_info *devip) | 1661 | unsigned int num, struct sdebug_dev_info *devip) |
1541 | { | 1662 | { |
@@ -1563,12 +1684,162 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, | |||
1563 | } | 1684 | } |
1564 | return check_condition_result; | 1685 | return check_condition_result; |
1565 | } | 1686 | } |
1687 | |||
1688 | /* DIX + T10 DIF */ | ||
1689 | if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { | ||
1690 | int prot_ret = prot_verify_read(SCpnt, lba, num); | ||
1691 | |||
1692 | if (prot_ret) { | ||
1693 | mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); | ||
1694 | return illegal_condition_result; | ||
1695 | } | ||
1696 | } | ||
1697 | |||
1566 | read_lock_irqsave(&atomic_rw, iflags); | 1698 | read_lock_irqsave(&atomic_rw, iflags); |
1567 | ret = do_device_access(SCpnt, devip, lba, num, 0); | 1699 | ret = do_device_access(SCpnt, devip, lba, num, 0); |
1568 | read_unlock_irqrestore(&atomic_rw, iflags); | 1700 | read_unlock_irqrestore(&atomic_rw, iflags); |
1569 | return ret; | 1701 | return ret; |
1570 | } | 1702 | } |
1571 | 1703 | ||
1704 | void dump_sector(unsigned char *buf, int len) | ||
1705 | { | ||
1706 | int i, j; | ||
1707 | |||
1708 | printk(KERN_ERR ">>> Sector Dump <<<\n"); | ||
1709 | |||
1710 | for (i = 0 ; i < len ; i += 16) { | ||
1711 | printk(KERN_ERR "%04d: ", i); | ||
1712 | |||
1713 | for (j = 0 ; j < 16 ; j++) { | ||
1714 | unsigned char c = buf[i+j]; | ||
1715 | if (c >= 0x20 && c < 0x7e) | ||
1716 | printk(" %c ", buf[i+j]); | ||
1717 | else | ||
1718 | printk("%02x ", buf[i+j]); | ||
1719 | } | ||
1720 | |||
1721 | printk("\n"); | ||
1722 | } | ||
1723 | } | ||
1724 | |||
1725 | static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | ||
1726 | unsigned int sectors) | ||
1727 | { | ||
1728 | int i, j, ret; | ||
1729 | struct sd_dif_tuple *sdt; | ||
1730 | struct scatterlist *dsgl = scsi_sglist(SCpnt); | ||
1731 | struct scatterlist *psgl = scsi_prot_sglist(SCpnt); | ||
1732 | void *daddr, *paddr; | ||
1733 | sector_t tmp_sec = start_sec; | ||
1734 | sector_t sector; | ||
1735 | int ppage_offset; | ||
1736 | unsigned short csum; | ||
1737 | |||
1738 | sector = do_div(tmp_sec, sdebug_store_sectors); | ||
1739 | |||
1740 | if (((SCpnt->cmnd[1] >> 5) & 7) != 1) { | ||
1741 | printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n"); | ||
1742 | return 0; | ||
1743 | } | ||
1744 | |||
1745 | BUG_ON(scsi_sg_count(SCpnt) == 0); | ||
1746 | BUG_ON(scsi_prot_sg_count(SCpnt) == 0); | ||
1747 | |||
1748 | paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset; | ||
1749 | ppage_offset = 0; | ||
1750 | |||
1751 | /* For each data page */ | ||
1752 | scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { | ||
1753 | daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset; | ||
1754 | |||
1755 | /* For each sector-sized chunk in data page */ | ||
1756 | for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) { | ||
1757 | |||
1758 | /* If we're at the end of the current | ||
1759 | * protection page advance to the next one | ||
1760 | */ | ||
1761 | if (ppage_offset >= psgl->length) { | ||
1762 | kunmap_atomic(paddr, KM_IRQ1); | ||
1763 | psgl = sg_next(psgl); | ||
1764 | BUG_ON(psgl == NULL); | ||
1765 | paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) | ||
1766 | + psgl->offset; | ||
1767 | ppage_offset = 0; | ||
1768 | } | ||
1769 | |||
1770 | sdt = paddr + ppage_offset; | ||
1771 | |||
1772 | switch (scsi_debug_guard) { | ||
1773 | case 1: | ||
1774 | csum = ip_compute_csum(daddr, | ||
1775 | scsi_debug_sector_size); | ||
1776 | break; | ||
1777 | case 0: | ||
1778 | csum = cpu_to_be16(crc_t10dif(daddr, | ||
1779 | scsi_debug_sector_size)); | ||
1780 | break; | ||
1781 | default: | ||
1782 | BUG(); | ||
1783 | ret = 0; | ||
1784 | goto out; | ||
1785 | } | ||
1786 | |||
1787 | if (sdt->guard_tag != csum) { | ||
1788 | printk(KERN_ERR | ||
1789 | "%s: GUARD check failed on sector %lu " \ | ||
1790 | "rcvd 0x%04x, calculated 0x%04x\n", | ||
1791 | __func__, (unsigned long)sector, | ||
1792 | be16_to_cpu(sdt->guard_tag), | ||
1793 | be16_to_cpu(csum)); | ||
1794 | ret = 0x01; | ||
1795 | dump_sector(daddr, scsi_debug_sector_size); | ||
1796 | goto out; | ||
1797 | } | ||
1798 | |||
1799 | if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && | ||
1800 | be32_to_cpu(sdt->ref_tag) | ||
1801 | != (start_sec & 0xffffffff)) { | ||
1802 | printk(KERN_ERR | ||
1803 | "%s: REF check failed on sector %lu\n", | ||
1804 | __func__, (unsigned long)sector); | ||
1805 | ret = 0x03; | ||
1806 | dump_sector(daddr, scsi_debug_sector_size); | ||
1807 | goto out; | ||
1808 | } | ||
1809 | |||
1810 | /* Would be great to copy this in bigger | ||
1811 | * chunks. However, for the sake of | ||
1812 | * correctness we need to verify each sector | ||
1813 | * before writing it to "stable" storage | ||
1814 | */ | ||
1815 | memcpy(dif_storep + dif_offset(sector), sdt, 8); | ||
1816 | |||
1817 | sector++; | ||
1818 | |||
1819 | if (sector == sdebug_store_sectors) | ||
1820 | sector = 0; /* Force wrap */ | ||
1821 | |||
1822 | start_sec++; | ||
1823 | daddr += scsi_debug_sector_size; | ||
1824 | ppage_offset += sizeof(struct sd_dif_tuple); | ||
1825 | } | ||
1826 | |||
1827 | kunmap_atomic(daddr, KM_IRQ0); | ||
1828 | } | ||
1829 | |||
1830 | kunmap_atomic(paddr, KM_IRQ1); | ||
1831 | |||
1832 | dix_writes++; | ||
1833 | |||
1834 | return 0; | ||
1835 | |||
1836 | out: | ||
1837 | dif_errors++; | ||
1838 | kunmap_atomic(daddr, KM_IRQ0); | ||
1839 | kunmap_atomic(paddr, KM_IRQ1); | ||
1840 | return ret; | ||
1841 | } | ||
1842 | |||
1572 | static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, | 1843 | static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, |
1573 | unsigned int num, struct sdebug_dev_info *devip) | 1844 | unsigned int num, struct sdebug_dev_info *devip) |
1574 | { | 1845 | { |
@@ -1579,6 +1850,16 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, | |||
1579 | if (ret) | 1850 | if (ret) |
1580 | return ret; | 1851 | return ret; |
1581 | 1852 | ||
1853 | /* DIX + T10 DIF */ | ||
1854 | if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { | ||
1855 | int prot_ret = prot_verify_write(SCpnt, lba, num); | ||
1856 | |||
1857 | if (prot_ret) { | ||
1858 | mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); | ||
1859 | return illegal_condition_result; | ||
1860 | } | ||
1861 | } | ||
1862 | |||
1582 | write_lock_irqsave(&atomic_rw, iflags); | 1863 | write_lock_irqsave(&atomic_rw, iflags); |
1583 | ret = do_device_access(SCpnt, devip, lba, num, 1); | 1864 | ret = do_device_access(SCpnt, devip, lba, num, 1); |
1584 | write_unlock_irqrestore(&atomic_rw, iflags); | 1865 | write_unlock_irqrestore(&atomic_rw, iflags); |
@@ -2095,6 +2376,10 @@ module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); | |||
2095 | module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, | 2376 | module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, |
2096 | S_IRUGO | S_IWUSR); | 2377 | S_IRUGO | S_IWUSR); |
2097 | module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); | 2378 | module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); |
2379 | module_param_named(dix, scsi_debug_dix, int, S_IRUGO); | ||
2380 | module_param_named(dif, scsi_debug_dif, int, S_IRUGO); | ||
2381 | module_param_named(guard, scsi_debug_guard, int, S_IRUGO); | ||
2382 | module_param_named(ato, scsi_debug_ato, int, S_IRUGO); | ||
2098 | 2383 | ||
2099 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); | 2384 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); |
2100 | MODULE_DESCRIPTION("SCSI debug adapter driver"); | 2385 | MODULE_DESCRIPTION("SCSI debug adapter driver"); |
@@ -2117,7 +2402,10 @@ MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); | |||
2117 | MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); | 2402 | MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); |
2118 | MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); | 2403 | MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); |
2119 | MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)"); | 2404 | MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)"); |
2120 | 2405 | MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); | |
2406 | MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); | ||
2407 | MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); | ||
2408 | MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); | ||
2121 | 2409 | ||
2122 | static char sdebug_info[256]; | 2410 | static char sdebug_info[256]; |
2123 | 2411 | ||
@@ -2164,14 +2452,14 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta | |||
2164 | "delay=%d, max_luns=%d, scsi_level=%d\n" | 2452 | "delay=%d, max_luns=%d, scsi_level=%d\n" |
2165 | "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" | 2453 | "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" |
2166 | "number of aborts=%d, device_reset=%d, bus_resets=%d, " | 2454 | "number of aborts=%d, device_reset=%d, bus_resets=%d, " |
2167 | "host_resets=%d\n", | 2455 | "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n", |
2168 | SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, | 2456 | SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, |
2169 | scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, | 2457 | scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, |
2170 | scsi_debug_cmnd_count, scsi_debug_delay, | 2458 | scsi_debug_cmnd_count, scsi_debug_delay, |
2171 | scsi_debug_max_luns, scsi_debug_scsi_level, | 2459 | scsi_debug_max_luns, scsi_debug_scsi_level, |
2172 | scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, | 2460 | scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, |
2173 | sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, | 2461 | sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, |
2174 | num_host_resets); | 2462 | num_host_resets, dix_reads, dix_writes, dif_errors); |
2175 | if (pos < offset) { | 2463 | if (pos < offset) { |
2176 | len = 0; | 2464 | len = 0; |
2177 | begin = pos; | 2465 | begin = pos; |
@@ -2452,6 +2740,31 @@ static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) | |||
2452 | } | 2740 | } |
2453 | DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); | 2741 | DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); |
2454 | 2742 | ||
2743 | static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf) | ||
2744 | { | ||
2745 | return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix); | ||
2746 | } | ||
2747 | DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL); | ||
2748 | |||
2749 | static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf) | ||
2750 | { | ||
2751 | return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif); | ||
2752 | } | ||
2753 | DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL); | ||
2754 | |||
2755 | static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf) | ||
2756 | { | ||
2757 | return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard); | ||
2758 | } | ||
2759 | DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL); | ||
2760 | |||
2761 | static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf) | ||
2762 | { | ||
2763 | return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato); | ||
2764 | } | ||
2765 | DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL); | ||
2766 | |||
2767 | |||
2455 | /* Note: The following function creates attribute files in the | 2768 | /* Note: The following function creates attribute files in the |
2456 | /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these | 2769 | /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these |
2457 | files (over those found in the /sys/module/scsi_debug/parameters | 2770 | files (over those found in the /sys/module/scsi_debug/parameters |
@@ -2478,11 +2791,19 @@ static int do_create_driverfs_files(void) | |||
2478 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); | 2791 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); |
2479 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); | 2792 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); |
2480 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); | 2793 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); |
2794 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix); | ||
2795 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif); | ||
2796 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard); | ||
2797 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato); | ||
2481 | return ret; | 2798 | return ret; |
2482 | } | 2799 | } |
2483 | 2800 | ||
2484 | static void do_remove_driverfs_files(void) | 2801 | static void do_remove_driverfs_files(void) |
2485 | { | 2802 | { |
2803 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato); | ||
2804 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard); | ||
2805 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif); | ||
2806 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix); | ||
2486 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); | 2807 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); |
2487 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); | 2808 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); |
2488 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); | 2809 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); |
@@ -2526,11 +2847,33 @@ static int __init scsi_debug_init(void) | |||
2526 | case 4096: | 2847 | case 4096: |
2527 | break; | 2848 | break; |
2528 | default: | 2849 | default: |
2529 | printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n", | 2850 | printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n", |
2530 | scsi_debug_sector_size); | 2851 | scsi_debug_sector_size); |
2531 | return -EINVAL; | 2852 | return -EINVAL; |
2532 | } | 2853 | } |
2533 | 2854 | ||
2855 | switch (scsi_debug_dif) { | ||
2856 | |||
2857 | case SD_DIF_TYPE0_PROTECTION: | ||
2858 | case SD_DIF_TYPE1_PROTECTION: | ||
2859 | case SD_DIF_TYPE3_PROTECTION: | ||
2860 | break; | ||
2861 | |||
2862 | default: | ||
2863 | printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n"); | ||
2864 | return -EINVAL; | ||
2865 | } | ||
2866 | |||
2867 | if (scsi_debug_guard > 1) { | ||
2868 | printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n"); | ||
2869 | return -EINVAL; | ||
2870 | } | ||
2871 | |||
2872 | if (scsi_debug_ato > 1) { | ||
2873 | printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n"); | ||
2874 | return -EINVAL; | ||
2875 | } | ||
2876 | |||
2534 | if (scsi_debug_dev_size_mb < 1) | 2877 | if (scsi_debug_dev_size_mb < 1) |
2535 | scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ | 2878 | scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ |
2536 | sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; | 2879 | sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; |
@@ -2563,6 +2906,24 @@ static int __init scsi_debug_init(void) | |||
2563 | if (scsi_debug_num_parts > 0) | 2906 | if (scsi_debug_num_parts > 0) |
2564 | sdebug_build_parts(fake_storep, sz); | 2907 | sdebug_build_parts(fake_storep, sz); |
2565 | 2908 | ||
2909 | if (scsi_debug_dif) { | ||
2910 | int dif_size; | ||
2911 | |||
2912 | dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); | ||
2913 | dif_storep = vmalloc(dif_size); | ||
2914 | |||
2915 | printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n", | ||
2916 | dif_size, dif_storep); | ||
2917 | |||
2918 | if (dif_storep == NULL) { | ||
2919 | printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n"); | ||
2920 | ret = -ENOMEM; | ||
2921 | goto free_vm; | ||
2922 | } | ||
2923 | |||
2924 | memset(dif_storep, 0xff, dif_size); | ||
2925 | } | ||
2926 | |||
2566 | ret = device_register(&pseudo_primary); | 2927 | ret = device_register(&pseudo_primary); |
2567 | if (ret < 0) { | 2928 | if (ret < 0) { |
2568 | printk(KERN_WARNING "scsi_debug: device_register error: %d\n", | 2929 | printk(KERN_WARNING "scsi_debug: device_register error: %d\n", |
@@ -2615,6 +2976,8 @@ bus_unreg: | |||
2615 | dev_unreg: | 2976 | dev_unreg: |
2616 | device_unregister(&pseudo_primary); | 2977 | device_unregister(&pseudo_primary); |
2617 | free_vm: | 2978 | free_vm: |
2979 | if (dif_storep) | ||
2980 | vfree(dif_storep); | ||
2618 | vfree(fake_storep); | 2981 | vfree(fake_storep); |
2619 | 2982 | ||
2620 | return ret; | 2983 | return ret; |
@@ -2632,6 +2995,9 @@ static void __exit scsi_debug_exit(void) | |||
2632 | bus_unregister(&pseudo_lld_bus); | 2995 | bus_unregister(&pseudo_lld_bus); |
2633 | device_unregister(&pseudo_primary); | 2996 | device_unregister(&pseudo_primary); |
2634 | 2997 | ||
2998 | if (dif_storep) | ||
2999 | vfree(dif_storep); | ||
3000 | |||
2635 | vfree(fake_storep); | 3001 | vfree(fake_storep); |
2636 | } | 3002 | } |
2637 | 3003 | ||
@@ -2732,6 +3098,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
2732 | struct sdebug_dev_info *devip = NULL; | 3098 | struct sdebug_dev_info *devip = NULL; |
2733 | int inj_recovered = 0; | 3099 | int inj_recovered = 0; |
2734 | int inj_transport = 0; | 3100 | int inj_transport = 0; |
3101 | int inj_dif = 0; | ||
3102 | int inj_dix = 0; | ||
2735 | int delay_override = 0; | 3103 | int delay_override = 0; |
2736 | 3104 | ||
2737 | scsi_set_resid(SCpnt, 0); | 3105 | scsi_set_resid(SCpnt, 0); |
@@ -2769,6 +3137,10 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
2769 | inj_recovered = 1; /* to reads and writes below */ | 3137 | inj_recovered = 1; /* to reads and writes below */ |
2770 | else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) | 3138 | else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) |
2771 | inj_transport = 1; /* to reads and writes below */ | 3139 | inj_transport = 1; /* to reads and writes below */ |
3140 | else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts) | ||
3141 | inj_dif = 1; /* to reads and writes below */ | ||
3142 | else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts) | ||
3143 | inj_dix = 1; /* to reads and writes below */ | ||
2772 | } | 3144 | } |
2773 | 3145 | ||
2774 | if (devip->wlun) { | 3146 | if (devip->wlun) { |
@@ -2870,6 +3242,12 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
2870 | mk_sense_buffer(devip, ABORTED_COMMAND, | 3242 | mk_sense_buffer(devip, ABORTED_COMMAND, |
2871 | TRANSPORT_PROBLEM, ACK_NAK_TO); | 3243 | TRANSPORT_PROBLEM, ACK_NAK_TO); |
2872 | errsts = check_condition_result; | 3244 | errsts = check_condition_result; |
3245 | } else if (inj_dif && (0 == errsts)) { | ||
3246 | mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); | ||
3247 | errsts = illegal_condition_result; | ||
3248 | } else if (inj_dix && (0 == errsts)) { | ||
3249 | mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); | ||
3250 | errsts = illegal_condition_result; | ||
2873 | } | 3251 | } |
2874 | break; | 3252 | break; |
2875 | case REPORT_LUNS: /* mandatory, ignore unit attention */ | 3253 | case REPORT_LUNS: /* mandatory, ignore unit attention */ |
@@ -2894,6 +3272,12 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
2894 | mk_sense_buffer(devip, RECOVERED_ERROR, | 3272 | mk_sense_buffer(devip, RECOVERED_ERROR, |
2895 | THRESHOLD_EXCEEDED, 0); | 3273 | THRESHOLD_EXCEEDED, 0); |
2896 | errsts = check_condition_result; | 3274 | errsts = check_condition_result; |
3275 | } else if (inj_dif && (0 == errsts)) { | ||
3276 | mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); | ||
3277 | errsts = illegal_condition_result; | ||
3278 | } else if (inj_dix && (0 == errsts)) { | ||
3279 | mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); | ||
3280 | errsts = illegal_condition_result; | ||
2897 | } | 3281 | } |
2898 | break; | 3282 | break; |
2899 | case MODE_SENSE: | 3283 | case MODE_SENSE: |
@@ -2982,6 +3366,7 @@ static int sdebug_driver_probe(struct device * dev) | |||
2982 | int error = 0; | 3366 | int error = 0; |
2983 | struct sdebug_host_info *sdbg_host; | 3367 | struct sdebug_host_info *sdbg_host; |
2984 | struct Scsi_Host *hpnt; | 3368 | struct Scsi_Host *hpnt; |
3369 | int host_prot; | ||
2985 | 3370 | ||
2986 | sdbg_host = to_sdebug_host(dev); | 3371 | sdbg_host = to_sdebug_host(dev); |
2987 | 3372 | ||
@@ -3000,6 +3385,50 @@ static int sdebug_driver_probe(struct device * dev) | |||
3000 | hpnt->max_id = scsi_debug_num_tgts; | 3385 | hpnt->max_id = scsi_debug_num_tgts; |
3001 | hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ | 3386 | hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ |
3002 | 3387 | ||
3388 | host_prot = 0; | ||
3389 | |||
3390 | switch (scsi_debug_dif) { | ||
3391 | |||
3392 | case SD_DIF_TYPE1_PROTECTION: | ||
3393 | host_prot = SHOST_DIF_TYPE1_PROTECTION; | ||
3394 | if (scsi_debug_dix) | ||
3395 | host_prot |= SHOST_DIX_TYPE1_PROTECTION; | ||
3396 | break; | ||
3397 | |||
3398 | case SD_DIF_TYPE2_PROTECTION: | ||
3399 | host_prot = SHOST_DIF_TYPE2_PROTECTION; | ||
3400 | if (scsi_debug_dix) | ||
3401 | host_prot |= SHOST_DIX_TYPE2_PROTECTION; | ||
3402 | break; | ||
3403 | |||
3404 | case SD_DIF_TYPE3_PROTECTION: | ||
3405 | host_prot = SHOST_DIF_TYPE3_PROTECTION; | ||
3406 | if (scsi_debug_dix) | ||
3407 | host_prot |= SHOST_DIX_TYPE3_PROTECTION; | ||
3408 | break; | ||
3409 | |||
3410 | default: | ||
3411 | if (scsi_debug_dix) | ||
3412 | host_prot |= SHOST_DIX_TYPE0_PROTECTION; | ||
3413 | break; | ||
3414 | } | ||
3415 | |||
3416 | scsi_host_set_prot(hpnt, host_prot); | ||
3417 | |||
3418 | printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n", | ||
3419 | (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", | ||
3420 | (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", | ||
3421 | (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", | ||
3422 | (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", | ||
3423 | (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", | ||
3424 | (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", | ||
3425 | (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); | ||
3426 | |||
3427 | if (scsi_debug_guard == 1) | ||
3428 | scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); | ||
3429 | else | ||
3430 | scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); | ||
3431 | |||
3003 | error = scsi_add_host(hpnt, &sdbg_host->dev); | 3432 | error = scsi_add_host(hpnt, &sdbg_host->dev); |
3004 | if (error) { | 3433 | if (error) { |
3005 | printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); | 3434 | printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); |