1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. All rights reserved. 5 * Copyright (c) 2017, Western Digital Corporation or its affiliates. 6 * 7 * Redistribution and use in sourete and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of sourete code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "nvme_internal.h" 35 36 /* 37 * Allocate a request, set its command and submit it 38 * to the controller admin queue. 39 */ 40 static int nvme_admin_submit_cmd(struct nvme_ctrlr *ctrlr, 41 struct nvme_cmd *cmd, 42 void *buf, uint32_t len, 43 nvme_cmd_cb cb_fn, void *cb_arg) 44 { 45 struct nvme_request *req; 46 47 if (buf) 48 req = nvme_request_allocate_contig(&ctrlr->adminq, buf, len, 49 cb_fn, cb_arg); 50 else 51 req = nvme_request_allocate_null(&ctrlr->adminq, cb_fn, cb_arg); 52 if (!req) 53 return ENOMEM; 54 55 memcpy(&req->cmd, cmd, sizeof(req->cmd)); 56 57 return nvme_qpair_submit_request(&ctrlr->adminq, req); 58 } 59 60 /* 61 * Poll the controller admin queue waiting for a 62 * command completion. 63 */ 64 static int nvme_admin_wait_cmd(struct nvme_ctrlr *ctrlr, 65 struct nvme_completion_poll_status *status) 66 { 67 68 /* Wait for completion and check result */ 69 while (status->done == false) 70 nvme_qpair_poll(&ctrlr->adminq, 0); 71 72 if (nvme_cpl_is_error(&status->cpl)) { 73 nvme_notice("Admin command failed\n"); 74 return ENXIO; 75 } 76 77 return 0; 78 } 79 80 /* 81 * Execute an admin command. 82 */ 83 static int nvme_admin_exec_cmd(struct nvme_ctrlr *ctrlr, 84 struct nvme_cmd *cmd, 85 void *buf, uint32_t len) 86 { 87 struct nvme_completion_poll_status status; 88 int ret; 89 90 /* Submit the command */ 91 status.done = false; 92 ret = nvme_admin_submit_cmd(ctrlr, cmd, buf, len, 93 nvme_request_completion_poll_cb, 94 &status); 95 if (ret != 0) 96 return ret; 97 98 /* Wait for the command completion and check result */ 99 return nvme_admin_wait_cmd(ctrlr, &status); 100 } 101 102 /* 103 * Get a controller information. 104 */ 105 int nvme_admin_identify_ctrlr(struct nvme_ctrlr *ctrlr, 106 struct nvme_ctrlr_data *cdata) 107 { 108 struct nvme_cmd cmd; 109 110 /* Setup the command */ 111 memset(&cmd, 0, sizeof(struct nvme_cmd)); 112 cmd.opc = NVME_OPC_IDENTIFY; 113 cmd.cdw10 = NVME_IDENTIFY_CTRLR; 114 115 /* Execute the command */ 116 return nvme_admin_exec_cmd(ctrlr, &cmd, 117 cdata, sizeof(struct nvme_ctrlr_data)); 118 } 119 120 /* 121 * Get a controller feature. 122 */ 123 int nvme_admin_get_feature(struct nvme_ctrlr *ctrlr, 124 enum nvme_feat_sel sel, 125 enum nvme_feat feature, 126 uint32_t cdw11, 127 uint32_t *attributes) 128 { 129 struct nvme_completion_poll_status status; 130 struct nvme_cmd cmd; 131 int ret; 132 133 /* Setup the command */ 134 memset(&cmd, 0, sizeof(struct nvme_cmd)); 135 cmd.opc = NVME_OPC_GET_FEATURES; 136 cmd.cdw10 = (sel << 8) | feature; 137 cmd.cdw11 = cdw11; 138 139 /* Submit the command */ 140 status.done = false; 141 ret = nvme_admin_submit_cmd(ctrlr, &cmd, NULL, 0, 142 nvme_request_completion_poll_cb, 143 &status); 144 if (ret == 0) { 145 /* Wait for the command completion and check result */ 146 ret = nvme_admin_wait_cmd(ctrlr, &status); 147 if (ret == 0 && attributes) 148 *attributes = status.cpl.cdw0; 149 } 150 151 return ret; 152 } 153 154 /* 155 * Set a feature. 156 */ 157 int nvme_admin_set_feature(struct nvme_ctrlr *ctrlr, 158 bool save, 159 enum nvme_feat feature, 160 uint32_t cdw11, 161 uint32_t cdw12, 162 uint32_t *attributes) 163 { 164 struct nvme_completion_poll_status status; 165 struct nvme_cmd cmd; 166 int ret; 167 168 /* Setup the command */ 169 memset(&cmd, 0, sizeof(struct nvme_cmd)); 170 cmd.opc = NVME_OPC_SET_FEATURES; 171 cmd.cdw10 = feature; 172 if (save) 173 cmd.cdw10 |= (1 << 31); 174 cmd.cdw11 = cdw11; 175 cmd.cdw12 = cdw12; 176 177 /* Submit the command */ 178 status.done = false; 179 ret = nvme_admin_submit_cmd(ctrlr, &cmd, NULL, 0, 180 nvme_request_completion_poll_cb, 181 &status); 182 if (ret == 0) { 183 /* Wait for the command completion and check result */ 184 ret = nvme_admin_wait_cmd(ctrlr, &status); 185 if (ret == 0 && attributes) 186 *attributes = status.cpl.cdw0; 187 } 188 189 return ret; 190 } 191 192 /* 193 * Create an I/O queue. 194 */ 195 int nvme_admin_create_ioq(struct nvme_ctrlr *ctrlr, 196 struct nvme_qpair *qpair, 197 enum nvme_io_queue_type io_qtype) 198 { 199 struct nvme_cmd cmd; 200 201 /* Setup the command */ 202 memset(&cmd, 0, sizeof(struct nvme_cmd)); 203 switch(io_qtype) { 204 case NVME_IO_SUBMISSION_QUEUE: 205 cmd.opc = NVME_OPC_CREATE_IO_SQ; 206 cmd.cdw11 = (qpair->id << 16) | (qpair->qprio << 1) | 0x1; 207 cmd.dptr.prp.prp1 = qpair->cmd_bus_addr; 208 break; 209 case NVME_IO_COMPLETION_QUEUE: 210 cmd.opc = NVME_OPC_CREATE_IO_CQ; 211 #ifdef __HAIKU__ // TODO: Option! 212 cmd.cdw11 = 0x1 | 0x2; /* enable interrupts */ 213 #else 214 cmd.cdw11 = 0x1; 215 #endif 216 cmd.dptr.prp.prp1 = qpair->cpl_bus_addr; 217 break; 218 default: 219 return EINVAL; 220 } 221 222 cmd.cdw10 = ((qpair->entries - 1) << 16) | qpair->id; 223 224 /* Execute the command */ 225 return nvme_admin_exec_cmd(ctrlr, &cmd, NULL, 0); 226 } 227 228 /* 229 * Delete an I/O queue. 230 */ 231 int nvme_admin_delete_ioq(struct nvme_ctrlr *ctrlr, 232 struct nvme_qpair *qpair, 233 enum nvme_io_queue_type io_qtype) 234 { 235 struct nvme_cmd cmd; 236 237 /* Setup the command */ 238 memset(&cmd, 0, sizeof(struct nvme_cmd)); 239 switch(io_qtype) { 240 case NVME_IO_SUBMISSION_QUEUE: 241 cmd.opc = NVME_OPC_DELETE_IO_SQ; 242 break; 243 case NVME_IO_COMPLETION_QUEUE: 244 cmd.opc = NVME_OPC_DELETE_IO_CQ; 245 break; 246 default: 247 return EINVAL; 248 } 249 cmd.cdw10 = qpair->id; 250 251 /* Execute the command */ 252 return nvme_admin_exec_cmd(ctrlr, &cmd, NULL, 0); 253 } 254 255 /* 256 * Get a namespace information. 257 */ 258 int nvme_admin_identify_ns(struct nvme_ctrlr *ctrlr, 259 uint16_t nsid, 260 struct nvme_ns_data *nsdata) 261 { 262 struct nvme_cmd cmd; 263 264 /* Setup the command */ 265 memset(&cmd, 0, sizeof(struct nvme_cmd)); 266 cmd.opc = NVME_OPC_IDENTIFY; 267 cmd.cdw10 = NVME_IDENTIFY_NS; 268 cmd.nsid = nsid; 269 270 /* Execute the command */ 271 return nvme_admin_exec_cmd(ctrlr, &cmd, 272 nsdata, sizeof(struct nvme_ns_data)); 273 } 274 275 /* 276 * Attach a namespace. 277 */ 278 int nvme_admin_attach_ns(struct nvme_ctrlr *ctrlr, 279 uint32_t nsid, 280 struct nvme_ctrlr_list *clist) 281 { 282 struct nvme_cmd cmd; 283 284 /* Setup the command */ 285 memset(&cmd, 0, sizeof(struct nvme_cmd)); 286 cmd.opc = NVME_OPC_NS_ATTACHMENT; 287 cmd.nsid = nsid; 288 cmd.cdw10 = NVME_NS_CTRLR_ATTACH; 289 290 /* Execute the command */ 291 return nvme_admin_exec_cmd(ctrlr, &cmd, 292 clist, sizeof(struct nvme_ctrlr_list)); 293 } 294 295 /* 296 * Detach a namespace. 297 */ 298 int nvme_admin_detach_ns(struct nvme_ctrlr *ctrlr, 299 uint32_t nsid, 300 struct nvme_ctrlr_list *clist) 301 { 302 struct nvme_cmd cmd; 303 304 /* Setup the command */ 305 memset(&cmd, 0, sizeof(struct nvme_cmd)); 306 cmd.opc = NVME_OPC_NS_ATTACHMENT; 307 cmd.nsid = nsid; 308 cmd.cdw10 = NVME_NS_CTRLR_DETACH; 309 310 /* Execute the command */ 311 return nvme_admin_exec_cmd(ctrlr, &cmd, 312 clist, sizeof(struct nvme_ctrlr_list)); 313 } 314 315 /* 316 * Create a namespace. 317 */ 318 int nvme_admin_create_ns(struct nvme_ctrlr *ctrlr, 319 struct nvme_ns_data *nsdata, 320 unsigned int *nsid) 321 { 322 struct nvme_completion_poll_status status; 323 struct nvme_cmd cmd; 324 int ret; 325 326 /* Setup the command */ 327 memset(&cmd, 0, sizeof(struct nvme_cmd)); 328 cmd.opc = NVME_OPC_NS_MANAGEMENT; 329 cmd.cdw10 = NVME_NS_MANAGEMENT_CREATE; 330 331 /* Submit the command */ 332 status.done = false; 333 ret = nvme_admin_submit_cmd(ctrlr, &cmd, 334 nsdata, sizeof(struct nvme_ns_data), 335 nvme_request_completion_poll_cb, 336 &status); 337 if (ret == 0) 338 /* Wait for the command completion and check result */ 339 ret = nvme_admin_wait_cmd(ctrlr, &status); 340 341 if (ret != 0) 342 return ret; 343 344 *nsid = status.cpl.cdw0; 345 346 return 0; 347 } 348 349 /* 350 * Delete a namespace. 351 */ 352 int nvme_admin_delete_ns(struct nvme_ctrlr *ctrlr, 353 unsigned int nsid) 354 { 355 struct nvme_cmd cmd; 356 357 /* Setup the command */ 358 memset(&cmd, 0, sizeof(struct nvme_cmd)); 359 cmd.opc = NVME_OPC_NS_MANAGEMENT; 360 cmd.cdw10 = NVME_NS_MANAGEMENT_DELETE; 361 cmd.nsid = nsid; 362 363 /* Execute the command */ 364 return nvme_admin_exec_cmd(ctrlr, &cmd, NULL, 0); 365 } 366 367 /* 368 * Format media. 369 * (entire device or just the specified namespace) 370 */ 371 int nvme_admin_format_nvm(struct nvme_ctrlr *ctrlr, 372 unsigned int nsid, 373 struct nvme_format *format) 374 { 375 struct nvme_cmd cmd; 376 377 /* Setup the command */ 378 memset(&cmd, 0, sizeof(struct nvme_cmd)); 379 cmd.opc = NVME_OPC_FORMAT_NVM; 380 cmd.nsid = nsid; 381 memcpy(&cmd.cdw10, format, sizeof(uint32_t)); 382 383 /* Execute the command */ 384 return nvme_admin_exec_cmd(ctrlr, &cmd, NULL, 0); 385 } 386 387 /* 388 * Get a log page. 389 */ 390 int nvme_admin_get_log_page(struct nvme_ctrlr *ctrlr, 391 uint8_t log_page, 392 uint32_t nsid, 393 void *payload, 394 uint32_t payload_size) 395 { 396 struct nvme_cmd cmd; 397 398 /* Setup the command */ 399 memset(&cmd, 0, sizeof(struct nvme_cmd)); 400 cmd.opc = NVME_OPC_GET_LOG_PAGE; 401 cmd.nsid = nsid; 402 cmd.cdw10 = ((payload_size / sizeof(uint32_t)) - 1) << 16; 403 cmd.cdw10 |= log_page; 404 405 /* Execute the command */ 406 return nvme_admin_exec_cmd(ctrlr, &cmd, payload, payload_size); 407 } 408 409 /* 410 * Abort an admin or an I/O command. 411 */ 412 int nvme_admin_abort_cmd(struct nvme_ctrlr *ctrlr, 413 uint16_t cid, uint16_t sqid) 414 { 415 struct nvme_cmd cmd; 416 417 /* Setup the command */ 418 memset(&cmd, 0, sizeof(struct nvme_cmd)); 419 cmd.opc = NVME_OPC_ABORT; 420 cmd.cdw10 = (cid << 16) | sqid; 421 422 /* Execute the command */ 423 return nvme_admin_exec_cmd(ctrlr, &cmd, NULL, 0); 424 } 425 426 /* 427 * Validate a FW. 428 */ 429 int nvme_admin_fw_commit(struct nvme_ctrlr *ctrlr, 430 const struct nvme_fw_commit *fw_commit) 431 { 432 struct nvme_cmd cmd; 433 434 /* Setup the command */ 435 memset(&cmd, 0, sizeof(struct nvme_cmd)); 436 cmd.opc = NVME_OPC_FIRMWARE_COMMIT; 437 memcpy(&cmd.cdw10, fw_commit, sizeof(uint32_t)); 438 439 /* Execute the command */ 440 return nvme_admin_exec_cmd(ctrlr, &cmd, NULL, 0); 441 } 442 443 /* 444 * Download to the device a firmware. 445 */ 446 int nvme_admin_fw_image_dl(struct nvme_ctrlr *ctrlr, 447 void *fw, uint32_t size, 448 uint32_t offset) 449 { 450 struct nvme_cmd cmd; 451 452 /* Setup the command */ 453 memset(&cmd, 0, sizeof(struct nvme_cmd)); 454 cmd.opc = NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD; 455 cmd.cdw10 = (size >> 2) - 1; 456 cmd.cdw11 = offset >> 2; 457 458 /* Execute the command */ 459 return nvme_admin_exec_cmd(ctrlr, &cmd, fw, size); 460 } 461