Skip to content

Commit 395cef0

Browse files
martinkpetersenJames Bottomley
authored andcommitted
[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>
1 parent 4e7392e commit 395cef0

File tree

1 file changed

+116
-23
lines changed

1 file changed

+116
-23
lines changed

drivers/scsi/scsi_debug.c

Lines changed: 116 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include <scsi/scsi_host.h>
5151
#include <scsi/scsicam.h>
5252
#include <scsi/scsi_eh.h>
53+
#include <scsi/scsi_dbg.h>
5354

5455
#include "sd.h"
5556
#include "scsi_logging.h"
@@ -64,6 +65,7 @@ static const char * scsi_debug_version_date = "20070104";
6465
#define PARAMETER_LIST_LENGTH_ERR 0x1a
6566
#define INVALID_OPCODE 0x20
6667
#define ADDR_OUT_OF_RANGE 0x21
68+
#define INVALID_COMMAND_OPCODE 0x20
6769
#define INVALID_FIELD_IN_CDB 0x24
6870
#define INVALID_FIELD_IN_PARAM_LIST 0x26
6971
#define POWERON_RESET 0x29
@@ -180,7 +182,7 @@ static int sdebug_sectors_per; /* sectors per cylinder */
180182
#define SDEBUG_SENSE_LEN 32
181183

182184
#define SCSI_DEBUG_CANQUEUE 255
183-
#define SCSI_DEBUG_MAX_CMD_LEN 16
185+
#define SCSI_DEBUG_MAX_CMD_LEN 32
184186

185187
struct sdebug_dev_info {
186188
struct list_head dev_list;
@@ -296,9 +298,25 @@ static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
296298
}
297299

298300
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)
300303
{
304+
*ei_lba = 0;
305+
301306
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+
302320
case WRITE_16:
303321
case READ_16:
304322
*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
@@ -1589,7 +1607,7 @@ static int do_device_access(struct scsi_cmnd *scmd,
15891607
}
15901608

15911609
static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1592-
unsigned int sectors)
1610+
unsigned int sectors, u32 ei_lba)
15931611
{
15941612
unsigned int i, resid;
15951613
struct scatterlist *psgl;
@@ -1636,13 +1654,23 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
16361654
return 0x01;
16371655
}
16381656

1639-
if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
1657+
if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
16401658
be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
16411659
printk(KERN_ERR "%s: REF check failed on sector %lu\n",
16421660
__func__, (unsigned long)sector);
16431661
dif_errors++;
16441662
return 0x03;
16451663
}
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++;
16461674
}
16471675

16481676
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,
16701698
}
16711699

16721700
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)
16741703
{
16751704
unsigned long iflags;
16761705
int ret;
@@ -1699,7 +1728,7 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
16991728

17001729
/* DIX + T10 DIF */
17011730
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);
17031732

17041733
if (prot_ret) {
17051734
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
@@ -1735,7 +1764,7 @@ void dump_sector(unsigned char *buf, int len)
17351764
}
17361765

17371766
static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
1738-
unsigned int sectors)
1767+
unsigned int sectors, u32 ei_lba)
17391768
{
17401769
int i, j, ret;
17411770
struct sd_dif_tuple *sdt;
@@ -1749,11 +1778,6 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
17491778

17501779
sector = do_div(tmp_sec, sdebug_store_sectors);
17511780

1752-
if (((SCpnt->cmnd[1] >> 5) & 7) != 1) {
1753-
printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n");
1754-
return 0;
1755-
}
1756-
17571781
BUG_ON(scsi_sg_count(SCpnt) == 0);
17581782
BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
17591783

@@ -1808,7 +1832,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
18081832
goto out;
18091833
}
18101834

1811-
if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
1835+
if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
18121836
be32_to_cpu(sdt->ref_tag)
18131837
!= (start_sec & 0xffffffff)) {
18141838
printk(KERN_ERR
@@ -1819,6 +1843,16 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
18191843
goto out;
18201844
}
18211845

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+
18221856
/* Would be great to copy this in bigger
18231857
* chunks. However, for the sake of
18241858
* correctness we need to verify each sector
@@ -1832,6 +1866,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
18321866
sector = 0; /* Force wrap */
18331867

18341868
start_sec++;
1869+
ei_lba++;
18351870
daddr += scsi_debug_sector_size;
18361871
ppage_offset += sizeof(struct sd_dif_tuple);
18371872
}
@@ -1853,7 +1888,8 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
18531888
}
18541889

18551890
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)
18571893
{
18581894
unsigned long iflags;
18591895
int ret;
@@ -1864,7 +1900,7 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
18641900

18651901
/* DIX + T10 DIF */
18661902
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);
18681904

18691905
if (prot_ret) {
18701906
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
@@ -2872,11 +2908,12 @@ static int __init scsi_debug_init(void)
28722908

28732909
case SD_DIF_TYPE0_PROTECTION:
28742910
case SD_DIF_TYPE1_PROTECTION:
2911+
case SD_DIF_TYPE2_PROTECTION:
28752912
case SD_DIF_TYPE3_PROTECTION:
28762913
break;
28772914

28782915
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");
28802917
return -EINVAL;
28812918
}
28822919

@@ -3121,6 +3158,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
31213158
int len, k;
31223159
unsigned int num;
31233160
unsigned long long lba;
3161+
u32 ei_lba;
31243162
int errsts = 0;
31253163
int target = SCpnt->device->id;
31263164
struct sdebug_dev_info *devip = NULL;
@@ -3254,14 +3292,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
32543292
case READ_16:
32553293
case READ_12:
32563294
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 */
32573310
case READ_6:
3311+
read:
32583312
errsts = check_readiness(SCpnt, 0, devip);
32593313
if (errsts)
32603314
break;
32613315
if (scsi_debug_fake_rw)
32623316
break;
3263-
get_data_transfer_info(cmd, &lba, &num);
3264-
errsts = resp_read(SCpnt, lba, num, devip);
3317+
get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3318+
errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
32653319
if (inj_recovered && (0 == errsts)) {
32663320
mk_sense_buffer(devip, RECOVERED_ERROR,
32673321
THRESHOLD_EXCEEDED, 0);
@@ -3288,14 +3342,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
32883342
case WRITE_16:
32893343
case WRITE_12:
32903344
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 */
32913360
case WRITE_6:
3361+
write:
32923362
errsts = check_readiness(SCpnt, 0, devip);
32933363
if (errsts)
32943364
break;
32953365
if (scsi_debug_fake_rw)
32963366
break;
3297-
get_data_transfer_info(cmd, &lba, &num);
3298-
errsts = resp_write(SCpnt, lba, num, devip);
3367+
get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3368+
errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
32993369
if (inj_recovered && (0 == errsts)) {
33003370
mk_sense_buffer(devip, RECOVERED_ERROR,
33013371
THRESHOLD_EXCEEDED, 0);
@@ -3341,15 +3411,38 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
33413411
break;
33423412
if (scsi_debug_fake_rw)
33433413
break;
3344-
get_data_transfer_info(cmd, &lba, &num);
3345-
errsts = resp_read(SCpnt, lba, num, devip);
3414+
get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3415+
errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
33463416
if (errsts)
33473417
break;
3348-
errsts = resp_write(SCpnt, lba, num, devip);
3418+
errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
33493419
if (errsts)
33503420
break;
33513421
errsts = resp_xdwriteread(SCpnt, lba, num, devip);
33523422
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+
33533446
default:
33543447
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
33553448
printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "

0 commit comments

Comments
 (0)