1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (C) 2012-2013 Intel Corporation 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "nvme_private.h" 33 34 void 35 nvme_ctrlr_cmd_identify_controller(struct nvme_controller *ctrlr, void *payload, 36 nvme_cb_fn_t cb_fn, void *cb_arg) 37 { 38 struct nvme_request *req; 39 struct nvme_command *cmd; 40 41 req = nvme_allocate_request_vaddr(payload, 42 sizeof(struct nvme_controller_data), cb_fn, cb_arg); 43 44 cmd = &req->cmd; 45 cmd->opc = NVME_OPC_IDENTIFY; 46 47 /* 48 * TODO: create an identify command data structure, which 49 * includes this CNS bit in cdw10. 50 */ 51 cmd->cdw10 = htole32(1); 52 53 nvme_ctrlr_submit_admin_request(ctrlr, req); 54 } 55 56 void 57 nvme_ctrlr_cmd_identify_namespace(struct nvme_controller *ctrlr, uint32_t nsid, 58 void *payload, nvme_cb_fn_t cb_fn, void *cb_arg) 59 { 60 struct nvme_request *req; 61 struct nvme_command *cmd; 62 63 req = nvme_allocate_request_vaddr(payload, 64 sizeof(struct nvme_namespace_data), cb_fn, cb_arg); 65 66 cmd = &req->cmd; 67 cmd->opc = NVME_OPC_IDENTIFY; 68 69 /* 70 * TODO: create an identify command data structure 71 */ 72 cmd->nsid = htole32(nsid); 73 74 nvme_ctrlr_submit_admin_request(ctrlr, req); 75 } 76 77 void 78 nvme_ctrlr_cmd_create_io_cq(struct nvme_controller *ctrlr, 79 struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg) 80 { 81 struct nvme_request *req; 82 struct nvme_command *cmd; 83 84 req = nvme_allocate_request_null(cb_fn, cb_arg); 85 86 cmd = &req->cmd; 87 cmd->opc = NVME_OPC_CREATE_IO_CQ; 88 89 /* 90 * TODO: create a create io completion queue command data 91 * structure. 92 */ 93 cmd->cdw10 = htole32(((io_que->num_entries-1) << 16) | io_que->id); 94 /* 0x3 = interrupts enabled | physically contiguous */ 95 cmd->cdw11 = htole32((io_que->vector << 16) | 0x3); 96 cmd->prp1 = htole64(io_que->cpl_bus_addr); 97 98 nvme_ctrlr_submit_admin_request(ctrlr, req); 99 } 100 101 void 102 nvme_ctrlr_cmd_create_io_sq(struct nvme_controller *ctrlr, 103 struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg) 104 { 105 struct nvme_request *req; 106 struct nvme_command *cmd; 107 108 req = nvme_allocate_request_null(cb_fn, cb_arg); 109 110 cmd = &req->cmd; 111 cmd->opc = NVME_OPC_CREATE_IO_SQ; 112 113 /* 114 * TODO: create a create io submission queue command data 115 * structure. 116 */ 117 cmd->cdw10 = htole32(((io_que->num_entries-1) << 16) | io_que->id); 118 /* 0x1 = physically contiguous */ 119 cmd->cdw11 = htole32((io_que->id << 16) | 0x1); 120 cmd->prp1 = htole64(io_que->cmd_bus_addr); 121 122 nvme_ctrlr_submit_admin_request(ctrlr, req); 123 } 124 125 void 126 nvme_ctrlr_cmd_delete_io_cq(struct nvme_controller *ctrlr, 127 struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg) 128 { 129 struct nvme_request *req; 130 struct nvme_command *cmd; 131 132 req = nvme_allocate_request_null(cb_fn, cb_arg); 133 134 cmd = &req->cmd; 135 cmd->opc = NVME_OPC_DELETE_IO_CQ; 136 137 /* 138 * TODO: create a delete io completion queue command data 139 * structure. 140 */ 141 cmd->cdw10 = htole32(io_que->id); 142 143 nvme_ctrlr_submit_admin_request(ctrlr, req); 144 } 145 146 void 147 nvme_ctrlr_cmd_delete_io_sq(struct nvme_controller *ctrlr, 148 struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg) 149 { 150 struct nvme_request *req; 151 struct nvme_command *cmd; 152 153 req = nvme_allocate_request_null(cb_fn, cb_arg); 154 155 cmd = &req->cmd; 156 cmd->opc = NVME_OPC_DELETE_IO_SQ; 157 158 /* 159 * TODO: create a delete io submission queue command data 160 * structure. 161 */ 162 cmd->cdw10 = htole32(io_que->id); 163 164 nvme_ctrlr_submit_admin_request(ctrlr, req); 165 } 166 167 void 168 nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint8_t feature, 169 uint32_t cdw11, uint32_t cdw12, uint32_t cdw13, uint32_t cdw14, 170 uint32_t cdw15, void *payload, uint32_t payload_size, 171 nvme_cb_fn_t cb_fn, void *cb_arg) 172 { 173 struct nvme_request *req; 174 struct nvme_command *cmd; 175 176 req = nvme_allocate_request_null(cb_fn, cb_arg); 177 178 cmd = &req->cmd; 179 cmd->opc = NVME_OPC_SET_FEATURES; 180 cmd->cdw10 = htole32(feature); 181 cmd->cdw11 = htole32(cdw11); 182 cmd->cdw12 = htole32(cdw12); 183 cmd->cdw13 = htole32(cdw13); 184 cmd->cdw14 = htole32(cdw14); 185 cmd->cdw15 = htole32(cdw15); 186 187 nvme_ctrlr_submit_admin_request(ctrlr, req); 188 } 189 190 void 191 nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint8_t feature, 192 uint32_t cdw11, void *payload, uint32_t payload_size, 193 nvme_cb_fn_t cb_fn, void *cb_arg) 194 { 195 struct nvme_request *req; 196 struct nvme_command *cmd; 197 198 req = nvme_allocate_request_null(cb_fn, cb_arg); 199 200 cmd = &req->cmd; 201 cmd->opc = NVME_OPC_GET_FEATURES; 202 cmd->cdw10 = htole32(feature); 203 cmd->cdw11 = htole32(cdw11); 204 205 nvme_ctrlr_submit_admin_request(ctrlr, req); 206 } 207 208 void 209 nvme_ctrlr_cmd_set_num_queues(struct nvme_controller *ctrlr, 210 uint32_t num_queues, nvme_cb_fn_t cb_fn, void *cb_arg) 211 { 212 uint32_t cdw11; 213 214 cdw11 = ((num_queues - 1) << 16) | (num_queues - 1); 215 nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_NUMBER_OF_QUEUES, cdw11, 216 0, 0, 0, 0, NULL, 0, cb_fn, cb_arg); 217 } 218 219 void 220 nvme_ctrlr_cmd_set_async_event_config(struct nvme_controller *ctrlr, 221 uint32_t state, nvme_cb_fn_t cb_fn, void *cb_arg) 222 { 223 uint32_t cdw11; 224 225 cdw11 = state; 226 nvme_ctrlr_cmd_set_feature(ctrlr, 227 NVME_FEAT_ASYNC_EVENT_CONFIGURATION, cdw11, 0, 0, 0, 0, NULL, 0, 228 cb_fn, cb_arg); 229 } 230 231 void 232 nvme_ctrlr_cmd_set_interrupt_coalescing(struct nvme_controller *ctrlr, 233 uint32_t microseconds, uint32_t threshold, nvme_cb_fn_t cb_fn, void *cb_arg) 234 { 235 uint32_t cdw11; 236 237 if ((microseconds/100) >= 0x100) { 238 nvme_printf(ctrlr, "invalid coal time %d, disabling\n", 239 microseconds); 240 microseconds = 0; 241 threshold = 0; 242 } 243 244 if (threshold >= 0x100) { 245 nvme_printf(ctrlr, "invalid threshold %d, disabling\n", 246 threshold); 247 threshold = 0; 248 microseconds = 0; 249 } 250 251 cdw11 = ((microseconds/100) << 8) | threshold; 252 nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_INTERRUPT_COALESCING, cdw11, 253 0, 0, 0, 0, NULL, 0, cb_fn, cb_arg); 254 } 255 256 void 257 nvme_ctrlr_cmd_get_log_page(struct nvme_controller *ctrlr, uint8_t log_page, 258 uint32_t nsid, void *payload, uint32_t payload_size, nvme_cb_fn_t cb_fn, 259 void *cb_arg) 260 { 261 struct nvme_request *req; 262 struct nvme_command *cmd; 263 264 req = nvme_allocate_request_vaddr(payload, payload_size, cb_fn, cb_arg); 265 266 cmd = &req->cmd; 267 cmd->opc = NVME_OPC_GET_LOG_PAGE; 268 cmd->nsid = htole32(nsid); 269 cmd->cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16; 270 cmd->cdw10 |= log_page; 271 cmd->cdw10 = htole32(cmd->cdw10); 272 273 nvme_ctrlr_submit_admin_request(ctrlr, req); 274 } 275 276 void 277 nvme_ctrlr_cmd_get_error_page(struct nvme_controller *ctrlr, 278 struct nvme_error_information_entry *payload, uint32_t num_entries, 279 nvme_cb_fn_t cb_fn, void *cb_arg) 280 { 281 282 KASSERT(num_entries > 0, ("%s called with num_entries==0\n", __func__)); 283 284 /* Controller's error log page entries is 0-based. */ 285 KASSERT(num_entries <= (ctrlr->cdata.elpe + 1), 286 ("%s called with num_entries=%d but (elpe+1)=%d\n", __func__, 287 num_entries, ctrlr->cdata.elpe + 1)); 288 289 if (num_entries > (ctrlr->cdata.elpe + 1)) 290 num_entries = ctrlr->cdata.elpe + 1; 291 292 nvme_ctrlr_cmd_get_log_page(ctrlr, NVME_LOG_ERROR, 293 NVME_GLOBAL_NAMESPACE_TAG, payload, sizeof(*payload) * num_entries, 294 cb_fn, cb_arg); 295 } 296 297 void 298 nvme_ctrlr_cmd_get_health_information_page(struct nvme_controller *ctrlr, 299 uint32_t nsid, struct nvme_health_information_page *payload, 300 nvme_cb_fn_t cb_fn, void *cb_arg) 301 { 302 303 nvme_ctrlr_cmd_get_log_page(ctrlr, NVME_LOG_HEALTH_INFORMATION, 304 nsid, payload, sizeof(*payload), cb_fn, cb_arg); 305 } 306 307 void 308 nvme_ctrlr_cmd_get_firmware_page(struct nvme_controller *ctrlr, 309 struct nvme_firmware_page *payload, nvme_cb_fn_t cb_fn, void *cb_arg) 310 { 311 312 nvme_ctrlr_cmd_get_log_page(ctrlr, NVME_LOG_FIRMWARE_SLOT, 313 NVME_GLOBAL_NAMESPACE_TAG, payload, sizeof(*payload), cb_fn, 314 cb_arg); 315 } 316 317 void 318 nvme_ctrlr_cmd_abort(struct nvme_controller *ctrlr, uint16_t cid, 319 uint16_t sqid, nvme_cb_fn_t cb_fn, void *cb_arg) 320 { 321 struct nvme_request *req; 322 struct nvme_command *cmd; 323 324 req = nvme_allocate_request_null(cb_fn, cb_arg); 325 326 cmd = &req->cmd; 327 cmd->opc = NVME_OPC_ABORT; 328 cmd->cdw10 = htole32((cid << 16) | sqid); 329 330 nvme_ctrlr_submit_admin_request(ctrlr, req); 331 } 332