]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/nvmecontrol/ns.c
Usage cleanup pt 2
[FreeBSD/FreeBSD.git] / sbin / nvmecontrol / ns.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017 Netflix, Inc
5  * Copyright (C) 2018 Alexander Motin <mav@FreeBSD.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/ioccom.h>
34
35 #include <err.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include "nvmecontrol.h"
43
44 SET_DECLARE(ns, struct nvme_function);
45
46 #define NS_USAGE                                                        \
47         "ns (create|delete|attach|detach)\n"
48
49 /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
50
51 #define NSCREATE_USAGE                                                  \
52         "ns create -s size [-c cap] [-f fmt] [-m mset] [-n nmic] [-p pi] [-l pil] nvmeN\n"
53
54 #define NSDELETE_USAGE                                                  \
55         "ns delete -n nsid nvmeN\n"
56
57 #define NSATTACH_USAGE                                                  \
58         "ns attach -n nsid [-c ctrlrid] nvmeN \n"
59
60 #define NSDETACH_USAGE                                                  \
61         "ns detach -n nsid [-c ctrlrid] nvmeN\n"
62
63 void nscreate(struct nvme_function *nf, int argc, char *argv[]);
64 void nsdelete(struct nvme_function *nf, int argc, char *argv[]);
65 void nsattach(struct nvme_function *nf, int argc, char *argv[]);
66 void nsdetach(struct nvme_function *nf, int argc, char *argv[]);
67
68 NVME_COMMAND(ns, create, nscreate, NSCREATE_USAGE);
69 NVME_COMMAND(ns, delete, nsdelete, NSDELETE_USAGE);
70 NVME_COMMAND(ns, attach, nsattach, NSATTACH_USAGE);
71 NVME_COMMAND(ns, detach, nsdetach, NSDETACH_USAGE);
72
73 struct ns_result_str {
74         uint16_t res;
75         const char * str;
76 };
77
78 static struct ns_result_str ns_result[] = {
79         { 0x2,  "Invalid Field"},
80         { 0xa,  "Invalid Format"},
81         { 0xb,  "Invalid Namespace or format"},
82         { 0x15, "Namespace insufficent capacity"},
83         { 0x16, "Namespace ID unavaliable"},
84         { 0x18, "Namespace already attached"},
85         { 0x19, "Namespace is private"},
86         { 0x1a, "Namespace is not attached"},
87         { 0x1b, "Thin provisioning not supported"},
88         { 0x1c, "Controller list invalid"},
89         { 0xFFFF, "Unknown"}
90 };
91
92 static const char *
93 get_res_str(uint16_t res)
94 {
95         struct ns_result_str *t = ns_result;
96
97         while (t->res != 0xFFFF) {
98                 if (t->res == res)
99                         return (t->str);
100                 t++;
101         }
102         return t->str;
103 }
104
105 /*
106  * NS MGMT Command specific status values:
107  * 0xa = Invalid Format
108  * 0x15 = Namespace Insuffience capacity
109  * 0x16 = Namespace ID  unavailable (number namespaces exceeded)
110  * 0xb = Thin Provisioning Not supported
111  */
112 void
113 nscreate(struct nvme_function *nf, int argc, char *argv[])
114 {
115         struct nvme_pt_command  pt;
116         struct nvme_controller_data cd;
117         struct nvme_namespace_data nsdata;
118         int64_t nsze = -1, cap = -1;
119         int     ch, fd, result, lbaf = 0, mset = 0, nmic = -1, pi = 0, pil = 0;
120
121         if (optind >= argc)
122                 usage(nf);
123
124         while ((ch = getopt(argc, argv, "s:c:f:m:n:p:l:")) != -1) {
125                 switch (ch) {
126                 case 's':
127                         nsze = strtol(optarg, (char **)NULL, 0);
128                         break;
129                 case 'c':
130                         cap = strtol(optarg, (char **)NULL, 0);
131                         break;
132                 case 'f':
133                         lbaf = strtol(optarg, (char **)NULL, 0);
134                         break;
135                 case 'm':
136                         mset = strtol(optarg, NULL, 0);
137                         break;
138                 case 'n':
139                         nmic = strtol(optarg, NULL, 0);
140                         break;
141                 case 'p':
142                         pi = strtol(optarg, NULL, 0);
143                         break;
144                 case 'l':
145                         pil = strtol(optarg, NULL, 0);
146                         break;
147                 default:
148                         usage(nf);
149                 }
150         }
151
152         if (optind >= argc)
153                 usage(nf);
154
155         if (cap == -1)
156                 cap = nsze;
157         if (nsze == -1 || cap == -1)
158                 usage(nf);
159
160         open_dev(argv[optind], &fd, 1, 1);
161         read_controller_data(fd, &cd);
162
163         /* Check that controller can execute this command. */
164         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
165             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
166                 errx(1, "controller does not support namespace management");
167
168         /* Allow namespaces sharing if Multi-Path I/O is supported. */
169         if (nmic == -1) {
170                 nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK <<
171                      NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0;
172         }
173
174         memset(&nsdata, 0, sizeof(nsdata));
175         nsdata.nsze = (uint64_t)nsze;
176         nsdata.ncap = (uint64_t)cap;
177         nsdata.flbas = ((lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK)
178              << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) |
179             ((mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK)
180              << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT);
181         nsdata.dps = ((pi & NVME_NS_DATA_DPS_MD_START_MASK)
182              << NVME_NS_DATA_DPS_MD_START_SHIFT) |
183             ((pil & NVME_NS_DATA_DPS_PIT_MASK)
184              << NVME_NS_DATA_DPS_PIT_SHIFT);
185         nsdata.nmic = nmic;
186         nvme_namespace_data_swapbytes(&nsdata);
187
188         memset(&pt, 0, sizeof(pt));
189         pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
190
191         pt.cmd.cdw10 = 0; /* create */
192         pt.buf = &nsdata;
193         pt.len = sizeof(struct nvme_namespace_data);
194         pt.is_read = 0; /* passthrough writes data to ctrlr */
195         if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
196                 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
197
198         if (nvme_completion_is_error(&pt.cpl)) {
199                 errx(1, "namespace creation failed: %s",
200                     get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
201                     NVME_STATUS_SC_MASK));
202         }
203         printf("namespace %d created\n", pt.cpl.cdw0);
204         exit(0);
205 }
206
207 void
208 nsdelete(struct nvme_function *nf, int argc, char *argv[])
209 {
210         struct nvme_pt_command  pt;
211         struct nvme_controller_data cd;
212         int     ch, fd, result, nsid = -2;
213         char buf[2];
214
215         if (optind >= argc)
216                 usage(nf);
217
218         while ((ch = getopt(argc, argv, "n:")) != -1) {
219                 switch ((char)ch) {
220                 case  'n':
221                         nsid = strtol(optarg, (char **)NULL, 0);
222                         break;
223                 default:
224                         usage(nf);
225                 }
226         }
227
228         if (optind >= argc || nsid == -2)
229                 usage(nf);
230
231         open_dev(argv[optind], &fd, 1, 1);
232         read_controller_data(fd, &cd);
233
234         /* Check that controller can execute this command. */
235         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
236             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
237                 errx(1, "controller does not support namespace management");
238
239         memset(&pt, 0, sizeof(pt));
240         pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
241         pt.cmd.cdw10 = 1; /* delete */
242         pt.buf = buf;
243         pt.len = sizeof(buf);
244         pt.is_read = 1;
245         pt.cmd.nsid = (uint32_t)nsid;
246
247         if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
248                 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
249
250         if (nvme_completion_is_error(&pt.cpl)) {
251                 errx(1, "namespace deletion failed: %s",
252                     get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
253                     NVME_STATUS_SC_MASK));
254         }
255         printf("namespace %d deleted\n", nsid);
256         exit(0);
257 }
258
259 /*
260  * Attach and Detach use Dword 10, and a controller list (section 4.9)
261  * This struct is 4096 bytes in size.
262  * 0h = attach
263  * 1h = detach
264  *
265  * Result values for both attach/detach:
266  *
267  * Completion 18h = Already attached
268  *            19h = NS is private and already attached to a controller
269  *            1Ah = Not attached, request could not be completed
270  *            1Ch = Controller list invalid.
271  *
272  * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
273  */
274 void
275 nsattach(struct nvme_function *nf, int argc, char *argv[])
276 {
277         struct nvme_pt_command  pt;
278         struct nvme_controller_data cd;
279         int     ctrlrid = -2;
280         int     fd, ch, result, nsid = -1;
281         uint16_t clist[2048];
282
283         if (optind >= argc)
284                 usage(nf);
285
286         while ((ch = getopt(argc, argv, "n:c:")) != -1) {
287                 switch (ch) {
288                 case 'n':
289                         nsid = strtol(optarg, (char **)NULL, 0);
290                         break;
291                 case 'c':
292                         ctrlrid = strtol(optarg, (char **)NULL, 0);
293                         break;
294                 default:
295                         usage(nf);
296                 }
297         }
298
299         if (optind >= argc)
300                 usage(nf);
301
302         if (nsid == -1 )
303                 usage(nf);
304
305         open_dev(argv[optind], &fd, 1, 1);
306         read_controller_data(fd, &cd);
307
308         /* Check that controller can execute this command. */
309         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
310             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
311                 errx(1, "controller does not support namespace management");
312
313         if (ctrlrid == -1) {
314                 /* Get full list of controllers to attach to. */
315                 memset(&pt, 0, sizeof(pt));
316                 pt.cmd.opc = NVME_OPC_IDENTIFY;
317                 pt.cmd.cdw10 = htole32(0x13);
318                 pt.buf = clist;
319                 pt.len = sizeof(clist);
320                 pt.is_read = 1;
321                 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
322                         err(1, "identify request failed");
323                 if (nvme_completion_is_error(&pt.cpl))
324                         errx(1, "identify request returned error");
325         } else {
326                 /* By default attach to this controller. */
327                 if (ctrlrid == -2)
328                         ctrlrid = cd.ctrlr_id;
329                 memset(&clist, 0, sizeof(clist));
330                 clist[0] = htole16(1);
331                 clist[1] = htole16(ctrlrid);
332         }
333
334         memset(&pt, 0, sizeof(pt));
335         pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
336         pt.cmd.cdw10 = 0; /* attach */
337         pt.cmd.nsid = (uint32_t)nsid;
338         pt.buf = &clist;
339         pt.len = sizeof(clist);
340
341         if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
342                 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
343
344         if (nvme_completion_is_error(&pt.cpl)) {
345                 errx(1, "namespace attach failed: %s",
346                     get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
347                     NVME_STATUS_SC_MASK));
348         }
349         printf("namespace %d attached\n", nsid);
350         exit(0);
351 }
352
353 void
354 nsdetach(struct nvme_function *nf, int argc, char *argv[])
355 {
356         struct nvme_pt_command  pt;
357         struct nvme_controller_data cd;
358         int     ctrlrid = -2;
359         int     fd, ch, result, nsid = -1;
360         uint16_t clist[2048];
361
362         if (optind >= argc)
363                 usage(nf);
364
365         while ((ch = getopt(argc, argv, "n:c:")) != -1) {
366                 switch (ch) {
367                 case 'n':
368                         nsid = strtol(optarg, (char **)NULL, 0);
369                         break;
370                 case 'c':
371                         ctrlrid = strtol(optarg, (char **)NULL, 0);
372                         break;
373                 default:
374                         usage(nf);
375                 }
376         }
377
378         if (optind >= argc)
379                 usage(nf);
380
381         if (nsid == -1)
382                 usage(nf);
383
384         open_dev(argv[optind], &fd, 1, 1);
385         read_controller_data(fd, &cd);
386
387         /* Check that controller can execute this command. */
388         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
389             NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
390                 errx(1, "controller does not support namespace management");
391
392         if (ctrlrid == -1) {
393                 /* Get list of controllers this namespace attached to. */
394                 memset(&pt, 0, sizeof(pt));
395                 pt.cmd.opc = NVME_OPC_IDENTIFY;
396                 pt.cmd.nsid = htole32(nsid);
397                 pt.cmd.cdw10 = htole32(0x12);
398                 pt.buf = clist;
399                 pt.len = sizeof(clist);
400                 pt.is_read = 1;
401                 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
402                         err(1, "identify request failed");
403                 if (nvme_completion_is_error(&pt.cpl))
404                         errx(1, "identify request returned error");
405                 if (clist[0] == 0) {
406                         ctrlrid = cd.ctrlr_id;
407                         memset(&clist, 0, sizeof(clist));
408                         clist[0] = htole16(1);
409                         clist[1] = htole16(ctrlrid);
410                 }
411         } else {
412                 /* By default detach from this controller. */
413                 if (ctrlrid == -2)
414                         ctrlrid = cd.ctrlr_id;
415                 memset(&clist, 0, sizeof(clist));
416                 clist[0] = htole16(1);
417                 clist[1] = htole16(ctrlrid);
418         }
419
420         memset(&pt, 0, sizeof(pt));
421         pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
422         pt.cmd.cdw10 = 1; /* detach */
423         pt.cmd.nsid = (uint32_t)nsid;
424         pt.buf = &clist;
425         pt.len = sizeof(clist);
426
427         if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
428                 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
429
430         if (nvme_completion_is_error(&pt.cpl)) {
431                 errx(1, "namespace detach failed: %s",
432                     get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
433                     NVME_STATUS_SC_MASK));
434         }
435         printf("namespace %d detached\n", nsid);
436         exit(0);
437 }
438
439 static void
440 ns(struct nvme_function *nf __unused, int argc, char *argv[])
441 {
442
443         DISPATCH(argc, argv, ns);
444 }
445
446 NVME_COMMAND(top, ns, ns, NS_USAGE);