Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Martin K. Petersen and committed by
James Bottomley
395cef03 4e7392ec

+116 -23
+116 -23
drivers/scsi/scsi_debug.c
··· 50 50 #include <scsi/scsi_host.h> 51 51 #include <scsi/scsicam.h> 52 52 #include <scsi/scsi_eh.h> 53 + #include <scsi/scsi_dbg.h> 53 54 54 55 #include "sd.h" 55 56 #include "scsi_logging.h" ··· 65 64 #define PARAMETER_LIST_LENGTH_ERR 0x1a 66 65 #define INVALID_OPCODE 0x20 67 66 #define ADDR_OUT_OF_RANGE 0x21 67 + #define INVALID_COMMAND_OPCODE 0x20 68 68 #define INVALID_FIELD_IN_CDB 0x24 69 69 #define INVALID_FIELD_IN_PARAM_LIST 0x26 70 70 #define POWERON_RESET 0x29 ··· 182 180 #define SDEBUG_SENSE_LEN 32 183 181 184 182 #define SCSI_DEBUG_CANQUEUE 255 185 - #define SCSI_DEBUG_MAX_CMD_LEN 16 183 + #define SCSI_DEBUG_MAX_CMD_LEN 32 186 184 187 185 struct sdebug_dev_info { 188 186 struct list_head dev_list; ··· 298 296 } 299 297 300 298 static void get_data_transfer_info(unsigned char *cmd, 301 - unsigned long long *lba, unsigned int *num) 299 + unsigned long long *lba, unsigned int *num, 300 + u32 *ei_lba) 302 301 { 302 + *ei_lba = 0; 303 + 303 304 switch (*cmd) { 305 + case VARIABLE_LENGTH_CMD: 306 + *lba = (u64)cmd[19] | (u64)cmd[18] << 8 | 307 + (u64)cmd[17] << 16 | (u64)cmd[16] << 24 | 308 + (u64)cmd[15] << 32 | (u64)cmd[14] << 40 | 309 + (u64)cmd[13] << 48 | (u64)cmd[12] << 56; 310 + 311 + *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 | 312 + (u32)cmd[21] << 16 | (u32)cmd[20] << 24; 313 + 314 + *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 | 315 + (u32)cmd[28] << 24; 316 + break; 317 + 304 318 case WRITE_16: 305 319 case READ_16: 306 320 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | ··· 1607 1589 } 1608 1590 1609 1591 static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 1610 - unsigned int sectors) 1592 + unsigned int sectors, u32 ei_lba) 1611 1593 { 1612 1594 unsigned int i, resid; 1613 1595 struct scatterlist *psgl; ··· 1654 1636 return 0x01; 1655 1637 } 1656 1638 1657 - if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && 1639 + if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && 1658 1640 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { 1659 1641 printk(KERN_ERR "%s: REF check failed on sector %lu\n", 1660 1642 __func__, (unsigned long)sector); 1661 1643 dif_errors++; 1662 1644 return 0x03; 1663 1645 } 1646 + 1647 + if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 1648 + be32_to_cpu(sdt[i].ref_tag) != ei_lba) { 1649 + printk(KERN_ERR "%s: REF check failed on sector %lu\n", 1650 + __func__, (unsigned long)sector); 1651 + dif_errors++; 1652 + return 0x03; 1653 + } 1654 + 1655 + ei_lba++; 1664 1656 } 1665 1657 1666 1658 resid = sectors * 8; /* Bytes of protection data to copy into sgl */ ··· 1698 1670 } 1699 1671 1700 1672 static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, 1701 - unsigned int num, struct sdebug_dev_info *devip) 1673 + unsigned int num, struct sdebug_dev_info *devip, 1674 + u32 ei_lba) 1702 1675 { 1703 1676 unsigned long iflags; 1704 1677 int ret; ··· 1728 1699 1729 1700 /* DIX + T10 DIF */ 1730 1701 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { 1731 - int prot_ret = prot_verify_read(SCpnt, lba, num); 1702 + int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba); 1732 1703 1733 1704 if (prot_ret) { 1734 1705 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); ··· 1764 1735 } 1765 1736 1766 1737 static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 1767 - unsigned int sectors) 1738 + unsigned int sectors, u32 ei_lba) 1768 1739 { 1769 1740 int i, j, ret; 1770 1741 struct sd_dif_tuple *sdt; ··· 1777 1748 unsigned short csum; 1778 1749 1779 1750 sector = do_div(tmp_sec, sdebug_store_sectors); 1780 - 1781 - if (((SCpnt->cmnd[1] >> 5) & 7) != 1) { 1782 - printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n"); 1783 - return 0; 1784 - } 1785 1751 1786 1752 BUG_ON(scsi_sg_count(SCpnt) == 0); 1787 1753 BUG_ON(scsi_prot_sg_count(SCpnt) == 0); ··· 1832 1808 goto out; 1833 1809 } 1834 1810 1835 - if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && 1811 + if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && 1836 1812 be32_to_cpu(sdt->ref_tag) 1837 1813 != (start_sec & 0xffffffff)) { 1814 + printk(KERN_ERR 1815 + "%s: REF check failed on sector %lu\n", 1816 + __func__, (unsigned long)sector); 1817 + ret = 0x03; 1818 + dump_sector(daddr, scsi_debug_sector_size); 1819 + goto out; 1820 + } 1821 + 1822 + if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 1823 + be32_to_cpu(sdt->ref_tag) != ei_lba) { 1838 1824 printk(KERN_ERR 1839 1825 "%s: REF check failed on sector %lu\n", 1840 1826 __func__, (unsigned long)sector); ··· 1866 1832 sector = 0; /* Force wrap */ 1867 1833 1868 1834 start_sec++; 1835 + ei_lba++; 1869 1836 daddr += scsi_debug_sector_size; 1870 1837 ppage_offset += sizeof(struct sd_dif_tuple); 1871 1838 } ··· 1888 1853 } 1889 1854 1890 1855 static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, 1891 - unsigned int num, struct sdebug_dev_info *devip) 1856 + unsigned int num, struct sdebug_dev_info *devip, 1857 + u32 ei_lba) 1892 1858 { 1893 1859 unsigned long iflags; 1894 1860 int ret; ··· 1900 1864 1901 1865 /* DIX + T10 DIF */ 1902 1866 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { 1903 - int prot_ret = prot_verify_write(SCpnt, lba, num); 1867 + int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba); 1904 1868 1905 1869 if (prot_ret) { 1906 1870 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); ··· 2908 2872 2909 2873 case SD_DIF_TYPE0_PROTECTION: 2910 2874 case SD_DIF_TYPE1_PROTECTION: 2875 + case SD_DIF_TYPE2_PROTECTION: 2911 2876 case SD_DIF_TYPE3_PROTECTION: 2912 2877 break; 2913 2878 2914 2879 default: 2915 - printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n"); 2880 + printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n"); 2916 2881 return -EINVAL; 2917 2882 } 2918 2883 ··· 3158 3121 int len, k; 3159 3122 unsigned int num; 3160 3123 unsigned long long lba; 3124 + u32 ei_lba; 3161 3125 int errsts = 0; 3162 3126 int target = SCpnt->device->id; 3163 3127 struct sdebug_dev_info *devip = NULL; ··· 3292 3254 case READ_16: 3293 3255 case READ_12: 3294 3256 case READ_10: 3257 + /* READ{10,12,16} and DIF Type 2 are natural enemies */ 3258 + if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 3259 + cmd[1] & 0xe0) { 3260 + mk_sense_buffer(devip, ILLEGAL_REQUEST, 3261 + INVALID_COMMAND_OPCODE, 0); 3262 + errsts = check_condition_result; 3263 + break; 3264 + } 3265 + 3266 + if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 3267 + scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 3268 + (cmd[1] & 0xe0) == 0) 3269 + printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); 3270 + 3271 + /* fall through */ 3295 3272 case READ_6: 3273 + read: 3296 3274 errsts = check_readiness(SCpnt, 0, devip); 3297 3275 if (errsts) 3298 3276 break; 3299 3277 if (scsi_debug_fake_rw) 3300 3278 break; 3301 - get_data_transfer_info(cmd, &lba, &num); 3302 - errsts = resp_read(SCpnt, lba, num, devip); 3279 + get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3280 + errsts = resp_read(SCpnt, lba, num, devip, ei_lba); 3303 3281 if (inj_recovered && (0 == errsts)) { 3304 3282 mk_sense_buffer(devip, RECOVERED_ERROR, 3305 3283 THRESHOLD_EXCEEDED, 0); ··· 3342 3288 case WRITE_16: 3343 3289 case WRITE_12: 3344 3290 case WRITE_10: 3291 + /* WRITE{10,12,16} and DIF Type 2 are natural enemies */ 3292 + if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 3293 + cmd[1] & 0xe0) { 3294 + mk_sense_buffer(devip, ILLEGAL_REQUEST, 3295 + INVALID_COMMAND_OPCODE, 0); 3296 + errsts = check_condition_result; 3297 + break; 3298 + } 3299 + 3300 + if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 3301 + scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 3302 + (cmd[1] & 0xe0) == 0) 3303 + printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); 3304 + 3305 + /* fall through */ 3345 3306 case WRITE_6: 3307 + write: 3346 3308 errsts = check_readiness(SCpnt, 0, devip); 3347 3309 if (errsts) 3348 3310 break; 3349 3311 if (scsi_debug_fake_rw) 3350 3312 break; 3351 - get_data_transfer_info(cmd, &lba, &num); 3352 - errsts = resp_write(SCpnt, lba, num, devip); 3313 + get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3314 + errsts = resp_write(SCpnt, lba, num, devip, ei_lba); 3353 3315 if (inj_recovered && (0 == errsts)) { 3354 3316 mk_sense_buffer(devip, RECOVERED_ERROR, 3355 3317 THRESHOLD_EXCEEDED, 0); ··· 3411 3341 break; 3412 3342 if (scsi_debug_fake_rw) 3413 3343 break; 3414 - get_data_transfer_info(cmd, &lba, &num); 3415 - errsts = resp_read(SCpnt, lba, num, devip); 3344 + get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3345 + errsts = resp_read(SCpnt, lba, num, devip, ei_lba); 3416 3346 if (errsts) 3417 3347 break; 3418 - errsts = resp_write(SCpnt, lba, num, devip); 3348 + errsts = resp_write(SCpnt, lba, num, devip, ei_lba); 3419 3349 if (errsts) 3420 3350 break; 3421 3351 errsts = resp_xdwriteread(SCpnt, lba, num, devip); 3422 3352 break; 3353 + case VARIABLE_LENGTH_CMD: 3354 + if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) { 3355 + 3356 + if ((cmd[10] & 0xe0) == 0) 3357 + printk(KERN_ERR 3358 + "Unprotected RD/WR to DIF device\n"); 3359 + 3360 + if (cmd[9] == READ_32) { 3361 + BUG_ON(SCpnt->cmd_len < 32); 3362 + goto read; 3363 + } 3364 + 3365 + if (cmd[9] == WRITE_32) { 3366 + BUG_ON(SCpnt->cmd_len < 32); 3367 + goto write; 3368 + } 3369 + } 3370 + 3371 + mk_sense_buffer(devip, ILLEGAL_REQUEST, 3372 + INVALID_FIELD_IN_CDB, 0); 3373 + errsts = check_condition_result; 3374 + break; 3375 + 3423 3376 default: 3424 3377 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3425 3378 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "