ipfw3_nat: move func prototype into header
[dragonfly.git] / sbin / nvmectl / nvmectl.c
blob4329b1c08d4d5027a181094f96e8ec32aeb39e1e
1 /*
2 * Copyright (c) 2016 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. 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 * 3. Neither the name of The DragonFly Project 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.
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
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include "nvmectl.h"
37 typedef int (*cmd_t)(int ac, char **av, const char *id, int fd);
39 static cmd_t parsecmd(int ac, char **av, int *globokp);
40 static int cmd_info(int ac, char **av, const char *id, int fd);
41 static int cmd_errors(int ac, char **av, const char *id, int fd);
42 static void usage(int rc);
44 int VerboseOpt;
46 int
47 main(int ac, char **av)
49 int rc = 0;
50 int ch;
51 int nvmei;
52 int globok;
53 int i;
54 cmd_t cmd;
56 while ((ch = getopt(ac, av, "v")) != -1) {
57 switch(ch) {
58 case 'v':
59 ++VerboseOpt;
60 break;
61 default:
62 usage(1);
63 break;
67 ac -= optind;
68 av += optind;
70 for (nvmei = ac; nvmei > 0; --nvmei) {
71 if (strncmp(av[nvmei - 1], "nvme", 4) != 0)
72 break;
74 if (nvmei == 0)
75 usage(1);
77 globok = 0;
78 cmd = parsecmd(nvmei, av, &globok);
80 if (nvmei == ac && globok) {
81 i = 0;
82 for (;;) {
83 char *path;
84 int fd;
86 if (i)
87 printf("\n");
88 asprintf(&path, "/dev/nvme%d", i);
89 fd = open(path, O_RDWR);
90 free(path);
91 if (fd < 0)
92 break;
93 rc += cmd(nvmei, av, path + 5, fd);
94 close(fd);
95 ++i;
97 } else if (nvmei == ac && !globok) {
98 fprintf(stderr, "must specify nvmeX device for command\n");
99 } else {
100 for (i = nvmei; i < ac; ++i) {
101 char *path;
102 int fd;
104 if (i != nvmei)
105 printf("\n");
107 asprintf(&path, "/dev/%s", av[i]);
108 fd = open(path, O_RDWR);
109 if (fd < 0) {
110 fprintf(stderr, "open \"%s\": %s\n",
111 path,
112 strerror(errno));
113 } else {
114 rc += cmd(nvmei, av, path + 5, fd);
115 close(fd);
117 free(path);
120 return (rc ? 1 : 0);
123 static
124 cmd_t
125 parsecmd(int ac, char **av, int *globokp)
127 if (ac == 0)
128 usage(1);
129 if (strcmp(av[0], "info") == 0) {
130 *globokp = 1;
131 return cmd_info;
133 if (strcmp(av[0], "errors") == 0) {
134 *globokp = 1;
135 return cmd_errors;
137 fprintf(stderr, "Command %s not recognized\n", av[0]);
139 usage(1);
140 return NULL; /* NOT REACHED */
143 static
145 cmd_info(int ac __unused, char **av __unused, const char *id, int fd)
147 nvme_getlog_ioctl_t ioc;
148 nvme_log_smart_data_t *smart;
149 int count;
150 int i;
152 bzero(&ioc, sizeof(ioc));
153 ioc.lid = NVME_LID_SMART;
154 ioc.ret_size = sizeof(ioc.info.logsmart);
156 if (ioctl(fd, NVMEIOCGETLOG, &ioc) < 0) {
157 fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
158 return 1;
160 if (NVME_COMQ_STATUS_CODE_GET(ioc.status)) {
161 fprintf(stderr, "%s: type %d code 0x%02x\n",
163 NVME_COMQ_STATUS_TYPE_GET(ioc.status),
164 NVME_COMQ_STATUS_CODE_GET(ioc.status));
165 return 1;
167 printf("%s:\n", id);
168 smart = &ioc.info.logsmart;
170 printf("\tcrit_flags:\t");
171 if (smart->crit_flags) {
172 if (smart->crit_flags & NVME_SMART_CRF_RES80)
173 printf(" 80");
174 if (smart->crit_flags & NVME_SMART_CRF_RES40)
175 printf(" 40");
176 if (smart->crit_flags & NVME_SMART_CRF_RES20)
177 printf(" 20");
178 if (smart->crit_flags & NVME_SMART_CRF_VOLTL_BKUP_FAIL)
179 printf(" MEM_BACKUP_FAILED");
180 if (smart->crit_flags & NVME_SMART_CRF_MEDIA_RO)
181 printf(" MEDIA_RDONLY");
182 if (smart->crit_flags & NVME_SMART_CRF_UNRELIABLE)
183 printf(" MEDIA_UNRELIABLE");
184 if (smart->crit_flags & NVME_SMART_CRF_ABOVE_THRESH)
185 printf(" TOO_HOT");
186 if (smart->crit_flags & NVME_SMART_CRF_BELOW_THRESH)
187 printf(" TOO_COLD");
188 } else {
189 printf("none\n");
191 printf("\tcomp_temp:\t%dC\n",
192 (int)(smart->comp_temp1 + (smart->comp_temp2 << 8)) - 273);
193 printf("\tLIFE_LEFT:\t%d%% (%d%% used)\n",
194 100 - (int)smart->rated_life,
195 (int)smart->rated_life);
197 printf("\tread_bytes:\t%s\n",
198 format_number(smart->read_count[0] * 512000));
199 printf("\twrite_bytes:\t%s\n",
200 format_number(smart->write_count[0] * 512000));
201 printf("\tread_cmds:\t%s\n",
202 format_number(smart->read_cmds[0]));
203 printf("\twrite_cmds:\t%s\n",
204 format_number(smart->write_cmds[0]));
205 printf("\tbusy_time:\t%ld min (%1.2f hrs)\n",
206 smart->busy_time[0],
207 (double)smart->busy_time[0] / 60.0);
208 printf("\tpowon_hours:\t%ld\n", smart->powon_hours[0]);
209 printf("\tpower_cyc:\t%ld\n", smart->power_cycles[0]);
210 printf("\tunsafe_shut:\t%ld\n", smart->unsafe_shutdowns[0]);
212 printf("\tUNRECOV_ERR:\t%ld", smart->unrecoverable_errors[0]);
213 if (smart->unrecoverable_errors[0])
214 printf("\t*******WARNING*******");
215 printf("\n");
217 printf("\terr_log_ent:\t%ld\n", smart->error_log_entries[0]);
218 printf("\twarn_temp_time:\t%d min (%1.2f hrs)\n",
219 smart->warn_comp_temp_time,
220 (double)smart->warn_comp_temp_time / 60.0);
221 printf("\tcrit_temp_time:\t%d min (%1.2f hrs)\n",
222 smart->crit_comp_temp_time,
223 (double)smart->crit_comp_temp_time / 60.0);
225 printf("\ttemp_sensors:\t");
226 for (i = count = 0; i < 8; ++i) {
227 if (smart->temp_sensors[i]) {
228 if (count)
229 printf(" ");
230 printf("%dC", smart->temp_sensors[i] - 273);
231 ++count;
234 if (count == 0)
235 printf("none");
236 printf("\n");
238 return 0;
241 static
243 cmd_errors(int ac __unused, char **av __unused, const char *id, int fd)
245 nvme_getlog_ioctl_t ioc;
246 nvme_log_error_data_t *errs;
247 int i;
249 bzero(&ioc, sizeof(ioc));
250 ioc.lid = NVME_LID_ERROR;
251 ioc.ret_size = sizeof(ioc.info.logsmart);
253 if (ioctl(fd, NVMEIOCGETLOG, &ioc) < 0) {
254 fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
255 return 1;
257 if (NVME_COMQ_STATUS_CODE_GET(ioc.status)) {
258 fprintf(stderr, "%s: type %d code 0x%02x\n",
260 NVME_COMQ_STATUS_TYPE_GET(ioc.status),
261 NVME_COMQ_STATUS_CODE_GET(ioc.status));
262 return 1;
264 printf("%s:\n", id);
265 errs = &ioc.info.logerr[0];
267 for (i = 0; i < 64; ++i) {
268 if (errs->error_count == 0 && errs->subq_id == 0 &&
269 errs->cmd_id == 0 && errs->status == 0 &&
270 errs->param == 0 && errs->nsid == 0 &&
271 errs->vendor == 0 && errs->csi == 0 && errs->lba == 0)
272 continue;
274 if (errs->param || errs->vendor || errs->csi) {
275 printf("\t%2d cnt=%-3ld subq=%-2d cmdi=%-3d "
276 "status=%d,0x%02x parm=%04x nsid=%-3d vend=%d "
277 "csi=0x%lx lba=%ld",
278 i, errs->error_count,
279 (int16_t)errs->subq_id,
280 (int16_t)errs->cmd_id,
281 NVME_COMQ_STATUS_TYPE_GET(errs->status),
282 NVME_COMQ_STATUS_CODE_GET(errs->status),
283 errs->param, errs->nsid,
284 errs->vendor,
285 errs->csi, errs->lba);
286 } else {
287 printf("\t%2d cnt=%-3ld subq=%-2d cmdi=%-3d "
288 "status=%d,0x%02x nsid=%-3d lba=%ld",
289 i, errs->error_count,
290 (int16_t)errs->subq_id,
291 (int16_t)errs->cmd_id,
292 NVME_COMQ_STATUS_TYPE_GET(errs->status),
293 NVME_COMQ_STATUS_CODE_GET(errs->status),
294 errs->nsid,
295 errs->lba);
297 if (errs->status & NVME_COMQ_STATUS_DNR)
298 printf(" DNR");
299 printf(" %s\n", status_to_str(errs->status));
300 ++errs;
303 return 0;
306 static
307 void
308 usage(int rc)
310 fprintf(stderr,
311 "nvmectl [-v] cmd [nvme0,1,2...]\n"
312 "\tinfo\n"
313 "\terrors\n"
315 exit(rc);