diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2009-09-18 17:33:03 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-10-02 10:47:17 -0400 |
commit | 395cef030c99349d238563095adc63ea72641192 (patch) | |
tree | 39c13437e8da8ef77805bba1e2a2d3e710f2bc48 /drivers/scsi | |
parent | 4e7392ec582cf06753b0969ca9ab959923e38493 (diff) |
[SCSI] scsi_debug: Implement support for DIF Type 2
Add support for 32-byte READ/WRITE as well as DIF Type 2 protection.
Reject protected 10/12/16 byte READ/WRITE commands when Type 2 is
enabled.
Verify Type 2 reference tag according to Expected Initial LBA in 32-byte
CDB.
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Acked-by: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 139 |
1 files changed, 116 insertions, 23 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index fb9af207d61d..c4103bef41b5 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <scsi/scsi_host.h> | 50 | #include <scsi/scsi_host.h> |
51 | #include <scsi/scsicam.h> | 51 | #include <scsi/scsicam.h> |
52 | #include <scsi/scsi_eh.h> | 52 | #include <scsi/scsi_eh.h> |
53 | #include <scsi/scsi_dbg.h> | ||
53 | 54 | ||
54 | #include "sd.h" | 55 | #include "sd.h" |
55 | #include "scsi_logging.h" | 56 | #include "scsi_logging.h" |
@@ -64,6 +65,7 @@ static const char * scsi_debug_version_date = "20070104"; | |||
64 | #define PARAMETER_LIST_LENGTH_ERR 0x1a | 65 | #define PARAMETER_LIST_LENGTH_ERR 0x1a |
65 | #define INVALID_OPCODE 0x20 | 66 | #define INVALID_OPCODE 0x20 |
66 | #define ADDR_OUT_OF_RANGE 0x21 | 67 | #define ADDR_OUT_OF_RANGE 0x21 |
68 | #define INVALID_COMMAND_OPCODE 0x20 | ||
67 | #define INVALID_FIELD_IN_CDB 0x24 | 69 | #define INVALID_FIELD_IN_CDB 0x24 |
68 | #define INVALID_FIELD_IN_PARAM_LIST 0x26 | 70 | #define INVALID_FIELD_IN_PARAM_LIST 0x26 |
69 | #define POWERON_RESET 0x29 | 71 | #define POWERON_RESET 0x29 |
@@ -180,7 +182,7 @@ static int sdebug_sectors_per; /* sectors per cylinder */ | |||
180 | #define SDEBUG_SENSE_LEN 32 | 182 | #define SDEBUG_SENSE_LEN 32 |
181 | 183 | ||
182 | #define SCSI_DEBUG_CANQUEUE 255 | 184 | #define SCSI_DEBUG_CANQUEUE 255 |
183 | #define SCSI_DEBUG_MAX_CMD_LEN 16 | 185 | #define SCSI_DEBUG_MAX_CMD_LEN 32 |
184 | 186 | ||
185 | struct sdebug_dev_info { | 187 | struct sdebug_dev_info { |
186 | struct list_head dev_list; | 188 | struct list_head dev_list; |
@@ -296,9 +298,25 @@ static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, | |||
296 | } | 298 | } |
297 | 299 | ||
298 | static void get_data_transfer_info(unsigned char *cmd, | 300 | static void get_data_transfer_info(unsigned char *cmd, |
299 | unsigned long long *lba, unsigned int *num) | 301 | unsigned long long *lba, unsigned int *num, |
302 | u32 *ei_lba) | ||
300 | { | 303 | { |
304 | *ei_lba = 0; | ||
305 | |||
301 | switch (*cmd) { | 306 | switch (*cmd) { |
307 | case VARIABLE_LENGTH_CMD: | ||
308 | *lba = (u64)cmd[19] | (u64)cmd[18] << 8 | | ||
309 | (u64)cmd[17] << 16 | (u64)cmd[16] << 24 | | ||
310 | (u64)cmd[15] << 32 | (u64)cmd[14] << 40 | | ||
311 | (u64)cmd[13] << 48 | (u64)cmd[12] << 56; | ||
312 | |||
313 | *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 | | ||
314 | (u32)cmd[21] << 16 | (u32)cmd[20] << 24; | ||
315 | |||
316 | *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 | | ||
317 | (u32)cmd[28] << 24; | ||
318 | break; | ||
319 | |||
302 | case WRITE_16: | 320 | case WRITE_16: |
303 | case READ_16: | 321 | case READ_16: |
304 | *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | | 322 | *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | |
@@ -1589,7 +1607,7 @@ static int do_device_access(struct scsi_cmnd *scmd, | |||
1589 | } | 1607 | } |
1590 | 1608 | ||
1591 | static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, | 1609 | static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, |
1592 | unsigned int sectors) | 1610 | unsigned int sectors, u32 ei_lba) |
1593 | { | 1611 | { |
1594 | unsigned int i, resid; | 1612 | unsigned int i, resid; |
1595 | struct scatterlist *psgl; | 1613 | struct scatterlist *psgl; |
@@ -1636,13 +1654,23 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1636 | return 0x01; | 1654 | return 0x01; |
1637 | } | 1655 | } |
1638 | 1656 | ||
1639 | if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && | 1657 | if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && |
1640 | be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { | 1658 | be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { |
1641 | printk(KERN_ERR "%s: REF check failed on sector %lu\n", | 1659 | printk(KERN_ERR "%s: REF check failed on sector %lu\n", |
1642 | __func__, (unsigned long)sector); | 1660 | __func__, (unsigned long)sector); |
1643 | dif_errors++; | 1661 | dif_errors++; |
1644 | return 0x03; | 1662 | return 0x03; |
1645 | } | 1663 | } |
1664 | |||
1665 | if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && | ||
1666 | be32_to_cpu(sdt[i].ref_tag) != ei_lba) { | ||
1667 | printk(KERN_ERR "%s: REF check failed on sector %lu\n", | ||
1668 | __func__, (unsigned long)sector); | ||
1669 | dif_errors++; | ||
1670 | return 0x03; | ||
1671 | } | ||
1672 | |||
1673 | ei_lba++; | ||
1646 | } | 1674 | } |
1647 | 1675 | ||
1648 | resid = sectors * 8; /* Bytes of protection data to copy into sgl */ | 1676 | resid = sectors * 8; /* Bytes of protection data to copy into sgl */ |
@@ -1670,7 +1698,8 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1670 | } | 1698 | } |
1671 | 1699 | ||
1672 | static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, | 1700 | static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, |
1673 | unsigned int num, struct sdebug_dev_info *devip) | 1701 | unsigned int num, struct sdebug_dev_info *devip, |
1702 | u32 ei_lba) | ||
1674 | { | 1703 | { |
1675 | unsigned long iflags; | 1704 | unsigned long iflags; |
1676 | int ret; | 1705 | int ret; |
@@ -1699,7 +1728,7 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, | |||
1699 | 1728 | ||
1700 | /* DIX + T10 DIF */ | 1729 | /* DIX + T10 DIF */ |
1701 | if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { | 1730 | if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { |
1702 | int prot_ret = prot_verify_read(SCpnt, lba, num); | 1731 | int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba); |
1703 | 1732 | ||
1704 | if (prot_ret) { | 1733 | if (prot_ret) { |
1705 | mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); | 1734 | mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); |
@@ -1735,7 +1764,7 @@ void dump_sector(unsigned char *buf, int len) | |||
1735 | } | 1764 | } |
1736 | 1765 | ||
1737 | static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | 1766 | static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, |
1738 | unsigned int sectors) | 1767 | unsigned int sectors, u32 ei_lba) |
1739 | { | 1768 | { |
1740 | int i, j, ret; | 1769 | int i, j, ret; |
1741 | struct sd_dif_tuple *sdt; | 1770 | struct sd_dif_tuple *sdt; |
@@ -1749,11 +1778,6 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1749 | 1778 | ||
1750 | sector = do_div(tmp_sec, sdebug_store_sectors); | 1779 | sector = do_div(tmp_sec, sdebug_store_sectors); |
1751 | 1780 | ||
1752 | if (((SCpnt->cmnd[1] >> 5) & 7) != 1) { | ||
1753 | printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n"); | ||
1754 | return 0; | ||
1755 | } | ||
1756 | |||
1757 | BUG_ON(scsi_sg_count(SCpnt) == 0); | 1781 | BUG_ON(scsi_sg_count(SCpnt) == 0); |
1758 | BUG_ON(scsi_prot_sg_count(SCpnt) == 0); | 1782 | BUG_ON(scsi_prot_sg_count(SCpnt) == 0); |
1759 | 1783 | ||
@@ -1808,7 +1832,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1808 | goto out; | 1832 | goto out; |
1809 | } | 1833 | } |
1810 | 1834 | ||
1811 | if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && | 1835 | if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && |
1812 | be32_to_cpu(sdt->ref_tag) | 1836 | be32_to_cpu(sdt->ref_tag) |
1813 | != (start_sec & 0xffffffff)) { | 1837 | != (start_sec & 0xffffffff)) { |
1814 | printk(KERN_ERR | 1838 | printk(KERN_ERR |
@@ -1819,6 +1843,16 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1819 | goto out; | 1843 | goto out; |
1820 | } | 1844 | } |
1821 | 1845 | ||
1846 | if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && | ||
1847 | be32_to_cpu(sdt->ref_tag) != ei_lba) { | ||
1848 | printk(KERN_ERR | ||
1849 | "%s: REF check failed on sector %lu\n", | ||
1850 | __func__, (unsigned long)sector); | ||
1851 | ret = 0x03; | ||
1852 | dump_sector(daddr, scsi_debug_sector_size); | ||
1853 | goto out; | ||
1854 | } | ||
1855 | |||
1822 | /* Would be great to copy this in bigger | 1856 | /* Would be great to copy this in bigger |
1823 | * chunks. However, for the sake of | 1857 | * chunks. However, for the sake of |
1824 | * correctness we need to verify each sector | 1858 | * correctness we need to verify each sector |
@@ -1832,6 +1866,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1832 | sector = 0; /* Force wrap */ | 1866 | sector = 0; /* Force wrap */ |
1833 | 1867 | ||
1834 | start_sec++; | 1868 | start_sec++; |
1869 | ei_lba++; | ||
1835 | daddr += scsi_debug_sector_size; | 1870 | daddr += scsi_debug_sector_size; |
1836 | ppage_offset += sizeof(struct sd_dif_tuple); | 1871 | ppage_offset += sizeof(struct sd_dif_tuple); |
1837 | } | 1872 | } |
@@ -1853,7 +1888,8 @@ out: | |||
1853 | } | 1888 | } |
1854 | 1889 | ||
1855 | static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, | 1890 | static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, |
1856 | unsigned int num, struct sdebug_dev_info *devip) | 1891 | unsigned int num, struct sdebug_dev_info *devip, |
1892 | u32 ei_lba) | ||
1857 | { | 1893 | { |
1858 | unsigned long iflags; | 1894 | unsigned long iflags; |
1859 | int ret; | 1895 | int ret; |
@@ -1864,7 +1900,7 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, | |||
1864 | 1900 | ||
1865 | /* DIX + T10 DIF */ | 1901 | /* DIX + T10 DIF */ |
1866 | if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { | 1902 | if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { |
1867 | int prot_ret = prot_verify_write(SCpnt, lba, num); | 1903 | int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba); |
1868 | 1904 | ||
1869 | if (prot_ret) { | 1905 | if (prot_ret) { |
1870 | mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); | 1906 | mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); |
@@ -2872,11 +2908,12 @@ static int __init scsi_debug_init(void) | |||
2872 | 2908 | ||
2873 | case SD_DIF_TYPE0_PROTECTION: | 2909 | case SD_DIF_TYPE0_PROTECTION: |
2874 | case SD_DIF_TYPE1_PROTECTION: | 2910 | case SD_DIF_TYPE1_PROTECTION: |
2911 | case SD_DIF_TYPE2_PROTECTION: | ||
2875 | case SD_DIF_TYPE3_PROTECTION: | 2912 | case SD_DIF_TYPE3_PROTECTION: |
2876 | break; | 2913 | break; |
2877 | 2914 | ||
2878 | default: | 2915 | default: |
2879 | printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n"); | 2916 | printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n"); |
2880 | return -EINVAL; | 2917 | return -EINVAL; |
2881 | } | 2918 | } |
2882 | 2919 | ||
@@ -3121,6 +3158,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
3121 | int len, k; | 3158 | int len, k; |
3122 | unsigned int num; | 3159 | unsigned int num; |
3123 | unsigned long long lba; | 3160 | unsigned long long lba; |
3161 | u32 ei_lba; | ||
3124 | int errsts = 0; | 3162 | int errsts = 0; |
3125 | int target = SCpnt->device->id; | 3163 | int target = SCpnt->device->id; |
3126 | struct sdebug_dev_info *devip = NULL; | 3164 | struct sdebug_dev_info *devip = NULL; |
@@ -3254,14 +3292,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
3254 | case READ_16: | 3292 | case READ_16: |
3255 | case READ_12: | 3293 | case READ_12: |
3256 | case READ_10: | 3294 | case READ_10: |
3295 | /* READ{10,12,16} and DIF Type 2 are natural enemies */ | ||
3296 | if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && | ||
3297 | cmd[1] & 0xe0) { | ||
3298 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
3299 | INVALID_COMMAND_OPCODE, 0); | ||
3300 | errsts = check_condition_result; | ||
3301 | break; | ||
3302 | } | ||
3303 | |||
3304 | if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || | ||
3305 | scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && | ||
3306 | (cmd[1] & 0xe0) == 0) | ||
3307 | printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); | ||
3308 | |||
3309 | /* fall through */ | ||
3257 | case READ_6: | 3310 | case READ_6: |
3311 | read: | ||
3258 | errsts = check_readiness(SCpnt, 0, devip); | 3312 | errsts = check_readiness(SCpnt, 0, devip); |
3259 | if (errsts) | 3313 | if (errsts) |
3260 | break; | 3314 | break; |
3261 | if (scsi_debug_fake_rw) | 3315 | if (scsi_debug_fake_rw) |
3262 | break; | 3316 | break; |
3263 | get_data_transfer_info(cmd, &lba, &num); | 3317 | get_data_transfer_info(cmd, &lba, &num, &ei_lba); |
3264 | errsts = resp_read(SCpnt, lba, num, devip); | 3318 | errsts = resp_read(SCpnt, lba, num, devip, ei_lba); |
3265 | if (inj_recovered && (0 == errsts)) { | 3319 | if (inj_recovered && (0 == errsts)) { |
3266 | mk_sense_buffer(devip, RECOVERED_ERROR, | 3320 | mk_sense_buffer(devip, RECOVERED_ERROR, |
3267 | THRESHOLD_EXCEEDED, 0); | 3321 | THRESHOLD_EXCEEDED, 0); |
@@ -3288,14 +3342,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
3288 | case WRITE_16: | 3342 | case WRITE_16: |
3289 | case WRITE_12: | 3343 | case WRITE_12: |
3290 | case WRITE_10: | 3344 | case WRITE_10: |
3345 | /* WRITE{10,12,16} and DIF Type 2 are natural enemies */ | ||
3346 | if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && | ||
3347 | cmd[1] & 0xe0) { | ||
3348 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
3349 | INVALID_COMMAND_OPCODE, 0); | ||
3350 | errsts = check_condition_result; | ||
3351 | break; | ||
3352 | } | ||
3353 | |||
3354 | if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || | ||
3355 | scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && | ||
3356 | (cmd[1] & 0xe0) == 0) | ||
3357 | printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); | ||
3358 | |||
3359 | /* fall through */ | ||
3291 | case WRITE_6: | 3360 | case WRITE_6: |
3361 | write: | ||
3292 | errsts = check_readiness(SCpnt, 0, devip); | 3362 | errsts = check_readiness(SCpnt, 0, devip); |
3293 | if (errsts) | 3363 | if (errsts) |
3294 | break; | 3364 | break; |
3295 | if (scsi_debug_fake_rw) | 3365 | if (scsi_debug_fake_rw) |
3296 | break; | 3366 | break; |
3297 | get_data_transfer_info(cmd, &lba, &num); | 3367 | get_data_transfer_info(cmd, &lba, &num, &ei_lba); |
3298 | errsts = resp_write(SCpnt, lba, num, devip); | 3368 | errsts = resp_write(SCpnt, lba, num, devip, ei_lba); |
3299 | if (inj_recovered && (0 == errsts)) { | 3369 | if (inj_recovered && (0 == errsts)) { |
3300 | mk_sense_buffer(devip, RECOVERED_ERROR, | 3370 | mk_sense_buffer(devip, RECOVERED_ERROR, |
3301 | THRESHOLD_EXCEEDED, 0); | 3371 | THRESHOLD_EXCEEDED, 0); |
@@ -3341,15 +3411,38 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
3341 | break; | 3411 | break; |
3342 | if (scsi_debug_fake_rw) | 3412 | if (scsi_debug_fake_rw) |
3343 | break; | 3413 | break; |
3344 | get_data_transfer_info(cmd, &lba, &num); | 3414 | get_data_transfer_info(cmd, &lba, &num, &ei_lba); |
3345 | errsts = resp_read(SCpnt, lba, num, devip); | 3415 | errsts = resp_read(SCpnt, lba, num, devip, ei_lba); |
3346 | if (errsts) | 3416 | if (errsts) |
3347 | break; | 3417 | break; |
3348 | errsts = resp_write(SCpnt, lba, num, devip); | 3418 | errsts = resp_write(SCpnt, lba, num, devip, ei_lba); |
3349 | if (errsts) | 3419 | if (errsts) |
3350 | break; | 3420 | break; |
3351 | errsts = resp_xdwriteread(SCpnt, lba, num, devip); | 3421 | errsts = resp_xdwriteread(SCpnt, lba, num, devip); |
3352 | break; | 3422 | break; |
3423 | case VARIABLE_LENGTH_CMD: | ||
3424 | if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) { | ||
3425 | |||
3426 | if ((cmd[10] & 0xe0) == 0) | ||
3427 | printk(KERN_ERR | ||
3428 | "Unprotected RD/WR to DIF device\n"); | ||
3429 | |||
3430 | if (cmd[9] == READ_32) { | ||
3431 | BUG_ON(SCpnt->cmd_len < 32); | ||
3432 | goto read; | ||
3433 | } | ||
3434 | |||
3435 | if (cmd[9] == WRITE_32) { | ||
3436 | BUG_ON(SCpnt->cmd_len < 32); | ||
3437 | goto write; | ||
3438 | } | ||
3439 | } | ||
3440 | |||
3441 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
3442 | INVALID_FIELD_IN_CDB, 0); | ||
3443 | errsts = check_condition_result; | ||
3444 | break; | ||
3445 | |||
3353 | default: | 3446 | default: |
3354 | if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) | 3447 | if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) |
3355 | printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " | 3448 | printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " |