Skip to content

Commit 38d5c83

Browse files
doug-gilbertChristoph Hellwig
authored andcommitted
scsi_debug: add Report supported opcodes+tmfs; Compare and write
The Report supported operation codes command is very closely integrated into the table driven parser and very useful for testing it. Its cdb masks form the basis of the 'strict' parameter's checks. The Report supported TMFs command is a simple extension. The Compare and write command may even be useful, as it should be atomic due to the read-write lock that the driver uses on its backing store (ram). Signed-off-by: Douglas Gilbert <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent c2248fc commit 38d5c83

File tree

1 file changed

+307
-19
lines changed

1 file changed

+307
-19
lines changed

drivers/scsi/scsi_debug.c

Lines changed: 307 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,6 @@ static const unsigned char opcode_ind_arr[256] = {
307307
#define FF_SA (F_SA_HIGH | F_SA_LOW)
308308

309309
struct sdebug_dev_info;
310-
static int scsi_debug_queuecommand(struct scsi_cmnd *scp);
311310
static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
312311
static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
313312
static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
@@ -322,9 +321,12 @@ static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
322321
static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
323322
static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
324323
static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
324+
static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
325+
static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
325326
static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
326327
static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
327328
static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
329+
static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
328330

329331
struct opcode_info_t {
330332
u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff
@@ -383,10 +385,10 @@ static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
383385
};
384386

385387
static const struct opcode_info_t maint_in_iarr[2] = {
386-
{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, NULL, NULL,
388+
{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
387389
{12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
388390
0xc7, 0, 0, 0, 0} },
389-
{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, NULL, NULL,
391+
{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
390392
{12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
391393
0, 0} },
392394
};
@@ -487,7 +489,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
487489
{0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
488490
{10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
489491
0, 0, 0, 0} },
490-
{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, NULL, NULL,
492+
{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
491493
{16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
492494
0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
493495

@@ -1603,6 +1605,184 @@ static int resp_report_tgtpgs(struct scsi_cmnd * scp,
16031605
return ret;
16041606
}
16051607

1608+
static int
1609+
resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1610+
{
1611+
bool rctd;
1612+
u8 reporting_opts, req_opcode, sdeb_i, supp;
1613+
u16 req_sa, u;
1614+
u32 alloc_len, a_len;
1615+
int k, offset, len, errsts, count, bump, na;
1616+
const struct opcode_info_t *oip;
1617+
const struct opcode_info_t *r_oip;
1618+
u8 *arr;
1619+
u8 *cmd = scp->cmnd;
1620+
1621+
rctd = !!(cmd[2] & 0x80);
1622+
reporting_opts = cmd[2] & 0x7;
1623+
req_opcode = cmd[3];
1624+
req_sa = get_unaligned_be16(cmd + 4);
1625+
alloc_len = get_unaligned_be32(cmd + 6);
1626+
if (alloc_len < 4 && alloc_len > 0xffff) {
1627+
mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1628+
return check_condition_result;
1629+
}
1630+
if (alloc_len > 8192)
1631+
a_len = 8192;
1632+
else
1633+
a_len = alloc_len;
1634+
arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_KERNEL);
1635+
if (NULL == arr) {
1636+
mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1637+
INSUFF_RES_ASCQ);
1638+
return check_condition_result;
1639+
}
1640+
switch (reporting_opts) {
1641+
case 0: /* all commands */
1642+
/* count number of commands */
1643+
for (count = 0, oip = opcode_info_arr;
1644+
oip->num_attached != 0xff; ++oip) {
1645+
if (F_INV_OP & oip->flags)
1646+
continue;
1647+
count += (oip->num_attached + 1);
1648+
}
1649+
bump = rctd ? 20 : 8;
1650+
put_unaligned_be32(count * bump, arr);
1651+
for (offset = 4, oip = opcode_info_arr;
1652+
oip->num_attached != 0xff && offset < a_len; ++oip) {
1653+
if (F_INV_OP & oip->flags)
1654+
continue;
1655+
na = oip->num_attached;
1656+
arr[offset] = oip->opcode;
1657+
put_unaligned_be16(oip->sa, arr + offset + 2);
1658+
if (rctd)
1659+
arr[offset + 5] |= 0x2;
1660+
if (FF_SA & oip->flags)
1661+
arr[offset + 5] |= 0x1;
1662+
put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1663+
if (rctd)
1664+
put_unaligned_be16(0xa, arr + offset + 8);
1665+
r_oip = oip;
1666+
for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1667+
if (F_INV_OP & oip->flags)
1668+
continue;
1669+
offset += bump;
1670+
arr[offset] = oip->opcode;
1671+
put_unaligned_be16(oip->sa, arr + offset + 2);
1672+
if (rctd)
1673+
arr[offset + 5] |= 0x2;
1674+
if (FF_SA & oip->flags)
1675+
arr[offset + 5] |= 0x1;
1676+
put_unaligned_be16(oip->len_mask[0],
1677+
arr + offset + 6);
1678+
if (rctd)
1679+
put_unaligned_be16(0xa,
1680+
arr + offset + 8);
1681+
}
1682+
oip = r_oip;
1683+
offset += bump;
1684+
}
1685+
break;
1686+
case 1: /* one command: opcode only */
1687+
case 2: /* one command: opcode plus service action */
1688+
case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1689+
sdeb_i = opcode_ind_arr[req_opcode];
1690+
oip = &opcode_info_arr[sdeb_i];
1691+
if (F_INV_OP & oip->flags) {
1692+
supp = 1;
1693+
offset = 4;
1694+
} else {
1695+
if (1 == reporting_opts) {
1696+
if (FF_SA & oip->flags) {
1697+
mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1698+
2, 2);
1699+
kfree(arr);
1700+
return check_condition_result;
1701+
}
1702+
req_sa = 0;
1703+
} else if (2 == reporting_opts &&
1704+
0 == (FF_SA & oip->flags)) {
1705+
mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1706+
kfree(arr); /* point at requested sa */
1707+
return check_condition_result;
1708+
}
1709+
if (0 == (FF_SA & oip->flags) &&
1710+
req_opcode == oip->opcode)
1711+
supp = 3;
1712+
else if (0 == (FF_SA & oip->flags)) {
1713+
na = oip->num_attached;
1714+
for (k = 0, oip = oip->arrp; k < na;
1715+
++k, ++oip) {
1716+
if (req_opcode == oip->opcode)
1717+
break;
1718+
}
1719+
supp = (k >= na) ? 1 : 3;
1720+
} else if (req_sa != oip->sa) {
1721+
na = oip->num_attached;
1722+
for (k = 0, oip = oip->arrp; k < na;
1723+
++k, ++oip) {
1724+
if (req_sa == oip->sa)
1725+
break;
1726+
}
1727+
supp = (k >= na) ? 1 : 3;
1728+
} else
1729+
supp = 3;
1730+
if (3 == supp) {
1731+
u = oip->len_mask[0];
1732+
put_unaligned_be16(u, arr + 2);
1733+
arr[4] = oip->opcode;
1734+
for (k = 1; k < u; ++k)
1735+
arr[4 + k] = (k < 16) ?
1736+
oip->len_mask[k] : 0xff;
1737+
offset = 4 + u;
1738+
} else
1739+
offset = 4;
1740+
}
1741+
arr[1] = (rctd ? 0x80 : 0) | supp;
1742+
if (rctd) {
1743+
put_unaligned_be16(0xa, arr + offset);
1744+
offset += 12;
1745+
}
1746+
break;
1747+
default:
1748+
mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1749+
kfree(arr);
1750+
return check_condition_result;
1751+
}
1752+
offset = (offset < a_len) ? offset : a_len;
1753+
len = (offset < alloc_len) ? offset : alloc_len;
1754+
errsts = fill_from_dev_buffer(scp, arr, len);
1755+
kfree(arr);
1756+
return errsts;
1757+
}
1758+
1759+
static int
1760+
resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1761+
{
1762+
bool repd;
1763+
u32 alloc_len, len;
1764+
u8 arr[16];
1765+
u8 *cmd = scp->cmnd;
1766+
1767+
memset(arr, 0, sizeof(arr));
1768+
repd = !!(cmd[2] & 0x80);
1769+
alloc_len = get_unaligned_be32(cmd + 6);
1770+
if (alloc_len < 4) {
1771+
mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1772+
return check_condition_result;
1773+
}
1774+
arr[0] = 0xc8; /* ATS | ATSS | LURS */
1775+
arr[1] = 0x1; /* ITNRS */
1776+
if (repd) {
1777+
arr[3] = 0xc;
1778+
len = 16;
1779+
} else
1780+
len = 4;
1781+
1782+
len = (len < alloc_len) ? len : alloc_len;
1783+
return fill_from_dev_buffer(scp, arr, len);
1784+
}
1785+
16061786
/* <<Following mode page info copied from ST318451LW>> */
16071787

16081788
static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
@@ -2165,6 +2345,38 @@ do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write)
21652345
return ret;
21662346
}
21672347

