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 2016 Nexenta Systems, Inc. 14 */ 15 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #include <fcntl.h> 19 #include <unistd.h> 20 #include <stropts.h> 21 #include <err.h> 22 #include <libdevinfo.h> 23 #include <sys/nvme.h> 24 #include <assert.h> 25 26 #include "nvmeadm.h" 27 28 29 static boolean_t 30 nvme_ioctl(int fd, int ioc, size_t *bufsize, void **buf, uint64_t arg, 31 uint64_t *res) 32 { 33 nvme_ioctl_t nioc = { 0 }; 34 35 if (buf != NULL) 36 *buf = NULL; 37 38 if (res != NULL) 39 *res = ~0ULL; 40 41 if (bufsize != NULL && *bufsize != 0) { 42 assert(buf != NULL); 43 44 if ((nioc.n_buf = (uintptr_t)calloc(*bufsize, 1)) == NULL) 45 err(-1, "nvme_ioctl()"); 46 47 nioc.n_len = *bufsize; 48 } 49 50 nioc.n_arg = arg; 51 52 if (ioctl(fd, ioc, &nioc) != 0) { 53 if (debug) 54 warn("nvme_ioctl()"); 55 if (nioc.n_buf != 0) 56 free((void *)nioc.n_buf); 57 58 return (B_FALSE); 59 } 60 61 if (res != NULL) 62 *res = nioc.n_arg; 63 64 if (bufsize != NULL) 65 *bufsize = nioc.n_len; 66 67 if (buf != NULL) 68 *buf = (void *)nioc.n_buf; 69 70 return (B_TRUE); 71 } 72 73 nvme_capabilities_t * 74 nvme_capabilities(int fd) 75 { 76 void *cap = NULL; 77 size_t bufsize = sizeof (nvme_capabilities_t); 78 79 (void) nvme_ioctl(fd, NVME_IOC_CAPABILITIES, &bufsize, &cap, 0, NULL); 80 81 return (cap); 82 } 83 84 nvme_version_t * 85 nvme_version(int fd) 86 { 87 void *vs = NULL; 88 size_t bufsize = sizeof (nvme_version_t); 89 90 (void) nvme_ioctl(fd, NVME_IOC_VERSION, &bufsize, &vs, 0, NULL); 91 92 return (vs); 93 } 94 95 nvme_identify_ctrl_t * 96 nvme_identify_ctrl(int fd) 97 { 98 void *idctl = NULL; 99 size_t bufsize = NVME_IDENTIFY_BUFSIZE; 100 101 (void) nvme_ioctl(fd, NVME_IOC_IDENTIFY_CTRL, &bufsize, &idctl, 0, 102 NULL); 103 104 return (idctl); 105 } 106 107 nvme_identify_nsid_t * 108 nvme_identify_nsid(int fd) 109 { 110 void *idns = NULL; 111 size_t bufsize = NVME_IDENTIFY_BUFSIZE; 112 113 (void) nvme_ioctl(fd, NVME_IOC_IDENTIFY_NSID, &bufsize, &idns, 0, NULL); 114 115 return (idns); 116 } 117 118 void * 119 nvme_get_logpage(int fd, uint8_t logpage, size_t *bufsize) 120 { 121 void *buf = NULL; 122 123 (void) nvme_ioctl(fd, NVME_IOC_GET_LOGPAGE, bufsize, &buf, logpage, 124 NULL); 125 126 return (buf); 127 } 128 129 boolean_t 130 nvme_get_feature(int fd, uint8_t feature, uint32_t arg, uint64_t *res, 131 size_t *bufsize, void **buf) 132 { 133 return (nvme_ioctl(fd, NVME_IOC_GET_FEATURES, bufsize, buf, 134 (uint64_t)feature << 32 | arg, res)); 135 } 136 137 int 138 nvme_intr_cnt(int fd) 139 { 140 uint64_t res = 0; 141 142 (void) nvme_ioctl(fd, NVME_IOC_INTR_CNT, NULL, NULL, 0, &res); 143 return ((int)res); 144 } 145 146 boolean_t 147 nvme_format_nvm(int fd, uint8_t lbaf, uint8_t ses) 148 { 149 nvme_format_nvm_t frmt = { 0 }; 150 151 frmt.b.fm_lbaf = lbaf & 0xf; 152 frmt.b.fm_ses = ses & 0x7; 153 154 return (nvme_ioctl(fd, NVME_IOC_FORMAT, NULL, NULL, frmt.r, NULL)); 155 } 156 157 boolean_t 158 nvme_detach(int fd) 159 { 160 return (nvme_ioctl(fd, NVME_IOC_DETACH, NULL, NULL, 0, NULL)); 161 } 162 163 boolean_t 164 nvme_attach(int fd) 165 { 166 return (nvme_ioctl(fd, NVME_IOC_ATTACH, NULL, NULL, 0, NULL)); 167 } 168 169 int 170 nvme_open(di_minor_t minor) 171 { 172 char *devpath, *path; 173 int fd; 174 175 if ((devpath = di_devfs_minor_path(minor)) == NULL) 176 err(-1, "nvme_open()"); 177 178 if (asprintf(&path, "/devices%s", devpath) < 0) { 179 di_devfs_path_free(devpath); 180 err(-1, "nvme_open()"); 181 } 182 183 di_devfs_path_free(devpath); 184 185 fd = open(path, O_RDWR); 186 free(path); 187 188 if (fd < 0) { 189 if (debug) 190 warn("nvme_open(%s)", path); 191 return (-1); 192 } 193 194 return (fd); 195 } 196 197 void 198 nvme_close(int fd) 199 { 200 (void) close(fd); 201 } 202