diff options
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 174 |
1 files changed, 70 insertions, 104 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index d055450c2a4a..cb4fefa1bfba 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -258,7 +258,7 @@ struct sdebug_queued_cmd { | |||
258 | static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; | 258 | static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; |
259 | 259 | ||
260 | static unsigned char * fake_storep; /* ramdisk storage */ | 260 | static unsigned char * fake_storep; /* ramdisk storage */ |
261 | static unsigned char *dif_storep; /* protection info */ | 261 | static struct sd_dif_tuple *dif_storep; /* protection info */ |
262 | static void *map_storep; /* provisioning map */ | 262 | static void *map_storep; /* provisioning map */ |
263 | 263 | ||
264 | static unsigned long map_size; | 264 | static unsigned long map_size; |
@@ -277,11 +277,6 @@ static char sdebug_proc_name[] = "scsi_debug"; | |||
277 | 277 | ||
278 | static struct bus_type pseudo_lld_bus; | 278 | static struct bus_type pseudo_lld_bus; |
279 | 279 | ||
280 | static inline sector_t dif_offset(sector_t sector) | ||
281 | { | ||
282 | return sector << 3; | ||
283 | } | ||
284 | |||
285 | static struct device_driver sdebug_driverfs_driver = { | 280 | static struct device_driver sdebug_driverfs_driver = { |
286 | .name = sdebug_proc_name, | 281 | .name = sdebug_proc_name, |
287 | .bus = &pseudo_lld_bus, | 282 | .bus = &pseudo_lld_bus, |
@@ -1736,6 +1731,50 @@ static int do_device_access(struct scsi_cmnd *scmd, | |||
1736 | return ret; | 1731 | return ret; |
1737 | } | 1732 | } |
1738 | 1733 | ||
1734 | static u16 dif_compute_csum(const void *buf, int len) | ||
1735 | { | ||
1736 | u16 csum; | ||
1737 | |||
1738 | switch (scsi_debug_guard) { | ||
1739 | case 1: | ||
1740 | csum = ip_compute_csum(buf, len); | ||
1741 | break; | ||
1742 | case 0: | ||
1743 | csum = cpu_to_be16(crc_t10dif(buf, len)); | ||
1744 | break; | ||
1745 | } | ||
1746 | return csum; | ||
1747 | } | ||
1748 | |||
1749 | static int dif_verify(struct sd_dif_tuple *sdt, const void *data, | ||
1750 | sector_t sector, u32 ei_lba) | ||
1751 | { | ||
1752 | u16 csum = dif_compute_csum(data, scsi_debug_sector_size); | ||
1753 | |||
1754 | if (sdt->guard_tag != csum) { | ||
1755 | pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", | ||
1756 | __func__, | ||
1757 | (unsigned long)sector, | ||
1758 | be16_to_cpu(sdt->guard_tag), | ||
1759 | be16_to_cpu(csum)); | ||
1760 | return 0x01; | ||
1761 | } | ||
1762 | if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && | ||
1763 | be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { | ||
1764 | pr_err("%s: REF check failed on sector %lu\n", | ||
1765 | __func__, (unsigned long)sector); | ||
1766 | return 0x03; | ||
1767 | } | ||
1768 | if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && | ||
1769 | be32_to_cpu(sdt->ref_tag) != ei_lba) { | ||
1770 | pr_err("%s: REF check failed on sector %lu\n", | ||
1771 | __func__, (unsigned long)sector); | ||
1772 | dif_errors++; | ||
1773 | return 0x03; | ||
1774 | } | ||
1775 | return 0; | ||
1776 | } | ||
1777 | |||
1739 | static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, | 1778 | static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, |
1740 | unsigned int sectors, u32 ei_lba) | 1779 | unsigned int sectors, u32 ei_lba) |
1741 | { | 1780 | { |
@@ -1748,71 +1787,38 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1748 | 1787 | ||
1749 | start_sec = do_div(tmp_sec, sdebug_store_sectors); | 1788 | start_sec = do_div(tmp_sec, sdebug_store_sectors); |
1750 | 1789 | ||
1751 | sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec)); | 1790 | sdt = dif_storep + start_sec; |
1752 | 1791 | ||
1753 | for (i = 0 ; i < sectors ; i++) { | 1792 | for (i = 0 ; i < sectors ; i++) { |
1754 | u16 csum; | 1793 | int ret; |
1755 | 1794 | ||
1756 | if (sdt[i].app_tag == 0xffff) | 1795 | if (sdt[i].app_tag == 0xffff) |
1757 | continue; | 1796 | continue; |
1758 | 1797 | ||
1759 | sector = start_sec + i; | 1798 | sector = start_sec + i; |
1760 | 1799 | ||
1761 | switch (scsi_debug_guard) { | 1800 | ret = dif_verify(&sdt[i], |
1762 | case 1: | 1801 | fake_storep + sector * scsi_debug_sector_size, |
1763 | csum = ip_compute_csum(fake_storep + | 1802 | sector, ei_lba); |
1764 | sector * scsi_debug_sector_size, | 1803 | if (ret) { |
1765 | scsi_debug_sector_size); | ||
1766 | break; | ||
1767 | case 0: | ||
1768 | csum = crc_t10dif(fake_storep + | ||
1769 | sector * scsi_debug_sector_size, | ||
1770 | scsi_debug_sector_size); | ||
1771 | csum = cpu_to_be16(csum); | ||
1772 | break; | ||
1773 | default: | ||
1774 | BUG(); | ||
1775 | } | ||
1776 | |||
1777 | if (sdt[i].guard_tag != csum) { | ||
1778 | printk(KERN_ERR "%s: GUARD check failed on sector %lu" \ | ||
1779 | " rcvd 0x%04x, data 0x%04x\n", __func__, | ||
1780 | (unsigned long)sector, | ||
1781 | be16_to_cpu(sdt[i].guard_tag), | ||
1782 | be16_to_cpu(csum)); | ||
1783 | dif_errors++; | ||
1784 | return 0x01; | ||
1785 | } | ||
1786 | |||
1787 | if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && | ||
1788 | be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { | ||
1789 | printk(KERN_ERR "%s: REF check failed on sector %lu\n", | ||
1790 | __func__, (unsigned long)sector); | ||
1791 | dif_errors++; | 1804 | dif_errors++; |
1792 | return 0x03; | 1805 | return ret; |
1793 | } | ||
1794 | |||
1795 | if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && | ||
1796 | be32_to_cpu(sdt[i].ref_tag) != ei_lba) { | ||
1797 | printk(KERN_ERR "%s: REF check failed on sector %lu\n", | ||
1798 | __func__, (unsigned long)sector); | ||
1799 | dif_errors++; | ||
1800 | return 0x03; | ||
1801 | } | 1806 | } |
1802 | 1807 | ||
1803 | ei_lba++; | 1808 | ei_lba++; |
1804 | } | 1809 | } |
1805 | 1810 | ||
1806 | resid = sectors * 8; /* Bytes of protection data to copy into sgl */ | 1811 | /* Bytes of protection data to copy into sgl */ |
1812 | resid = sectors * sizeof(*dif_storep); | ||
1807 | sector = start_sec; | 1813 | sector = start_sec; |
1808 | 1814 | ||
1809 | scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { | 1815 | scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { |
1810 | int len = min(psgl->length, resid); | 1816 | int len = min(psgl->length, resid); |
1811 | 1817 | ||
1812 | paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; | 1818 | paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; |
1813 | memcpy(paddr, dif_storep + dif_offset(sector), len); | 1819 | memcpy(paddr, dif_storep + sector, len); |
1814 | 1820 | ||
1815 | sector += len >> 3; | 1821 | sector += len / sizeof(*dif_storep); |
1816 | if (sector >= sdebug_store_sectors) { | 1822 | if (sector >= sdebug_store_sectors) { |
1817 | /* Force wrap */ | 1823 | /* Force wrap */ |
1818 | tmp_sec = sector; | 1824 | tmp_sec = sector; |
@@ -1910,22 +1916,21 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1910 | sector_t tmp_sec = start_sec; | 1916 | sector_t tmp_sec = start_sec; |
1911 | sector_t sector; | 1917 | sector_t sector; |
1912 | int ppage_offset; | 1918 | int ppage_offset; |
1913 | unsigned short csum; | ||
1914 | 1919 | ||
1915 | sector = do_div(tmp_sec, sdebug_store_sectors); | 1920 | sector = do_div(tmp_sec, sdebug_store_sectors); |
1916 | 1921 | ||
1917 | BUG_ON(scsi_sg_count(SCpnt) == 0); | 1922 | BUG_ON(scsi_sg_count(SCpnt) == 0); |
1918 | BUG_ON(scsi_prot_sg_count(SCpnt) == 0); | 1923 | BUG_ON(scsi_prot_sg_count(SCpnt) == 0); |
1919 | 1924 | ||
1920 | paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; | ||
1921 | ppage_offset = 0; | 1925 | ppage_offset = 0; |
1922 | 1926 | ||
1923 | /* For each data page */ | 1927 | /* For each data page */ |
1924 | scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { | 1928 | scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { |
1925 | daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset; | 1929 | daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset; |
1930 | paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; | ||
1926 | 1931 | ||
1927 | /* For each sector-sized chunk in data page */ | 1932 | /* For each sector-sized chunk in data page */ |
1928 | for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) { | 1933 | for (j = 0; j < dsgl->length; j += scsi_debug_sector_size) { |
1929 | 1934 | ||
1930 | /* If we're at the end of the current | 1935 | /* If we're at the end of the current |
1931 | * protection page advance to the next one | 1936 | * protection page advance to the next one |
@@ -1941,51 +1946,9 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1941 | 1946 | ||
1942 | sdt = paddr + ppage_offset; | 1947 | sdt = paddr + ppage_offset; |
1943 | 1948 | ||
1944 | switch (scsi_debug_guard) { | 1949 | ret = dif_verify(sdt, daddr + j, start_sec, ei_lba); |
1945 | case 1: | 1950 | if (ret) { |
1946 | csum = ip_compute_csum(daddr, | 1951 | dump_sector(daddr + j, scsi_debug_sector_size); |
1947 | scsi_debug_sector_size); | ||
1948 | break; | ||
1949 | case 0: | ||
1950 | csum = cpu_to_be16(crc_t10dif(daddr, | ||
1951 | scsi_debug_sector_size)); | ||
1952 | break; | ||
1953 | default: | ||
1954 | BUG(); | ||
1955 | ret = 0; | ||
1956 | goto out; | ||
1957 | } | ||
1958 | |||
1959 | if (sdt->guard_tag != csum) { | ||
1960 | printk(KERN_ERR | ||
1961 | "%s: GUARD check failed on sector %lu " \ | ||
1962 | "rcvd 0x%04x, calculated 0x%04x\n", | ||
1963 | __func__, (unsigned long)sector, | ||
1964 | be16_to_cpu(sdt->guard_tag), | ||
1965 | be16_to_cpu(csum)); | ||
1966 | ret = 0x01; | ||
1967 | dump_sector(daddr, scsi_debug_sector_size); | ||
1968 | goto out; | ||
1969 | } | ||
1970 | |||
1971 | if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && | ||
1972 | be32_to_cpu(sdt->ref_tag) | ||
1973 | != (start_sec & 0xffffffff)) { | ||
1974 | printk(KERN_ERR | ||
1975 | "%s: REF check failed on sector %lu\n", | ||
1976 | __func__, (unsigned long)sector); | ||
1977 | ret = 0x03; | ||
1978 | dump_sector(daddr, scsi_debug_sector_size); | ||
1979 | goto out; | ||
1980 | } | ||
1981 | |||
1982 | if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && | ||
1983 | be32_to_cpu(sdt->ref_tag) != ei_lba) { | ||
1984 | printk(KERN_ERR | ||
1985 | "%s: REF check failed on sector %lu\n", | ||
1986 | __func__, (unsigned long)sector); | ||
1987 | ret = 0x03; | ||
1988 | dump_sector(daddr, scsi_debug_sector_size); | ||
1989 | goto out; | 1952 | goto out; |
1990 | } | 1953 | } |
1991 | 1954 | ||
@@ -1994,7 +1957,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1994 | * correctness we need to verify each sector | 1957 | * correctness we need to verify each sector |
1995 | * before writing it to "stable" storage | 1958 | * before writing it to "stable" storage |
1996 | */ | 1959 | */ |
1997 | memcpy(dif_storep + dif_offset(sector), sdt, 8); | 1960 | memcpy(dif_storep + sector, sdt, sizeof(*sdt)); |
1998 | 1961 | ||
1999 | sector++; | 1962 | sector++; |
2000 | 1963 | ||
@@ -2003,23 +1966,21 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
2003 | 1966 | ||
2004 | start_sec++; | 1967 | start_sec++; |
2005 | ei_lba++; | 1968 | ei_lba++; |
2006 | daddr += scsi_debug_sector_size; | ||
2007 | ppage_offset += sizeof(struct sd_dif_tuple); | 1969 | ppage_offset += sizeof(struct sd_dif_tuple); |
2008 | } | 1970 | } |
2009 | 1971 | ||
1972 | kunmap_atomic(paddr); | ||
2010 | kunmap_atomic(daddr); | 1973 | kunmap_atomic(daddr); |
2011 | } | 1974 | } |
2012 | 1975 | ||
2013 | kunmap_atomic(paddr); | ||
2014 | |||
2015 | dix_writes++; | 1976 | dix_writes++; |
2016 | 1977 | ||
2017 | return 0; | 1978 | return 0; |
2018 | 1979 | ||
2019 | out: | 1980 | out: |
2020 | dif_errors++; | 1981 | dif_errors++; |
2021 | kunmap_atomic(daddr); | ||
2022 | kunmap_atomic(paddr); | 1982 | kunmap_atomic(paddr); |
1983 | kunmap_atomic(daddr); | ||
2023 | return ret; | 1984 | return ret; |
2024 | } | 1985 | } |
2025 | 1986 | ||
@@ -2092,6 +2053,11 @@ static void unmap_region(sector_t lba, unsigned int len) | |||
2092 | scsi_debug_sector_size * | 2053 | scsi_debug_sector_size * |
2093 | scsi_debug_unmap_granularity); | 2054 | scsi_debug_unmap_granularity); |
2094 | } | 2055 | } |
2056 | if (dif_storep) { | ||
2057 | memset(dif_storep + lba, 0xff, | ||
2058 | sizeof(*dif_storep) * | ||
2059 | scsi_debug_unmap_granularity); | ||
2060 | } | ||
2095 | } | 2061 | } |
2096 | lba = map_index_to_lba(index + 1); | 2062 | lba = map_index_to_lba(index + 1); |
2097 | } | 2063 | } |
@@ -3400,7 +3366,7 @@ static int __init scsi_debug_init(void) | |||
3400 | if (scsi_debug_num_parts > 0) | 3366 | if (scsi_debug_num_parts > 0) |
3401 | sdebug_build_parts(fake_storep, sz); | 3367 | sdebug_build_parts(fake_storep, sz); |
3402 | 3368 | ||
3403 | if (scsi_debug_dif) { | 3369 | if (scsi_debug_dix) { |
3404 | int dif_size; | 3370 | int dif_size; |
3405 | 3371 | ||
3406 | dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); | 3372 | dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); |