scsi: ufs: ufs device queue depth test

This test is trying to stress the edge cases of the UFS device queue.
This queue has two such edges, the total queue depth and the command per
LU. To test those edges properly, two deviations from the edge in addition
to the edge are tested as well. One deviation will be fixed (1), and the
second will be picked randomly.
The test will fill a request queue with random read requests. The amount
of request will vary each iteration and will be either the one of the
edges or the sum of this edge with one deviations.
Only reads or only writes will be tested within each iteration.

Change-Id: Ib02a63b2c8d6898f01e418a617ccc79eba67dab5
Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
This commit is contained in:
Dolev Raviv 2013-10-10 10:14:17 +03:00 committed by David Keitel
parent f0e8866cef
commit e39c9f9b7e

View file

@ -36,6 +36,7 @@
#define THREADS_COMPLETION_TIMOUT msecs_to_jiffies(10000) /* 10 sec */ #define THREADS_COMPLETION_TIMOUT msecs_to_jiffies(10000) /* 10 sec */
#define MAX_PARALLEL_QUERIES 33 #define MAX_PARALLEL_QUERIES 33
#define RANDOM_REQUEST_THREADS 4 #define RANDOM_REQUEST_THREADS 4
#define LUN_DEPTH_TEST_SIZE 9
/* the amount of requests that will be inserted */ /* the amount of requests that will be inserted */
#define LONG_SEQ_TEST_NUM_REQS 256 #define LONG_SEQ_TEST_NUM_REQS 256
@ -91,6 +92,8 @@ enum ufs_test_testcases {
UFS_TEST_LONG_SEQUENTIAL_MIXED, UFS_TEST_LONG_SEQUENTIAL_MIXED,
UFS_TEST_PARALLEL_READ_AND_WRITE, UFS_TEST_PARALLEL_READ_AND_WRITE,
UFS_TEST_LUN_DEPTH,
NUM_TESTS, NUM_TESTS,
}; };
@ -100,6 +103,9 @@ enum ufs_test_stage {
UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE1, UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE1,
UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE2, UFS_TEST_LONG_SEQUENTIAL_MIXED_STAGE2,
UFS_TEST_LUN_DEPTH_TEST_RUNNING,
UFS_TEST_LUN_DEPTH_DONE_ISSUING_REQ,
}; };
struct ufs_test_data { struct ufs_test_data {
@ -186,12 +192,21 @@ enum scenario_id {
/* scenarios for parallel read and write test */ /* scenarios for parallel read and write test */
SCEN_RANDOM_READ_50, SCEN_RANDOM_READ_50,
SCEN_RANDOM_WRITE_50, SCEN_RANDOM_WRITE_50,
SCEN_RANDOM_READ_32_NO_FLUSH,
SCEN_RANDOM_WRITE_32_NO_FLUSH,
SCEN_RANDOM_MAX, SCEN_RANDOM_MAX,
}; };
static struct test_scenario test_scenario[SCEN_RANDOM_MAX] = { static struct test_scenario test_scenario[SCEN_RANDOM_MAX] = {
{NULL, READ, 0, 50, true, 5}, /* SCEN_RANDOM_READ_50 */ {NULL, READ, 0, 50, true, 5}, /* SCEN_RANDOM_READ_50 */
{NULL, WRITE, 0, 50, true, 5}, /* SCEN_RANDOM_WRITE_50 */ {NULL, WRITE, 0, 50, true, 5}, /* SCEN_RANDOM_WRITE_50 */
/* SCEN_RANDOM_READ_32_NO_FLUSH */
{NULL, READ, 1, 32, true, 64},
/* SCEN_RANDOM_WRITE_32_NO_FLUSH */
{NULL, WRITE, 1, 32, true, 64},
}; };
static static
@ -229,6 +244,9 @@ static char *ufs_test_get_test_case_str(struct test_data *td)
case UFS_TEST_PARALLEL_READ_AND_WRITE: case UFS_TEST_PARALLEL_READ_AND_WRITE:
return "UFS parallel read and write test"; return "UFS parallel read and write test";
break; break;
case UFS_TEST_LUN_DEPTH:
return "UFS LUN depth test";
break;
default: default:
return "Unknown test"; return "Unknown test";
} }
@ -344,6 +362,23 @@ static int ufs_test_show(struct seq_file *file, int test_case)
"multiple random requests. One thread will issue only read " "multiple random requests. One thread will issue only read "
"requests, while the other will only issue write requests.\n"; "requests, while the other will only issue write requests.\n";
break; break;
case UFS_TEST_LUN_DEPTH:
test_description = "\nufs_test_lun_depth\n"
"=========\n"
"Description:\n"
"This test is trying to stress the edge cases of the UFS "
"device queue. This queue has two such edges, the total queue "
"depth and the command per LU. To test those edges properly, "
"two deviations from the edge in addition to the edge are "
"tested as well. One deviation will be fixed (1), and the "
"second will be picked randomly.\n"
"The test will fill a request queue with random read "
"requests. The amount of request will vary each iteration and "
"will be either the one of the edges or the sum of this edge "
"with one deviations.\n"
"The test will test for each iteration once only reads and "
"once only writes.\n";
break;
default: default:
test_description = "Unknown test"; test_description = "Unknown test";
} }
@ -565,7 +600,8 @@ static void scenario_free_end_io_fn(struct request *rq, int err)
static bool ufs_test_multi_thread_completion(void) static bool ufs_test_multi_thread_completion(void)
{ {
return atomic_read(&utd->outstanding_threads) <= 0; return atomic_read(&utd->outstanding_threads) <= 0 &&
utd->test_stage != UFS_TEST_LUN_DEPTH_TEST_RUNNING;
} }
/** /**
@ -691,6 +727,81 @@ static int ufs_test_run_parallel_read_and_write_test(struct test_data *td)
return 0; return 0;
} }
static void ufs_test_run_synchronous_scenario(struct test_scenario *read_data)
{
init_completion(&utd->outstanding_complete);
atomic_set(&utd->outstanding_threads, 1);
async_schedule(ufs_test_run_scenario, read_data);
if (!wait_for_completion_timeout(&utd->outstanding_complete,
THREADS_COMPLETION_TIMOUT)) {
test_pr_err("%s: Multi-thread test timed-out %d threads left",
__func__, atomic_read(&utd->outstanding_threads));
}
}
static int ufs_test_run_lun_depth_test(struct test_data *td)
{
struct test_scenario *read_data, *write_data;
struct scsi_device *sdev;
bool changed_seed = false;
int i = 0, num_req[LUN_DEPTH_TEST_SIZE];
int lun_qdepth, nutrs;
BUG_ON(!td || !td->req_q || !td->req_q->queuedata);
sdev = (struct scsi_device *)td->req_q->queuedata;
lun_qdepth = sdev->max_queue_depth;
nutrs = sdev->host->can_queue;
/* in case there is no specific queue size per LU */
if (lun_qdepth == nutrs)
lun_qdepth = lun_qdepth >> 2;
/* allow randomness even if user forgot */
if (utd->random_test_seed <= 0) {
changed_seed = true;
utd->random_test_seed = 1;
}
/* initialize the number of request for each iteration */
num_req[i++] = ufs_test_pseudo_random_seed(
&utd->random_test_seed, 1, lun_qdepth - 2);
num_req[i++] = lun_qdepth - 1;
num_req[i++] = lun_qdepth;
num_req[i++] = lun_qdepth + 1;
num_req[i++] = lun_qdepth + 1 + ufs_test_pseudo_random_seed(
&utd->random_test_seed, 1, nutrs - lun_qdepth - 2);
num_req[i++] = nutrs - 1;
num_req[i++] = nutrs;
num_req[i++] = nutrs + 1;
/* a random number up to 10, not to cause overflow or timeout */
num_req[i++] = nutrs + 1 + ufs_test_pseudo_random_seed(
&utd->random_test_seed, 1, 10);
utd->test_stage = UFS_TEST_LUN_DEPTH_TEST_RUNNING;
utd->fail_threads = 0;
read_data = get_scenario(td, SCEN_RANDOM_READ_32_NO_FLUSH);
write_data = get_scenario(td, SCEN_RANDOM_READ_32_NO_FLUSH);
for (i = 0; i < LUN_DEPTH_TEST_SIZE; i++) {
int reqs = num_req[i];
read_data->total_req = reqs;
write_data->total_req = reqs;
ufs_test_run_synchronous_scenario(read_data);
ufs_test_run_synchronous_scenario(write_data);
}
utd->test_stage = UFS_TEST_LUN_DEPTH_DONE_ISSUING_REQ;
check_test_completion();
/* clear random seed if changed */
if (changed_seed)
utd->random_test_seed = 0;
return 0;
}
static void long_seq_test_free_end_io_fn(struct request *rq, int err) static void long_seq_test_free_end_io_fn(struct request *rq, int err)
{ {
struct test_request *test_rq; struct test_request *test_rq;
@ -920,6 +1031,9 @@ static ssize_t ufs_test_write(struct file *file, const char __user *buf,
utd->test_info.check_test_completion_fn = utd->test_info.check_test_completion_fn =
ufs_test_multi_thread_completion; ufs_test_multi_thread_completion;
break; break;
case UFS_TEST_LUN_DEPTH:
utd->test_info.run_test_fn = ufs_test_run_lun_depth_test;
break;
default: default:
test_pr_err("%s: Unknown test-case: %d", __func__, test_case); test_pr_err("%s: Unknown test-case: %d", __func__, test_case);
WARN_ON(true); WARN_ON(true);
@ -952,6 +1066,7 @@ TEST_OPS(long_sequential_read, LONG_SEQUENTIAL_READ);
TEST_OPS(long_sequential_write, LONG_SEQUENTIAL_WRITE); TEST_OPS(long_sequential_write, LONG_SEQUENTIAL_WRITE);
TEST_OPS(long_sequential_mixed, LONG_SEQUENTIAL_MIXED); TEST_OPS(long_sequential_mixed, LONG_SEQUENTIAL_MIXED);
TEST_OPS(parallel_read_and_write, PARALLEL_READ_AND_WRITE); TEST_OPS(parallel_read_and_write, PARALLEL_READ_AND_WRITE);
TEST_OPS(lun_depth, LUN_DEPTH);
static void ufs_test_debugfs_cleanup(void) static void ufs_test_debugfs_cleanup(void)
{ {
@ -1006,6 +1121,9 @@ static int ufs_test_debugfs_init(void)
if (ret) if (ret)
goto exit_err; goto exit_err;
add_test(utd, parallel_read_and_write, PARALLEL_READ_AND_WRITE); add_test(utd, parallel_read_and_write, PARALLEL_READ_AND_WRITE);
if (ret)
goto exit_err;
add_test(utd, lun_depth, LUN_DEPTH);
if (ret) if (ret)
goto exit_err; goto exit_err;