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