2348+
/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2349+
* arr into fake_store(lba,num) and return true. If comparison fails then
2350+
* return false. */
2351+
static bool
2352+
comp_write_worker(u64 lba, u32 num, const u8 *arr)
2353+
{
2354+
bool res;
2355+
u64 block, rest = 0;
2356+
u32 store_blks = sdebug_store_sectors;
2357+
u32 lb_size = scsi_debug_sector_size;
2358+
2359+
block = do_div(lba, store_blks);
2360+
if (block + num > store_blks)
2361+
rest = block + num - store_blks;
2362+
2363+
res = !memcmp(fake_storep + (block * lb_size), arr,
2364+
(num - rest) * lb_size);
2365+
if (!res)
2366+
return res;
2367+
if (rest)
2368+
res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2369+
rest * lb_size);
2370+
if (!res)
2371+
return res;
2372+
arr += num * lb_size;
2373+
memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2374+
if (rest)
2375+
memcpy(fake_storep, arr + ((num - rest) * lb_size),
2376+
rest * lb_size);
2377+
return res;
2378+
}
2379+
21682380
static __be16 dif_compute_csum(const void *buf, int len)
21692381
{
21702382
__be16 csum;
@@ -2821,6 +3033,82 @@ resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
28213033
return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
28223034
}
28233035

