Merging upstream version 1.6.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
adbb3a10cc
commit
6add9877e4
871 changed files with 8481 additions and 1502 deletions
460
test/ioctl/discovery.c
Normal file
460
test/ioctl/discovery.c
Normal file
|
@ -0,0 +1,460 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include <libnvme.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
|
||||
#include "../../src/nvme/private.h"
|
||||
#include "mock.h"
|
||||
#include "util.h"
|
||||
|
||||
#define TEST_FD 0xFD
|
||||
|
||||
static void arbitrary_ascii_string(size_t max_len, char *str, char *log_str)
|
||||
{
|
||||
size_t len;
|
||||
size_t i;
|
||||
|
||||
len = arbitrary_range(max_len + 1);
|
||||
for (i = 0; i < len; i++) {
|
||||
/*
|
||||
* ASCII strings shall contain only code values 20h through 7Eh.
|
||||
* Exclude 20h (space) because it ends the string.
|
||||
*/
|
||||
str[i] = log_str[i] = arbitrary_range(0x7E - 0x20) + 0x20 + 1;
|
||||
}
|
||||
for (i = len; i < max_len; i++) {
|
||||
str[i] = '\0';
|
||||
log_str[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
static void arbitrary_entry(struct nvmf_disc_log_entry *entry,
|
||||
struct nvmf_disc_log_entry *log_entry)
|
||||
{
|
||||
arbitrary(entry, sizeof(*entry));
|
||||
memcpy(log_entry, entry, sizeof(*entry));
|
||||
arbitrary_ascii_string(
|
||||
sizeof(entry->trsvcid), entry->trsvcid, log_entry->trsvcid);
|
||||
arbitrary_ascii_string(
|
||||
sizeof(entry->traddr), entry->traddr, log_entry->traddr);
|
||||
}
|
||||
|
||||
static void arbitrary_entries(size_t len,
|
||||
struct nvmf_disc_log_entry *entries,
|
||||
struct nvmf_disc_log_entry *log_entries)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
arbitrary_entry(&entries[i], &log_entries[i]);
|
||||
}
|
||||
|
||||
static void test_no_entries(nvme_ctrl_t c)
|
||||
{
|
||||
struct nvmf_discovery_log header = {};
|
||||
/* No entries to fetch after fetching the header */
|
||||
struct mock_cmd mock_admin_cmds[] = {
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header),
|
||||
.cdw10 = (sizeof(header) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header,
|
||||
},
|
||||
};
|
||||
struct nvmf_discovery_log *log = NULL;
|
||||
|
||||
set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds));
|
||||
check(nvmf_get_discovery_log(c, &log, 1) == 0, "discovery failed: %m");
|
||||
end_mock_cmds();
|
||||
cmp(log, &header, sizeof(header), "incorrect header");
|
||||
free(log);
|
||||
}
|
||||
|
||||
static void test_four_entries(nvme_ctrl_t c)
|
||||
{
|
||||
size_t num_entries = 4;
|
||||
struct nvmf_disc_log_entry entries[num_entries];
|
||||
struct nvmf_disc_log_entry log_entries[num_entries];
|
||||
struct nvmf_discovery_log header = {.numrec = cpu_to_le64(num_entries)};
|
||||
/*
|
||||
* All 4 entries should be fetched at once
|
||||
* followed by the header again (to ensure genctr hasn't changed)
|
||||
*/
|
||||
struct mock_cmd mock_admin_cmds[] = {
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header),
|
||||
.cdw10 = (sizeof(header) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(entries),
|
||||
.cdw10 = (sizeof(entries) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.cdw12 = sizeof(header), /* LPOL */
|
||||
.out_data = log_entries,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header),
|
||||
.cdw10 = (sizeof(header) / 4 - 1) << 16 /* NUMDL */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header,
|
||||
},
|
||||
};
|
||||
struct nvmf_discovery_log *log = NULL;
|
||||
|
||||
arbitrary_entries(num_entries, entries, log_entries);
|
||||
set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds));
|
||||
check(nvmf_get_discovery_log(c, &log, 1) == 0, "discovery failed: %m");
|
||||
end_mock_cmds();
|
||||
cmp(log, &header, sizeof(header), "incorrect header");
|
||||
cmp(log->entries, entries, sizeof(entries), "incorrect entries");
|
||||
free(log);
|
||||
}
|
||||
|
||||
static void test_five_entries(nvme_ctrl_t c)
|
||||
{
|
||||
size_t num_entries = 5;
|
||||
struct nvmf_disc_log_entry entries[num_entries];
|
||||
struct nvmf_disc_log_entry log_entries[num_entries];
|
||||
size_t first_entries = 4;
|
||||
size_t first_data_len = first_entries * sizeof(*entries);
|
||||
size_t second_entries = num_entries - first_entries;
|
||||
size_t second_data_len = second_entries * sizeof(*entries);
|
||||
struct nvmf_discovery_log header = {.numrec = cpu_to_le64(num_entries)};
|
||||
/*
|
||||
* The first 4 entries (4 KB) are fetched together,
|
||||
* followed by last entry separately.
|
||||
* Finally, the header is fetched again to check genctr.
|
||||
*/
|
||||
struct mock_cmd mock_admin_cmds[] = {
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header),
|
||||
.cdw10 = (sizeof(header) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = first_data_len,
|
||||
.cdw10 = (first_data_len / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.cdw12 = sizeof(header), /* LPOL */
|
||||
.out_data = log_entries,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = second_data_len,
|
||||
.cdw10 = (second_data_len / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.cdw12 = sizeof(header) + first_data_len, /* LPOL */
|
||||
.out_data = log_entries + first_entries,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header),
|
||||
.cdw10 = (sizeof(header) / 4 - 1) << 16 /* NUMDL */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header,
|
||||
},
|
||||
};
|
||||
struct nvmf_discovery_log *log = NULL;
|
||||
|
||||
arbitrary_entries(num_entries, entries, log_entries);
|
||||
set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds));
|
||||
check(nvmf_get_discovery_log(c, &log, 1) == 0, "discovery failed: %m");
|
||||
end_mock_cmds();
|
||||
cmp(log, &header, sizeof(header), "incorrect header");
|
||||
cmp(log->entries, entries, sizeof(entries), "incorrect entries");
|
||||
free(log);
|
||||
}
|
||||
|
||||
static void test_genctr_change(nvme_ctrl_t c)
|
||||
{
|
||||
struct nvmf_disc_log_entry entries1[1];
|
||||
struct nvmf_discovery_log header1 = {
|
||||
.numrec = cpu_to_le64(ARRAY_SIZE(entries1)),
|
||||
};
|
||||
size_t num_entries2 = 2;
|
||||
struct nvmf_disc_log_entry entries2[num_entries2];
|
||||
struct nvmf_disc_log_entry log_entries2[num_entries2];
|
||||
struct nvmf_discovery_log header2 = {
|
||||
.genctr = cpu_to_le64(1),
|
||||
.numrec = cpu_to_le64(num_entries2),
|
||||
};
|
||||
/*
|
||||
* genctr changes after the entries are fetched the first time,
|
||||
* so the log page fetch is retried
|
||||
*/
|
||||
struct mock_cmd mock_admin_cmds[] = {
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header1),
|
||||
.cdw10 = (sizeof(header1) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header1,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(entries1),
|
||||
.cdw10 = (sizeof(entries1) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* NUMDL */
|
||||
.cdw12 = sizeof(header1), /* LPOL */
|
||||
.out_data = entries1,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header2),
|
||||
.cdw10 = (sizeof(header2) / 4 - 1) << 16 /* NUMDL */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header2,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header2),
|
||||
.cdw10 = (sizeof(header2) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header2,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(entries2),
|
||||
.cdw10 = (sizeof(entries2) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.cdw12 = sizeof(header2), /* LPOL */
|
||||
.out_data = log_entries2,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header2),
|
||||
.cdw10 = (sizeof(header2) / 4 - 1) << 16 /* NUMDL */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header2,
|
||||
},
|
||||
};
|
||||
struct nvmf_discovery_log *log = NULL;
|
||||
|
||||
arbitrary(entries1, sizeof(entries1));
|
||||
arbitrary_entries(num_entries2, entries2, log_entries2);
|
||||
set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds));
|
||||
check(nvmf_get_discovery_log(c, &log, 2) == 0, "discovery failed: %m");
|
||||
end_mock_cmds();
|
||||
cmp(log, &header2, sizeof(header2), "incorrect header");
|
||||
cmp(log->entries, entries2, sizeof(entries2), "incorrect entries");
|
||||
free(log);
|
||||
}
|
||||
|
||||
static void test_max_retries(nvme_ctrl_t c)
|
||||
{
|
||||
struct nvmf_disc_log_entry entry;
|
||||
struct nvmf_discovery_log header1 = {.numrec = cpu_to_le64(1)};
|
||||
struct nvmf_discovery_log header2 = {
|
||||
.genctr = cpu_to_le64(1),
|
||||
.numrec = cpu_to_le64(1),
|
||||
};
|
||||
struct nvmf_discovery_log header3 = {
|
||||
.genctr = cpu_to_le64(2),
|
||||
.numrec = cpu_to_le64(1),
|
||||
};
|
||||
/* genctr changes in both attempts, hitting the max retries (2) */
|
||||
struct mock_cmd mock_admin_cmds[] = {
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header1),
|
||||
.cdw10 = (sizeof(header1) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header1,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(entry),
|
||||
.cdw10 = (sizeof(entry) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.cdw12 = sizeof(header1), /* LPOL */
|
||||
.out_data = &entry,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header2),
|
||||
.cdw10 = (sizeof(header2) / 4 - 1) << 16 /* NUMDL */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header2,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header2),
|
||||
.cdw10 = (sizeof(header2) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header2,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(entry),
|
||||
.cdw10 = (sizeof(entry) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.cdw12 = sizeof(header2), /* LPOL */
|
||||
.out_data = &entry,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header3),
|
||||
.cdw10 = (sizeof(header3) / 4 - 1) << 16 /* NUMDL */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header3,
|
||||
},
|
||||
};
|
||||
struct nvmf_discovery_log *log = NULL;
|
||||
|
||||
arbitrary(&entry, sizeof(entry));
|
||||
set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds));
|
||||
check(nvmf_get_discovery_log(c, &log, 2) == -1, "discovery succeeded");
|
||||
end_mock_cmds();
|
||||
check(errno == EAGAIN, "discovery failed: %m");
|
||||
check(!log, "unexpected log page returned");
|
||||
}
|
||||
|
||||
static void test_header_error(nvme_ctrl_t c)
|
||||
{
|
||||
size_t header_size = sizeof(struct nvmf_discovery_log);
|
||||
/* Stop after an error in fetching the header the first time */
|
||||
struct mock_cmd mock_admin_cmds[] = {
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = header_size,
|
||||
.cdw10 = (header_size / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.err = NVME_SC_INVALID_OPCODE,
|
||||
},
|
||||
};
|
||||
struct nvmf_discovery_log *log = NULL;
|
||||
|
||||
set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds));
|
||||
check(nvmf_get_discovery_log(c, &log, 1) == -1, "discovery succeeded");
|
||||
end_mock_cmds();
|
||||
check(!log, "unexpected log page returned");
|
||||
}
|
||||
|
||||
static void test_entries_error(nvme_ctrl_t c)
|
||||
{
|
||||
struct nvmf_discovery_log header = {.numrec = cpu_to_le64(1)};
|
||||
size_t entry_size = sizeof(struct nvmf_disc_log_entry);
|
||||
/* Stop after an error in fetching the entries */
|
||||
struct mock_cmd mock_admin_cmds[] = {
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header),
|
||||
.cdw10 = (sizeof(header) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = entry_size,
|
||||
.cdw10 = (entry_size / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.cdw12 = sizeof(header), /* LPOL */
|
||||
.err = -EIO,
|
||||
},
|
||||
};
|
||||
struct nvmf_discovery_log *log = NULL;
|
||||
|
||||
set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds));
|
||||
check(nvmf_get_discovery_log(c, &log, 1) == -1, "discovery succeeded");
|
||||
end_mock_cmds();
|
||||
check(errno == EIO, "discovery failed: %m");
|
||||
check(!log, "unexpected log page returned");
|
||||
}
|
||||
|
||||
static void test_genctr_error(nvme_ctrl_t c)
|
||||
{
|
||||
struct nvmf_disc_log_entry entry;
|
||||
struct nvmf_discovery_log header = {.numrec = cpu_to_le64(1)};
|
||||
/* Stop after an error in refetching the header */
|
||||
struct mock_cmd mock_admin_cmds[] = {
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header),
|
||||
.cdw10 = (sizeof(header) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.out_data = &header,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(entry),
|
||||
.cdw10 = (sizeof(entry) / 4 - 1) << 16 /* NUMDL */
|
||||
| 1 << 15 /* RAE */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.cdw12 = sizeof(header), /* LPOL */
|
||||
.out_data = &entry,
|
||||
},
|
||||
{
|
||||
.opcode = nvme_admin_get_log_page,
|
||||
.data_len = sizeof(header),
|
||||
.cdw10 = (sizeof(header) / 4 - 1) << 16 /* NUMDL */
|
||||
| NVME_LOG_LID_DISCOVER, /* LID */
|
||||
.err = NVME_SC_INTERNAL,
|
||||
},
|
||||
};
|
||||
struct nvmf_discovery_log *log = NULL;
|
||||
|
||||
arbitrary(&entry, sizeof(entry));
|
||||
set_mock_admin_cmds(mock_admin_cmds, ARRAY_SIZE(mock_admin_cmds));
|
||||
check(nvmf_get_discovery_log(c, &log, 1) == -1, "discovery succeeded");
|
||||
end_mock_cmds();
|
||||
check(!log, "unexpected log page returned");
|
||||
}
|
||||
|
||||
static void run_test(const char *test_name, void (*test_fn)(nvme_ctrl_t))
|
||||
{
|
||||
struct nvme_ctrl c = {.fd = TEST_FD};
|
||||
|
||||
printf("Running test %s...", test_name);
|
||||
fflush(stdout);
|
||||
check(asprintf(&c.name, "%s_ctrl", test_name) >= 0, "asprintf() failed");
|
||||
test_fn(&c);
|
||||
free(c.name);
|
||||
puts(" OK");
|
||||
}
|
||||
|
||||
#define RUN_TEST(name) run_test(#name, test_ ## name)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
set_mock_fd(TEST_FD);
|
||||
RUN_TEST(no_entries);
|
||||
RUN_TEST(four_entries);
|
||||
RUN_TEST(five_entries);
|
||||
RUN_TEST(genctr_change);
|
||||
RUN_TEST(max_retries);
|
||||
RUN_TEST(header_error);
|
||||
RUN_TEST(entries_error);
|
||||
RUN_TEST(genctr_error);
|
||||
}
|
1604
test/ioctl/features.c
Normal file
1604
test/ioctl/features.c
Normal file
File diff suppressed because it is too large
Load diff
572
test/ioctl/identify.c
Normal file
572
test/ioctl/identify.c
Normal file
|
@ -0,0 +1,572 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include <libnvme.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mock.h"
|
||||
#include "util.h"
|
||||
|
||||
#define TEST_FD 0xFD
|
||||
#define TEST_NSID 0x12345678
|
||||
#define TEST_NVMSETID 0xABCD
|
||||
#define TEST_UUID 123
|
||||
#define TEST_CSI NVME_CSI_KV
|
||||
#define TEST_CNTID 0x4321
|
||||
#define TEST_DOMID 0xFEDC
|
||||
#define TEST_ENDGID 0x0123
|
||||
#define TEST_SC NVME_SC_INVALID_FIELD
|
||||
|
||||
static void test_ns(void)
|
||||
{
|
||||
struct nvme_id_ns expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_NS,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_ns(TEST_FD, TEST_NSID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_ctrl(void)
|
||||
{
|
||||
struct nvme_id_ctrl expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_CTRL,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_ctrl(TEST_FD, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_active_ns_list(void)
|
||||
{
|
||||
struct nvme_ns_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_NS_ACTIVE_LIST,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_active_ns_list(TEST_FD, TEST_NSID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_ns_descs(void)
|
||||
{
|
||||
uint8_t expected_id[NVME_IDENTIFY_DATA_SIZE];
|
||||
struct nvme_ns_id_desc *id;
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_NS_DESC_LIST,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(expected_id, sizeof(expected_id));
|
||||
id = calloc(1, NVME_IDENTIFY_DATA_SIZE);
|
||||
check(id, "memory allocation failed");
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_ns_descs(TEST_FD, TEST_NSID, id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(id, expected_id, sizeof(expected_id), "incorrect identify data");
|
||||
free(id);
|
||||
}
|
||||
|
||||
static void test_nvmset_list(void)
|
||||
{
|
||||
struct nvme_id_nvmset_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_NVMSET_LIST,
|
||||
.cdw11 = TEST_NVMSETID,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_nvmset_list(TEST_FD, TEST_NVMSETID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_ns_csi(void)
|
||||
{
|
||||
uint8_t expected_id[NVME_IDENTIFY_DATA_SIZE];
|
||||
uint8_t id[NVME_IDENTIFY_DATA_SIZE] = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_CSI_NS,
|
||||
.cdw11 = TEST_CSI << 24,
|
||||
.cdw14 = TEST_UUID,
|
||||
.out_data = expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_ns_csi(TEST_FD, TEST_NSID, TEST_UUID, TEST_CSI, id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(id, expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_zns_identify_ns(void)
|
||||
{
|
||||
struct nvme_zns_id_ns expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_CSI_NS,
|
||||
.cdw11 = NVME_CSI_ZNS << 24,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_zns_identify_ns(TEST_FD, TEST_NSID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_nvm_identify_ctrl(void)
|
||||
{
|
||||
struct nvme_id_ctrl_nvm expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_CSI_CTRL,
|
||||
.cdw11 = NVME_CSI_NVM << 24,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_nvm_identify_ctrl(TEST_FD, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_zns_identify_ctrl(void)
|
||||
{
|
||||
struct nvme_zns_id_ctrl expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_CSI_CTRL,
|
||||
.cdw11 = NVME_CSI_ZNS << 24,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_zns_identify_ctrl(TEST_FD, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_active_ns_list_csi(void)
|
||||
{
|
||||
struct nvme_ns_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_CSI_NS_ACTIVE_LIST,
|
||||
.cdw11 = TEST_CSI << 24,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_active_ns_list_csi(
|
||||
TEST_FD, TEST_NSID, TEST_CSI, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_independent_identify_ns(void)
|
||||
{
|
||||
struct nvme_id_independent_id_ns expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_CSI_INDEPENDENT_ID_NS,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
/* That's a mouthful! */
|
||||
err = nvme_identify_independent_identify_ns(TEST_FD, TEST_NSID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_allocated_ns_list(void)
|
||||
{
|
||||
struct nvme_ns_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_allocated_ns_list(TEST_FD, TEST_NSID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_allocated_ns(void)
|
||||
{
|
||||
struct nvme_id_ns expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_ALLOCATED_NS,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_allocated_ns(TEST_FD, TEST_NSID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_nsid_ctrl_list(void)
|
||||
{
|
||||
struct nvme_ctrl_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = TEST_CNTID << 16
|
||||
| NVME_IDENTIFY_CNS_NS_CTRL_LIST,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_nsid_ctrl_list(TEST_FD, TEST_NSID, TEST_CNTID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_ctrl_list(void)
|
||||
{
|
||||
struct nvme_ctrl_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = TEST_CNTID << 16
|
||||
| NVME_IDENTIFY_CNS_CTRL_LIST,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_ctrl_list(TEST_FD, TEST_CNTID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_primary_ctrl(void)
|
||||
{
|
||||
struct nvme_primary_ctrl_cap expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = TEST_CNTID << 16
|
||||
| NVME_IDENTIFY_CNS_PRIMARY_CTRL_CAP,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_primary_ctrl(TEST_FD, TEST_CNTID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_secondary_ctrl_list(void)
|
||||
{
|
||||
struct nvme_secondary_ctrl_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = TEST_CNTID << 16
|
||||
| NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_secondary_ctrl_list(TEST_FD, TEST_CNTID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_ns_granularity(void)
|
||||
{
|
||||
struct nvme_id_ns_granularity_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_NS_GRANULARITY,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_ns_granularity(TEST_FD, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_uuid(void)
|
||||
{
|
||||
struct nvme_id_uuid_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_UUID_LIST,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_uuid(TEST_FD, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_domain_list(void)
|
||||
{
|
||||
struct nvme_id_domain_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_DOMAIN_LIST,
|
||||
.cdw11 = TEST_DOMID,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_domain_list(TEST_FD, TEST_DOMID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_endurance_group_list(void)
|
||||
{
|
||||
struct nvme_id_endurance_group_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_ENDURANCE_GROUP_ID,
|
||||
.cdw11 = TEST_ENDGID,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_endurance_group_list(TEST_FD, TEST_ENDGID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_allocated_ns_list_csi(void)
|
||||
{
|
||||
struct nvme_ns_list expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_CSI_ALLOCATED_NS_LIST,
|
||||
.cdw11 = TEST_CSI << 24,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_allocated_ns_list_csi(
|
||||
TEST_FD, TEST_NSID, TEST_CSI, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
static void test_iocs(void)
|
||||
{
|
||||
struct nvme_id_iocs expected_id, id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(expected_id),
|
||||
.cdw10 = TEST_CNTID << 16
|
||||
| NVME_IDENTIFY_CNS_COMMAND_SET_STRUCTURE,
|
||||
.out_data = &expected_id,
|
||||
};
|
||||
int err;
|
||||
|
||||
arbitrary(&expected_id, sizeof(expected_id));
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_iocs(TEST_FD, TEST_CNTID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == 0, "identify returned error %d, errno %m", err);
|
||||
cmp(&id, &expected_id, sizeof(id), "incorrect identify data");
|
||||
}
|
||||
|
||||
/*
|
||||
* All identify functions tail-call nvme_identify(),
|
||||
* so testing errors in any of them will do
|
||||
*/
|
||||
|
||||
static void test_status_code_error(void)
|
||||
{
|
||||
struct nvme_id_nvmset_list id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.data_len = sizeof(id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_NVMSET_LIST,
|
||||
.cdw11 = TEST_NVMSETID,
|
||||
.err = TEST_SC,
|
||||
};
|
||||
int err;
|
||||
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_nvmset_list(TEST_FD, TEST_NVMSETID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == TEST_SC, "got error %d, expected %d", err, TEST_SC);
|
||||
}
|
||||
|
||||
static void test_kernel_error(void)
|
||||
{
|
||||
struct nvme_id_ns id = {};
|
||||
struct mock_cmd mock_admin_cmd = {
|
||||
.opcode = nvme_admin_identify,
|
||||
.nsid = TEST_NSID,
|
||||
.data_len = sizeof(id),
|
||||
.cdw10 = NVME_IDENTIFY_CNS_NS,
|
||||
.err = -EIO,
|
||||
};
|
||||
int err;
|
||||
|
||||
set_mock_admin_cmds(&mock_admin_cmd, 1);
|
||||
err = nvme_identify_ns(TEST_FD, TEST_NSID, &id);
|
||||
end_mock_cmds();
|
||||
check(err == -1, "got error %d, expected -1", err);
|
||||
check(errno == EIO, "unexpected error %m");
|
||||
}
|
||||
|
||||
static void run_test(const char *test_name, void (*test_fn)(void))
|
||||
{
|
||||
printf("Running test %s...", test_name);
|
||||
fflush(stdout);
|
||||
test_fn();
|
||||
puts(" OK");
|
||||
}
|
||||
|
||||
#define RUN_TEST(name) run_test(#name, test_ ## name)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
set_mock_fd(TEST_FD);
|
||||
RUN_TEST(ns);
|
||||
RUN_TEST(ctrl);
|
||||
RUN_TEST(active_ns_list);
|
||||
RUN_TEST(ns_descs);
|
||||
RUN_TEST(nvmset_list);
|
||||
RUN_TEST(ns_csi);
|
||||
RUN_TEST(zns_identify_ns);
|
||||
RUN_TEST(nvm_identify_ctrl);
|
||||
RUN_TEST(zns_identify_ctrl);
|
||||
RUN_TEST(active_ns_list_csi);
|
||||
RUN_TEST(independent_identify_ns);
|
||||
RUN_TEST(allocated_ns_list);
|
||||
RUN_TEST(allocated_ns);
|
||||
RUN_TEST(nsid_ctrl_list);
|
||||
RUN_TEST(ctrl_list);
|
||||
RUN_TEST(primary_ctrl);
|
||||
RUN_TEST(secondary_ctrl_list);
|
||||
RUN_TEST(ns_granularity);
|
||||
RUN_TEST(uuid);
|
||||
RUN_TEST(domain_list);
|
||||
RUN_TEST(endurance_group_list);
|
||||
RUN_TEST(allocated_ns_list_csi);
|
||||
RUN_TEST(iocs);
|
||||
RUN_TEST(status_code_error);
|
||||
RUN_TEST(kernel_error);
|
||||
}
|
32
test/ioctl/meson.build
Normal file
32
test/ioctl/meson.build
Normal file
|
@ -0,0 +1,32 @@
|
|||
mock_ioctl = library(
|
||||
'mock-ioctl',
|
||||
['mock.c', 'util.c'],
|
||||
)
|
||||
|
||||
discovery = executable(
|
||||
'test-discovery',
|
||||
'discovery.c',
|
||||
dependencies: libnvme_dep,
|
||||
include_directories: [incdir, internal_incdir],
|
||||
link_with: mock_ioctl,
|
||||
)
|
||||
|
||||
test('discovery', discovery, env: ['LD_PRELOAD=' + mock_ioctl.full_path()])
|
||||
|
||||
features = executable(
|
||||
'test-features',
|
||||
'features.c',
|
||||
dependencies: libnvme_dep,
|
||||
link_with: mock_ioctl,
|
||||
)
|
||||
|
||||
test('features', features, env: ['LD_PRELOAD=' + mock_ioctl.full_path()])
|
||||
|
||||
identify = executable(
|
||||
'test-identify',
|
||||
'identify.c',
|
||||
dependencies: libnvme_dep,
|
||||
link_with: mock_ioctl,
|
||||
)
|
||||
|
||||
test('identify', identify, env: ['LD_PRELOAD=' + mock_ioctl.full_path()])
|
168
test/ioctl/mock.c
Normal file
168
test/ioctl/mock.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "mock.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "../../src/nvme/ioctl.h"
|
||||
#include "util.h"
|
||||
|
||||
struct mock_cmds {
|
||||
const char *name;
|
||||
const struct mock_cmd *cmds;
|
||||
size_t remaining_cmds;
|
||||
};
|
||||
|
||||
static int mock_fd = -1;
|
||||
static struct mock_cmds mock_admin_cmds = {.name = "admin"};
|
||||
static struct mock_cmds mock_io_cmds = {.name = "IO"};
|
||||
|
||||
static void set_mock_cmds(
|
||||
struct mock_cmds *mock_cmds, const struct mock_cmd *cmds, size_t len)
|
||||
{
|
||||
mock_cmds->cmds = cmds;
|
||||
mock_cmds->remaining_cmds = len;
|
||||
}
|
||||
|
||||
static void mock_cmds_done(const struct mock_cmds *mock_cmds)
|
||||
{
|
||||
check(!mock_cmds->remaining_cmds,
|
||||
"%zu %s commands not executed",
|
||||
mock_cmds->remaining_cmds, mock_cmds->name);
|
||||
}
|
||||
|
||||
void set_mock_fd(int fd)
|
||||
{
|
||||
mock_fd = fd;
|
||||
}
|
||||
|
||||
void set_mock_admin_cmds(const struct mock_cmd *cmds, size_t len)
|
||||
{
|
||||
set_mock_cmds(&mock_admin_cmds, cmds, len);
|
||||
}
|
||||
|
||||
void set_mock_io_cmds(const struct mock_cmd *cmds, size_t len)
|
||||
{
|
||||
set_mock_cmds(&mock_io_cmds, cmds, len);
|
||||
}
|
||||
|
||||
void end_mock_cmds(void)
|
||||
{
|
||||
mock_cmds_done(&mock_admin_cmds);
|
||||
mock_cmds_done(&mock_io_cmds);
|
||||
}
|
||||
|
||||
#define execute_ioctl(cmd, mock_cmd) ({ \
|
||||
check((cmd)->opcode == (mock_cmd)->opcode, \
|
||||
"got opcode %" PRIu8 ", expected %" PRIu8, \
|
||||
(cmd)->opcode, (mock_cmd)->opcode); \
|
||||
check((cmd)->flags == (mock_cmd)->flags, \
|
||||
"got flags %" PRIu8 ", expected %" PRIu8, \
|
||||
(cmd)->flags, (mock_cmd)->flags); \
|
||||
check((cmd)->nsid == (mock_cmd)->nsid, \
|
||||
"got nsid %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->nsid, (mock_cmd)->nsid); \
|
||||
check((cmd)->cdw2 == (mock_cmd)->cdw2, \
|
||||
"got cdw2 %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->cdw2, (mock_cmd)->cdw2); \
|
||||
check((cmd)->cdw3 == (mock_cmd)->cdw3, \
|
||||
"got cdw3 %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->cdw3, (mock_cmd)->cdw3); \
|
||||
check((cmd)->metadata_len == (mock_cmd)->metadata_len, \
|
||||
"got metadata_len %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->metadata_len, (mock_cmd)->metadata_len); \
|
||||
cmp((void const *)(uintptr_t)(cmd)->metadata, \
|
||||
(mock_cmd)->metadata, \
|
||||
(cmd)->metadata_len, \
|
||||
"incorrect metadata"); \
|
||||
__u32 data_len = (cmd)->data_len; \
|
||||
check(data_len == (mock_cmd)->data_len, \
|
||||
"got data_len %" PRIu32 ", expected %" PRIu32, \
|
||||
data_len, (mock_cmd)->data_len); \
|
||||
void *data = (void *)(uintptr_t)(cmd)->addr; \
|
||||
if ((mock_cmd)->in_data) { \
|
||||
cmp(data, (mock_cmd)->in_data, data_len, "incorrect data"); \
|
||||
} \
|
||||
check((cmd)->cdw10 == (mock_cmd)->cdw10, \
|
||||
"got cdw10 %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->cdw10, (mock_cmd)->cdw10); \
|
||||
check((cmd)->cdw11 == (mock_cmd)->cdw11, \
|
||||
"got cdw11 %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->cdw11, (mock_cmd)->cdw11); \
|
||||
check((cmd)->cdw12 == (mock_cmd)->cdw12, \
|
||||
"got cdw12 %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->cdw12, (mock_cmd)->cdw12); \
|
||||
check((cmd)->cdw13 == (mock_cmd)->cdw13, \
|
||||
"got cdw13 %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->cdw13, (mock_cmd)->cdw13); \
|
||||
check((cmd)->cdw14 == (mock_cmd)->cdw14, \
|
||||
"got cdw14 %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->cdw14, (mock_cmd)->cdw14); \
|
||||
check((cmd)->cdw15 == (mock_cmd)->cdw15, \
|
||||
"got cdw15 %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->cdw15, (mock_cmd)->cdw15); \
|
||||
check((cmd)->timeout_ms == (mock_cmd)->timeout_ms, \
|
||||
"got timeout_ms %" PRIu32 ", expected %" PRIu32, \
|
||||
(cmd)->timeout_ms, (mock_cmd)->timeout_ms); \
|
||||
(cmd)->result = (mock_cmd)->result; \
|
||||
if ((mock_cmd)->out_data) { \
|
||||
memcpy(data, (mock_cmd)->out_data, data_len); \
|
||||
} \
|
||||
})
|
||||
|
||||
int ioctl(int fd, unsigned long request, ...)
|
||||
{
|
||||
struct mock_cmds *mock_cmds;
|
||||
bool result64;
|
||||
const struct mock_cmd *mock_cmd;
|
||||
va_list args;
|
||||
void *cmd;
|
||||
|
||||
check(fd == mock_fd, "got fd %d, expected %d", fd, mock_fd);
|
||||
switch (request) {
|
||||
case NVME_IOCTL_ADMIN_CMD:
|
||||
mock_cmds = &mock_admin_cmds;
|
||||
result64 = false;
|
||||
break;
|
||||
case NVME_IOCTL_ADMIN64_CMD:
|
||||
mock_cmds = &mock_admin_cmds;
|
||||
result64 = true;
|
||||
break;
|
||||
case NVME_IOCTL_IO_CMD:
|
||||
mock_cmds = &mock_io_cmds;
|
||||
result64 = false;
|
||||
break;
|
||||
case NVME_IOCTL_IO64_CMD:
|
||||
mock_cmds = &mock_io_cmds;
|
||||
result64 = true;
|
||||
break;
|
||||
default:
|
||||
fail("unexpected %s %lu", __func__, request);
|
||||
}
|
||||
check(mock_cmds->remaining_cmds,
|
||||
"unexpected %s command", mock_cmds->name);
|
||||
mock_cmd = mock_cmds->cmds++;
|
||||
mock_cmds->remaining_cmds--;
|
||||
|
||||
va_start(args, request);
|
||||
cmd = va_arg(args, void *);
|
||||
va_end(args);
|
||||
if (result64) {
|
||||
execute_ioctl((struct nvme_passthru_cmd64 *)cmd, mock_cmd);
|
||||
} else {
|
||||
check((uint32_t)mock_cmd->result == mock_cmd->result,
|
||||
"expected 64-bit %s for result %" PRIu64,
|
||||
__func__, mock_cmd->result);
|
||||
execute_ioctl((struct nvme_passthru_cmd *)cmd, mock_cmd);
|
||||
}
|
||||
if (mock_cmd->err < 0) {
|
||||
errno = -mock_cmd->err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mock_cmd->err;
|
||||
}
|
104
test/ioctl/mock.h
Normal file
104
test/ioctl/mock.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef _LIBNVME_TEST_IOCTL_MOCK_H
|
||||
#define _LIBNVME_TEST_IOCTL_MOCK_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* struct mock_cmd - a mock NVMe passthru ioctl() invocation
|
||||
* @opcode: the expected `opcode` passed to ioctl()
|
||||
* @flags: the expected `flags` passed to ioctl()
|
||||
* @nsid: the expected `nsid` passed to ioctl()
|
||||
* @cdw2: the expected `cdw2` passed to ioctl()
|
||||
* @cdw3: the expected `cdw3` passed to ioctl()
|
||||
* @metadata: the expected `metadata` of length `metadata_len` passed to ioctl()
|
||||
* @in_data: the expected `addr` of length `data_len` passed to ioctl().
|
||||
* Set this to NULL to skip checking the data,
|
||||
* for example if the command is in the read direction.
|
||||
* @metadata_len: the expected `metadata_len` passed to ioctl()
|
||||
* @data_len: the expected `data_len` passed to ioctl()
|
||||
* @cdw10: the expected `cdw10` passed to ioctl()
|
||||
* @cdw11: the expected `cdw11` passed to ioctl()
|
||||
* @cdw12: the expected `cdw12` passed to ioctl()
|
||||
* @cdw13: the expected `cdw13` passed to ioctl()
|
||||
* @cdw14: the expected `cdw14` passed to ioctl()
|
||||
* @cdw15: the expected `cdw15` passed to ioctl()
|
||||
* @timeout_ms: the expected `timeout_ms` passed to ioctl()
|
||||
* @out_data: if not NULL, `data_len` bytes to copy to the caller's `addr`
|
||||
* @result: copied to the caller's `result`.
|
||||
* If `result` doesn't fit in a u32, the ioctl() must be the 64-bit one.
|
||||
* @err: If negative, ioctl() returns -1 and sets `errno` to `-err`.
|
||||
* Otherwise, ioctl() returns `err`, representing a NVMe status code.
|
||||
*/
|
||||
struct mock_cmd {
|
||||
uint8_t opcode;
|
||||
uint8_t flags;
|
||||
uint32_t nsid;
|
||||
uint32_t cdw2;
|
||||
uint32_t cdw3;
|
||||
const void *metadata;
|
||||
const void *in_data;
|
||||
uint32_t metadata_len;
|
||||
uint32_t data_len;
|
||||
uint32_t cdw10;
|
||||
uint32_t cdw11;
|
||||
uint32_t cdw12;
|
||||
uint32_t cdw13;
|
||||
uint32_t cdw14;
|
||||
uint32_t cdw15;
|
||||
uint32_t timeout_ms;
|
||||
const void *out_data;
|
||||
uint64_t result;
|
||||
int err;
|
||||
};
|
||||
|
||||
/**
|
||||
* set_mock_fd() - sets the expected file descriptor for NVMe passthru ioctls()
|
||||
* @fd: file descriptor expected to be passed to ioctl()
|
||||
*/
|
||||
void set_mock_fd(int fd);
|
||||
|
||||
/**
|
||||
* set_mock_admin_cmds() - mocks NVMe admin passthru ioctl() invocations
|
||||
* @cmds: pointer to start of the mock_cmd slice
|
||||
* @len: length of the mock_cmd slice (number of ioctl() invocations)
|
||||
*
|
||||
* Provides a sequence of mocks for NVMe admin passthru ioctl() invocations.
|
||||
* Each ioctl() consumes the next mock from the sequence.
|
||||
* Its arguments are checked against the mock's expected arguments,
|
||||
* aborting the process if unexpected arguments are passed.
|
||||
* The mock results (return value, NVMe result and data)
|
||||
* are returned from the ioctl().
|
||||
*
|
||||
* Analogous to set_mock_io_cmds(), but for admin commands.
|
||||
* Both admin and IO mocks can be active at the same time.
|
||||
*/
|
||||
void set_mock_admin_cmds(const struct mock_cmd *cmds, size_t len);
|
||||
|
||||
/**
|
||||
* set_mock_io_cmds() - mocks NVMe IO passthru ioctl() invocations
|
||||
* @cmds: pointer to start of the mock_cmd slice
|
||||
* @len: length of the mock_cmd slice (number of ioctl() invocations)
|
||||
*
|
||||
* Provides a sequence of mocks for NVMe IO passthru ioctl() invocations.
|
||||
* Each ioctl() consumes the next mock from the sequence.
|
||||
* Its arguments are checked against the mock's expected arguments,
|
||||
* aborting the process if unexpected arguments are passed.
|
||||
* The mock results (return value, NVMe result and data)
|
||||
* are returned from the ioctl().
|
||||
*
|
||||
* Analogous to set_mock_admin_cmds(), but for IO commands.
|
||||
* Both admin and IO mocks can be active at the same time.
|
||||
*/
|
||||
void set_mock_io_cmds(const struct mock_cmd *cmds, size_t len);
|
||||
|
||||
/**
|
||||
* end_mock_cmds() - finishes mocking NVMe passthru ioctl() invocations
|
||||
*
|
||||
* Checks that all mock ioctl() invocations were performed.
|
||||
*/
|
||||
void end_mock_cmds(void);
|
||||
|
||||
#endif /* #ifndef _LIBNVME_TEST_IOCTL_MOCK_H */
|
65
test/ioctl/util.c
Normal file
65
test/ioctl/util.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void hexdump(const uint8_t *buf, size_t len)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
fprintf(stderr, "%02X", buf[i++]);
|
||||
if (i >= len)
|
||||
break;
|
||||
|
||||
fputc(i % 16 > 0 ? ' ' : '\n', stderr);
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
void fail(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
fputc('\n', stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
void cmp(const void *actual, const void *expected, size_t len, const char *msg)
|
||||
{
|
||||
if (memcmp(actual, expected, len) == 0)
|
||||
return;
|
||||
|
||||
fputs(msg, stderr);
|
||||
fputs("\nactual:\n", stderr);
|
||||
hexdump(actual, len);
|
||||
fputs("expected:\n", stderr);
|
||||
hexdump(expected, len);
|
||||
abort();
|
||||
}
|
||||
|
||||
void arbitrary(void *buf_, size_t len)
|
||||
{
|
||||
uint8_t *buf = buf_;
|
||||
|
||||
while (len--)
|
||||
*(buf++) = rand();
|
||||
}
|
||||
|
||||
size_t arbitrary_range(size_t max)
|
||||
{
|
||||
size_t value;
|
||||
arbitrary(&value, sizeof(value));
|
||||
return value % max;
|
||||
}
|
19
test/ioctl/util.h
Normal file
19
test/ioctl/util.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef _LIBNVME_TEST_IOCTL_UTIL_H
|
||||
#define _LIBNVME_TEST_IOCTL_UTIL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdnoreturn.h>
|
||||
|
||||
noreturn void fail(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
#define check(condition, fmt...) ((condition) || (fail(fmt), 0))
|
||||
|
||||
void cmp(const void *actual, const void *expected, size_t len, const char *msg);
|
||||
|
||||
void arbitrary(void *buf, size_t len);
|
||||
|
||||
size_t arbitrary_range(size_t max);
|
||||
|
||||
#endif /* #ifndef _LIBNVME_TEST_IOCTL_UTIL_H */
|
|
@ -67,14 +67,20 @@ uuid = executable(
|
|||
test('uuid', uuid)
|
||||
|
||||
if conf.get('HAVE_NETDB')
|
||||
mock_ifaddrs = library(
|
||||
'mock-ifaddrs',
|
||||
['mock-ifaddrs.c', ],
|
||||
)
|
||||
|
||||
tree = executable(
|
||||
'tree',
|
||||
['tree.c'],
|
||||
dependencies: libnvme_dep,
|
||||
include_directories: [incdir, internal_incdir]
|
||||
include_directories: [incdir, internal_incdir],
|
||||
link_with: mock_ifaddrs,
|
||||
)
|
||||
|
||||
test('tree', tree)
|
||||
test('tree', tree, env: ['LD_PRELOAD=' + mock_ifaddrs.full_path()])
|
||||
|
||||
test_util = executable(
|
||||
'test-util',
|
||||
|
@ -84,4 +90,5 @@ if conf.get('HAVE_NETDB')
|
|||
test('Test util.c', test_util)
|
||||
endif
|
||||
|
||||
subdir('ioctl')
|
||||
subdir('nbft')
|
||||
|
|
110
test/mi-mctp.c
110
test/mi-mctp.c
|
@ -293,6 +293,89 @@ static void test_mi_resp_err(nvme_mi_ep_t ep, struct test_peer *peer)
|
|||
assert(rc == 0x2);
|
||||
}
|
||||
|
||||
static void setup_unaligned_ctrl_list_resp(struct test_peer *peer)
|
||||
{
|
||||
/* even number of controllers */
|
||||
peer->tx_buf[8] = 0x02;
|
||||
peer->tx_buf[9] = 0x00;
|
||||
|
||||
/* controller ID 1 */
|
||||
peer->tx_buf[10] = 0x01;
|
||||
peer->tx_buf[11] = 0x00;
|
||||
|
||||
/* controller ID 2 */
|
||||
peer->tx_buf[12] = 0x02;
|
||||
peer->tx_buf[13] = 0x00;
|
||||
|
||||
peer->tx_buf_len = 14;
|
||||
}
|
||||
|
||||
/* Will call through the xfer/submit API expecting a full-sized list (so
|
||||
* resp->data_len is set to sizeof(list)), but the endpoint will return an
|
||||
* unaligned short list.
|
||||
*/
|
||||
static void test_mi_resp_unaligned(nvme_mi_ep_t ep, struct test_peer *peer)
|
||||
{
|
||||
struct nvme_ctrl_list list;
|
||||
int rc;
|
||||
|
||||
setup_unaligned_ctrl_list_resp(peer);
|
||||
|
||||
memset(&list, 0, sizeof(list));
|
||||
|
||||
rc = nvme_mi_mi_read_mi_data_ctrl_list(ep, 0, &list);
|
||||
assert(rc == 0);
|
||||
|
||||
assert(le16_to_cpu(list.num) == 2);
|
||||
assert(le16_to_cpu(list.identifier[0]) == 1);
|
||||
assert(le16_to_cpu(list.identifier[1]) == 2);
|
||||
}
|
||||
|
||||
/* Will call through the xfer/submit API expecting an unaligned list,
|
||||
* and get a response of exactly that size.
|
||||
*/
|
||||
static void test_mi_resp_unaligned_expected(nvme_mi_ep_t ep,
|
||||
struct test_peer *peer)
|
||||
{
|
||||
/* direct access to the raw submit() API */
|
||||
extern int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
|
||||
struct nvme_mi_resp *resp);
|
||||
struct nvme_mi_mi_resp_hdr resp_hdr;
|
||||
struct nvme_mi_mi_req_hdr req_hdr;
|
||||
struct nvme_ctrl_list list;
|
||||
struct nvme_mi_resp resp;
|
||||
struct nvme_mi_req req;
|
||||
int rc;
|
||||
|
||||
setup_unaligned_ctrl_list_resp(peer);
|
||||
|
||||
memset(&list, 0, sizeof(list));
|
||||
|
||||
memset(&req_hdr, 0, sizeof(req_hdr));
|
||||
req_hdr.hdr.type = NVME_MI_MSGTYPE_NVME;
|
||||
req_hdr.hdr.nmp = (NVME_MI_ROR_REQ << 7) | (NVME_MI_MT_MI << 3);
|
||||
req_hdr.opcode = nvme_mi_mi_opcode_mi_data_read;
|
||||
req_hdr.cdw0 = cpu_to_le32(nvme_mi_dtyp_ctrl_list << 24);
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.hdr = &req_hdr.hdr;
|
||||
req.hdr_len = sizeof(req_hdr);
|
||||
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
resp.hdr = &resp_hdr.hdr;
|
||||
resp.hdr_len = sizeof(resp_hdr);
|
||||
resp.data = &list;
|
||||
resp.data_len = peer->tx_buf_len;
|
||||
|
||||
rc = nvme_mi_submit(ep, &req, &resp);
|
||||
assert(rc == 0);
|
||||
assert(resp.data_len == 6); /* 2-byte length, 2*2 byte controller IDs */
|
||||
|
||||
assert(le16_to_cpu(list.num) == 2);
|
||||
assert(le16_to_cpu(list.identifier[0]) == 1);
|
||||
assert(le16_to_cpu(list.identifier[1]) == 2);
|
||||
}
|
||||
|
||||
static void test_admin_resp_err(nvme_mi_ep_t ep, struct test_peer *peer)
|
||||
{
|
||||
struct nvme_id_ctrl id;
|
||||
|
@ -340,30 +423,6 @@ static void test_admin_resp_sizes(nvme_mi_ep_t ep, struct test_peer *peer)
|
|||
nvme_mi_close_ctrl(ctrl);
|
||||
}
|
||||
|
||||
/* test: unaligned response sizes - should always report a transport error */
|
||||
static void test_admin_resp_sizes_unaligned(nvme_mi_ep_t ep, struct test_peer *peer)
|
||||
{
|
||||
struct nvme_id_ctrl id;
|
||||
nvme_mi_ctrl_t ctrl;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
ctrl = nvme_mi_init_ctrl(ep, 1);
|
||||
assert(ctrl);
|
||||
|
||||
peer->tx_buf[4] = 0x02; /* internal error */
|
||||
|
||||
for (i = 8; i <= 4096 + 8; i++) {
|
||||
peer->tx_buf_len = i;
|
||||
if (!(i & 0x3))
|
||||
continue;
|
||||
rc = nvme_mi_admin_identify_ctrl(ctrl, &id);
|
||||
assert(rc < 0);
|
||||
}
|
||||
|
||||
nvme_mi_close_ctrl(ctrl);
|
||||
}
|
||||
|
||||
/* test: timeout value passed to poll */
|
||||
static int poll_fn_timeout_value(struct test_peer *peer, struct pollfd *fds,
|
||||
nfds_t nfds, int timeout)
|
||||
|
@ -664,9 +723,10 @@ struct test {
|
|||
DEFINE_TEST(read_mi_data),
|
||||
DEFINE_TEST(poll_err),
|
||||
DEFINE_TEST(mi_resp_err),
|
||||
DEFINE_TEST(mi_resp_unaligned),
|
||||
DEFINE_TEST(mi_resp_unaligned_expected),
|
||||
DEFINE_TEST(admin_resp_err),
|
||||
DEFINE_TEST(admin_resp_sizes),
|
||||
DEFINE_TEST(admin_resp_sizes_unaligned),
|
||||
DEFINE_TEST(poll_timeout_value),
|
||||
DEFINE_TEST(poll_timeout),
|
||||
DEFINE_TEST(mpr_mi),
|
||||
|
|
|
@ -1245,7 +1245,6 @@ static int test_admin_id_secondary_ctrl_list_cb(struct nvme_mi_ep *ep,
|
|||
void *data)
|
||||
{
|
||||
__u16 cns, ctrlid;
|
||||
__u32 nsid;
|
||||
__u8 *hdr;
|
||||
|
||||
hdr = (__u8 *)req->hdr;
|
||||
|
@ -1256,9 +1255,6 @@ static int test_admin_id_secondary_ctrl_list_cb(struct nvme_mi_ep *ep,
|
|||
cns = hdr[45] << 8 | hdr[44];
|
||||
assert(cns == NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST);
|
||||
|
||||
nsid = hdr[11] << 24 | hdr[10] << 16 | hdr[9] << 8 | hdr[8];
|
||||
assert(nsid == 0x01020304);
|
||||
|
||||
ctrlid = hdr[47] << 8 | hdr[46];
|
||||
assert(ctrlid == 5);
|
||||
|
||||
|
@ -1280,8 +1276,7 @@ static void test_admin_id_secondary_ctrl_list(struct nvme_mi_ep *ep)
|
|||
ctrl = nvme_mi_init_ctrl(ep, 5);
|
||||
assert(ctrl);
|
||||
|
||||
rc = nvme_mi_admin_identify_secondary_ctrl_list(ctrl, 0x01020304,
|
||||
5, &list);
|
||||
rc = nvme_mi_admin_identify_secondary_ctrl_list(ctrl, 5, &list);
|
||||
assert(!rc);
|
||||
}
|
||||
|
||||
|
|
123
test/mock-ifaddrs.c
Normal file
123
test/mock-ifaddrs.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/**
|
||||
* This file is part of libnvme.
|
||||
* Copyright (c) 2023 Martin Belanger, Dell Technologies Inc.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
struct ifaddrs_storage {
|
||||
struct ifaddrs ifa;
|
||||
union {
|
||||
/* Reserve space for the biggest of the sockaddr types */
|
||||
struct sockaddr_in s4;
|
||||
struct sockaddr_in6 s6;
|
||||
} addr, netmask, broadaddr;
|
||||
char name[IF_NAMESIZE + 1];
|
||||
};
|
||||
|
||||
static void init_entry(struct ifaddrs_storage *storage,
|
||||
const char *ifname,
|
||||
int family,
|
||||
uint32_t addr1,
|
||||
uint32_t addr2,
|
||||
uint32_t addr3,
|
||||
uint32_t addr4,
|
||||
bool last)
|
||||
{
|
||||
struct ifaddrs *p;
|
||||
|
||||
p = &storage->ifa;
|
||||
p->ifa_next = last ? NULL : &storage[1].ifa;
|
||||
p->ifa_name = storage->name;
|
||||
strcpy(p->ifa_name, ifname);
|
||||
p->ifa_flags = 0;
|
||||
|
||||
if (family == AF_INET) {
|
||||
struct sockaddr_in *ipv4;
|
||||
|
||||
ipv4 = &storage->addr.s4;
|
||||
ipv4->sin_family = family;
|
||||
ipv4->sin_port = 0;
|
||||
ipv4->sin_addr.s_addr = htonl(addr1);
|
||||
p->ifa_addr = (struct sockaddr *)ipv4;
|
||||
|
||||
ipv4 = &storage->netmask.s4;
|
||||
ipv4->sin_family = family;
|
||||
ipv4->sin_port = 0;
|
||||
ipv4->sin_addr.s_addr = 0xffffff00;
|
||||
p->ifa_netmask = (struct sockaddr *)ipv4;
|
||||
|
||||
ipv4 = &storage->broadaddr.s4;
|
||||
ipv4->sin_family = family;
|
||||
ipv4->sin_port = 0;
|
||||
ipv4->sin_addr.s_addr = 0;
|
||||
p->ifa_broadaddr = (struct sockaddr *)ipv4;;
|
||||
} else {
|
||||
struct sockaddr_in6 *ipv6;
|
||||
|
||||
ipv6 = &storage->addr.s6;
|
||||
ipv6->sin6_family = family;
|
||||
ipv6->sin6_port = 0;
|
||||
ipv6->sin6_flowinfo = 0;
|
||||
ipv6->sin6_addr.s6_addr32[0] = htonl(addr1);
|
||||
ipv6->sin6_addr.s6_addr32[1] = htonl(addr2);
|
||||
ipv6->sin6_addr.s6_addr32[2] = htonl(addr3);
|
||||
ipv6->sin6_addr.s6_addr32[3] = htonl(addr4);
|
||||
ipv6->sin6_scope_id = 0;
|
||||
p->ifa_addr = (struct sockaddr *)ipv6;
|
||||
|
||||
ipv6 = &storage->netmask.s6;
|
||||
ipv6->sin6_family = family;
|
||||
ipv6->sin6_port = 0;
|
||||
ipv6->sin6_flowinfo = 0;
|
||||
ipv6->sin6_addr.s6_addr32[0] = 0xffffffff;
|
||||
ipv6->sin6_addr.s6_addr32[1] = 0xffffffff;
|
||||
ipv6->sin6_addr.s6_addr32[2] = 0xffffffff;
|
||||
ipv6->sin6_addr.s6_addr32[3] = 0;
|
||||
ipv6->sin6_scope_id = 0;
|
||||
p->ifa_netmask = (struct sockaddr *)ipv6;
|
||||
|
||||
ipv6 = &storage->broadaddr.s6;
|
||||
ipv6->sin6_family = family;
|
||||
ipv6->sin6_port = 0;
|
||||
ipv6->sin6_flowinfo = 0;
|
||||
ipv6->sin6_addr.s6_addr32[0] = 0;
|
||||
ipv6->sin6_addr.s6_addr32[1] = 0;
|
||||
ipv6->sin6_addr.s6_addr32[2] = 0;
|
||||
ipv6->sin6_addr.s6_addr32[3] = 0;
|
||||
ipv6->sin6_scope_id = 0;
|
||||
p->ifa_broadaddr = (struct sockaddr *)ipv6;
|
||||
}
|
||||
|
||||
p->ifa_data = NULL;
|
||||
}
|
||||
|
||||
int getifaddrs(struct ifaddrs **ifap) {
|
||||
struct ifaddrs_storage *storage;
|
||||
|
||||
/* Allocate memory for 4 interfaces */
|
||||
storage = (struct ifaddrs_storage *)calloc(4, sizeof(struct ifaddrs_storage));
|
||||
*ifap = &storage[0].ifa;
|
||||
|
||||
init_entry(&storage[0], "eth0", AF_INET, 0xc0a80114, 0, 0, 0, false); /* 192.168.1.20 */
|
||||
init_entry(&storage[1], "eth0", AF_INET6, 0xfe800000, 0, 0, 0xdeadbeef, false); /* fe80::dead:beef */
|
||||
|
||||
/* Loopback interface */
|
||||
init_entry(&storage[2], "lo", AF_INET, 0x7f000001, 0, 0, 0, false); /* 127.0.0.1 */
|
||||
init_entry(&storage[3], "lo", AF_INET6, 0, 0, 0, 1, true); /* ::1 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void freeifaddrs(struct ifaddrs *ifa) {
|
||||
free(ifa);
|
||||
}
|
||||
|
18
test/test.c
18
test/test.c
|
@ -16,6 +16,7 @@
|
|||
* somewhere.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
@ -112,7 +113,7 @@ static int test_ctrl(nvme_ctrl_t c)
|
|||
printf(" PASSED: Identify Primary\n");
|
||||
else
|
||||
printf(" ERROR: Identify Primary:%x\n", ret);
|
||||
ret = nvme_identify_secondary_ctrl_list(fd, 1, 0, &sec);
|
||||
ret = nvme_identify_secondary_ctrl_list(fd, 0, &sec);
|
||||
if (!ret)
|
||||
printf(" PASSED: Identify Secondary\n");
|
||||
else
|
||||
|
@ -197,7 +198,7 @@ static int test_ctrl(nvme_ctrl_t c)
|
|||
printf(" Temperature Threshold:%x\n", result);
|
||||
else if (ret > 0)
|
||||
printf(" ERROR: Temperature Threshold:%x\n", ret);
|
||||
ret = nvme_get_features_err_recovery(fd, sel, &result);
|
||||
ret = nvme_get_features_err_recovery2(fd, sel, 0, &result);
|
||||
if (!ret)
|
||||
printf(" Error Recovery:%x\n", result);
|
||||
else if (ret > 0)
|
||||
|
@ -257,12 +258,12 @@ static int test_ctrl(nvme_ctrl_t c)
|
|||
printf(" SW Progress Marker:%x\n", result);
|
||||
else if (ret > 0)
|
||||
printf(" ERROR: Sanitize:%x\n", ret);
|
||||
ret = nvme_get_features_resv_mask(fd, sel, &result);
|
||||
ret = nvme_get_features_resv_mask2(fd, sel, 0, &result);
|
||||
if (!ret)
|
||||
printf(" Reservation Mask:%x\n", result);
|
||||
else if (ret > 0)
|
||||
printf(" ERROR: Reservation Mask:%x\n", ret);
|
||||
ret = nvme_get_features_resv_persist(fd, sel, &result);
|
||||
ret = nvme_get_features_resv_persist2(fd, sel, 0, &result);
|
||||
if (!ret)
|
||||
printf(" Reservation Persistence:%x\n", result);
|
||||
else if (ret > 0)
|
||||
|
@ -274,7 +275,7 @@ static int test_namespace(nvme_ns_t n)
|
|||
{
|
||||
int ret, nsid = nvme_ns_get_nsid(n), fd = nvme_ns_get_fd(n);
|
||||
struct nvme_id_ns ns = { 0 }, allocated = { 0 };
|
||||
struct nvme_ns_id_desc descs = { 0 };
|
||||
struct nvme_ns_id_desc *descs;
|
||||
__u32 result = 0;
|
||||
__u8 flbas;
|
||||
|
||||
|
@ -292,11 +293,16 @@ static int test_namespace(nvme_ns_t n)
|
|||
printf(" Identify allocated ns\n");
|
||||
else
|
||||
printf(" ERROR: Identify allocated ns:%x\n", ret);
|
||||
ret = nvme_identify_ns_descs(fd, nsid, &descs);
|
||||
descs = malloc(NVME_IDENTIFY_DATA_SIZE);
|
||||
if (!descs)
|
||||
return -1;
|
||||
|
||||
ret = nvme_identify_ns_descs(fd, nsid, descs);
|
||||
if (!ret)
|
||||
printf(" Identify NS Descriptors\n");
|
||||
else
|
||||
printf(" ERROR: Identify NS Descriptors:%x\n", ret);
|
||||
free(descs);
|
||||
ret = nvme_get_features_write_protect(fd, nsid,
|
||||
NVME_GET_FEATURES_SEL_CURRENT, &result);
|
||||
if (!ret)
|
||||
|
|
1107
test/tree.c
1107
test/tree.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue