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 */
nvme_admin_submit_cmd(struct nvme_ctrlr * ctrlr,struct nvme_cmd * cmd,void * buf,uint32_t len,nvme_cmd_cb cb_fn,void * cb_arg)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 */
nvme_admin_wait_cmd(struct nvme_ctrlr * ctrlr,struct nvme_completion_poll_status * status)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 */
nvme_admin_exec_cmd(struct nvme_ctrlr * ctrlr,struct nvme_cmd * cmd,void * buf,uint32_t len)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 */
nvme_admin_identify_ctrlr(struct nvme_ctrlr * ctrlr,struct nvme_ctrlr_data * cdata)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 */
nvme_admin_get_feature(struct nvme_ctrlr * ctrlr,enum nvme_feat_sel sel,enum nvme_feat feature,uint32_t cdw11,uint32_t * attributes)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 */
nvme_admin_set_feature(struct nvme_ctrlr * ctrlr,bool save,enum nvme_feat feature,uint32_t cdw11,uint32_t cdw12,uint32_t * attributes)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 */
nvme_admin_create_ioq(struct nvme_ctrlr * ctrlr,struct nvme_qpair * qpair,enum nvme_io_queue_type io_qtype)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 */
nvme_admin_delete_ioq(struct nvme_ctrlr * ctrlr,struct nvme_qpair * qpair,enum nvme_io_queue_type io_qtype)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 */
nvme_admin_identify_ns(struct nvme_ctrlr * ctrlr,uint16_t nsid,struct nvme_ns_data * nsdata)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 */
nvme_admin_attach_ns(struct nvme_ctrlr * ctrlr,uint32_t nsid,struct nvme_ctrlr_list * clist)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 */
nvme_admin_detach_ns(struct nvme_ctrlr * ctrlr,uint32_t nsid,struct nvme_ctrlr_list * clist)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 */
nvme_admin_create_ns(struct nvme_ctrlr * ctrlr,struct nvme_ns_data * nsdata,unsigned int * nsid)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 */
nvme_admin_delete_ns(struct nvme_ctrlr * ctrlr,unsigned int nsid)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 */
nvme_admin_format_nvm(struct nvme_ctrlr * ctrlr,unsigned int nsid,struct nvme_format * format)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 */
nvme_admin_get_log_page(struct nvme_ctrlr * ctrlr,uint8_t log_page,uint32_t nsid,void * payload,uint32_t payload_size)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 */
nvme_admin_abort_cmd(struct nvme_ctrlr * ctrlr,uint16_t cid,uint16_t sqid)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 */
nvme_admin_fw_commit(struct nvme_ctrlr * ctrlr,const struct nvme_fw_commit * fw_commit)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 */
nvme_admin_fw_image_dl(struct nvme_ctrlr * ctrlr,void * fw,uint32_t size,uint32_t offset)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