Index: sbin/nvmecontrol/nvmecontrol.8 =================================================================== --- sbin/nvmecontrol/nvmecontrol.8 +++ sbin/nvmecontrol/nvmecontrol.8 @@ -178,7 +178,8 @@ .Op Fl w workload_hint .Nm .Ic selftest -.Aq Fl c Ar code +.Aq Fl Ar s | Fl Ar e | Fl Ar a | Fl c Ar code +.Op Fl n Ar nsid .Aq Ar device-id | Ar namespace-id .Nm .Ic wdc cap-diag @@ -234,7 +235,7 @@ The namespace .Aq nsid to use instead of the namespace associated with the device. -A +An .Ar nsid of .Dq 0 @@ -504,6 +505,12 @@ .Ss selftest Start the specified device self-test: .Bl -tag -width 6n +.It Fl s +Start a short device self-test operation +.It Fl e +Start an extended device self-test operation +.It Fl a +Abort the device self-test operation .It Fl c Ar code Specify the device self-test command code. Common codes are: @@ -517,6 +524,22 @@ .It Dv 0xf Abort the device self-test operation .El +.It Fl n +.Bl -tag -width 6n +The namespace +.Aq nsid +to use instead of the namespace associated with the device. +An +.Ar nsid +of +.Dq 0 +specifies that the device self-test operation be run on the controller, independent of any namespaces. +An +.Ar nsid +of +.Dq 0xFFFFFFFF +specifies that the device self-test operation be run on all active namespaces. +.El .El .Ss wdc The various wdc command retrieve log data from the wdc/hgst drives. @@ -612,7 +635,7 @@ .Aq nsid you can use it to get information on other namespaces, or to query the drive itself. -A +An .Aq nsid of .Dq 0 Index: sbin/nvmecontrol/selftest.c =================================================================== --- sbin/nvmecontrol/selftest.c +++ sbin/nvmecontrol/selftest.c @@ -49,9 +49,17 @@ static struct options { const char *dev; + uint32_t nsid; + bool shrt; /* Short Self-test */ + bool ext; /* Extended Self-test */ + bool abrt; /* Abort Self-test */ uint8_t stc; /* Self-test Code */ } opt = { .dev = NULL, + .nsid = 0, + .shrt = false, + .ext = false, + .abrt = false, .stc = SELFTEST_CODE_NONE, }; @@ -82,6 +90,7 @@ int fd; char *path; uint32_t nsid; + uint8_t stc; if (arg_parse(argc, argv, f)) return; @@ -89,15 +98,38 @@ open_dev(opt.dev, &fd, 1, 1); get_nsid(fd, &path, &nsid); if (nsid != 0) { + if (opt.nsid != 0) { + fprintf(stderr, "invalid nsid options.\n"); + arg_help(argc, argv, f); + } close(fd); open_dev(path, &fd, 1, 1); + } else { + nsid = opt.nsid; } free(path); - if (opt.stc == SELFTEST_CODE_NONE) - errx(EX_USAGE, "must specify a Self-test Code"); - else if (opt.stc > SELFTEST_CODE_MAX) - errx(EX_DATAERR, "illegal Self-test Code 0x%x", opt.stc); + if (opt.abrt) { + if (opt.stc != SELFTEST_CODE_NONE || opt.shrt || opt.ext) { + fprintf(stderr, "Abort option cannot use with other options.\n"); + arg_help(argc, argv, f); + } + stc = 0xF; + } else if (opt.stc == SELFTEST_CODE_NONE && + !opt.shrt && opt.ext) { + stc = 0x2; + } else if (opt.stc == SELFTEST_CODE_NONE && + opt.shrt && !opt.ext) { + stc = 0x1; + } else if (opt.stc != SELFTEST_CODE_NONE && + !opt.shrt && !opt.ext) { + if (opt.stc > SELFTEST_CODE_MAX) + errx(EX_DATAERR, "illegal Self-test Code 0x%x", opt.stc); + stc = opt.stc; + } else { + fprintf(stderr, "invalid options.\n"); + arg_help(argc, argv, f); + } if (read_controller_data(fd, &cdata)) errx(EX_IOERR, "Identify request failed"); @@ -106,7 +138,7 @@ NVME_CTRLR_DATA_OACS_SELFTEST_MASK) == 0) errx(EX_UNAVAILABLE, "controller does not support self-test"); - selftest_op(fd, nsid, opt.stc); + selftest_op(fd, nsid, stc); close(fd); exit(0); @@ -114,6 +146,14 @@ static const struct opts selftest_opts[] = { #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } + OPT("nsid", 'n', arg_uint32, opt, nsid, + "Namespace Id"), + OPT("short", 's', arg_none, opt, shrt, + "Execute short Self-test"), + OPT("extended", 'e', arg_none, opt, ext, + "Execute extended Self-test"), + OPT("abort", 'a', arg_none, opt, abrt, + "Abort Self-test operation"), OPT("test-code", 'c', arg_uint8, opt, stc, "Self-test Code to execute"), { NULL, 0, arg_none, NULL, NULL }