3036+
static int
3037+
resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3038+
{
3039+
u8 *cmd = scp->cmnd;
3040+
u8 *arr;
3041+
u8 *fake_storep_hold;
3042+
u64 lba;
3043+
u32 dnum;
3044+
u32 lb_size = scsi_debug_sector_size;
3045+
u8 num;
3046+
unsigned long iflags;
3047+
int ret;
3048+
3049+
lba = get_unaligned_be32(cmd + 2);
3050+
num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3051+
if (0 == num)
3052+
return 0; /* degenerate case, not an error */
3053+
dnum = 2 * num;
3054+
arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3055+
if (NULL == arr) {
3056+
mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3057+
INSUFF_RES_ASCQ);
3058+
return check_condition_result;
3059+
}
3060+
if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3061+
(cmd[1] & 0xe0)) {
3062+
mk_sense_invalid_opcode(scp);
3063+
return check_condition_result;
3064+
}
3065+
if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3066+
scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3067+
(cmd[1] & 0xe0) == 0)
3068+
sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3069+
"to DIF device\n");
3070+
3071+
/* inline check_device_access_params() */
3072+
if (lba + num > sdebug_capacity) {
3073+
mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3074+
return check_condition_result;
3075+
}
3076+
/* transfer length excessive (tie in to block limits VPD page) */
3077+
if (num > sdebug_store_sectors) {
3078+
/* needs work to find which cdb byte 'num' comes from */
3079+
mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3080+
return check_condition_result;
3081+
}
3082+
3083+
write_lock_irqsave(&atomic_rw, iflags);
3084+
3085+
/* trick do_device_access() to fetch both compare and write buffers
3086+
* from data-in into arr. Safe (atomic) since write_lock held. */
3087+
fake_storep_hold = fake_storep;
3088+
fake_storep = arr;
3089+
ret = do_device_access(scp, 0, dnum, true);
3090+
fake_storep = fake_storep_hold;
3091+
if (ret == -1) {
3092+
write_unlock_irqrestore(&atomic_rw, iflags);
3093+
kfree(arr);
3094+
return DID_ERROR << 16;
3095+
} else if ((ret < (dnum * lb_size)) &&
3096+
(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
3097+
sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3098+
"indicated=%u, IO sent=%d bytes\n", my_name,
3099+
dnum * lb_size, ret);
3100+
if (!comp_write_worker(lba, num, arr)) {
3101+
write_unlock_irqrestore(&atomic_rw, iflags);
3102+
kfree(arr);
3103+
mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3104+
return check_condition_result;
3105+
}
3106+
if (scsi_debug_lbp())
3107+
map_region(lba, num);
3108+
write_unlock_irqrestore(&atomic_rw, iflags);
3109+
return 0;
3110+
}
3111+
28243112
struct unmap_block_desc {
28253113
__be64 lba;
28263114
__be32 blocks;
@@ -4668,21 +4956,6 @@ static void sdebug_remove_adapter(void)
46684956
--scsi_debug_add_host;
46694957
}
46704958

4671-
static int
4672-
sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
4673-
{
4674-
if (scsi_debug_host_lock) {
4675-
unsigned long iflags;
4676-
int rc;
4677-
4678-
spin_lock_irqsave(shost->host_lock, iflags);
4679-
rc = scsi_debug_queuecommand(cmd);
4680-
spin_unlock_irqrestore(shost->host_lock, iflags);
4681-
return rc;
4682-
} else
4683-
return scsi_debug_queuecommand(cmd);
4684-
}
4685-
46864959
static int
46874960
sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
46884961
{
@@ -4912,6 +5185,21 @@ scsi_debug_queuecommand(struct scsi_cmnd *scp)
49125185
return schedule_resp(scp, devip, check_condition_result, 0);
49135186
}
49145187

5188+
static int
5189+
sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
5190+
{
5191+
if (scsi_debug_host_lock) {
5192+
unsigned long iflags;
5193+
int rc;
5194+
5195+
spin_lock_irqsave(shost->host_lock, iflags);
5196+
rc = scsi_debug_queuecommand(cmd);
5197+
spin_unlock_irqrestore(shost->host_lock, iflags);
5198+
return rc;
5199+
} else
5200+
return scsi_debug_queuecommand(cmd);
5201+
}
5202+
49155203
static struct scsi_host_template sdebug_driver_template = {
49165204
.show_info = scsi_debug_show_info,
49175205
.write_info = scsi_debug_write_info,

0 commit comments

Comments
 (0)