diff options
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 125 |
1 files changed, 77 insertions, 48 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index b02bdc6c2cd1..2c36bae3bd4b 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 | ||
@@ -3207,16 +3226,7 @@ static void do_remove_driverfs_files(void) | |||
3207 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); | 3226 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); |
3208 | } | 3227 | } |
3209 | 3228 | ||
3210 | static void pseudo_0_release(struct device *dev) | 3229 | struct device *pseudo_primary; |
3211 | { | ||
3212 | if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) | ||
3213 | printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); | ||
3214 | } | ||
3215 | |||
3216 | static struct device pseudo_primary = { | ||
3217 | .init_name = "pseudo_0", | ||
3218 | .release = pseudo_0_release, | ||
3219 | }; | ||
3220 | 3230 | ||
3221 | static int __init scsi_debug_init(void) | 3231 | static int __init scsi_debug_init(void) |
3222 | { | 3232 | { |
@@ -3322,10 +3332,21 @@ static int __init scsi_debug_init(void) | |||
3322 | memset(dif_storep, 0xff, dif_size); | 3332 | memset(dif_storep, 0xff, dif_size); |
3323 | } | 3333 | } |
3324 | 3334 | ||
3325 | if (scsi_debug_unmap_granularity) { | 3335 | /* Thin Provisioning */ |
3336 | if (scsi_debug_tpu || scsi_debug_tpws) { | ||
3326 | unsigned int map_bytes; | 3337 | unsigned int map_bytes; |
3327 | 3338 | ||
3328 | if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { | 3339 | scsi_debug_unmap_max_blocks = |
3340 | clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); | ||
3341 | |||
3342 | scsi_debug_unmap_max_desc = | ||
3343 | clamp(scsi_debug_unmap_max_desc, 0U, 256U); | ||
3344 | |||
3345 | scsi_debug_unmap_granularity = | ||
3346 | clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU); | ||
3347 | |||
3348 | if (scsi_debug_unmap_alignment && | ||
3349 | scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { | ||
3329 | printk(KERN_ERR | 3350 | printk(KERN_ERR |
3330 | "%s: ERR: unmap_granularity < unmap_alignment\n", | 3351 | "%s: ERR: unmap_granularity < unmap_alignment\n", |
3331 | __func__); | 3352 | __func__); |
@@ -3352,10 +3373,10 @@ static int __init scsi_debug_init(void) | |||
3352 | map_region(0, 2); | 3373 | map_region(0, 2); |
3353 | } | 3374 | } |
3354 | 3375 | ||
3355 | ret = device_register(&pseudo_primary); | 3376 | pseudo_primary = root_device_register("pseudo_0"); |
3356 | if (ret < 0) { | 3377 | if (IS_ERR(pseudo_primary)) { |
3357 | printk(KERN_WARNING "scsi_debug: device_register error: %d\n", | 3378 | printk(KERN_WARNING "scsi_debug: root_device_register() error\n"); |
3358 | ret); | 3379 | ret = PTR_ERR(pseudo_primary); |
3359 | goto free_vm; | 3380 | goto free_vm; |
3360 | } | 3381 | } |
3361 | ret = bus_register(&pseudo_lld_bus); | 3382 | ret = bus_register(&pseudo_lld_bus); |
@@ -3402,7 +3423,7 @@ del_files: | |||
3402 | bus_unreg: | 3423 | bus_unreg: |
3403 | bus_unregister(&pseudo_lld_bus); | 3424 | bus_unregister(&pseudo_lld_bus); |
3404 | dev_unreg: | 3425 | dev_unreg: |
3405 | device_unregister(&pseudo_primary); | 3426 | root_device_unregister(pseudo_primary); |
3406 | free_vm: | 3427 | free_vm: |
3407 | if (map_storep) | 3428 | if (map_storep) |
3408 | vfree(map_storep); | 3429 | vfree(map_storep); |
@@ -3423,7 +3444,7 @@ static void __exit scsi_debug_exit(void) | |||
3423 | do_remove_driverfs_files(); | 3444 | do_remove_driverfs_files(); |
3424 | driver_unregister(&sdebug_driverfs_driver); | 3445 | driver_unregister(&sdebug_driverfs_driver); |
3425 | bus_unregister(&pseudo_lld_bus); | 3446 | bus_unregister(&pseudo_lld_bus); |
3426 | device_unregister(&pseudo_primary); | 3447 | root_device_unregister(pseudo_primary); |
3427 | 3448 | ||
3428 | if (dif_storep) | 3449 | if (dif_storep) |
3429 | vfree(dif_storep); | 3450 | vfree(dif_storep); |
@@ -3474,7 +3495,7 @@ static int sdebug_add_adapter(void) | |||
3474 | spin_unlock(&sdebug_host_list_lock); | 3495 | spin_unlock(&sdebug_host_list_lock); |
3475 | 3496 | ||
3476 | sdbg_host->dev.bus = &pseudo_lld_bus; | 3497 | sdbg_host->dev.bus = &pseudo_lld_bus; |
3477 | sdbg_host->dev.parent = &pseudo_primary; | 3498 | sdbg_host->dev.parent = pseudo_primary; |
3478 | sdbg_host->dev.release = &sdebug_release_adapter; | 3499 | sdbg_host->dev.release = &sdebug_release_adapter; |
3479 | dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); | 3500 | dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); |
3480 | 3501 | ||
@@ -3642,7 +3663,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) | |||
3642 | errsts = resp_readcap16(SCpnt, devip); | 3663 | errsts = resp_readcap16(SCpnt, devip); |
3643 | else if (cmd[1] == SAI_GET_LBA_STATUS) { | 3664 | else if (cmd[1] == SAI_GET_LBA_STATUS) { |
3644 | 3665 | ||
3645 | if (scsi_debug_unmap_max_desc == 0) { | 3666 | if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) { |
3646 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 3667 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
3647 | INVALID_COMMAND_OPCODE, 0); | 3668 | INVALID_COMMAND_OPCODE, 0); |
3648 | errsts = check_condition_result; | 3669 | errsts = check_condition_result; |
@@ -3753,8 +3774,16 @@ write: | |||
3753 | } | 3774 | } |
3754 | break; | 3775 | break; |
3755 | case WRITE_SAME_16: | 3776 | case WRITE_SAME_16: |
3756 | if (cmd[1] & 0x8) | 3777 | if (cmd[1] & 0x8) { |
3757 | unmap = 1; | 3778 | if (scsi_debug_tpws == 0) { |
3779 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | ||
3780 | INVALID_FIELD_IN_CDB, 0); | ||
3781 | errsts = check_condition_result; | ||
3782 | } else | ||
3783 | unmap = 1; | ||
3784 | } | ||
3785 | if (errsts) | ||
3786 | break; | ||
3758 | /* fall through */ | 3787 | /* fall through */ |
3759 | case WRITE_SAME: | 3788 | case WRITE_SAME: |
3760 | errsts = check_readiness(SCpnt, 0, devip); | 3789 | errsts = check_readiness(SCpnt, 0, devip); |
@@ -3768,7 +3797,7 @@ write: | |||
3768 | if (errsts) | 3797 | if (errsts) |
3769 | break; | 3798 | break; |
3770 | 3799 | ||
3771 | if (scsi_debug_unmap_max_desc == 0) { | 3800 | if (scsi_debug_unmap_max_desc == 0 || scsi_debug_tpu == 0) { |
3772 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 3801 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
3773 | INVALID_COMMAND_OPCODE, 0); | 3802 | INVALID_COMMAND_OPCODE, 0); |
3774 | errsts = check_condition_result; | 3803 | errsts = check_condition_result; |