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 | |
| 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>
| -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 " |
