1/*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2015 Netflix, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/param.h> 29 30#ifdef _KERNEL 31#include "opt_scsi.h" 32 33#include <sys/systm.h> 34#include <sys/libkern.h> 35#include <sys/kernel.h> 36#include <sys/malloc.h> 37#include <sys/sysctl.h> 38#else 39#include <errno.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#ifndef min 44#define min(a,b) (((a)<(b))?(a):(b)) 45#endif 46#endif 47 48#include <cam/cam.h> 49#include <cam/cam_ccb.h> 50#include <cam/cam_queue.h> 51#include <cam/cam_xpt.h> 52#include <cam/nvme/nvme_all.h> 53#include <sys/sbuf.h> 54#include <sys/endian.h> 55 56#ifdef _KERNEL 57#include <cam/cam_periph.h> 58#include <cam/cam_xpt_sim.h> 59#include <cam/cam_xpt_periph.h> 60#include <cam/cam_xpt_internal.h> 61#endif 62 63void 64nvme_ns_cmd(struct ccb_nvmeio *nvmeio, uint8_t cmd, uint32_t nsid, 65 uint32_t cdw10, uint32_t cdw11, uint32_t cdw12, uint32_t cdw13, 66 uint32_t cdw14, uint32_t cdw15) 67{ 68 bzero(&nvmeio->cmd, sizeof(struct nvme_command)); 69 nvmeio->cmd.opc = cmd; 70 nvmeio->cmd.nsid = htole32(nsid); 71 nvmeio->cmd.cdw10 = htole32(cdw10); 72 nvmeio->cmd.cdw11 = htole32(cdw11); 73 nvmeio->cmd.cdw12 = htole32(cdw12); 74 nvmeio->cmd.cdw13 = htole32(cdw13); 75 nvmeio->cmd.cdw14 = htole32(cdw14); 76 nvmeio->cmd.cdw15 = htole32(cdw15); 77} 78 79int 80nvme_identify_match(caddr_t identbuffer, caddr_t table_entry) 81{ 82 return 0; 83} 84 85void 86nvme_print_ident(const struct nvme_controller_data *cdata, 87 const struct nvme_namespace_data *data, struct sbuf *sb) 88{ 89 nvme_print_ident_short(cdata, data, sb); 90 sbuf_putc(sb, '\n'); 91} 92 93void 94nvme_print_ident_short(const struct nvme_controller_data *cdata, 95 const struct nvme_namespace_data *data, struct sbuf *sb) 96{ 97 sbuf_putc(sb, '<'); 98 cam_strvis_sbuf(sb, cdata->mn, sizeof(cdata->mn), 99 CAM_STRVIS_FLAG_NONASCII_SPC); 100 sbuf_putc(sb, ' '); 101 cam_strvis_sbuf(sb, cdata->fr, sizeof(cdata->fr), 102 CAM_STRVIS_FLAG_NONASCII_SPC); 103 sbuf_putc(sb, ' '); 104 cam_strvis_sbuf(sb, cdata->sn, sizeof(cdata->sn), 105 CAM_STRVIS_FLAG_NONASCII_SPC); 106 sbuf_putc(sb, '>'); 107} 108 109/* XXX need to do nvme admin opcodes too, but those aren't used yet by nda */ 110static const char * 111nvme_opc2str[] = { 112 "FLUSH", 113 "WRITE", 114 "READ", 115 "RSVD-3", 116 "WRITE_UNCORRECTABLE", 117 "COMPARE", 118 "RSVD-6", 119 "RSVD-7", 120 "WRITE_ZEROES", 121 "DATASET_MANAGEMENT", 122 "RSVD-a", 123 "RSVD-b", 124 "RSVD-c", 125 "RESERVATION_REGISTER", 126 "RESERVATION_REPORT", 127 "RSVD-f", 128 "RSVD-10", 129 "RESERVATION_ACQUIRE", 130 "RSVD-12", 131 "RSVD-13", 132 "RSVD-14", 133 "RESERVATION_RELEASE", 134}; 135 136const char * 137nvme_op_string(const struct nvme_command *cmd, int admin) 138{ 139 140 if (admin) { 141 return "ADMIN"; 142 } else { 143 if (cmd->opc >= nitems(nvme_opc2str)) 144 return "UNKNOWN"; 145 return nvme_opc2str[cmd->opc]; 146 } 147} 148 149const char * 150nvme_cmd_string(const struct nvme_command *cmd, char *cmd_string, size_t len) 151{ 152 struct sbuf sb; 153 int error; 154 155 if (len == 0) 156 return (""); 157 158 sbuf_new(&sb, cmd_string, len, SBUF_FIXEDLEN); 159 nvme_cmd_sbuf(cmd, &sb); 160 161 error = sbuf_finish(&sb); 162 if (error != 0 && 163#ifdef _KERNEL 164 error != ENOMEM) 165#else 166 errno != ENOMEM) 167#endif 168 return (""); 169 170 return(sbuf_data(&sb)); 171} 172 173void 174nvme_cmd_sbuf(const struct nvme_command *cmd, struct sbuf *sb) 175{ 176 177 /* 178 * cid, rsvd areas and mptr not printed, since they are used 179 * only internally by the SIM. 180 */ 181 sbuf_printf(sb, 182 "opc=%x fuse=%x nsid=%x prp1=%llx prp2=%llx cdw=%x %x %x %x %x %x", 183 cmd->opc, cmd->fuse, cmd->nsid, 184 (unsigned long long)cmd->prp1, (unsigned long long)cmd->prp2, 185 cmd->cdw10, cmd->cdw11, cmd->cdw12, 186 cmd->cdw13, cmd->cdw14, cmd->cdw15); 187} 188 189/* 190 * nvme_command_sbuf() returns 0 for success and -1 for failure. 191 */ 192int 193nvme_command_sbuf(struct ccb_nvmeio *nvmeio, struct sbuf *sb) 194{ 195 196 sbuf_printf(sb, "%s. NCB: ", nvme_op_string(&nvmeio->cmd, 197 nvmeio->ccb_h.func_code == XPT_NVME_ADMIN)); 198 nvme_cmd_sbuf(&nvmeio->cmd, sb); 199 return(0); 200} 201 202#ifdef _KERNEL 203const void * 204nvme_get_identify_cntrl(struct cam_periph *periph) 205{ 206 struct cam_ed *device; 207 208 device = periph->path->device; 209 210 return device->nvme_cdata; 211} 212 213const void * 214nvme_get_identify_ns(struct cam_periph *periph) 215{ 216 struct cam_ed *device; 217 218 device = periph->path->device; 219 220 return device->nvme_data; 221} 222#endif 223