diff options
-rw-r--r-- | drivers/scsi/scsi_debug.c | 100 |
1 files changed, 69 insertions, 31 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index b02bdc6c2cd..06329d47b38 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -109,10 +109,12 @@ static const char * scsi_debug_version_date = "20100324"; | |||
109 | #define DEF_PHYSBLK_EXP 0 | 109 | #define DEF_PHYSBLK_EXP 0 |
110 | #define DEF_LOWEST_ALIGNED 0 | 110 | #define DEF_LOWEST_ALIGNED 0 |
111 | #define DEF_OPT_BLKS 64 | 111 | #define DEF_OPT_BLKS 64 |
112 | #define DEF_UNMAP_MAX_BLOCKS 0 | 112 | #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF |
113 | #define DEF_UNMAP_MAX_DESC 0 | 113 | #define DEF_UNMAP_MAX_DESC 256 |
114 | #define DEF_UNMAP_GRANULARITY 0 | 114 | #define DEF_UNMAP_GRANULARITY 1 |
115 | #define DEF_UNMAP_ALIGNMENT 0 | 115 | #define DEF_UNMAP_ALIGNMENT 0 |
116 | #define DEF_TPWS 0 | ||
117 | #define DEF_TPU 0 | ||
116 | 118 | ||
117 | /* bit mask values for scsi_debug_opts */ | 119 | /* bit mask values for scsi_debug_opts */ |
118 | #define SCSI_DEBUG_OPT_NOISE 1 | 120 | #define SCSI_DEBUG_OPT_NOISE 1 |
@@ -177,10 +179,12 @@ static int scsi_debug_ato = DEF_ATO; | |||
177 | static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; | 179 | static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; |
178 | static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; | 180 | static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; |
179 | static int scsi_debug_opt_blks = DEF_OPT_BLKS; | 181 | static int scsi_debug_opt_blks = DEF_OPT_BLKS; |
180 | static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; | 182 | static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; |
181 | static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; | 183 | static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; |
182 | static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; | 184 | static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; |
183 | static int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; | 185 | static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; |
186 | static unsigned int scsi_debug_tpws = DEF_TPWS; | ||
187 | static unsigned int scsi_debug_tpu = DEF_TPU; | ||
184 | 188 | ||
185 | static int scsi_debug_cmnd_count = 0; | 189 | static int scsi_debug_cmnd_count = 0; |
186 | 190 | ||
@@ -723,16 +727,9 @@ static int inquiry_evpd_b0(unsigned char * arr) | |||
723 | /* Optimal Transfer Length */ | 727 | /* Optimal Transfer Length */ |
724 | put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); | 728 | put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); |
725 | 729 | ||
726 | if (scsi_debug_unmap_max_desc) { | 730 | if (scsi_debug_tpu) { |
727 | unsigned int blocks; | ||
728 | |||
729 | if (scsi_debug_unmap_max_blocks) | ||
730 | blocks = scsi_debug_unmap_max_blocks; | ||
731 | else | ||
732 | blocks = 0xffffffff; | ||
733 | |||
734 | /* Maximum Unmap LBA Count */ | 731 | /* Maximum Unmap LBA Count */ |
735 | put_unaligned_be32(blocks, &arr[16]); | 732 | put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]); |
736 | 733 | ||
737 | /* Maximum Unmap Block Descriptor Count */ | 734 | /* Maximum Unmap Block Descriptor Count */ |
738 | put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); | 735 | put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); |
@@ -745,10 +742,9 @@ static int inquiry_evpd_b0(unsigned char * arr) | |||
745 | } | 742 | } |
746 | 743 | ||
747 | /* Optimal Unmap Granularity */ | 744 | /* Optimal Unmap Granularity */ |
748 | if (scsi_debug_unmap_granularity) { | 745 | put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); |
749 | put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); | 746 | |
750 | return 0x3c; /* Mandatory page length for thin provisioning */ | 747 | return 0x3c; /* Mandatory page length for thin provisioning */ |
751 | } | ||
752 | 748 | ||
753 | return sizeof(vpdb0_data); | 749 | return sizeof(vpdb0_data); |
754 | } | 750 | } |
@@ -765,6 +761,21 @@ static int inquiry_evpd_b1(unsigned char *arr) | |||
765 | return 0x3c; | 761 | return 0x3c; |
766 | } | 762 | } |
767 | 763 | ||
764 | /* Thin provisioning VPD page (SBC-3) */ | ||
765 | static int inquiry_evpd_b2(unsigned char *arr) | ||
766 | { | ||
767 | memset(arr, 0, 0x8); | ||
768 | arr[0] = 0; /* threshold exponent */ | ||
769 | |||
770 | if (scsi_debug_tpu) | ||
771 | arr[1] = 1 << 7; | ||
772 | |||
773 | if (scsi_debug_tpws) | ||
774 | arr[1] |= 1 << 6; | ||
775 | |||
776 | return 0x8; | ||
777 | } | ||
778 | |||
768 | #define SDEBUG_LONG_INQ_SZ 96 | 779 | #define SDEBUG_LONG_INQ_SZ 96 |
769 | #define SDEBUG_MAX_INQ_ARR_SZ 584 | 780 | #define SDEBUG_MAX_INQ_ARR_SZ 584 |
770 | 781 | ||
@@ -820,6 +831,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
820 | arr[n++] = 0x89; /* ATA information */ | 831 | arr[n++] = 0x89; /* ATA information */ |
821 | arr[n++] = 0xb0; /* Block limits (SBC) */ | 832 | arr[n++] = 0xb0; /* Block limits (SBC) */ |
822 | arr[n++] = 0xb1; /* Block characteristics (SBC) */ | 833 | arr[n++] = 0xb1; /* Block characteristics (SBC) */ |
834 | arr[n++] = 0xb2; /* Thin provisioning (SBC) */ | ||
823 | arr[3] = n - 4; /* number of supported VPD pages */ | 835 | arr[3] = n - 4; /* number of supported VPD pages */ |
824 | } else if (0x80 == cmd[2]) { /* unit serial number */ | 836 | } else if (0x80 == cmd[2]) { /* unit serial number */ |
825 | arr[1] = cmd[2]; /*sanity */ | 837 | arr[1] = cmd[2]; /*sanity */ |
@@ -867,6 +879,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
867 | } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ | 879 | } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ |
868 | arr[1] = cmd[2]; /*sanity */ | 880 | arr[1] = cmd[2]; /*sanity */ |
869 | arr[3] = inquiry_evpd_b1(&arr[4]); | 881 | arr[3] = inquiry_evpd_b1(&arr[4]); |
882 | } else if (0xb2 == cmd[2]) { /* Thin provisioning (SBC) */ | ||
883 | arr[1] = cmd[2]; /*sanity */ | ||
884 | arr[3] = inquiry_evpd_b2(&arr[4]); | ||
870 | } else { | 885 | } else { |
871 | /* Illegal request, invalid field in cdb */ | 886 | /* Illegal request, invalid field in cdb */ |
872 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 887 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
@@ -1038,7 +1053,7 @@ static int resp_readcap16(struct scsi_cmnd * scp, | |||
1038 | arr[13] = scsi_debug_physblk_exp & 0xf; | 1053 | arr[13] = scsi_debug_physblk_exp & 0xf; |
1039 | arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; | 1054 | arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; |
1040 | 1055 | ||
1041 | if (scsi_debug_unmap_granularity) | 1056 | if (scsi_debug_tpu || scsi_debug_tpws) |
1042 | arr[14] |= 0x80; /* TPE */ | 1057 | arr[14] |= 0x80; /* TPE */ |
1043 | 1058 | ||
1044 | arr[15] = scsi_debug_lowest_aligned & 0xff; | 1059 | arr[15] = scsi_debug_lowest_aligned & 0xff; |
@@ -2708,6 +2723,8 @@ module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO); | |||
2708 | module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); | 2723 | module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); |
2709 | module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); | 2724 | module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); |
2710 | module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); | 2725 | module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); |
2726 | module_param_named(tpu, scsi_debug_tpu, int, S_IRUGO); | ||
2727 | module_param_named(tpws, scsi_debug_tpws, int, S_IRUGO); | ||
2711 | 2728 | ||
2712 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); | 2729 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); |
2713 | MODULE_DESCRIPTION("SCSI debug adapter driver"); | 2730 | MODULE_DESCRIPTION("SCSI debug adapter driver"); |
@@ -2739,10 +2756,12 @@ MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); | |||
2739 | MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); | 2756 | MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); |
2740 | MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); | 2757 | MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); |
2741 | MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); | 2758 | MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); |
2742 | MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0)"); | 2759 | MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); |
2743 | MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=0)"); | 2760 | MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); |
2744 | MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=0)"); | 2761 | MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); |
2745 | MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); | 2762 | MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); |
2763 | MODULE_PARM_DESC(tpu, "enable TP, support UNMAP command (def=0)"); | ||
2764 | MODULE_PARM_DESC(tpws, "enable TP, support WRITE SAME(16) with UNMAP bit (def=0)"); | ||
2746 | 2765 | ||
2747 | static char sdebug_info[256]; | 2766 | static char sdebug_info[256]; |
2748 | 2767 | ||
@@ -3130,7 +3149,7 @@ static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf) | |||
3130 | { | 3149 | { |
3131 | ssize_t count; | 3150 | ssize_t count; |
3132 | 3151 | ||
3133 | if (scsi_debug_unmap_granularity == 0) | 3152 | if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) |
3134 | return scnprintf(buf, PAGE_SIZE, "0-%u\n", | 3153 | return scnprintf(buf, PAGE_SIZE, "0-%u\n", |
3135 | sdebug_store_sectors); | 3154 | sdebug_store_sectors); |
3136 | 3155 | ||
@@ -3322,10 +3341,21 @@ static int __init scsi_debug_init(void) | |||
3322 | memset(dif_storep, 0xff, dif_size); | 3341 | memset(dif_storep, 0xff, dif_size); |
3323 | } | 3342 | } |
3324 | 3343 | ||
3325 | if (scsi_debug_unmap_granularity) { | 3344 | /* Thin Provisioning */ |
3345 | if (scsi_debug_tpu || scsi_debug_tpws) { | ||
3326 | unsigned int map_bytes; | 3346 | unsigned int map_bytes; |
3327 | 3347 | ||
3328 | if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { | 3348 | scsi_debug_unmap_max_blocks = |
3349 | clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); | ||
3350 | |||
3351 | scsi_debug_unmap_max_desc = | ||
3352 | clamp(scsi_debug_unmap_max_desc, 0U, 256U); | ||
3353 | |||
3354 | scsi_debug_unmap_granularity = | ||
3355 | clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU); | ||
3356 | |||
3357 | if (scsi_debug_unmap_alignment && | ||
3358 | scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { | ||
3329 | printk(KERN_ERR | 3359 | printk(KERN_ERR |
3330 | "%s: ERR: unmap_granularity < unmap_alignment\n", | 3360 | "%s: ERR: unmap_granularity < unmap_alignment\n", |
3331 | __func__); | 3361 | __func__); |
@@ -3642,7 +3672,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
3642 | errsts = resp_readcap16(SCpnt, devip); | 3672 | errsts = resp_readcap16(SCpnt, devip); |
3643 | else if (cmd[1] == SAI_GET_LBA_STATUS) { | 3673 | else if (cmd[1] == SAI_GET_LBA_STATUS) { |
3644 | 3674 | ||
3645 | if (scsi_debug_unmap_max_desc == 0) { | 3675 | if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) { |
3646 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 3676 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
3647 | INVALID_COMMAND_OPCODE, 0); | 3677 | INVALID_COMMAND_OPCODE, 0); |
3648 | errsts = check_condition_result; | 3678 | errsts = check_condition_result; |
@@ -3753,8 +3783,16 @@ write: | |||
3753 | } | 3783 | } |
3754 | break; | 3784 | break; |
3755 | case WRITE_SAME_16: | 3785 | case WRITE_SAME_16: |
3756 | if (cmd[1] & 0x8) | 3786 | if (cmd[1] & 0x8) { |
3757 | unmap = 1; | 3787 | if (scsi_debug_tpws == 0) { |
3788 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
3789 | INVALID_FIELD_IN_CDB, 0); | ||
3790 | errsts = check_condition_result; | ||
3791 | } else | ||
3792 | unmap = 1; | ||
3793 | } | ||
3794 | if (errsts) | ||
3795 | break; | ||
3758 | /* fall through */ | 3796 | /* fall through */ |
3759 | case WRITE_SAME: | 3797 | case WRITE_SAME: |
3760 | errsts = check_readiness(SCpnt, 0, devip); | 3798 | errsts = check_readiness(SCpnt, 0, devip); |
@@ -3768,7 +3806,7 @@ write: | |||
3768 | if (errsts) | 3806 | if (errsts) |
3769 | break; | 3807 | break; |
3770 | 3808 | ||
3771 | if (scsi_debug_unmap_max_desc == 0) { | 3809 | if (scsi_debug_unmap_max_desc == 0 || scsi_debug_tpu == 0) { |
3772 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 3810 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
3773 | INVALID_COMMAND_OPCODE, 0); | 3811 | INVALID_COMMAND_OPCODE, 0); |
3774 | errsts = check_condition_result; | 3812 | errsts = check_condition_result; |