libmultipath: nvme: update to nvme-cli v1.9
[multipath-tools/.git] / libmultipath / nvme / nvme-ioctl.c
1 #include <assert.h>
2 #include <sys/ioctl.h>
3 #include <sys/stat.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <unistd.h>
7
8 #include <errno.h>
9 #include <getopt.h>
10 #include <fcntl.h>
11 #include <inttypes.h>
12 #include <locale.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <math.h>
18
19 #include "nvme-ioctl.h"
20
21 static int nvme_verify_chr(int fd)
22 {
23         static struct stat nvme_stat;
24         int err = fstat(fd, &nvme_stat);
25
26         if (err < 0) {
27                 perror("fstat");
28                 return errno;
29         }
30         if (!S_ISCHR(nvme_stat.st_mode)) {
31                 fprintf(stderr,
32                         "Error: requesting reset on non-controller handle\n");
33                 return ENOTBLK;
34         }
35         return 0;
36 }
37
38 int nvme_subsystem_reset(int fd)
39 {
40         int ret;
41
42         ret = nvme_verify_chr(fd);
43         if (ret)
44                 return ret;
45         return ioctl(fd, NVME_IOCTL_SUBSYS_RESET);
46 }
47
48 int nvme_reset_controller(int fd)
49 {
50         int ret;
51
52         ret = nvme_verify_chr(fd);
53         if (ret)
54                 return ret;
55         return ioctl(fd, NVME_IOCTL_RESET);
56 }
57
58 int nvme_ns_rescan(int fd)
59 {
60         int ret;
61
62         ret = nvme_verify_chr(fd);
63         if (ret)
64                 return ret;
65         return ioctl(fd, NVME_IOCTL_RESCAN);
66 }
67
68 int nvme_get_nsid(int fd)
69 {
70         static struct stat nvme_stat;
71         int err = fstat(fd, &nvme_stat);
72
73         if (err < 0)
74                 return -errno;
75
76         if (!S_ISBLK(nvme_stat.st_mode)) {
77                 fprintf(stderr,
78                         "Error: requesting namespace-id from non-block device\n");
79                 errno = ENOTBLK;
80                 return -errno;
81         }
82         return ioctl(fd, NVME_IOCTL_ID);
83 }
84
85 int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
86                          struct nvme_passthru_cmd *cmd)
87 {
88         return ioctl(fd, ioctl_cmd, cmd);
89 }
90
91 static int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd)
92 {
93         return ioctl(fd, NVME_IOCTL_ADMIN_CMD, cmd);
94 }
95
96 static int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd)
97 {
98         return ioctl(fd, NVME_IOCTL_IO_CMD, cmd);
99 }
100
101 int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode,
102                   __u8 flags, __u16 rsvd,
103                   __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11,
104                   __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15,
105                   __u32 data_len, void *data, __u32 metadata_len,
106                   void *metadata, __u32 timeout_ms, __u32 *result)
107 {
108         struct nvme_passthru_cmd cmd = {
109                 .opcode         = opcode,
110                 .flags          = flags,
111                 .rsvd1          = rsvd,
112                 .nsid           = nsid,
113                 .cdw2           = cdw2,
114                 .cdw3           = cdw3,
115                 .metadata       = (__u64)(uintptr_t) metadata,
116                 .addr           = (__u64)(uintptr_t) data,
117                 .metadata_len   = metadata_len,
118                 .data_len       = data_len,
119                 .cdw10          = cdw10,
120                 .cdw11          = cdw11,
121                 .cdw12          = cdw12,
122                 .cdw13          = cdw13,
123                 .cdw14          = cdw14,
124                 .cdw15          = cdw15,
125                 .timeout_ms     = timeout_ms,
126                 .result         = 0,
127         };
128         int err;
129
130         err = nvme_submit_passthru(fd, ioctl_cmd, &cmd);
131         if (!err && result)
132                 *result = cmd.result;
133         return err;
134 }
135
136 int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
137             __u32 dsmgmt, __u32 reftag, __u16 apptag, __u16 appmask, void *data,
138             void *metadata)
139 {
140         struct nvme_user_io io = {
141                 .opcode         = opcode,
142                 .flags          = 0,
143                 .control        = control,
144                 .nblocks        = nblocks,
145                 .rsvd           = 0,
146                 .metadata       = (__u64)(uintptr_t) metadata,
147                 .addr           = (__u64)(uintptr_t) data,
148                 .slba           = slba,
149                 .dsmgmt         = dsmgmt,
150                 .reftag         = reftag,
151                 .appmask        = appmask,
152                 .apptag         = apptag,
153         };
154         return ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
155 }
156
157 int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
158               __u32 reftag, __u16 apptag, __u16 appmask, void *data,
159               void *metadata)
160 {
161         return nvme_io(fd, nvme_cmd_read, slba, nblocks, control, dsmgmt,
162                        reftag, apptag, appmask, data, metadata);
163 }
164
165 int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
166                __u32 reftag, __u16 apptag, __u16 appmask, void *data,
167                void *metadata)
168 {
169         return nvme_io(fd, nvme_cmd_write, slba, nblocks, control, dsmgmt,
170                        reftag, apptag, appmask, data, metadata);
171 }
172
173 int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
174                  __u32 reftag, __u16 apptag, __u16 appmask, void *data,
175                  void *metadata)
176 {
177         return nvme_io(fd, nvme_cmd_compare, slba, nblocks, control, dsmgmt,
178                        reftag, apptag, appmask, data, metadata);
179 }
180
181 int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks,
182                 __u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
183 {
184         struct nvme_passthru_cmd cmd = {
185                 .opcode         = nvme_cmd_verify,
186                 .nsid           = nsid,
187                 .cdw10          = slba & 0xffffffff,
188                 .cdw11          = slba >> 32,
189                 .cdw12          = nblocks | (control << 16),
190                 .cdw14          = reftag,
191                 .cdw15          = apptag | (appmask << 16),
192         };
193
194         return nvme_submit_io_passthru(fd, &cmd);
195 }
196
197 int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
198                      __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10,
199                      __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14,
200                      __u32 cdw15, __u32 data_len, void *data,
201                      __u32 metadata_len, void *metadata, __u32 timeout_ms)
202 {
203         return nvme_passthru(fd, NVME_IOCTL_IO_CMD, opcode, flags, rsvd, nsid,
204                              cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14,
205                              cdw15, data_len, data, metadata_len, metadata,
206                              timeout_ms, NULL);
207 }
208
209 int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb,
210                      __u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
211 {
212         struct nvme_passthru_cmd cmd = {
213                 .opcode         = nvme_cmd_write_zeroes,
214                 .nsid           = nsid,
215                 .cdw10          = slba & 0xffffffff,
216                 .cdw11          = slba >> 32,
217                 .cdw12          = nlb | (control << 16),
218                 .cdw14          = reftag,
219                 .cdw15          = apptag | (appmask << 16),
220         };
221
222         return nvme_submit_io_passthru(fd, &cmd);
223 }
224
225 int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb)
226 {
227         struct nvme_passthru_cmd cmd = {
228                 .opcode         = nvme_cmd_write_uncor,
229                 .nsid           = nsid,
230                 .cdw10          = slba & 0xffffffff,
231                 .cdw11          = slba >> 32,
232                 .cdw12          = nlb,
233         };
234
235         return nvme_submit_io_passthru(fd, &cmd);
236 }
237
238 int nvme_flush(int fd, __u32 nsid)
239 {
240         struct nvme_passthru_cmd cmd = {
241                 .opcode         = nvme_cmd_flush,
242                 .nsid           = nsid,
243         };
244
245         return nvme_submit_io_passthru(fd, &cmd);
246 }
247
248 int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
249              __u16 nr_ranges)
250 {
251         struct nvme_passthru_cmd cmd = {
252                 .opcode         = nvme_cmd_dsm,
253                 .nsid           = nsid,
254                 .addr           = (__u64)(uintptr_t) dsm,
255                 .data_len       = nr_ranges * sizeof(*dsm),
256                 .cdw10          = nr_ranges - 1,
257                 .cdw11          = cdw11,
258         };
259
260         return nvme_submit_io_passthru(fd, &cmd);
261 }
262
263 struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas,
264                                             __u64 *slbas, __u16 nr_ranges)
265 {
266         int i;
267         struct nvme_dsm_range *dsm = malloc(nr_ranges * sizeof(*dsm));
268
269         if (!dsm) {
270                 fprintf(stderr, "malloc: %s\n", strerror(errno));
271                 return NULL;
272         }
273         for (i = 0; i < nr_ranges; i++) {
274                 dsm[i].cattr = cpu_to_le32(ctx_attrs[i]);
275                 dsm[i].nlb = cpu_to_le32(llbas[i]);
276                 dsm[i].slba = cpu_to_le64(slbas[i]);
277         }
278         return dsm;
279 }
280
281 int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
282                       bool iekey, __u64 crkey, __u64 nrkey)
283 {
284         __le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) };
285         __u32 cdw10 = (racqa & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8;
286         struct nvme_passthru_cmd cmd = {
287                 .opcode         = nvme_cmd_resv_acquire,
288                 .nsid           = nsid,
289                 .cdw10          = cdw10,
290                 .addr           = (__u64)(uintptr_t) (payload),
291                 .data_len       = sizeof(payload),
292         };
293
294         return nvme_submit_io_passthru(fd, &cmd);
295 }
296
297 int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
298                        bool iekey, __u64 crkey, __u64 nrkey)
299 {
300         __le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) };
301         __u32 cdw10 = (rrega & 0x7) | (iekey ? 1 << 3 : 0) | cptpl << 30;
302
303         struct nvme_passthru_cmd cmd = {
304                 .opcode         = nvme_cmd_resv_register,
305                 .nsid           = nsid,
306                 .cdw10          = cdw10,
307                 .addr           = (__u64)(uintptr_t) (payload),
308                 .data_len       = sizeof(payload),
309         };
310
311         return nvme_submit_io_passthru(fd, &cmd);
312 }
313
314 int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela,
315                       bool iekey, __u64 crkey)
316 {
317         __le64 payload[1] = { cpu_to_le64(crkey) };
318         __u32 cdw10 = (rrela & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8;
319
320         struct nvme_passthru_cmd cmd = {
321                 .opcode         = nvme_cmd_resv_release,
322                 .nsid           = nsid,
323                 .cdw10          = cdw10,
324                 .addr           = (__u64)(uintptr_t) (payload),
325                 .data_len       = sizeof(payload),
326         };
327
328         return nvme_submit_io_passthru(fd, &cmd);
329 }
330
331 int nvme_resv_report(int fd, __u32 nsid, __u32 numd, __u32 cdw11, void *data)
332 {
333         struct nvme_passthru_cmd cmd = {
334                 .opcode         = nvme_cmd_resv_report,
335                 .nsid           = nsid,
336                 .cdw10          = numd,
337                 .cdw11          = cdw11,
338                 .addr           = (__u64)(uintptr_t) data,
339                 .data_len       = (numd + 1) << 2,
340         };
341
342         return nvme_submit_io_passthru(fd, &cmd);
343 }
344
345 int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data)
346 {
347         struct nvme_admin_cmd cmd = {
348                 .opcode         = nvme_admin_identify,
349                 .nsid           = nsid,
350                 .addr           = (__u64)(uintptr_t) data,
351                 .data_len       = NVME_IDENTIFY_DATA_SIZE,
352                 .cdw10          = cdw10,
353                 .cdw11          = cdw11,
354         };
355
356         return nvme_submit_admin_passthru(fd, &cmd);
357 }
358
359 int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data)
360 {
361         return nvme_identify13(fd, nsid, cdw10, 0, data);
362 }
363
364 int nvme_identify_ctrl(int fd, void *data)
365 {
366         return nvme_identify(fd, 0, 1, data);
367 }
368
369 int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data)
370 {
371         int cns = present ? NVME_ID_CNS_NS_PRESENT : NVME_ID_CNS_NS;
372
373         return nvme_identify(fd, nsid, cns, data);
374 }
375
376 int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data)
377 {
378         int cns = all ? NVME_ID_CNS_NS_PRESENT_LIST : NVME_ID_CNS_NS_ACTIVE_LIST;
379
380         return nvme_identify(fd, nsid, cns, data);
381 }
382
383 int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
384 {
385         int cns = nsid ? NVME_ID_CNS_CTRL_NS_LIST : NVME_ID_CNS_CTRL_LIST;
386
387         return nvme_identify(fd, nsid, (cntid << 16) | cns, data);
388 }
389
390 int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
391 {
392         return nvme_identify(fd, nsid, (cntid << 16) | NVME_ID_CNS_SCNDRY_CTRL_LIST, data);
393 }
394
395 int nvme_identify_ns_descs(int fd, __u32 nsid, void *data)
396 {
397
398         return nvme_identify(fd, nsid, NVME_ID_CNS_NS_DESC_LIST, data);
399 }
400
401 int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data)
402 {
403         return nvme_identify13(fd, 0, NVME_ID_CNS_NVMSET_LIST, nvmset_id, data);
404 }
405
406 int nvme_identify_ns_granularity(int fd, void *data)
407 {
408         return nvme_identify13(fd, 0, NVME_ID_CNS_NS_GRANULARITY, 0, data);
409 }
410
411 int nvme_identify_uuid(int fd, void *data)
412 {
413         return nvme_identify(fd, 0, NVME_ID_CNS_UUID_LIST, data);
414 }
415
416 int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
417                  __u16 lsi, bool rae, __u8 uuid_ix, __u32 data_len, void *data)
418 {
419         struct nvme_admin_cmd cmd = {
420                 .opcode         = nvme_admin_get_log_page,
421                 .nsid           = nsid,
422                 .addr           = (__u64)(uintptr_t) data,
423                 .data_len       = data_len,
424         };
425         __u32 numd = (data_len >> 2) - 1;
426         __u16 numdu = numd >> 16, numdl = numd & 0xffff;
427
428         cmd.cdw10 = log_id | (numdl << 16) | (rae ? 1 << 15 : 0);
429         if (lsp)
430                 cmd.cdw10 |= lsp << 8;
431
432         cmd.cdw11 = numdu | (lsi << 16);
433         cmd.cdw12 = lpo;
434         cmd.cdw13 = (lpo >> 32);
435         cmd.cdw14 = uuid_ix;
436
437         return nvme_submit_admin_passthru(fd, &cmd);
438
439 }
440
441 int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
442                  __u32 data_len, void *data)
443 {
444         void *ptr = data;
445         __u32 offset = 0, xfer_len = data_len;
446         int ret;
447
448         /*
449          * 4k is the smallest possible transfer unit, so by
450          * restricting ourselves for 4k transfers we avoid having
451          * to check the MDTS value of the controller.
452          */
453         do {
454                 xfer_len = data_len - offset;
455                 if (xfer_len > 4096)
456                         xfer_len = 4096;
457
458                 ret = nvme_get_log13(fd, nsid, log_id, NVME_NO_LOG_LSP,
459                                      offset, 0, rae, xfer_len, ptr);
460                 if (ret)
461                         return ret;
462
463                 offset += xfer_len;
464                 ptr += xfer_len;
465         } while (offset < data_len);
466
467         return 0;
468 }
469
470 int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
471                            int ctrl_init, size_t log_page_size, __u64 offset)
472 {
473         if (ctrl_init)
474                 return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_CTRL,
475                                       NVME_NO_LOG_LSP, offset,
476                                       0, 1, log_page_size, lp);
477         if (generate_report)
478                 return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST,
479                                       NVME_TELEM_LSP_CREATE, offset,
480                                       0, 1, log_page_size, lp);
481         else
482                 return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST,
483                                       NVME_NO_LOG_LSP, offset,
484                                       0, 1, log_page_size, lp);
485 }
486
487 int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log)
488 {
489         return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_FW_SLOT, true,
490                         sizeof(*fw_log), fw_log);
491 }
492
493 int nvme_changed_ns_list_log(int fd, struct nvme_changed_ns_list_log *changed_ns_list_log)
494 {
495         return nvme_get_log(fd, 0, NVME_LOG_CHANGED_NS, true,
496                         sizeof(changed_ns_list_log->log),
497                         changed_ns_list_log->log);
498 }
499
500 int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log)
501 {
502         return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_ERROR, false,
503                         entries * sizeof(*err_log), err_log);
504 }
505
506 int nvme_endurance_log(int fd, __u16 group_id, struct nvme_endurance_group_log *endurance_log)
507 {
508         return nvme_get_log13(fd, 0, NVME_LOG_ENDURANCE_GROUP, 0, 0, group_id, 0,
509                         sizeof(*endurance_log), endurance_log);
510 }
511
512 int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log)
513 {
514         return nvme_get_log(fd, nsid, NVME_LOG_SMART, false,
515                         sizeof(*smart_log), smart_log);
516 }
517
518 int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo)
519 {
520         __u64 lpo = 0;
521
522         return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_ANA, rgo, lpo, 0,
523                         true, ana_log_len, ana_log);
524 }
525
526 int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log)
527 {
528         return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_DEVICE_SELF_TEST, false,
529                 sizeof(*self_test_log), self_test_log);
530 }
531
532 int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log)
533 {
534         return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_CMD_EFFECTS, false,
535                         sizeof(*effects_log), effects_log);
536 }
537
538 int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size)
539 {
540         return nvme_get_log(fd, 0, NVME_LOG_DISC, false, size, log);
541 }
542
543 int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log)
544 {
545         return nvme_get_log(fd, 0, NVME_LOG_SANITIZE, false,
546                         sizeof(*sanitize_log), sanitize_log);
547 }
548
549 int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11,
550                  __u32 cdw12, __u32 data_len, void *data, __u32 *result)
551 {
552         struct nvme_admin_cmd cmd = {
553                 .opcode         = opcode,
554                 .nsid           = nsid,
555                 .cdw10          = cdw10,
556                 .cdw11          = cdw11,
557                 .cdw12          = cdw12,
558                 .addr           = (__u64)(uintptr_t) data,
559                 .data_len       = data_len,
560         };
561         int err;
562
563         err = nvme_submit_admin_passthru(fd, &cmd);
564         if (!err && result)
565                 *result = cmd.result;
566         return err;
567 }
568
569 int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12,
570                      bool save, __u32 data_len, void *data, __u32 *result)
571 {
572         __u32 cdw10 = fid | (save ? 1 << 31 : 0);
573
574         return nvme_feature(fd, nvme_admin_set_features, nsid, cdw10, value,
575                             cdw12, data_len, data, result);
576 }
577
578
579 /*
580  * Perform the opposite operation of the byte-swapping code at the start of the
581  * kernel function nvme_user_cmd().
582  */
583 static void nvme_to_passthru_cmd(struct nvme_passthru_cmd *pcmd,
584                                  const struct nvme_command *ncmd)
585 {
586         assert(sizeof(*ncmd) < sizeof(*pcmd));
587         memset(pcmd, 0, sizeof(*pcmd));
588         pcmd->opcode = ncmd->common.opcode;
589         pcmd->flags = ncmd->common.flags;
590         pcmd->rsvd1 = ncmd->common.command_id;
591         pcmd->nsid = le32_to_cpu(ncmd->common.nsid);
592         pcmd->cdw2 = le32_to_cpu(ncmd->common.cdw2[0]);
593         pcmd->cdw3 = le32_to_cpu(ncmd->common.cdw2[1]);
594         /* Skip metadata and addr */
595         pcmd->cdw10 = le32_to_cpu(ncmd->common.cdw10[0]);
596         pcmd->cdw11 = le32_to_cpu(ncmd->common.cdw10[1]);
597         pcmd->cdw12 = le32_to_cpu(ncmd->common.cdw10[2]);
598         pcmd->cdw13 = le32_to_cpu(ncmd->common.cdw10[3]);
599         pcmd->cdw14 = le32_to_cpu(ncmd->common.cdw10[4]);
600         pcmd->cdw15 = le32_to_cpu(ncmd->common.cdw10[5]);
601 }
602
603 int nvme_get_property(int fd, int offset, uint64_t *value)
604 {
605         struct nvme_passthru_cmd pcmd;
606         struct nvmf_property_get_command pg = {
607                 .opcode = nvme_fabrics_command,
608                 .fctype = nvme_fabrics_type_property_get,
609                 .offset = cpu_to_le32(offset),
610                 .attrib = is_64bit_reg(offset),
611         };
612         struct nvme_command gcmd;
613         int err;
614
615         gcmd.prop_get = pg;
616         nvme_to_passthru_cmd(&pcmd, &gcmd);
617         err = nvme_submit_admin_passthru(fd, &pcmd);
618         if (!err) {
619                 /*
620                  * nvme_submit_admin_passthru() stores the lower 32 bits
621                  * of the property value in pcmd.result using CPU endianness.
622                  */
623                 *value = pcmd.result;
624         }
625         return err;
626 }
627
628 int nvme_get_properties(int fd, void **pbar)
629 {
630         int offset;
631         uint64_t value;
632         int err;
633         int size = getpagesize();
634
635         *pbar = malloc(size);
636         if (!*pbar) {
637                 fprintf(stderr, "malloc: %s\n", strerror(errno));
638                 return -ENOMEM;
639         }
640
641         memset(*pbar, 0xff, size);
642         for (offset = NVME_REG_CAP; offset <= NVME_REG_CMBSZ;) {
643                 err = nvme_get_property(fd, offset, &value);
644                 if (err > 0 && (err & 0xff) == NVME_SC_INVALID_FIELD) {
645                         err = 0;
646                         value = -1;
647                 } else if (err) {
648                         free(*pbar);
649                         break;
650                 }
651                 if (is_64bit_reg(offset)) {
652                         *(uint64_t *)(*pbar + offset) = value;
653                         offset += 8;
654                 } else {
655                         *(uint32_t *)(*pbar + offset) = value;
656                         offset += 4;
657                 }
658         }
659
660         return err;
661 }
662
663 int nvme_set_property(int fd, int offset, uint64_t value)
664 {
665         struct nvmf_property_set_command ps = {
666                 .opcode = nvme_fabrics_command,
667                 .fctype = nvme_fabrics_type_property_set,
668                 .offset = cpu_to_le32(offset),
669                 .value = cpu_to_le64(value),
670                 .attrib = is_64bit_reg(offset),
671         };
672         struct nvme_command scmd;
673         struct nvme_passthru_cmd pcmd;
674
675         scmd.prop_set = ps;
676         nvme_to_passthru_cmd(&pcmd, &scmd);
677         return nvme_submit_admin_passthru(fd, &pcmd);
678 }
679
680 int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, __u32 cdw11,
681                      __u32 data_len, void *data, __u32 *result)
682 {
683         __u32 cdw10 = fid | sel << 8;
684
685         return nvme_feature(fd, nvme_admin_get_features, nsid, cdw10, cdw11,
686                             0, data_len, data, result);
687 }
688
689 int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
690                 __u8 pil, __u8 ms, __u32 timeout)
691 {
692         __u32 cdw10 = lbaf | ms << 4 | pi << 5 | pil << 8 | ses << 9;
693         struct nvme_admin_cmd cmd = {
694                 .opcode         = nvme_admin_format_nvm,
695                 .nsid           = nsid,
696                 .cdw10          = cdw10,
697                 .timeout_ms     = timeout,
698         };
699
700         return nvme_submit_admin_passthru(fd, &cmd);
701 }
702
703 int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
704                    __u8 dps, __u8 nmic, __u32 timeout, __u32 *result)
705 {
706         struct nvme_id_ns ns = {
707                 .nsze           = cpu_to_le64(nsze),
708                 .ncap           = cpu_to_le64(ncap),
709                 .flbas          = flbas,
710                 .dps            = dps,
711                 .nmic           = nmic,
712         };
713         struct nvme_admin_cmd cmd = {
714                 .opcode         = nvme_admin_ns_mgmt,
715                 .addr           = (__u64)(uintptr_t) ((void *)&ns),
716                 .cdw10          = 0,
717                 .data_len       = 0x1000,
718                 .timeout_ms     = timeout,
719         };
720         int err;
721
722         err = nvme_submit_admin_passthru(fd, &cmd);
723         if (!err && result)
724                 *result = cmd.result;
725         return err;
726 }
727
728 int nvme_ns_delete(int fd, __u32 nsid, __u32 timeout)
729 {
730         struct nvme_admin_cmd cmd = {
731                 .opcode         = nvme_admin_ns_mgmt,
732                 .nsid           = nsid,
733                 .cdw10          = 1,
734                 .timeout_ms     = timeout,
735         };
736
737         return nvme_submit_admin_passthru(fd, &cmd);
738 }
739
740 int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist,
741                        bool attach)
742 {
743         int i;
744         __u8 buf[0x1000];
745         struct nvme_controller_list *cntlist =
746                                         (struct nvme_controller_list *)buf;
747         struct nvme_admin_cmd cmd = {
748                 .opcode         = nvme_admin_ns_attach,
749                 .nsid           = nsid,
750                 .addr           = (__u64)(uintptr_t) cntlist,
751                 .cdw10          = attach ? 0 : 1,
752                 .data_len       = 0x1000,
753         };
754
755         memset(buf, 0, sizeof(buf));
756         cntlist->num = cpu_to_le16(num_ctrls);
757         for (i = 0; i < num_ctrls; i++)
758                 cntlist->identifier[i] = cpu_to_le16(ctrlist[i]);
759
760         return nvme_submit_admin_passthru(fd, &cmd);
761 }
762
763 int nvme_ns_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist)
764 {
765         return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, true);
766 }
767
768 int nvme_ns_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist)
769 {
770         return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, false);
771 }
772
773 int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data)
774 {
775         struct nvme_admin_cmd cmd = {
776                 .opcode         = nvme_admin_download_fw,
777                 .addr           = (__u64)(uintptr_t) data,
778                 .data_len       = data_len,
779                 .cdw10          = (data_len >> 2) - 1,
780                 .cdw11          = offset >> 2,
781         };
782
783         return nvme_submit_admin_passthru(fd, &cmd);
784 }
785
786 int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid)
787 {
788         struct nvme_admin_cmd cmd = {
789                 .opcode         = nvme_admin_activate_fw,
790                 .cdw10          = (bpid << 31) | (action << 3) | slot,
791         };
792
793         return nvme_submit_admin_passthru(fd, &cmd);
794 }
795
796 int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
797                   __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result)
798 {
799         struct nvme_admin_cmd cmd = {
800                 .opcode         = nvme_admin_security_send,
801                 .addr           = (__u64)(uintptr_t) data,
802                 .data_len       = data_len,
803                 .nsid           = nsid,
804                 .cdw10          = secp << 24 | spsp << 8 | nssf,
805                 .cdw11          = tl,
806         };
807         int err;
808
809         err = nvme_submit_admin_passthru(fd, &cmd);
810         if (!err && result)
811                 *result = cmd.result;
812         return err;
813 }
814
815 int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
816                   __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result)
817 {
818         struct nvme_admin_cmd cmd = {
819                 .opcode         = nvme_admin_security_recv,
820                 .nsid           = nsid,
821                 .cdw10          = secp << 24 | spsp << 8 | nssf,
822                 .cdw11          = al,
823                 .addr           = (__u64)(uintptr_t) data,
824                 .data_len       = data_len,
825         };
826         int err;
827
828         err = nvme_submit_admin_passthru(fd, &cmd);
829         if (!err && result)
830                 *result = cmd.result;
831         return err;
832 }
833
834 int nvme_get_lba_status(int fd, __u64 slba, __u32 mndw, __u8 atype, __u16 rl,
835                 void *data)
836 {
837         struct nvme_admin_cmd cmd = {
838                 .opcode =  nvme_admin_get_lba_status,
839                 .addr = (__u64)(uintptr_t) data,
840                 .cdw10 = slba & 0xffffffff,
841                 .cdw11 = slba >> 32,
842                 .cdw12 = mndw,
843                 .cdw13 = (atype << 24) | rl,
844         };
845
846         return nvme_submit_admin_passthru(fd, &cmd);
847 }
848
849 int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
850                   __u32 data_len, __u32 dw12, void *data, __u32 *result)
851 {
852         struct nvme_admin_cmd cmd = {
853                 .opcode         = nvme_admin_directive_send,
854                 .addr           = (__u64)(uintptr_t) data,
855                 .data_len       = data_len,
856                 .nsid           = nsid,
857                 .cdw10          = data_len? (data_len >> 2) - 1 : 0,
858                 .cdw11          = dspec << 16 | dtype << 8 | doper,
859                 .cdw12          = dw12,
860         };
861         int err;
862
863         err = nvme_submit_admin_passthru(fd, &cmd);
864         if (!err && result)
865                 *result = cmd.result;
866         return err;
867 }
868
869 int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
870                   __u32 data_len, __u32 dw12, void *data, __u32 *result)
871 {
872         struct nvme_admin_cmd cmd = {
873                 .opcode         = nvme_admin_directive_recv,
874                 .addr           = (__u64)(uintptr_t) data,
875                 .data_len       = data_len,
876                 .nsid           = nsid,
877                 .cdw10          = data_len? (data_len >> 2) - 1 : 0,
878                 .cdw11          = dspec << 16 | dtype << 8 | doper,
879                 .cdw12          = dw12,
880         };
881         int err;
882
883         err = nvme_submit_admin_passthru(fd, &cmd);
884         if (!err && result)
885                 *result = cmd.result;
886         return err;
887 }
888
889 int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
890                   __u8 no_dealloc, __u32 ovrpat)
891 {
892         struct nvme_admin_cmd cmd = {
893                 .opcode         = nvme_admin_sanitize_nvm,
894                 .cdw10          = no_dealloc << 9 | oipbp << 8 |
895                                   owpass << NVME_SANITIZE_OWPASS_SHIFT |
896                                   ause << 3 | sanact,
897                 .cdw11          = ovrpat,
898         };
899
900         return nvme_submit_admin_passthru(fd, &cmd);
901 }
902
903 int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10)
904 {
905         struct nvme_admin_cmd cmd = {
906                 .opcode = nvme_admin_dev_self_test,
907                 .nsid = nsid,
908                 .cdw10 = cdw10,
909         };
910
911         return nvme_submit_admin_passthru(fd, &cmd);
912 }
913
914 int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result)
915 {
916         struct nvme_admin_cmd cmd = {
917                 .opcode = nvme_admin_virtual_mgmt,
918                 .cdw10  = cdw10,
919                 .cdw11  = cdw11,
920         };
921         int err;
922
923         err = nvme_submit_admin_passthru(fd, &cmd);
924         if (!err && result)
925                 *result = cmd.result;
926
927         return err;
928 }