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 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 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