#include <err.h>
#include <string.h>
#include <umem.h>
#include <sys/stat.h>
#include "libnvme_test_common.h"
static bool
ctrl_disc_count_cb(nvme_t *nvme, const nvme_ctrl_disc_t *disc, void *arg)
{
uint32_t *valp = arg;
*valp = *valp + 1;
return (true);
}
static bool
ctrl_check_disc(const nvme_ctrl_disc_t *disc)
{
bool ret = true;
di_node_t ctrl_devi, minor_devi;
di_minor_t minor;
const char *mname;
ctrl_devi = nvme_ctrl_disc_devi(disc);
minor = nvme_ctrl_disc_minor(disc);
minor_devi = di_minor_devinfo(minor);
mname = di_minor_name(minor);
if (di_minor_spectype(minor) != S_IFCHR) {
warnx("TEST FAILED: %s minor is not a character device, found "
"0x%x\n", mname, di_minor_spectype(minor));
ret = false;
} else {
(void) printf("TEST PASSED: %s: minor is a character device\n",
mname);
}
if (strcmp(di_minor_nodetype(minor), DDI_NT_NVME_NEXUS) != 0) {
warnx("TEST FAILED: %s minor has wrong node type %s, expected "
"%s", mname, di_minor_nodetype(minor), DDI_NT_NVME_NEXUS);
} else {
(void) printf("TEST PASSED: %s minor has correct node types\n",
mname);
}
if (minor_devi != ctrl_devi) {
warnx("TEST FAILED: %s minor devi does not match the "
"controller devi", mname);
ret = false;
} else {
(void) printf("TEST PASSED: %s minor devi matches its "
"controller\n", mname);
}
return (ret);
}
static bool
ctrl_match(nvme_t *nvme, nvme_ctrl_t *targ)
{
bool ret = true, match = false;
nvme_ctrl_iter_t *iter = NULL;
const nvme_ctrl_disc_t *disc;
nvme_iter_t iret;
di_node_t targ_di;
if (!nvme_ctrl_devi(targ, &targ_di)) {
libnvme_test_ctrl_warn(targ, "failed to obtain di_node_t from "
"controller");
return (false);
}
if (!nvme_ctrl_discover_init(nvme, &iter)) {
libnvme_test_hdl_warn(nvme, "failed to initialize controller "
"discovery");
return (false);
}
while ((iret = nvme_ctrl_discover_step(iter, &disc)) ==
NVME_ITER_VALID) {
if (!ctrl_check_disc(disc)) {
ret = false;
}
if (nvme_ctrl_disc_devi(disc) == targ_di) {
match = true;
}
}
if (iret != NVME_ITER_DONE) {
libnvme_test_hdl_warn(nvme, "failed to iterate controllers");
ret = false;
}
if (!match) {
warnx("TEST FAILED: failed to find matching controller");
ret = false;
} else {
(void) printf("TEST PASSED: found matching controller in "
"discovery for device %s\n", getenv(NVME_TEST_DEV_ENVVAR));
}
nvme_ctrl_discover_fini(iter);
return (ret);
}
static bool
ctrl_disc_nop_cb(nvme_t *nvme, const nvme_ctrl_disc_t *disc, void *arg)
{
return (true);
}
static bool
ctrl_disc_bad_disc_init(nvme_t *nvme, nvme_ctrl_iter_t **iterp,
nvme_err_t exp_err, const char *desc)
{
if (nvme_ctrl_discover_init(nvme, iterp)) {
warnx("TEST FAILED: nvme_ctrl_discover_init() erroneously "
"passed despite %s\n", desc);
return (false);
} else if (nvme_err(nvme) != exp_err) {
warnx("TEST FAILED: nvme_ctrl_discover_init() returned "
"wrong error %s (0x%x), not %s (0x%x)",
nvme_errtostr(nvme, nvme_err(nvme)), nvme_err(nvme),
nvme_errtostr(nvme, exp_err), exp_err);
return (false);
} else {
(void) printf("TEST PASSED: nvme_ctrl_discover_init() failed "
"correctly for %s\n", desc);
return (true);
}
}
static bool
ctrl_disc_bad_disc(nvme_t *nvme, nvme_ctrl_disc_f func, nvme_err_t exp_err,
const char *desc)
{
if (nvme_ctrl_discover(nvme, func, NULL)) {
warnx("TEST FAILED: nvme_ctrl_discover() erroneously "
"passed despite %s\n", desc);
return (false);
} else if (nvme_err(nvme) != exp_err) {
warnx("TEST FAILED: nvme_ctrl_discover() returned "
"wrong error %s (0x%x), not %s (0x%x)",
nvme_errtostr(nvme, nvme_err(nvme)), nvme_err(nvme),
nvme_errtostr(nvme, exp_err), exp_err);
return (false);
} else {
(void) printf("TEST PASSED: nvme_ctrl_discover() failed "
"correctly for %s\n", desc);
return (true);
}
}
int
main(void)
{
int ret = EXIT_SUCCESS;
nvme_t *nvme;
nvme_ctrl_t *ctrl;
uint32_t nctrl = 0;
nvme_ctrl_iter_t *iter;
libnvme_test_init(&nvme, &ctrl);
if (!nvme_ctrl_discover(nvme, ctrl_disc_count_cb, &nctrl)) {
libnvme_test_hdl_warn(nvme, "failed to discover controllers");
ret = EXIT_FAILURE;
} else if (nctrl == 0) {
warnx("TEST FAILED: discovered zero controllers somehow!");
ret = EXIT_FAILURE;
} else {
(void) printf("TEST PASSED: discovered some number of "
"controllers");
}
if (!ctrl_match(nvme, ctrl)) {
ret = EXIT_FAILURE;
}
if (!ctrl_disc_bad_disc_init(nvme, NULL, NVME_ERR_BAD_PTR,
"invalid iter pointer")) {
ret = EXIT_FAILURE;
}
if (!ctrl_disc_bad_disc(nvme, NULL, NVME_ERR_BAD_PTR,
"invalid function pointer")) {
ret = EXIT_FAILURE;
}
umem_setmtbf(1);
if (!ctrl_disc_bad_disc_init(nvme, &iter, NVME_ERR_NO_MEM,
"no memory")) {
ret = EXIT_FAILURE;
}
if (!ctrl_disc_bad_disc(nvme, ctrl_disc_nop_cb, NVME_ERR_NO_MEM,
"no memory")) {
ret = EXIT_FAILURE;
}
umem_setmtbf(0);
if (ret == EXIT_SUCCESS) {
(void) printf("All tests passed successfully\n");
}
nvme_ctrl_fini(ctrl);
nvme_fini(nvme);
return (ret);
}