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