diff options
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 351 |
1 files changed, 344 insertions, 7 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index c4103bef41b5..0b575c871007 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -44,6 +44,8 @@ | |||
44 | 44 | ||
45 | #include <net/checksum.h> | 45 | #include <net/checksum.h> |
46 | 46 | ||
47 | #include <asm/unaligned.h> | ||
48 | |||
47 | #include <scsi/scsi.h> | 49 | #include <scsi/scsi.h> |
48 | #include <scsi/scsi_cmnd.h> | 50 | #include <scsi/scsi_cmnd.h> |
49 | #include <scsi/scsi_device.h> | 51 | #include <scsi/scsi_device.h> |
@@ -105,6 +107,10 @@ static const char * scsi_debug_version_date = "20070104"; | |||
105 | #define DEF_ATO 1 | 107 | #define DEF_ATO 1 |
106 | #define DEF_PHYSBLK_EXP 0 | 108 | #define DEF_PHYSBLK_EXP 0 |
107 | #define DEF_LOWEST_ALIGNED 0 | 109 | #define DEF_LOWEST_ALIGNED 0 |
110 | #define DEF_UNMAP_MAX_BLOCKS 0 | ||
111 | #define DEF_UNMAP_MAX_DESC 0 | ||
112 | #define DEF_UNMAP_GRANULARITY 0 | ||
113 | #define DEF_UNMAP_ALIGNMENT 0 | ||
108 | 114 | ||
109 | /* bit mask values for scsi_debug_opts */ | 115 | /* bit mask values for scsi_debug_opts */ |
110 | #define SCSI_DEBUG_OPT_NOISE 1 | 116 | #define SCSI_DEBUG_OPT_NOISE 1 |
@@ -162,6 +168,10 @@ static int scsi_debug_guard = DEF_GUARD; | |||
162 | static int scsi_debug_ato = DEF_ATO; | 168 | static int scsi_debug_ato = DEF_ATO; |
163 | static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; | 169 | static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; |
164 | static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; | 170 | static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; |
171 | static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; | ||
172 | static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; | ||
173 | static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; | ||
174 | static int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; | ||
165 | 175 | ||
166 | static int scsi_debug_cmnd_count = 0; | 176 | static int scsi_debug_cmnd_count = 0; |
167 | 177 | ||
@@ -223,7 +233,9 @@ static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; | |||
223 | 233 | ||
224 | static unsigned char * fake_storep; /* ramdisk storage */ | 234 | static unsigned char * fake_storep; /* ramdisk storage */ |
225 | static unsigned char *dif_storep; /* protection info */ | 235 | static unsigned char *dif_storep; /* protection info */ |
236 | static void *map_storep; /* provisioning map */ | ||
226 | 237 | ||
238 | static unsigned long map_size; | ||
227 | static int num_aborts = 0; | 239 | static int num_aborts = 0; |
228 | static int num_dev_resets = 0; | 240 | static int num_dev_resets = 0; |
229 | static int num_bus_resets = 0; | 241 | static int num_bus_resets = 0; |
@@ -317,6 +329,7 @@ static void get_data_transfer_info(unsigned char *cmd, | |||
317 | (u32)cmd[28] << 24; | 329 | (u32)cmd[28] << 24; |
318 | break; | 330 | break; |
319 | 331 | ||
332 | case WRITE_SAME_16: | ||
320 | case WRITE_16: | 333 | case WRITE_16: |
321 | case READ_16: | 334 | case READ_16: |
322 | *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | | 335 | *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | |
@@ -335,6 +348,7 @@ static void get_data_transfer_info(unsigned char *cmd, | |||
335 | *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | | 348 | *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | |
336 | (u32)cmd[6] << 24; | 349 | (u32)cmd[6] << 24; |
337 | break; | 350 | break; |
351 | case WRITE_SAME: | ||
338 | case WRITE_10: | 352 | case WRITE_10: |
339 | case READ_10: | 353 | case READ_10: |
340 | case XDWRITEREAD_10: | 354 | case XDWRITEREAD_10: |
@@ -671,10 +685,12 @@ static int inquiry_evpd_89(unsigned char * arr) | |||
671 | } | 685 | } |
672 | 686 | ||
673 | 687 | ||
688 | /* Block limits VPD page (SBC-3) */ | ||
674 | static unsigned char vpdb0_data[] = { | 689 | static unsigned char vpdb0_data[] = { |
675 | /* from 4th byte */ 0,0,0,4, | 690 | /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, |
676 | 0,0,0x4,0, | 691 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
677 | 0,0,0,64, | 692 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
693 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
678 | }; | 694 | }; |
679 | 695 | ||
680 | static int inquiry_evpd_b0(unsigned char * arr) | 696 | static int inquiry_evpd_b0(unsigned char * arr) |
@@ -691,14 +707,40 @@ static int inquiry_evpd_b0(unsigned char * arr) | |||
691 | arr[6] = (sdebug_store_sectors >> 8) & 0xff; | 707 | arr[6] = (sdebug_store_sectors >> 8) & 0xff; |
692 | arr[7] = sdebug_store_sectors & 0xff; | 708 | arr[7] = sdebug_store_sectors & 0xff; |
693 | } | 709 | } |
710 | |||
711 | if (scsi_debug_unmap_max_desc) { | ||
712 | unsigned int blocks; | ||
713 | |||
714 | if (scsi_debug_unmap_max_blocks) | ||
715 | blocks = scsi_debug_unmap_max_blocks; | ||
716 | else | ||
717 | blocks = 0xffffffff; | ||
718 | |||
719 | put_unaligned_be32(blocks, &arr[16]); | ||
720 | put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); | ||
721 | } | ||
722 | |||
723 | if (scsi_debug_unmap_alignment) { | ||
724 | put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]); | ||
725 | arr[28] |= 0x80; /* UGAVALID */ | ||
726 | } | ||
727 | |||
728 | if (scsi_debug_unmap_granularity) { | ||
729 | put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); | ||
730 | return 0x3c; /* Mandatory page length for thin provisioning */ | ||
731 | } | ||
732 | |||
694 | return sizeof(vpdb0_data); | 733 | return sizeof(vpdb0_data); |
695 | } | 734 | } |
696 | 735 | ||
736 | /* Block device characteristics VPD page (SBC-3) */ | ||
697 | static int inquiry_evpd_b1(unsigned char *arr) | 737 | static int inquiry_evpd_b1(unsigned char *arr) |
698 | { | 738 | { |
699 | memset(arr, 0, 0x3c); | 739 | memset(arr, 0, 0x3c); |
700 | arr[0] = 0; | 740 | arr[0] = 0; |
701 | arr[1] = 1; | 741 | arr[1] = 1; /* non rotating medium (e.g. solid state) */ |
742 | arr[2] = 0; | ||
743 | arr[3] = 5; /* less than 1.8" */ | ||
702 | 744 | ||
703 | return 0x3c; | 745 | return 0x3c; |
704 | } | 746 | } |
@@ -974,6 +1016,10 @@ static int resp_readcap16(struct scsi_cmnd * scp, | |||
974 | arr[11] = scsi_debug_sector_size & 0xff; | 1016 | arr[11] = scsi_debug_sector_size & 0xff; |
975 | arr[13] = scsi_debug_physblk_exp & 0xf; | 1017 | arr[13] = scsi_debug_physblk_exp & 0xf; |
976 | arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; | 1018 | arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; |
1019 | |||
1020 | if (scsi_debug_unmap_granularity) | ||
1021 | arr[14] |= 0x80; /* TPE */ | ||
1022 | |||
977 | arr[15] = scsi_debug_lowest_aligned & 0xff; | 1023 | arr[15] = scsi_debug_lowest_aligned & 0xff; |
978 | 1024 | ||
979 | if (scsi_debug_dif) { | 1025 | if (scsi_debug_dif) { |
@@ -1887,6 +1933,70 @@ out: | |||
1887 | return ret; | 1933 | return ret; |
1888 | } | 1934 | } |
1889 | 1935 | ||
1936 | static unsigned int map_state(sector_t lba, unsigned int *num) | ||
1937 | { | ||
1938 | unsigned int granularity, alignment, mapped; | ||
1939 | sector_t block, next, end; | ||
1940 | |||
1941 | granularity = scsi_debug_unmap_granularity; | ||
1942 | alignment = granularity - scsi_debug_unmap_alignment; | ||
1943 | block = lba + alignment; | ||
1944 | do_div(block, granularity); | ||
1945 | |||
1946 | mapped = test_bit(block, map_storep); | ||
1947 | |||
1948 | if (mapped) | ||
1949 | next = find_next_zero_bit(map_storep, map_size, block); | ||
1950 | else | ||
1951 | next = find_next_bit(map_storep, map_size, block); | ||
1952 | |||
1953 | end = next * granularity - scsi_debug_unmap_alignment; | ||
1954 | *num = end - lba; | ||
1955 | |||
1956 | return mapped; | ||
1957 | } | ||
1958 | |||
1959 | static void map_region(sector_t lba, unsigned int len) | ||
1960 | { | ||
1961 | unsigned int granularity, alignment; | ||
1962 | sector_t end = lba + len; | ||
1963 | |||
1964 | granularity = scsi_debug_unmap_granularity; | ||
1965 | alignment = granularity - scsi_debug_unmap_alignment; | ||
1966 | |||
1967 | while (lba < end) { | ||
1968 | sector_t block, rem; | ||
1969 | |||
1970 | block = lba + alignment; | ||
1971 | rem = do_div(block, granularity); | ||
1972 | |||
1973 | set_bit(block, map_storep); | ||
1974 | |||
1975 | lba += granularity - rem; | ||
1976 | } | ||
1977 | } | ||
1978 | |||
1979 | static void unmap_region(sector_t lba, unsigned int len) | ||
1980 | { | ||
1981 | unsigned int granularity, alignment; | ||
1982 | sector_t end = lba + len; | ||
1983 | |||
1984 | granularity = scsi_debug_unmap_granularity; | ||
1985 | alignment = granularity - scsi_debug_unmap_alignment; | ||
1986 | |||
1987 | while (lba < end) { | ||
1988 | sector_t block, rem; | ||
1989 | |||
1990 | block = lba + alignment; | ||
1991 | rem = do_div(block, granularity); | ||
1992 | |||
1993 | if (rem == 0 && lba + granularity <= end) | ||
1994 | clear_bit(block, map_storep); | ||
1995 | |||
1996 | lba += granularity - rem; | ||
1997 | } | ||
1998 | } | ||
1999 | |||
1890 | static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, | 2000 | static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, |
1891 | unsigned int num, struct sdebug_dev_info *devip, | 2001 | unsigned int num, struct sdebug_dev_info *devip, |
1892 | u32 ei_lba) | 2002 | u32 ei_lba) |
@@ -1910,6 +2020,8 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, | |||
1910 | 2020 | ||
1911 | write_lock_irqsave(&atomic_rw, iflags); | 2021 | write_lock_irqsave(&atomic_rw, iflags); |
1912 | ret = do_device_access(SCpnt, devip, lba, num, 1); | 2022 | ret = do_device_access(SCpnt, devip, lba, num, 1); |
2023 | if (scsi_debug_unmap_granularity) | ||
2024 | map_region(lba, num); | ||
1913 | write_unlock_irqrestore(&atomic_rw, iflags); | 2025 | write_unlock_irqrestore(&atomic_rw, iflags); |
1914 | if (-1 == ret) | 2026 | if (-1 == ret) |
1915 | return (DID_ERROR << 16); | 2027 | return (DID_ERROR << 16); |
@@ -1917,9 +2029,143 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, | |||
1917 | (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) | 2029 | (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) |
1918 | printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " | 2030 | printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " |
1919 | " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); | 2031 | " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); |
2032 | |||
2033 | return 0; | ||
2034 | } | ||
2035 | |||
2036 | static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba, | ||
2037 | unsigned int num, struct sdebug_dev_info *devip, | ||
2038 | u32 ei_lba, unsigned int unmap) | ||
2039 | { | ||
2040 | unsigned long iflags; | ||
2041 | unsigned long long i; | ||
2042 | int ret; | ||
2043 | |||
2044 | ret = check_device_access_params(devip, lba, num); | ||
2045 | if (ret) | ||
2046 | return ret; | ||
2047 | |||
2048 | write_lock_irqsave(&atomic_rw, iflags); | ||
2049 | |||
2050 | if (unmap && scsi_debug_unmap_granularity) { | ||
2051 | unmap_region(lba, num); | ||
2052 | goto out; | ||
2053 | } | ||
2054 | |||
2055 | /* Else fetch one logical block */ | ||
2056 | ret = fetch_to_dev_buffer(scmd, | ||
2057 | fake_storep + (lba * scsi_debug_sector_size), | ||
2058 | scsi_debug_sector_size); | ||
2059 | |||
2060 | if (-1 == ret) { | ||
2061 | write_unlock_irqrestore(&atomic_rw, iflags); | ||
2062 | return (DID_ERROR << 16); | ||
2063 | } else if ((ret < (num * scsi_debug_sector_size)) && | ||
2064 | (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) | ||
2065 | printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, " | ||
2066 | " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); | ||
2067 | |||
2068 | /* Copy first sector to remaining blocks */ | ||
2069 | for (i = 1 ; i < num ; i++) | ||
2070 | memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size), | ||
2071 | fake_storep + (lba * scsi_debug_sector_size), | ||
2072 | scsi_debug_sector_size); | ||
2073 | |||
2074 | if (scsi_debug_unmap_granularity) | ||
2075 | map_region(lba, num); | ||
2076 | out: | ||
2077 | write_unlock_irqrestore(&atomic_rw, iflags); | ||
2078 | |||
1920 | return 0; | 2079 | return 0; |
1921 | } | 2080 | } |
1922 | 2081 | ||
2082 | struct unmap_block_desc { | ||
2083 | __be64 lba; | ||
2084 | __be32 blocks; | ||
2085 | __be32 __reserved; | ||
2086 | }; | ||
2087 | |||
2088 | static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip) | ||
2089 | { | ||
2090 | unsigned char *buf; | ||
2091 | struct unmap_block_desc *desc; | ||
2092 | unsigned int i, payload_len, descriptors; | ||
2093 | int ret; | ||
2094 | |||
2095 | ret = check_readiness(scmd, 1, devip); | ||
2096 | if (ret) | ||
2097 | return ret; | ||
2098 | |||
2099 | payload_len = get_unaligned_be16(&scmd->cmnd[7]); | ||
2100 | BUG_ON(scsi_bufflen(scmd) != payload_len); | ||
2101 | |||
2102 | descriptors = (payload_len - 8) / 16; | ||
2103 | |||
2104 | buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC); | ||
2105 | if (!buf) | ||
2106 | return check_condition_result; | ||
2107 | |||
2108 | scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd)); | ||
2109 | |||
2110 | BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); | ||
2111 | BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); | ||
2112 | |||
2113 | desc = (void *)&buf[8]; | ||
2114 | |||
2115 | for (i = 0 ; i < descriptors ; i++) { | ||
2116 | unsigned long long lba = get_unaligned_be64(&desc[i].lba); | ||
2117 | unsigned int num = get_unaligned_be32(&desc[i].blocks); | ||
2118 | |||
2119 | ret = check_device_access_params(devip, lba, num); | ||
2120 | if (ret) | ||
2121 | goto out; | ||
2122 | |||
2123 | unmap_region(lba, num); | ||
2124 | } | ||
2125 | |||
2126 | ret = 0; | ||
2127 | |||
2128 | out: | ||
2129 | kfree(buf); | ||
2130 | |||
2131 | return ret; | ||
2132 | } | ||
2133 | |||
2134 | #define SDEBUG_GET_LBA_STATUS_LEN 32 | ||
2135 | |||
2136 | static int resp_get_lba_status(struct scsi_cmnd * scmd, | ||
2137 | struct sdebug_dev_info * devip) | ||
2138 | { | ||
2139 | unsigned long long lba; | ||
2140 | unsigned int alloc_len, mapped, num; | ||
2141 | unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN]; | ||
2142 | int ret; | ||
2143 | |||
2144 | ret = check_readiness(scmd, 1, devip); | ||
2145 | if (ret) | ||
2146 | return ret; | ||
2147 | |||
2148 | lba = get_unaligned_be64(&scmd->cmnd[2]); | ||
2149 | alloc_len = get_unaligned_be32(&scmd->cmnd[10]); | ||
2150 | |||
2151 | if (alloc_len < 24) | ||
2152 | return 0; | ||
2153 | |||
2154 | ret = check_device_access_params(devip, lba, 1); | ||
2155 | if (ret) | ||
2156 | return ret; | ||
2157 | |||
2158 | mapped = map_state(lba, &num); | ||
2159 | |||
2160 | memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); | ||
2161 | put_unaligned_be32(16, &arr[0]); /* Parameter Data Length */ | ||
2162 | put_unaligned_be64(lba, &arr[8]); /* LBA */ | ||
2163 | put_unaligned_be32(num, &arr[16]); /* Number of blocks */ | ||
2164 | arr[20] = !mapped; /* mapped = 0, unmapped = 1 */ | ||
2165 | |||
2166 | return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN); | ||
2167 | } | ||
2168 | |||
1923 | #define SDEBUG_RLUN_ARR_SZ 256 | 2169 | #define SDEBUG_RLUN_ARR_SZ 256 |
1924 | 2170 | ||
1925 | static int resp_report_luns(struct scsi_cmnd * scp, | 2171 | static int resp_report_luns(struct scsi_cmnd * scp, |
@@ -2430,6 +2676,10 @@ module_param_named(guard, scsi_debug_guard, int, S_IRUGO); | |||
2430 | module_param_named(ato, scsi_debug_ato, int, S_IRUGO); | 2676 | module_param_named(ato, scsi_debug_ato, int, S_IRUGO); |
2431 | module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); | 2677 | module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); |
2432 | module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); | 2678 | module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); |
2679 | module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO); | ||
2680 | module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); | ||
2681 | module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); | ||
2682 | module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); | ||
2433 | 2683 | ||
2434 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); | 2684 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); |
2435 | MODULE_DESCRIPTION("SCSI debug adapter driver"); | 2685 | MODULE_DESCRIPTION("SCSI debug adapter driver"); |
@@ -2458,6 +2708,10 @@ MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); | |||
2458 | MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); | 2708 | MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); |
2459 | MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); | 2709 | MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); |
2460 | MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); | 2710 | MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); |
2711 | MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0)"); | ||
2712 | MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=0)"); | ||
2713 | MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=0)"); | ||
2714 | MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); | ||
2461 | 2715 | ||
2462 | static char sdebug_info[256]; | 2716 | static char sdebug_info[256]; |
2463 | 2717 | ||
@@ -2816,6 +3070,23 @@ static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf) | |||
2816 | } | 3070 | } |
2817 | DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL); | 3071 | DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL); |
2818 | 3072 | ||
3073 | static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf) | ||
3074 | { | ||
3075 | ssize_t count; | ||
3076 | |||
3077 | if (scsi_debug_unmap_granularity == 0) | ||
3078 | return scnprintf(buf, PAGE_SIZE, "0-%u\n", | ||
3079 | sdebug_store_sectors); | ||
3080 | |||
3081 | count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size); | ||
3082 | |||
3083 | buf[count++] = '\n'; | ||
3084 | buf[count++] = 0; | ||
3085 | |||
3086 | return count; | ||
3087 | } | ||
3088 | DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL); | ||
3089 | |||
2819 | 3090 | ||
2820 | /* Note: The following function creates attribute files in the | 3091 | /* Note: The following function creates attribute files in the |
2821 | /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these | 3092 | /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these |
@@ -2847,11 +3118,13 @@ static int do_create_driverfs_files(void) | |||
2847 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif); | 3118 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif); |
2848 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard); | 3119 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard); |
2849 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato); | 3120 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato); |
3121 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map); | ||
2850 | return ret; | 3122 | return ret; |
2851 | } | 3123 | } |
2852 | 3124 | ||
2853 | static void do_remove_driverfs_files(void) | 3125 | static void do_remove_driverfs_files(void) |
2854 | { | 3126 | { |
3127 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map); | ||
2855 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato); | 3128 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato); |
2856 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard); | 3129 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard); |
2857 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif); | 3130 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif); |
@@ -2989,6 +3262,36 @@ static int __init scsi_debug_init(void) | |||
2989 | memset(dif_storep, 0xff, dif_size); | 3262 | memset(dif_storep, 0xff, dif_size); |
2990 | } | 3263 | } |
2991 | 3264 | ||
3265 | if (scsi_debug_unmap_granularity) { | ||
3266 | unsigned int map_bytes; | ||
3267 | |||
3268 | if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { | ||
3269 | printk(KERN_ERR | ||
3270 | "%s: ERR: unmap_granularity < unmap_alignment\n", | ||
3271 | __func__); | ||
3272 | return -EINVAL; | ||
3273 | } | ||
3274 | |||
3275 | map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity); | ||
3276 | map_bytes = map_size >> 3; | ||
3277 | map_storep = vmalloc(map_bytes); | ||
3278 | |||
3279 | printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n", | ||
3280 | map_size); | ||
3281 | |||
3282 | if (map_storep == NULL) { | ||
3283 | printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n"); | ||
3284 | ret = -ENOMEM; | ||
3285 | goto free_vm; | ||
3286 | } | ||
3287 | |||
3288 | memset(map_storep, 0x0, map_bytes); | ||
3289 | |||
3290 | /* Map first 1KB for partition table */ | ||
3291 | if (scsi_debug_num_parts) | ||
3292 | map_region(0, 2); | ||
3293 | } | ||
3294 | |||
2992 | ret = device_register(&pseudo_primary); | 3295 | ret = device_register(&pseudo_primary); |
2993 | if (ret < 0) { | 3296 | if (ret < 0) { |
2994 | printk(KERN_WARNING "scsi_debug: device_register error: %d\n", | 3297 | printk(KERN_WARNING "scsi_debug: device_register error: %d\n", |
@@ -3041,6 +3344,8 @@ bus_unreg: | |||
3041 | dev_unreg: | 3344 | dev_unreg: |
3042 | device_unregister(&pseudo_primary); | 3345 | device_unregister(&pseudo_primary); |
3043 | free_vm: | 3346 | free_vm: |
3347 | if (map_storep) | ||
3348 | vfree(map_storep); | ||
3044 | if (dif_storep) | 3349 | if (dif_storep) |
3045 | vfree(dif_storep); | 3350 | vfree(dif_storep); |
3046 | vfree(fake_storep); | 3351 | vfree(fake_storep); |
@@ -3167,6 +3472,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
3167 | int inj_dif = 0; | 3472 | int inj_dif = 0; |
3168 | int inj_dix = 0; | 3473 | int inj_dix = 0; |
3169 | int delay_override = 0; | 3474 | int delay_override = 0; |
3475 | int unmap = 0; | ||
3170 | 3476 | ||
3171 | scsi_set_resid(SCpnt, 0); | 3477 | scsi_set_resid(SCpnt, 0); |
3172 | if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { | 3478 | if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { |
@@ -3272,13 +3578,21 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
3272 | errsts = resp_readcap(SCpnt, devip); | 3578 | errsts = resp_readcap(SCpnt, devip); |
3273 | break; | 3579 | break; |
3274 | case SERVICE_ACTION_IN: | 3580 | case SERVICE_ACTION_IN: |
3275 | if (SAI_READ_CAPACITY_16 != cmd[1]) { | 3581 | if (cmd[1] == SAI_READ_CAPACITY_16) |
3582 | errsts = resp_readcap16(SCpnt, devip); | ||
3583 | else if (cmd[1] == SAI_GET_LBA_STATUS) { | ||
3584 | |||
3585 | if (scsi_debug_unmap_max_desc == 0) { | ||
3586 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
3587 | INVALID_COMMAND_OPCODE, 0); | ||
3588 | errsts = check_condition_result; | ||
3589 | } else | ||
3590 | errsts = resp_get_lba_status(SCpnt, devip); | ||
3591 | } else { | ||
3276 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 3592 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
3277 | INVALID_OPCODE, 0); | 3593 | INVALID_OPCODE, 0); |
3278 | errsts = check_condition_result; | 3594 | errsts = check_condition_result; |
3279 | break; | ||
3280 | } | 3595 | } |
3281 | errsts = resp_readcap16(SCpnt, devip); | ||
3282 | break; | 3596 | break; |
3283 | case MAINTENANCE_IN: | 3597 | case MAINTENANCE_IN: |
3284 | if (MI_REPORT_TARGET_PGS != cmd[1]) { | 3598 | if (MI_REPORT_TARGET_PGS != cmd[1]) { |
@@ -3378,6 +3692,29 @@ write: | |||
3378 | errsts = illegal_condition_result; | 3692 | errsts = illegal_condition_result; |
3379 | } | 3693 | } |
3380 | break; | 3694 | break; |
3695 | case WRITE_SAME_16: | ||
3696 | if (cmd[1] & 0x8) | ||
3697 | unmap = 1; | ||
3698 | /* fall through */ | ||
3699 | case WRITE_SAME: | ||
3700 | errsts = check_readiness(SCpnt, 0, devip); | ||
3701 | if (errsts) | ||
3702 | break; | ||
3703 | get_data_transfer_info(cmd, &lba, &num, &ei_lba); | ||
3704 | errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap); | ||
3705 | break; | ||
3706 | case UNMAP: | ||
3707 | errsts = check_readiness(SCpnt, 0, devip); | ||
3708 | if (errsts) | ||
3709 | break; | ||
3710 | |||
3711 | if (scsi_debug_unmap_max_desc == 0) { | ||
3712 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
3713 | INVALID_COMMAND_OPCODE, 0); | ||
3714 | errsts = check_condition_result; | ||
3715 | } else | ||
3716 | errsts = resp_unmap(SCpnt, devip); | ||
3717 | break; | ||
3381 | case MODE_SENSE: | 3718 | case MODE_SENSE: |
3382 | case MODE_SENSE_10: | 3719 | case MODE_SENSE_10: |
3383 | errsts = resp_mode_sense(SCpnt, target, devip); | 3720 | errsts = resp_mode_sense(SCpnt, target, devip); |