1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2024 Oxide Computer Company
14 */
15
16 /*
17 * Perform basic GET LOG PAGE commands just to prove that this works end to
18 * work. This is not intended to be an exhaustive set of tests, merely proving
19 * that things work. We utilize the SMART / Health information and the Firmware
20 * Slot information because these two pages have existed since NVMe 1.0 and both
21 * are the same fixed size (512 bytes). They both have useful pieces of expected
22 * non-zero data: the current temperature and firmware slot respectively. These
23 * are both within the first u32, so we just check that the entire u32 is
24 * non-zero and not all 1s.
25 *
26 * It's quite probably virtualized devices will lie about these. When they do,
27 * we should add specific devices to an exception list.
28 */
29
30 #include <err.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/sysmacros.h>
35
36 #include "nvme_ioctl_util.h"
37
38 typedef struct {
39 const char *lt_desc;
40 uint32_t lt_lid;
41 size_t lt_len;
42 } log_test_t;
43
44 static const log_test_t basic_log_tests[] = {
45 { "Health/SMART log page", NVME_LOGPAGE_HEALTH, 512 },
46 { "Firmware log page", NVME_LOGPAGE_FWSLOT, 512 },
47 };
48
49 static bool
basic_get_one_log(int fd,const log_test_t * test)50 basic_get_one_log(int fd, const log_test_t *test)
51 {
52 bool ret = true;
53 nvme_ioctl_get_logpage_t log;
54 void *data;
55
56 if ((data = calloc(test->lt_len, 1)) == NULL) {
57 err(EXIT_FAILURE, "%s: failed to allocate %zu bytes for "
58 "log page data", test->lt_desc, test->lt_len);
59 }
60
61 (void) memset(&log, 0, sizeof (log));
62 log.nigl_csi = NVME_CSI_NVM;
63 log.nigl_lid = test->lt_lid;
64 log.nigl_len = test->lt_len;
65 log.nigl_data = (uintptr_t)data;
66
67 if (ioctl(fd, NVME_IOC_GET_LOGPAGE, &log) != 0) {
68 warn("TEST FAILED: %s: failed to issue get log page ioctl",
69 test->lt_desc);
70 ret = false;
71 } else if (log.nigl_common.nioc_drv_err != NVME_IOCTL_E_OK) {
72 warnx("TEST FAILED: %s: get log page ioctl set error to 0x%x, "
73 "but expected success", test->lt_desc,
74 log.nigl_common.nioc_drv_err);
75 ret = false;
76 } else {
77 uint32_t t;
78
79 (void) printf("TEST PASSED: %s: successfully issued get log "
80 "page command\n", test->lt_desc);
81 (void) memcpy(&t, data, sizeof (t));
82 if (t == 0 || t == UINT32_MAX) {
83 warnx("TEST FAILED: %s: uint32_t at word 0 looks like "
84 "invalid data, found 0x%x", test->lt_desc, t);
85 ret = false;
86 } else {
87 (void) printf("TEST PASSED: %s: returned data passes "
88 "initial scrutiny\n", test->lt_desc);
89 }
90 }
91
92 free(data);
93 return (ret);
94 }
95
96 int
main(void)97 main(void)
98 {
99 int ret = EXIT_SUCCESS;
100 int fd = nvme_ioctl_test_get_fd(0);
101
102 for (size_t i = 0; i < ARRAY_SIZE(basic_log_tests); i++) {
103 if (!basic_get_one_log(fd, &basic_log_tests[i])) {
104 ret = EXIT_FAILURE;
105 }
106 }
107
108 VERIFY0(close(fd));
109 return (ret);
110 }
111