aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2014-11-24 21:27:12 -0500
committerChristoph Hellwig <hch@lst.de>2014-11-25 09:42:57 -0500
commit38d5c8336e60bf6e53a1da9586befe82fa75171b (patch)
tree84dbeb309cebaec54b09314850474789041737b4
parentc2248fc974df7be55a5f6db6b6f99a90b749581b (diff)
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 <dgilbert@interlog.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--drivers/scsi/scsi_debug.c326
1 files changed, 307 insertions, 19 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 2181427a1ea5..aa4b6b80aade 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -307,7 +307,6 @@ static const unsigned char opcode_ind_arr[256] = {
307#define FF_SA (F_SA_HIGH | F_SA_LOW) 307#define FF_SA (F_SA_HIGH | F_SA_LOW)
308 308
309struct sdebug_dev_info; 309struct sdebug_dev_info;
310static int scsi_debug_queuecommand(struct scsi_cmnd *scp);
311static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 310static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
312static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 311static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
313static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 312static 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 *);
322static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 321static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
323static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 322static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
324static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 323static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
324static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
325static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
325static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 326static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
326static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 327static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
327static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); 328static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
329static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
328 330
329struct opcode_info_t { 331struct opcode_info_t {
330 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff 332 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 */
383}; 385};
384 386
385static const struct opcode_info_t maint_in_iarr[2] = { 387static 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,
387 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 389 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
388 0xc7, 0, 0, 0, 0} }, 390 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,
390 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 392 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
391 0, 0} }, 393 0, 0} },
392}; 394};
@@ -487,7 +489,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
487 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */ 489 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
488 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 490 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
489 0, 0, 0, 0} }, 491 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,
491 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 493 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
492 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */ 494 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
493 495
@@ -1603,6 +1605,184 @@ static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1603 return ret; 1605 return ret;
1604} 1606}
1605 1607
1608static int
1609resp_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
1759static int
1760resp_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
1606/* <<Following mode page info copied from ST318451LW>> */ 1786/* <<Following mode page info copied from ST318451LW>> */
1607 1787
1608static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 1788static 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)
2165 return ret; 2345 return ret;
2166} 2346}
2167 2347
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. */
2351static bool
2352comp_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
2168static __be16 dif_compute_csum(const void *buf, int len) 2380static __be16 dif_compute_csum(const void *buf, int len)
2169{ 2381{
2170 __be16 csum; 2382 __be16 csum;
@@ -2821,6 +3033,82 @@ resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2821 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3033 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
2822} 3034}
2823 3035
3036static int
3037resp_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
2824struct unmap_block_desc { 3112struct unmap_block_desc {
2825 __be64 lba; 3113 __be64 lba;
2826 __be32 blocks; 3114 __be32 blocks;
@@ -4669,21 +4957,6 @@ static void sdebug_remove_adapter(void)
4669} 4957}
4670 4958
4671static int 4959static int
4672sdebug_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
4686static int
4687sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 4960sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
4688{ 4961{
4689 int num_in_q = 0; 4962 int num_in_q = 0;
@@ -4912,6 +5185,21 @@ check_cond:
4912 return schedule_resp(scp, devip, check_condition_result, 0); 5185 return schedule_resp(scp, devip, check_condition_result, 0);
4913} 5186}
4914 5187
5188static int
5189sdebug_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
4915static struct scsi_host_template sdebug_driver_template = { 5203static struct scsi_host_template sdebug_driver_template = {
4916 .show_info = scsi_debug_show_info, 5204 .show_info = scsi_debug_show_info,
4917 .write_info = scsi_debug_write_info, 5205 .write_info = scsi_debug_write_info,