diff options
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 959 |
1 files changed, 610 insertions, 349 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index e97ddf0574c8..0f9ba41e27d8 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -41,6 +41,7 @@ #include <linux/interrupt.h> #include <linux/atomic.h> #include <linux/hrtimer.h> +#include <linux/uuid.h> #include <net/checksum.h> @@ -125,7 +126,7 @@ static const char *sdebug_version_date = "20160430"; #define DEF_PHYSBLK_EXP 0 #define DEF_PTYPE TYPE_DISK #define DEF_REMOVABLE false -#define DEF_SCSI_LEVEL 6 /* INQUIRY, byte2 [6->SPC-4] */ +#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ #define DEF_SECTOR_SIZE 512 #define DEF_UNMAP_ALIGNMENT 0 #define DEF_UNMAP_GRANULARITY 1 @@ -135,6 +136,9 @@ static const char *sdebug_version_date = "20160430"; #define DEF_VPD_USE_HOSTNO 1 #define DEF_WRITESAME_LENGTH 0xFFFF #define DEF_STRICT 0 +#define DEF_STATISTICS false +#define DEF_SUBMIT_QUEUES 1 +#define DEF_UUID_CTL 0 #define JDELAY_OVERRIDDEN -9999 #define SDEBUG_LUN_0_VAL 0 @@ -201,20 +205,17 @@ static const char *sdebug_version_date = "20160430"; * or "peripheral device" addressing (value 0) */ #define SAM2_LUN_ADDRESS_METHOD 0 -/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued - * (for response) at one time. Can be reduced by max_queue option. Command - * responses are not queued when jdelay=0 and ndelay=0. The per-device - * DEF_CMD_PER_LUN can be changed via sysfs: - * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed - * SCSI_DEBUG_CANQUEUE. */ -#define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */ -#define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG) +/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued + * (for response) per submit queue at one time. Can be reduced by max_queue + * option. Command responses are not queued when jdelay=0 and ndelay=0. The + * per-device DEF_CMD_PER_LUN can be changed via sysfs: + * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth + * but cannot exceed SDEBUG_CANQUEUE . + */ +#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ +#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) #define DEF_CMD_PER_LUN 255 -#if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE -#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE" -#endif - #define F_D_IN 1 #define F_D_OUT 2 #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ @@ -242,10 +243,11 @@ struct sdebug_dev_info { unsigned int channel; unsigned int target; u64 lun; + uuid_be lu_name; struct sdebug_host_info *sdbg_host; unsigned long uas_bm[1]; atomic_t num_in_q; - char stopped; /* TODO: should be atomic */ + atomic_t stopped; bool used; }; @@ -262,23 +264,36 @@ struct sdebug_host_info { struct sdebug_defer { struct hrtimer hrt; struct execute_work ew; - int qa_indx; + int sqa_idx; /* index of sdebug_queue array */ + int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ + int issuing_cpu; }; struct sdebug_queued_cmd { - /* in_use flagged by a bit in queued_in_use_bm[] */ + /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue + * instance indicates this slot is in use. + */ struct sdebug_defer *sd_dp; struct scsi_cmnd *a_cmnd; + unsigned int inj_recovered:1; + unsigned int inj_transport:1; + unsigned int inj_dif:1; + unsigned int inj_dix:1; + unsigned int inj_short:1; }; -struct sdebug_scmd_extra_t { - bool inj_recovered; - bool inj_transport; - bool inj_dif; - bool inj_dix; - bool inj_short; +struct sdebug_queue { + struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; + unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; + spinlock_t qc_lock; + atomic_t blocked; /* to temporarily stop more being queued */ }; +static atomic_t sdebug_cmnd_count; /* number of incoming commands */ +static atomic_t sdebug_completions; /* count of deferred completions */ +static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ +static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ + struct opcode_info_t { u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ /* for terminating element */ @@ -326,6 +341,7 @@ enum sdeb_opcode_index { SDEB_I_LAST_ELEMENT = 30, /* keep this last */ }; + static const unsigned char opcode_ind_arr[256] = { /* 0x0; 0x0->0x1f: 6 byte cdbs */ SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, @@ -563,7 +579,7 @@ static int sdebug_fake_rw = DEF_FAKE_RW; static unsigned int sdebug_guard = DEF_GUARD; static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; static int sdebug_max_luns = DEF_MAX_LUNS; -static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE; +static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ static int sdebug_no_lun_0 = DEF_NO_LUN_0; @@ -587,6 +603,7 @@ static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; +static int sdebug_uuid_ctl = DEF_UUID_CTL; static bool sdebug_removable = DEF_REMOVABLE; static bool sdebug_clustering; static bool sdebug_host_lock = DEF_HOST_LOCK; @@ -594,10 +611,8 @@ static bool sdebug_strict = DEF_STRICT; static bool sdebug_any_injecting_opt; static bool sdebug_verbose; static bool have_dif_prot; - -static atomic_t sdebug_cmnd_count; -static atomic_t sdebug_completions; -static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */ +static bool sdebug_statistics = DEF_STATISTICS; +static bool sdebug_mq_active; static unsigned int sdebug_store_sectors; static sector_t sdebug_capacity; /* in sectors */ @@ -625,10 +640,9 @@ static int dix_writes; static int dix_reads; static int dif_errors; -static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; -static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS]; +static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ +static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ -static DEFINE_SPINLOCK(queued_arr_lock); static DEFINE_RWLOCK(atomic_rw); static char sdebug_proc_name[] = MY_NAME; @@ -651,7 +665,11 @@ static const int device_qfull_result = (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; -static inline unsigned int scsi_debug_lbp(void) +/* Only do the extra work involved in logical block provisioning if one or + * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing + * real reads and writes (i.e. not skipping them for speed). + */ +static inline bool scsi_debug_lbp(void) { return 0 == sdebug_fake_rw && (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); @@ -907,15 +925,16 @@ static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, static const char * inq_vendor_id = "Linux "; static const char * inq_product_id = "scsi_debug "; static const char *inq_product_rev = "0186"; /* version less '.' */ -static const u64 naa5_comp_a = 0x5222222000000000ULL; -static const u64 naa5_comp_b = 0x5333333000000000ULL; -static const u64 naa5_comp_c = 0x5111111000000000ULL; +/* Use some locally assigned NAAs for SAS addresses. */ +static const u64 naa3_comp_a = 0x3222222000000000ULL; +static const u64 naa3_comp_b = 0x3333333000000000ULL; +static const u64 naa3_comp_c = 0x3111111000000000ULL; /* Device identification VPD page. Returns number of bytes placed in arr */ -static int inquiry_evpd_83(unsigned char * arr, int port_group_id, - int target_dev_id, int dev_id_num, - const char * dev_id_str, - int dev_id_str_len) +static int inquiry_vpd_83(unsigned char *arr, int port_group_id, + int target_dev_id, int dev_id_num, + const char *dev_id_str, int dev_id_str_len, + const uuid_be *lu_name) { int num, port_a; char b[32]; @@ -932,13 +951,25 @@ static int inquiry_evpd_83(unsigned char * arr, int port_group_id, arr[3] = num; num += 4; if (dev_id_num >= 0) { - /* NAA-5, Logical unit identifier (binary) */ - arr[num++] = 0x1; /* binary (not necessarily sas) */ - arr[num++] = 0x3; /* PIV=0, lu, naa */ - arr[num++] = 0x0; - arr[num++] = 0x8; - put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num); - num += 8; + if (sdebug_uuid_ctl) { + /* Locally assigned UUID */ + arr[num++] = 0x1; /* binary (not necessarily sas) */ + arr[num++] = 0xa; /* PIV=0, lu, naa */ + arr[num++] = 0x0; + arr[num++] = 0x12; + arr[num++] = 0x10; /* uuid type=1, locally assigned */ + arr[num++] = 0x0; + memcpy(arr + num, lu_name, 16); + num += 16; + } else { + /* NAA-3, Logical unit identifier (binary) */ + arr[num++] = 0x1; /* binary (not necessarily sas) */ + arr[num++] = 0x3; /* PIV=0, lu, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); + num += 8; + } /* Target relative port number */ arr[num++] = 0x61; /* proto=sas, binary */ arr[num++] = 0x94; /* PIV=1, target port, rel port */ @@ -949,14 +980,14 @@ static int inquiry_evpd_83(unsigned char * arr, int port_group_id, arr[num++] = 0x0; arr[num++] = 0x1; /* relative port A */ } - /* NAA-5, Target port identifier */ + /* NAA-3, Target port identifier */ arr[num++] = 0x61; /* proto=sas, binary */ arr[num++] = 0x93; /* piv=1, target port, naa */ arr[num++] = 0x0; arr[num++] = 0x8; - put_unaligned_be64(naa5_comp_a + port_a, arr + num); + put_unaligned_be64(naa3_comp_a + port_a, arr + num); num += 8; - /* NAA-5, Target port group identifier */ + /* NAA-3, Target port group identifier */ arr[num++] = 0x61; /* proto=sas, binary */ arr[num++] = 0x95; /* piv=1, target port group id */ arr[num++] = 0x0; @@ -965,19 +996,19 @@ static int inquiry_evpd_83(unsigned char * arr, int port_group_id, arr[num++] = 0; put_unaligned_be16(port_group_id, arr + num); num += 2; - /* NAA-5, Target device identifier */ + /* NAA-3, Target device identifier */ arr[num++] = 0x61; /* proto=sas, binary */ arr[num++] = 0xa3; /* piv=1, target device, naa */ arr[num++] = 0x0; arr[num++] = 0x8; - put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num); + put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); num += 8; /* SCSI name string: Target device identifier */ arr[num++] = 0x63; /* proto=sas, UTF-8 */ arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ arr[num++] = 0x0; arr[num++] = 24; - memcpy(arr + num, "naa.52222220", 12); + memcpy(arr + num, "naa.32222220", 12); num += 12; snprintf(b, sizeof(b), "%08X", target_dev_id); memcpy(arr + num, b, 8); @@ -994,14 +1025,14 @@ static unsigned char vpd84_data[] = { }; /* Software interface identification VPD page */ -static int inquiry_evpd_84(unsigned char * arr) +static int inquiry_vpd_84(unsigned char *arr) { memcpy(arr, vpd84_data, sizeof(vpd84_data)); return sizeof(vpd84_data); } /* Management network addresses VPD page */ -static int inquiry_evpd_85(unsigned char * arr) +static int inquiry_vpd_85(unsigned char *arr) { int num = 0; const char * na1 = "https://www.kernel.org/config"; @@ -1036,7 +1067,7 @@ static int inquiry_evpd_85(unsigned char * arr) } /* SCSI ports VPD page */ -static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) +static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) { int num = 0; int port_a, port_b; @@ -1056,7 +1087,7 @@ static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) arr[num++] = 0x93; /* PIV=1, target port, NAA */ arr[num++] = 0x0; /* reserved */ arr[num++] = 0x8; /* length */ - put_unaligned_be64(naa5_comp_a + port_a, arr + num); + put_unaligned_be64(naa3_comp_a + port_a, arr + num); num += 8; arr[num++] = 0x0; /* reserved */ arr[num++] = 0x0; /* reserved */ @@ -1071,7 +1102,7 @@ static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) arr[num++] = 0x93; /* PIV=1, target port, NAA */ arr[num++] = 0x0; /* reserved */ arr[num++] = 0x8; /* length */ - put_unaligned_be64(naa5_comp_a + port_b, arr + num); + put_unaligned_be64(naa3_comp_a + port_b, arr + num); num += 8; return num; @@ -1123,7 +1154,7 @@ static unsigned char vpd89_data[] = { }; /* ATA Information VPD page */ -static int inquiry_evpd_89(unsigned char * arr) +static int inquiry_vpd_89(unsigned char *arr) { memcpy(arr, vpd89_data, sizeof(vpd89_data)); return sizeof(vpd89_data); @@ -1138,7 +1169,7 @@ static unsigned char vpdb0_data[] = { }; /* Block limits VPD page (SBC-3) */ -static int inquiry_evpd_b0(unsigned char * arr) +static int inquiry_vpd_b0(unsigned char *arr) { unsigned int gran; @@ -1181,7 +1212,7 @@ static int inquiry_evpd_b0(unsigned char * arr) } /* Block device characteristics VPD page (SBC-3) */ -static int inquiry_evpd_b1(unsigned char *arr) +static int inquiry_vpd_b1(unsigned char *arr) { memset(arr, 0, 0x3c); arr[0] = 0; @@ -1192,24 +1223,22 @@ static int inquiry_evpd_b1(unsigned char *arr) return 0x3c; } -/* Logical block provisioning VPD page (SBC-3) */ -static int inquiry_evpd_b2(unsigned char *arr) +/* Logical block provisioning VPD page (SBC-4) */ +static int inquiry_vpd_b2(unsigned char *arr) { memset(arr, 0, 0x4); arr[0] = 0; /* threshold exponent */ - if (sdebug_lbpu) arr[1] = 1 << 7; - if (sdebug_lbpws) arr[1] |= 1 << 6; - if (sdebug_lbpws10) arr[1] |= 1 << 5; - - if (sdebug_lbprz) - arr[1] |= 1 << 2; - + if (sdebug_lbprz && scsi_debug_lbp()) + arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ + /* anc_sup=0; dp=0 (no provisioning group descriptor) */ + /* minimum_percentage=0; provisioning_type=0 (unknown) */ + /* threshold_percentage=0 */ return 0x4; } @@ -1222,12 +1251,13 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) unsigned char * arr; unsigned char *cmd = scp->cmnd; int alloc_len, n, ret; - bool have_wlun; + bool have_wlun, is_disk; alloc_len = get_unaligned_be16(cmd + 3); arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); if (! arr) return DID_REQUEUE << 16; + is_disk = (sdebug_ptype == TYPE_DISK); have_wlun = scsi_is_wlun(scp->device->lun); if (have_wlun) pq_pdt = TYPE_WLUN; /* present, wlun */ @@ -1265,11 +1295,12 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[n++] = 0x86; /* extended inquiry */ arr[n++] = 0x87; /* mode page policy */ arr[n++] = 0x88; /* SCSI ports */ - arr[n++] = 0x89; /* ATA information */ - arr[n++] = 0xb0; /* Block limits (SBC) */ - arr[n++] = 0xb1; /* Block characteristics (SBC) */ - if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */ - arr[n++] = 0xb2; + if (is_disk) { /* SBC only */ + arr[n++] = 0x89; /* ATA information */ + arr[n++] = 0xb0; /* Block limits */ + arr[n++] = 0xb1; /* Block characteristics */ + arr[n++] = 0xb2; /* Logical Block Prov */ + } arr[3] = n - 4; /* number of supported VPD pages */ } else if (0x80 == cmd[2]) { /* unit serial number */ arr[1] = cmd[2]; /*sanity */ @@ -1277,21 +1308,22 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) memcpy(&arr[4], lu_id_str, len); } else if (0x83 == cmd[2]) { /* device identification */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_83(&arr[4], port_group_id, - target_dev_id, lu_id_num, - lu_id_str, len); + arr[3] = inquiry_vpd_83(&arr[4], port_group_id, + target_dev_id, lu_id_num, + lu_id_str, len, + &devip->lu_name); } else if (0x84 == cmd[2]) { /* Software interface ident. */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_84(&arr[4]); + arr[3] = inquiry_vpd_84(&arr[4]); } else if (0x85 == cmd[2]) { /* Management network addresses */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_85(&arr[4]); + arr[3] = inquiry_vpd_85(&arr[4]); } else if (0x86 == cmd[2]) { /* extended inquiry */ arr[1] = cmd[2]; /*sanity */ arr[3] = 0x3c; /* number of following entries */ if (sdebug_dif == SD_DIF_TYPE3_PROTECTION) arr[4] = 0x4; /* SPT: GRD_CHK:1 */ - else if (sdebug_dif) + else if (have_dif_prot) arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ else arr[4] = 0x0; /* no protection stuff */ @@ -1305,20 +1337,20 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[10] = 0x82; /* mlus, per initiator port */ } else if (0x88 == cmd[2]) { /* SCSI Ports */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); - } else if (0x89 == cmd[2]) { /* ATA information */ + arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); + } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */ arr[1] = cmd[2]; /*sanity */ - n = inquiry_evpd_89(&arr[4]); + n = inquiry_vpd_89(&arr[4]); put_unaligned_be16(n, arr + 2); - } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ + } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_b0(&arr[4]); - } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ + arr[3] = inquiry_vpd_b0(&arr[4]); + } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_b1(&arr[4]); - } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */ + arr[3] = inquiry_vpd_b1(&arr[4]); + } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_b2(&arr[4]); + arr[3] = inquiry_vpd_b2(&arr[4]); } else { mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); kfree(arr); @@ -1345,15 +1377,17 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) memcpy(&arr[16], inq_product_id, 16); memcpy(&arr[32], inq_product_rev, 4); /* version descriptors (2 bytes each) follow */ - arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */ - arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */ + put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ + put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ n = 62; - if (sdebug_ptype == TYPE_DISK) { - arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */ - } else if (sdebug_ptype == TYPE_TAPE) { - arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */ - } - arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */ + if (is_disk) { /* SBC-4 no version claimed */ + put_unaligned_be16(0x600, arr + n); + n += 2; + } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ + put_unaligned_be16(0x525, arr + n); + n += 2; + } + put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ ret = fill_from_dev_buffer(scp, arr, min(alloc_len, SDEBUG_LONG_INQ_SZ)); kfree(arr); @@ -1428,16 +1462,15 @@ static int resp_start_stop(struct scsi_cmnd * scp, struct sdebug_dev_info * devip) { unsigned char *cmd = scp->cmnd; - int power_cond, start; + int power_cond, stop; power_cond = (cmd[4] & 0xf0) >> 4; if (power_cond) { mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); return check_condition_result; } - start = cmd[4] & 1; - if (start == devip->stopped) - devip->stopped = !start; + stop = !(cmd[4] & 1); + atomic_xchg(&devip->stopped, stop); return 0; } @@ -1490,13 +1523,17 @@ static int resp_readcap16(struct scsi_cmnd * scp, if (scsi_debug_lbp()) { arr[14] |= 0x80; /* LBPME */ - if (sdebug_lbprz) - arr[14] |= 0x40; /* LBPRZ */ + /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in + * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 + * in the wider field maps to 0 in this field. + */ + if (sdebug_lbprz & 1) /* precisely what the draft requires */ + arr[14] |= 0x40; } arr[15] = sdebug_lowest_aligned & 0xff; - if (sdebug_dif) { + if (have_dif_prot) { arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ arr[12] |= 1; /* PROT_EN */ } @@ -1895,10 +1932,10 @@ static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, }; int port_a, port_b; - put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16); - put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24); - put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64); - put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72); + put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); + put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); + put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); + put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); port_a = target_dev_id + 1; port_b = port_a + 1; memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); @@ -1926,22 +1963,23 @@ static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) static int resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { - unsigned char dbd, llbaa; int pcontrol, pcode, subpcode, bd_len; unsigned char dev_spec; - int alloc_len, msense_6, offset, len, target_dev_id; + int alloc_len, offset, len, target_dev_id; int target = scp->device->id; unsigned char * ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; unsigned char *cmd = scp->cmnd; + bool dbd, llbaa, msense_6, is_disk, bad_pcode; - dbd = !!(cmd[1] & 0x8); + dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ pcontrol = (cmd[2] & 0xc0) >> 6; pcode = cmd[2] & 0x3f; subpcode = cmd[3]; msense_6 = (MODE_SENSE == cmd[0]); - llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); - if ((sdebug_ptype == TYPE_DISK) && (dbd == 0)) + llbaa = msense_6 ? false : !!(cmd[1] & 0x10); + is_disk = (sdebug_ptype == TYPE_DISK); + if (is_disk && !dbd) bd_len = llbaa ? 16 : 8; else bd_len = 0; @@ -1954,7 +1992,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp, target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + (devip->target * 1000) - 3; /* for disks set DPOFUA bit and clear write protect (WP) bit */ - if (sdebug_ptype == TYPE_DISK) + if (is_disk) dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ else dev_spec = 0x0; @@ -1993,6 +2031,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp, mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); return check_condition_result; } + bad_pcode = false; + switch (pcode) { case 0x1: /* Read-Write error recovery page, direct access */ len = resp_err_recov_pg(ap, pcontrol, target); @@ -2003,12 +2043,18 @@ static int resp_mode_sense(struct scsi_cmnd *scp, offset += len; break; case 0x3: /* Format device page, direct access */ - len = resp_format_pg(ap, pcontrol, target); - offset += len; + if (is_disk) { + len = resp_format_pg(ap, pcontrol, target); + offset += len; + } else + bad_pcode = true; break; case 0x8: /* Caching page, direct access */ - len = resp_caching_pg(ap, pcontrol, target); - offset += len; + if (is_disk) { + len = resp_caching_pg(ap, pcontrol, target); + offset += len; + } else + bad_pcode = true; break; case 0xa: /* Control Mode page, all devices */ len = resp_ctrl_m_pg(ap, pcontrol, target); @@ -2037,8 +2083,12 @@ static int resp_mode_sense(struct scsi_cmnd *scp, if ((0 == subpcode) || (0xff == subpcode)) { len = resp_err_recov_pg(ap, pcontrol, target); len += resp_disconnect_pg(ap + len, pcontrol, target); - len += resp_format_pg(ap + len, pcontrol, target); - len += resp_caching_pg(ap + len, pcontrol, target); + if (is_disk) { + len += resp_format_pg(ap + len, pcontrol, + target); + len += resp_caching_pg(ap + len, pcontrol, + target); + } len += resp_ctrl_m_pg(ap + len, pcontrol, target); len += resp_sas_sf_m_pg(ap + len, pcontrol, target); if (0xff == subpcode) { @@ -2047,13 +2097,17 @@ static int resp_mode_sense(struct scsi_cmnd *scp, len += resp_sas_sha_m_spg(ap + len, pcontrol); } len += resp_iec_m_pg(ap + len, pcontrol, target); + offset += len; } else { mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); return check_condition_result; } - offset += len; break; default: + bad_pcode = true; + break; + } + if (bad_pcode) { mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); return check_condition_result; } @@ -2450,6 +2504,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) { u8 *cmd = scp->cmnd; + struct sdebug_queued_cmd *sqcp; u64 lba; u32 num; u32 ei_lba; @@ -2509,11 +2564,14 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) "to DIF device\n"); } if (unlikely(sdebug_any_injecting_opt)) { - struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); + sqcp = (struct sdebug_queued_cmd *)scp->host_scribble; - if (ep->inj_short) - num /= 2; - } + if (sqcp) { + if (sqcp->inj_short) + num /= 2; + } + } else + sqcp = NULL; /* inline check_device_access_params() */ if (unlikely(lba + num > sdebug_capacity)) { @@ -2563,22 +2621,20 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) scsi_in(scp)->resid = scsi_bufflen(scp) - ret; - if (unlikely(sdebug_any_injecting_opt)) { - struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); - - if (ep->inj_recovered) { + if (unlikely(sqcp)) { + if (sqcp->inj_recovered) { mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); return check_condition_result; - } else if (ep->inj_transport) { + } else if (sqcp->inj_transport) { mk_sense_buffer(scp, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO); return check_condition_result; - } else if (ep->inj_dif) { + } else if (sqcp->inj_dif) { /* Logical block guard check failed */ mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); return illegal_condition_result; - } else if (ep->inj_dix) { + } else if (sqcp->inj_dix) { mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); return illegal_condition_result; } @@ -2742,9 +2798,10 @@ static void unmap_region(sector_t lba, unsigned int len) lba + sdebug_unmap_granularity <= end && index < map_size) { clear_bit(index, map_storep); - if (sdebug_lbprz) { + if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ memset(fake_storep + - lba * sdebug_sector_size, 0, + lba * sdebug_sector_size, + (sdebug_lbprz & 1) ? 0 : 0xff, sdebug_sector_size * sdebug_unmap_granularity); } @@ -2851,25 +2908,29 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) write_unlock_irqrestore(&atomic_rw, iflags); if (unlikely(-1 == ret)) return DID_ERROR << 16; - else if (sdebug_verbose && (ret < (num * sdebug_sector_size))) + else if (unlikely(sdebug_verbose && + (ret < (num * sdebug_sector_size)))) sdev_printk(KERN_INFO, scp->device, "%s: write: cdb indicated=%u, IO sent=%d bytes\n", my_name, num * sdebug_sector_size, ret); if (unlikely(sdebug_any_injecting_opt)) { - struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); + struct sdebug_queued_cmd *sqcp = + (struct sdebug_queued_cmd *)scp->host_scribble; - if (ep->inj_recovered) { - mk_sense_buffer(scp, RECOVERED_ERROR, - THRESHOLD_EXCEEDED, 0); - return check_condition_result; - } else if (ep->inj_dif) { - /* Logical block guard check failed */ - mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); - return illegal_condition_result; - } else if (ep->inj_dix) { - mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); - return illegal_condition_result; + if (sqcp) { + if (sqcp->inj_recovered) { + mk_sense_buffer(scp, RECOVERED_ERROR, + THRESHOLD_EXCEEDED, 0); + return check_condition_result; + } else if (sqcp->inj_dif) { + /* Logical block guard check failed */ + mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); + return illegal_condition_result; + } else if (sqcp->inj_dix) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); + return illegal_condition_result; + } } } return 0; @@ -3360,28 +3421,53 @@ static int resp_xdwriteread_10(struct scsi_cmnd *scp, return resp_xdwriteread(scp, lba, num, devip); } -/* Queued command completions converge here. */ +static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) +{ + struct sdebug_queue *sqp = sdebug_q_arr; + + if (sdebug_mq_active) { + u32 tag = blk_mq_unique_tag(cmnd->request); + u16 hwq = blk_mq_unique_tag_to_hwq(tag); + + if (unlikely(hwq >= submit_queues)) { + pr_warn("Unexpected hwq=%d, apply modulo\n", hwq); + hwq %= submit_queues; + } + pr_debug("tag=%u, hwq=%d\n", tag, hwq); + return sqp + hwq; + } else + return sqp; +} + +/* Queued (deferred) command completions converge here. */ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) { - int qa_indx; + int qc_idx; int retiring = 0; unsigned long iflags; + struct sdebug_queue *sqp; struct sdebug_queued_cmd *sqcp; struct scsi_cmnd *scp; struct sdebug_dev_info *devip; - atomic_inc(&sdebug_completions); - qa_indx = sd_dp->qa_indx; - if (unlikely((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE))) { - pr_err("wild qa_indx=%d\n", qa_indx); + qc_idx = sd_dp->qc_idx; + sqp = sdebug_q_arr + sd_dp->sqa_idx; + if (sdebug_statistics) { + atomic_inc(&sdebug_completions); + if (raw_smp_processor_id() != sd_dp->issuing_cpu) + atomic_inc(&sdebug_miss_cpus); + } + if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { + pr_err("wild qc_idx=%d\n", qc_idx); return; } - spin_lock_irqsave(&queued_arr_lock, iflags); - sqcp = &queued_arr[qa_indx]; + spin_lock_irqsave(&sqp->qc_lock, iflags); + sqcp = &sqp->qc_arr[qc_idx]; scp = sqcp->a_cmnd; if (unlikely(scp == NULL)) { - spin_unlock_irqrestore(&queued_arr_lock, iflags); - pr_err("scp is NULL\n"); + spin_unlock_irqrestore(&sqp->qc_lock, iflags); + pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n", + sd_dp->sqa_idx, qc_idx); return; } devip = (struct sdebug_dev_info *)scp->device->hostdata; @@ -3393,8 +3479,8 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) retiring = 1; sqcp->a_cmnd = NULL; - if (unlikely(!test_and_clear_bit(qa_indx, queued_in_use_bm))) { - spin_unlock_irqrestore(&queued_arr_lock, iflags); + if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { + spin_unlock_irqrestore(&sqp->qc_lock, iflags); pr_err("Unexpected completion\n"); return; } @@ -3403,18 +3489,18 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) int k, retval; retval = atomic_read(&retired_max_queue); - if (qa_indx >= retval) { - spin_unlock_irqrestore(&queued_arr_lock, iflags); + if (qc_idx >= retval) { + spin_unlock_irqrestore(&sqp->qc_lock, iflags); pr_err("index %d too large\n", retval); return; } - k = find_last_bit(queued_in_use_bm, retval); + k = find_last_bit(sqp->in_use_bm, retval); if ((k < sdebug_max_queue) || (k == retval)) atomic_set(&retired_max_queue, 0); else atomic_set(&retired_max_queue, k + 1); } - spin_unlock_irqrestore(&queued_arr_lock, iflags); + spin_unlock_irqrestore(&sqp->qc_lock, iflags); scp->scsi_done(scp); /* callback to mid level */ } @@ -3435,6 +3521,9 @@ static void sdebug_q_cmd_wq_complete(struct work_struct *work) sdebug_q_cmd_complete(sd_dp); } +static bool got_shared_uuid; +static uuid_be shared_uuid; + static struct sdebug_dev_info *sdebug_device_create( struct sdebug_host_info *sdbg_host, gfp_t flags) { @@ -3442,6 +3531,17 @@ static struct sdebug_dev_info *sdebug_device_create( devip = kzalloc(sizeof(*devip), flags); if (devip) { + if (sdebug_uuid_ctl == 1) + uuid_be_gen(&devip->lu_name); + else if (sdebug_uuid_ctl == 2) { + if (got_shared_uuid) + devip->lu_name = shared_uuid; + else { + uuid_be_gen(&shared_uuid); + got_shared_uuid = true; + devip->lu_name = shared_uuid; + } + } devip->sdbg_host = sdbg_host; list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); } @@ -3533,47 +3633,53 @@ static void scsi_debug_slave_destroy(struct scsi_device *sdp) } } +static void stop_qc_helper(struct sdebug_defer *sd_dp) +{ + if (!sd_dp) + return; + if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) + hrtimer_cancel(&sd_dp->hrt); + else if (sdebug_jdelay < 0) + cancel_work_sync(&sd_dp->ew.work); +} + /* If @cmnd found deletes its timer or work queue and returns true; else returns false */ static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) { unsigned long iflags; - int k, qmax, r_qmax; + int j, k, qmax, r_qmax; + struct sdebug_queue *sqp; struct sdebug_queued_cmd *sqcp; struct sdebug_dev_info *devip; struct sdebug_defer *sd_dp; - spin_lock_irqsave(&queued_arr_lock, iflags); - qmax = sdebug_max_queue; - r_qmax = atomic_read(&retired_max_queue); - if (r_qmax > qmax) - qmax = r_qmax; - for (k = 0; k < qmax; ++k) { - if (test_bit(k, queued_in_use_bm)) { - sqcp = &queued_arr[k]; - if (cmnd != sqcp->a_cmnd) - continue; - /* found command */ - devip = (struct sdebug_dev_info *) - cmnd->device->hostdata; - if (devip) - atomic_dec(&devip->num_in_q); - sqcp->a_cmnd = NULL; - sd_dp = sqcp->sd_dp; - spin_unlock_irqrestore(&queued_arr_lock, - iflags); - if (sdebug_jdelay > 0 || sdebug_ndelay > 0) { - if (sd_dp) - hrtimer_cancel(&sd_dp->hrt); - } else if (sdebug_jdelay < 0) { - if (sd_dp) - cancel_work_sync(&sd_dp->ew.work); + for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { + spin_lock_irqsave(&sqp->qc_lock, iflags); + qmax = sdebug_max_queue; + r_qmax = atomic_read(&retired_max_queue); + if (r_qmax > qmax) + qmax = r_qmax; + for (k = 0; k < qmax; ++k) { + if (test_bit(k, sqp->in_use_bm)) { + sqcp = &sqp->qc_arr[k]; + if (cmnd != sqcp->a_cmnd) + continue; + /* found */ + devip = (struct sdebug_dev_info *) + cmnd->device->hostdata; + if (devip) + atomic_dec(&devip->num_in_q); + sqcp->a_cmnd = NULL; + sd_dp = sqcp->sd_dp; + spin_unlock_irqrestore(&sqp->qc_lock, iflags); + stop_qc_helper(sd_dp); + clear_bit(k, sqp->in_use_bm); + return true; } - clear_bit(k, queued_in_use_bm); - return true; } + spin_unlock_irqrestore(&sqp->qc_lock, iflags); } - spin_unlock_irqrestore(&queued_arr_lock, iflags); return false; } @@ -3581,48 +3687,48 @@ static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) static void stop_all_queued(void) { unsigned long iflags; - int k; + int j, k; + struct sdebug_queue *sqp; struct sdebug_queued_cmd *sqcp; struct sdebug_dev_info *devip; struct sdebug_defer *sd_dp; - spin_lock_irqsave(&queued_arr_lock, iflags); - for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { - if (test_bit(k, queued_in_use_bm)) { - sqcp = &queued_arr[k]; - if (NULL == sqcp->a_cmnd) - continue; - devip = (struct sdebug_dev_info *) - sqcp->a_cmnd->device->hostdata; - if (devip) - atomic_dec(&devip->num_in_q); - sqcp->a_cmnd = NULL; - sd_dp = sqcp->sd_dp; - spin_unlock_irqrestore(&queued_arr_lock, iflags); - if (sdebug_jdelay > 0 || sdebug_ndelay > 0) { - if (sd_dp) - hrtimer_cancel(&sd_dp->hrt); - } else if (sdebug_jdelay < 0) { - if (sd_dp) - cancel_work_sync(&sd_dp->ew.work); + for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { + spin_lock_irqsave(&sqp->qc_lock, iflags); + for (k = 0; k < SDEBUG_CANQUEUE; ++k) { + if (test_bit(k, sqp->in_use_bm)) { + sqcp = &sqp->qc_arr[k]; + if (sqcp->a_cmnd == NULL) + continue; + devip = (struct sdebug_dev_info *) + sqcp->a_cmnd->device->hostdata; + if (devip) + atomic_dec(&devip->num_in_q); + sqcp->a_cmnd = NULL; + sd_dp = sqcp->sd_dp; + spin_unlock_irqrestore(&sqp->qc_lock, iflags); + stop_qc_helper(sd_dp); + clear_bit(k, sqp->in_use_bm); + spin_lock_irqsave(&sqp->qc_lock, iflags); } - clear_bit(k, queued_in_use_bm); - spin_lock_irqsave(&queued_arr_lock, iflags); } + spin_unlock_irqrestore(&sqp->qc_lock, iflags); } - spin_unlock_irqrestore(&queued_arr_lock, iflags); } /* Free queued command memory on heap */ static void free_all_queued(void) { - int k; + int j, k; + struct sdebug_queue *sqp; struct sdebug_queued_cmd *sqcp; - for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { - sqcp = &queued_arr[k]; - kfree(sqcp->sd_dp); - sqcp->sd_dp = NULL; + for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { + for (k = 0; k < SDEBUG_CANQUEUE; ++k) { + sqcp = &sqp->qc_arr[k]; + kfree(sqcp->sd_dp); + sqcp->sd_dp = NULL; + } } } @@ -3801,24 +3907,71 @@ static void __init sdebug_build_parts(unsigned char *ramp, } } +static void block_unblock_all_queues(bool block) +{ + int j; + struct sdebug_queue *sqp; + + for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) + atomic_set(&sqp->blocked, (int)block); +} + +/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 + * commands will be processed normally before triggers occur. + */ +static void tweak_cmnd_count(void) +{ + int count, modulo; + + modulo = abs(sdebug_every_nth); + if (modulo < 2) + return; + block_unblock_all_queues(true); + count = atomic_read(&sdebug_cmnd_count); + atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); + block_unblock_all_queues(false); +} + +static void clear_queue_stats(void) +{ + atomic_set(&sdebug_cmnd_count, 0); + atomic_set(&sdebug_completions, 0); + atomic_set(&sdebug_miss_cpus, 0); + atomic_set(&sdebug_a_tsf, 0); +} + +static void setup_inject(struct sdebug_queue *sqp, + struct sdebug_queued_cmd *sqcp) +{ + if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) + return; + sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts); + sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts); + sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts); + sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts); + sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts); +} + +/* Complete the processing of the thread that queued a SCSI command to this + * driver. It either completes the command by calling cmnd_done() or + * schedules a hr timer or work queue then returns 0. Returns + * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. + */ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, int scsi_result, int delta_jiff) { unsigned long iflags; int k, num_in_q, qdepth, inject; - struct sdebug_queued_cmd *sqcp = NULL; + struct sdebug_queue *sqp; + struct sdebug_queued_cmd *sqcp; struct scsi_device *sdp; struct sdebug_defer *sd_dp; - if (unlikely(WARN_ON(!cmnd))) - return SCSI_MLQUEUE_HOST_BUSY; - if (unlikely(devip == NULL)) { if (scsi_result == 0) scsi_result = DID_NO_CONNECT << 16; goto respond_in_thread; } - sdp = cmnd->device; if (unlikely(sdebug_verbose && scsi_result)) @@ -3828,17 +3981,22 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, goto respond_in_thread; /* schedule the response at a later time if resources permit */ - spin_lock_irqsave(&queued_arr_lock, iflags); + sqp = get_queue(cmnd); + spin_lock_irqsave(&sqp->qc_lock, iflags); + if (unlikely(atomic_read(&sqp->blocked))) { + spin_unlock_irqrestore(&sqp->qc_lock, iflags); + return SCSI_MLQUEUE_HOST_BUSY; + } num_in_q = atomic_read(&devip->num_in_q); qdepth = cmnd->device->queue_depth; inject = 0; if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { if (scsi_result) { - spin_unlock_irqrestore(&queued_arr_lock, iflags); + spin_unlock_irqrestore(&sqp->qc_lock, iflags); goto respond_in_thread; } else scsi_result = device_qfull_result; - } else if (unlikely((sdebug_every_nth != 0) && + } else if (unlikely(sdebug_every_nth && (SDEBUG_OPT_RARE_TSF & sdebug_opts) && (scsi_result == 0))) { if ((num_in_q == (qdepth - 1)) && @@ -3850,9 +4008,9 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, } } - k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue); + k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); if (unlikely(k >= sdebug_max_queue)) { - spin_unlock_irqrestore(&queued_arr_lock, iflags); + spin_unlock_irqrestore(&sqp->qc_lock, iflags); if (scsi_result) goto respond_in_thread; else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) @@ -3868,13 +4026,16 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, else return SCSI_MLQUEUE_HOST_BUSY; } - __set_bit(k, queued_in_use_bm); + __set_bit(k, sqp->in_use_bm); atomic_inc(&devip->num_in_q); - sqcp = &queued_arr[k]; + sqcp = &sqp->qc_arr[k]; sqcp->a_cmnd = cmnd; + cmnd->host_scribble = (unsigned char *)sqcp; cmnd->result = scsi_result; - spin_unlock_irqrestore(&queued_arr_lock, iflags); sd_dp = sqcp->sd_dp; + spin_unlock_irqrestore(&sqp->qc_lock, iflags); + if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt)) + setup_inject(sqp, sqcp); if (delta_jiff > 0 || sdebug_ndelay > 0) { ktime_t kt; @@ -3891,20 +4052,26 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, return SCSI_MLQUEUE_HOST_BUSY; sqcp->sd_dp = sd_dp; hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); + HRTIMER_MODE_REL_PINNED); sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; - sd_dp->qa_indx = k; + sd_dp->sqa_idx = sqp - sdebug_q_arr; + sd_dp->qc_idx = k; } - hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL); - } else { /* jdelay < 0 */ + if (sdebug_statistics) + sd_dp->issuing_cpu = raw_smp_processor_id(); + hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); + } else { /* jdelay < 0, use work queue */ if (NULL == sd_dp) { sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC); if (NULL == sd_dp) return SCSI_MLQUEUE_HOST_BUSY; sqcp->sd_dp = sd_dp; - sd_dp->qa_indx = k; + sd_dp->sqa_idx = sqp - sdebug_q_arr; + sd_dp->qc_idx = k; INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); } + if (sdebug_statistics) + sd_dp->issuing_cpu = raw_smp_processor_id(); schedule_work(&sd_dp->ew.work); } if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && @@ -3958,12 +4125,15 @@ module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); +module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); +module_param_named(submit_queues, submit_queues, int, S_IRUGO); module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); +module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, S_IRUGO | S_IWUSR); module_param_named(write_same_length, sdebug_write_same_length, int, @@ -3989,7 +4159,8 @@ MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); -MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)"); +MODULE_PARM_DESC(lbprz, + "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); @@ -4003,25 +4174,36 @@ MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); -MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])"); +MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); +MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); +MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); +MODULE_PARM_DESC(uuid_ctl, + "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); -static char sdebug_info[256]; +#define SDEBUG_INFO_LEN 256 +static char sdebug_info[SDEBUG_INFO_LEN]; static const char * scsi_debug_info(struct Scsi_Host * shp) { - sprintf(sdebug_info, - "scsi_debug, version %s [%s], dev_size_mb=%d, opts=0x%x", - SDEBUG_VERSION, sdebug_version_date, sdebug_dev_size_mb, - sdebug_opts); + int k; + + k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", + my_name, SDEBUG_VERSION, sdebug_version_date); + if (k >= (SDEBUG_INFO_LEN - 1)) + return sdebug_info; + scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, + " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", + sdebug_dev_size_mb, sdebug_opts, submit_queues, + "statistics", (int)sdebug_statistics); return sdebug_info; } @@ -4043,7 +4225,7 @@ static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); if (sdebug_every_nth != 0) - atomic_set(&sdebug_cmnd_count, 0); + tweak_cmnd_count(); return length; } @@ -4052,39 +4234,43 @@ static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, * output are not atomics so might be inaccurate in a busy system. */ static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) { - int f, l; - char b[32]; - - if (sdebug_every_nth > 0) - snprintf(b, sizeof(b), " (curr:%d)", - ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ? - atomic_read(&sdebug_a_tsf) : - atomic_read(&sdebug_cmnd_count))); - else - b[0] = '\0'; - - seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n" - "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " - "every_nth=%d%s\n" - "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n" - "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" - "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, " - "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d " - "usec_in_jiffy=%lu\n", - SDEBUG_VERSION, sdebug_version_date, - sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts, - sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay, - sdebug_max_luns, atomic_read(&sdebug_completions), - sdebug_sector_size, sdebug_cylinders_per, sdebug_heads, - sdebug_sectors_per, num_aborts, num_dev_resets, - num_target_resets, num_bus_resets, num_host_resets, - dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000); - - f = find_first_bit(queued_in_use_bm, sdebug_max_queue); - if (f != sdebug_max_queue) { - l = find_last_bit(queued_in_use_bm, sdebug_max_queue); - seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n", - "queued_in_use_bm", f, l); + int f, j, l; + struct sdebug_queue *sqp; + + seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", + SDEBUG_VERSION, sdebug_version_date); + seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", + sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, + sdebug_opts, sdebug_every_nth); + seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", + sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, + sdebug_sector_size, "bytes"); + seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", + sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, + num_aborts); + seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", + num_dev_resets, num_target_resets, num_bus_resets, + num_host_resets); + seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", + dix_reads, dix_writes, dif_errors); + seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n", + TICK_NSEC / 1000, "statistics", sdebug_statistics, + sdebug_mq_active); + seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n", + atomic_read(&sdebug_cmnd_count), + atomic_read(&sdebug_completions), + "miss_cpus", atomic_read(&sdebug_miss_cpus), + atomic_read(&sdebug_a_tsf)); + + seq_printf(m, "submit_queues=%d\n", submit_queues); + for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { + seq_printf(m, " queue %d:\n", j); + f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); + if (f != sdebug_max_queue) { + l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); + seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", + "first,last bits", f, l); + } } return 0; } @@ -4093,7 +4279,9 @@ static ssize_t delay_show(struct device_driver *ddp, char *buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); } -/* Returns -EBUSY if jdelay is being changed and commands are queued */ +/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit + * of delay is jiffies. + */ static ssize_t delay_store(struct device_driver *ddp, const char *buf, size_t count) { @@ -4102,21 +4290,27 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf, if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { res = count; if (sdebug_jdelay != jdelay) { - unsigned long iflags; - int k; - - spin_lock_irqsave(&queued_arr_lock, iflags); - k = find_first_bit(queued_in_use_bm, sdebug_max_queue); - if (k != sdebug_max_queue) - res = -EBUSY; /* have queued commands */ - else { + int j, k; + struct sdebug_queue *sqp; + + block_unblock_all_queues(true); + for (j = 0, sqp = sdebug_q_arr; j < submit_queues; + ++j, ++sqp) { + k = find_first_bit(sqp->in_use_bm, + sdebug_max_queue); + if (k != sdebug_max_queue) { + res = -EBUSY; /* queued commands */ + break; + } + } + if (res > 0) { /* make sure sdebug_defer instances get * re-allocated for new delay variant */ free_all_queued(); sdebug_jdelay = jdelay; sdebug_ndelay = 0; } - spin_unlock_irqrestore(&queued_arr_lock, iflags); + block_unblock_all_queues(false); } return res; } @@ -4133,18 +4327,26 @@ static ssize_t ndelay_show(struct device_driver *ddp, char *buf) static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, size_t count) { - unsigned long iflags; - int ndelay, res, k; + int ndelay, res; if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && - (ndelay >= 0) && (ndelay < 1000000000)) { + (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { res = count; if (sdebug_ndelay != ndelay) { - spin_lock_irqsave(&queued_arr_lock, iflags); - k = find_first_bit(queued_in_use_bm, sdebug_max_queue); - if (k != sdebug_max_queue) - res = -EBUSY; /* have queued commands */ - else { + int j, k; + struct sdebug_queue *sqp; + + block_unblock_all_queues(true); + for (j = 0, sqp = sdebug_q_arr; j < submit_queues; + ++j, ++sqp) { + k = find_first_bit(sqp->in_use_bm, + sdebug_max_queue); + if (k != sdebug_max_queue) { + res = -EBUSY; /* queued commands */ + break; + } + } + if (res > 0) { /* make sure sdebug_defer instances get * re-allocated for new delay variant */ free_all_queued(); @@ -4152,7 +4354,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN : DEF_JDELAY; } - spin_unlock_irqrestore(&queued_arr_lock, iflags); + block_unblock_all_queues(false); } return res; } @@ -4185,8 +4387,7 @@ opts_done: sdebug_opts = opts; sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); - atomic_set(&sdebug_cmnd_count, 0); - atomic_set(&sdebug_a_tsf, 0); + tweak_cmnd_count(); return count; } static DRIVER_ATTR_RW(opts); @@ -4316,7 +4517,11 @@ static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { sdebug_every_nth = nth; - atomic_set(&sdebug_cmnd_count, 0); + if (nth && !sdebug_statistics) { + pr_info("every_nth needs statistics=1, set it\n"); + sdebug_statistics = true; + } + tweak_cmnd_count(); return count; } return -EINVAL; @@ -4371,21 +4576,27 @@ static ssize_t max_queue_show(struct device_driver *ddp, char *buf) static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, size_t count) { - unsigned long iflags; - int n, k; + int j, n, k, a; + struct sdebug_queue *sqp; if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && - (n <= SCSI_DEBUG_CANQUEUE)) { - spin_lock_irqsave(&queued_arr_lock, iflags); - k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE); + (n <= SDEBUG_CANQUEUE)) { + block_unblock_all_queues(true); + k = 0; + for (j = 0, sqp = sdebug_q_arr; j < submit_queues; + ++j, ++sqp) { + a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); + if (a > k) + k = a; + } sdebug_max_queue = n; - if (SCSI_DEBUG_CANQUEUE == k) + if (k == SDEBUG_CANQUEUE) atomic_set(&retired_max_queue, 0); else if (k >= n) atomic_set(&retired_max_queue, k + 1); else atomic_set(&retired_max_queue, 0); - spin_unlock_irqrestore(&queued_arr_lock, iflags); + block_unblock_all_queues(false); return count; } return -EINVAL; @@ -4484,12 +4695,40 @@ static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, } static DRIVER_ATTR_RW(vpd_use_hostno); +static ssize_t statistics_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); +} +static ssize_t statistics_store(struct device_driver *ddp, const char *buf, + size_t count) +{ + int n; + + if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { + if (n > 0) + sdebug_statistics = true; + else { + clear_queue_stats(); + sdebug_statistics = false; + } + return count; + } + return -EINVAL; +} +static DRIVER_ATTR_RW(statistics); + static ssize_t sector_size_show(struct device_driver *ddp, char *buf) { return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); } static DRIVER_ATTR_RO(sector_size); +static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); +} +static DRIVER_ATTR_RO(submit_queues); + static ssize_t dix_show(struct device_driver *ddp, char *buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); @@ -4583,6 +4822,12 @@ static ssize_t strict_store(struct device_driver *ddp, const char *buf, } static DRIVER_ATTR_RW(strict); +static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); +} +static DRIVER_ATTR_RO(uuid_ctl); + /* Note: The following array creates attribute files in the /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these @@ -4610,6 +4855,8 @@ static struct attribute *sdebug_drv_attrs[] = { &driver_attr_add_host.attr, &driver_attr_vpd_use_hostno.attr, &driver_attr_sector_size.attr, + &driver_attr_statistics.attr, + &driver_attr_submit_queues.attr, &driver_attr_dix.attr, &driver_attr_dif.attr, &driver_attr_guard.attr, @@ -4619,6 +4866,7 @@ static struct attribute *sdebug_drv_attrs[] = { &driver_attr_host_lock.attr, &driver_attr_ndelay.attr, &driver_attr_strict.attr, + &driver_attr_uuid_ctl.attr, NULL, }; ATTRIBUTE_GROUPS(sdebug_drv); @@ -4632,8 +4880,6 @@ static int __init scsi_debug_init(void) int k; int ret; - atomic_set(&sdebug_cmnd_count, 0); - atomic_set(&sdebug_completions, 0); atomic_set(&retired_max_queue, 0); if (sdebug_ndelay >= 1000 * 1000 * 1000) { @@ -4692,6 +4938,17 @@ static int __init scsi_debug_init(void) return -EINVAL; } + if (submit_queues < 1) { + pr_err("submit_queues must be 1 or more\n"); + return -EINVAL; + } + sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), + GFP_KERNEL); + if (sdebug_q_arr == NULL) + return -ENOMEM; + for (k = 0; k < submit_queues; ++k) + spin_lock_init(&sdebug_q_arr[k].qc_lock); + if (sdebug_dev_size_mb < 1) sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ sz = (unsigned long)sdebug_dev_size_mb * 1048576; @@ -4719,7 +4976,8 @@ static int __init scsi_debug_init(void) fake_storep = vmalloc(sz); if (NULL == fake_storep) { pr_err("out of memory, 1\n"); - return -ENOMEM; + ret = -ENOMEM; + goto free_q_arr; } memset(fake_storep, 0, sz); if (sdebug_num_parts > 0) @@ -4758,7 +5016,8 @@ static int __init scsi_debug_init(void) sdebug_unmap_granularity <= sdebug_unmap_alignment) { pr_err("ERR: unmap_granularity <= unmap_alignment\n"); - return -EINVAL; + ret = -EINVAL; + goto free_vm; } map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; @@ -4819,7 +5078,8 @@ free_vm: vfree(map_storep); vfree(dif_storep); vfree(fake_storep); - +free_q_arr: + kfree(sdebug_q_arr); return ret; } @@ -4837,6 +5097,7 @@ static void __exit scsi_debug_exit(void) vfree(dif_storep); vfree(fake_storep); + kfree(sdebug_q_arr); } device_initcall(scsi_debug_init); @@ -4925,62 +5186,43 @@ static void sdebug_remove_adapter(void) static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) { int num_in_q = 0; - unsigned long iflags; struct sdebug_dev_info *devip; - spin_lock_irqsave(&queued_arr_lock, iflags); + block_unblock_all_queues(true); devip = (struct sdebug_dev_info *)sdev->hostdata; if (NULL == devip) { - spin_unlock_irqrestore(&queued_arr_lock, iflags); + block_unblock_all_queues(false); return -ENODEV; } num_in_q = atomic_read(&devip->num_in_q); - spin_unlock_irqrestore(&queued_arr_lock, iflags); if (qdepth < 1) qdepth = 1; - /* allow to exceed max host queued_arr elements for testing */ - if (qdepth > SCSI_DEBUG_CANQUEUE + 10) - qdepth = SCSI_DEBUG_CANQUEUE + 10; + /* allow to exceed max host qc_arr elements for testing */ + if (qdepth > SDEBUG_CANQUEUE + 10) + qdepth = SDEBUG_CANQUEUE + 10; scsi_change_queue_depth(sdev, qdepth); if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { - sdev_printk(KERN_INFO, sdev, - "%s: qdepth=%d, num_in_q=%d\n", + sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", __func__, qdepth, num_in_q); } + block_unblock_all_queues(false); return sdev->queue_depth; } -static int check_inject(struct scsi_cmnd *scp) +static bool fake_timeout(struct scsi_cmnd *scp) { - struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); - - memset(ep, 0, sizeof(struct sdebug_scmd_extra_t)); - - if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) { - atomic_set(&sdebug_cmnd_count, 0); + if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { if (sdebug_every_nth < -1) sdebug_every_nth = -1; if (SDEBUG_OPT_TIMEOUT & sdebug_opts) - return 1; /* ignore command causing timeout */ + return true; /* ignore command causing timeout */ else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && scsi_medium_access_command(scp)) - return 1; /* time out reads and writes */ - if (sdebug_any_injecting_opt) { - if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts) - ep->inj_recovered = true; - if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts) - ep->inj_transport = true; - if (SDEBUG_OPT_DIF_ERR & sdebug_opts) - ep->inj_dif = true; - if (SDEBUG_OPT_DIX_ERR & sdebug_opts) - ep->inj_dix = true; - if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts) - ep->inj_short = true; - } + return true; /* time out reads and writes */ } - return 0; + return false; } static int scsi_debug_queuecommand(struct Scsi_Host *shost, @@ -5001,6 +5243,8 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, bool has_wlun_rl; scsi_set_resid(scp, 0); + if (sdebug_statistics) + atomic_inc(&sdebug_cmnd_count); if (unlikely(sdebug_verbose && !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { char b[120]; @@ -5015,7 +5259,13 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, n += scnprintf(b + n, sb - n, "%02x ", (u32)cmd[k]); } - sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b); + if (sdebug_mq_active) + sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n", + my_name, blk_mq_unique_tag(scp->request), + b); + else + sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, + b); } has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)) @@ -5093,7 +5343,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, if (errsts) goto check_cond; } - if (unlikely((F_M_ACCESS & flags) && devip->stopped)) { + if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) { mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); if (sdebug_verbose) sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " @@ -5105,7 +5355,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, if (sdebug_fake_rw && (F_FAKE_RW & flags)) goto fini; if (unlikely(sdebug_every_nth)) { - if (check_inject(scp)) + if (fake_timeout(scp)) return 0; /* ignore command: make trouble */ } if (likely(oip->pfp)) @@ -5139,7 +5389,7 @@ static struct scsi_host_template sdebug_driver_template = { .eh_target_reset_handler = scsi_debug_target_reset, .eh_bus_reset_handler = scsi_debug_bus_reset, .eh_host_reset_handler = scsi_debug_host_reset, - .can_queue = SCSI_DEBUG_CANQUEUE, + .can_queue = SDEBUG_CANQUEUE, .this_id = 7, .sg_tablesize = SG_MAX_SEGMENTS, .cmd_per_lun = DEF_CMD_PER_LUN, @@ -5147,7 +5397,6 @@ static struct scsi_host_template sdebug_driver_template = { .use_clustering = DISABLE_CLUSTERING, .module = THIS_MODULE, .track_queue_depth = 1, - .cmd_size = sizeof(struct sdebug_scmd_extra_t), }; static int sdebug_driver_probe(struct device * dev) @@ -5168,6 +5417,16 @@ static int sdebug_driver_probe(struct device * dev) error = -ENODEV; return error; } + if (submit_queues > nr_cpu_ids) { + pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%d\n", + my_name, submit_queues, nr_cpu_ids); + submit_queues = nr_cpu_ids; + } + /* Decide whether to tell scsi subsystem that we want mq */ + /* Following should give the same answer for each host */ + sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1); + if (sdebug_mq_active) + hpnt->nr_hw_queues = submit_queues; sdbg_host->shost = hpnt; *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; @@ -5225,6 +5484,8 @@ static int sdebug_driver_probe(struct device * dev) sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); + if (sdebug_every_nth) /* need stats counters for every_nth */ + sdebug_statistics = true; error = scsi_add_host(hpnt, &sdbg_host->dev); if (error) { pr_err("scsi_add_host failed\n"); |