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