]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mfiutil/mfi_cmd.c
libfido2: update to 1.9.0
[FreeBSD/FreeBSD.git] / usr.sbin / mfiutil / mfi_cmd.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2008, 2009 Yahoo!, Inc.
5  * All rights reserved.
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  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The names of the authors may not be used to endorse or promote
16  *    products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33
34 #include <sys/param.h>
35 #include <sys/ioctl.h>
36 #include <sys/sysctl.h>
37 #include <sys/uio.h>
38
39 #include <err.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <time.h>
46 #include <unistd.h>
47 #include <paths.h>
48
49 #include "mfiutil.h"
50 #include <dev/mfi/mfi_ioctl.h>
51
52 static const char *mfi_status_codes[] = {
53         "Command completed successfully",
54         "Invalid command",
55         "Invalid DMCD opcode",
56         "Invalid parameter",
57         "Invalid Sequence Number",
58         "Abort isn't possible for the requested command",
59         "Application 'host' code not found",
60         "Application in use",
61         "Application not initialized",
62         "Array index invalid",
63         "Array row not empty",
64         "Configuration resource conflict",
65         "Device not found",
66         "Drive too small",
67         "Flash memory allocation failed",
68         "Flash download already in progress",
69         "Flash operation failed",
70         "Bad flash image",
71         "Incomplete flash image",
72         "Flash not open",
73         "Flash not started",
74         "Flush failed",
75         "Specified application doesn't have host-resident code",
76         "Volume consistency check in progress",
77         "Volume initialization in progress",
78         "Volume LBA out of range",
79         "Maximum number of volumes are already configured",
80         "Volume is not OPTIMAL",
81         "Volume rebuild in progress",
82         "Volume reconstruction in progress",
83         "Volume RAID level is wrong for requested operation",
84         "Too many spares assigned",
85         "Scratch memory not available",
86         "Error writing MFC data to SEEPROM",
87         "Required hardware is missing",
88         "Item not found",
89         "Volume drives are not within an enclosure",
90         "Drive clear in progress",
91         "Drive type mismatch (SATA vs SAS)",
92         "Patrol read disabled",
93         "Invalid row index",
94         "SAS Config - Invalid action",
95         "SAS Config - Invalid data",
96         "SAS Config - Invalid page",
97         "SAS Config - Invalid type",
98         "SCSI command completed with error",
99         "SCSI I/O request failed",
100         "SCSI RESERVATION_CONFLICT",
101         "One or more flush operations during shutdown failed",
102         "Firmware time is not set",
103         "Wrong firmware or drive state",
104         "Volume is offline",
105         "Peer controller rejected request",
106         "Unable to inform peer of communication changes",
107         "Volume reservation already in progress",
108         "I2C errors were detected",
109         "PCI errors occurred during XOR/DMA operation",
110         "Diagnostics failed",
111         "Unable to process command as boot messages are pending",
112         "Foreign configuration is incomplete"
113 };
114
115 const char *
116 mfi_status(u_int status_code)
117 {
118         static char buffer[16];
119
120         if (status_code == MFI_STAT_INVALID_STATUS)
121                 return ("Invalid status");
122         if (status_code < sizeof(mfi_status_codes) / sizeof(char *))
123                 return (mfi_status_codes[status_code]);
124         snprintf(buffer, sizeof(buffer), "Status: 0x%02x", status_code);
125         return (buffer);
126 }
127
128 const char *
129 mfi_raid_level(uint8_t primary_level, uint8_t secondary_level)
130 {
131         static char buf[16];
132
133         switch (primary_level) {
134         case DDF_RAID0:
135                 return ("RAID-0");
136         case DDF_RAID1:
137                 if (secondary_level != 0)
138                         return ("RAID-10");
139                 else
140                         return ("RAID-1");
141         case DDF_RAID1E:
142                 return ("RAID-1E");
143         case DDF_RAID3:
144                 return ("RAID-3");
145         case DDF_RAID5:
146                 if (secondary_level != 0)
147                         return ("RAID-50");
148                 else
149                         return ("RAID-5");
150         case DDF_RAID5E:
151                 return ("RAID-5E");
152         case DDF_RAID5EE:
153                 return ("RAID-5EE");
154         case DDF_RAID6:
155                 if (secondary_level != 0)
156                         return ("RAID-60");
157                 else
158                         return ("RAID-6");
159         case DDF_JBOD:
160                 return ("JBOD");
161         case DDF_CONCAT:
162                 return ("CONCAT");
163         default:
164                 sprintf(buf, "LVL 0x%02x", primary_level);
165                 return (buf);
166         }
167 }
168
169 static int
170 mfi_query_disk(int fd, uint8_t target_id, struct mfi_query_disk *info)
171 {
172
173         bzero(info, sizeof(*info));
174         info->array_id = target_id;
175         if (ioctl(fd, MFIIO_QUERY_DISK, info) < 0)
176                 return (-1);
177         if (!info->present) {
178                 errno = ENXIO;
179                 return (-1);
180         }
181         return (0);
182 }
183
184 const char *
185 mfi_volume_name(int fd, uint8_t target_id)
186 {
187         static struct mfi_query_disk info;
188         static char buf[4];
189
190         if (mfi_query_disk(fd, target_id, &info) < 0) {
191                 snprintf(buf, sizeof(buf), "%d", target_id);
192                 return (buf);
193         }
194         return (info.devname);
195 }
196
197 int
198 mfi_volume_busy(int fd, uint8_t target_id)
199 {
200         struct mfi_query_disk info;
201
202         /* Assume it isn't mounted if we can't get information. */
203         if (mfi_query_disk(fd, target_id, &info) < 0)
204                 return (0);
205         return (info.open != 0);
206 }
207
208 /*
209  * Check if the running kernel supports changing the RAID
210  * configuration of the mfi controller.
211  */
212 int
213 mfi_reconfig_supported(const char *dev)
214 {
215         char mibname[64];
216         const char *cp;
217         size_t len;
218         int dummy, mfi_unit;
219
220         cp = dev + strlen(_PATH_DEV);
221         if (strncmp(cp, MRSAS_TYPE, strlen(MRSAS_TYPE)) == 0)
222                 return (1);
223
224         cp += strlen(MFI_TYPE);
225         mfi_unit = strtol(cp, NULL, 10);;
226
227         len = sizeof(dummy);
228         snprintf(mibname, sizeof(mibname),
229             "dev.mfi.%d.delete_busy_volumes", mfi_unit);
230         return (sysctlbyname(mibname, &dummy, &len, NULL, 0) == 0);
231 }
232
233 int
234 mfi_lookup_volume(int fd, const char *name, uint8_t *target_id)
235 {
236         struct mfi_query_disk info;
237         struct mfi_ld_list list;
238         char *cp;
239         long val;
240         u_int i;
241
242         /* If it's a valid number, treat it as a raw target ID. */
243         val = strtol(name, &cp, 0);
244         if (*cp == '\0') {
245                 *target_id = val;
246                 return (0);
247         }
248
249         if (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_LIST, &list, sizeof(list),
250             NULL, 0, NULL) < 0)
251                 return (-1);
252
253         for (i = 0; i < list.ld_count; i++) {
254                 if (mfi_query_disk(fd, list.ld_list[i].ld.v.target_id,
255                     &info) < 0)
256                         continue;
257                 if (strcmp(name, info.devname) == 0) {
258                         *target_id = list.ld_list[i].ld.v.target_id;
259                         return (0);
260                 }
261         }
262         errno = EINVAL;
263         return (-1);
264 }
265
266 int
267 mfi_dcmd_command(int fd, uint32_t opcode, void *buf, size_t bufsize,
268     uint8_t *mbox, size_t mboxlen, uint8_t *statusp)
269 {
270         struct mfi_ioc_passthru ioc;
271         struct mfi_dcmd_frame *dcmd;
272         int r;
273
274         if ((mbox != NULL && (mboxlen == 0 || mboxlen > MFI_MBOX_SIZE)) ||
275             (mbox == NULL && mboxlen != 0)) {
276                 errno = EINVAL;
277                 return (-1);
278         }
279
280         bzero(&ioc, sizeof(ioc));
281         dcmd = &ioc.ioc_frame;
282         if (mbox)
283                 bcopy(mbox, dcmd->mbox, mboxlen);
284         dcmd->header.cmd = MFI_CMD_DCMD;
285         dcmd->header.timeout = 0;
286         dcmd->header.flags = 0;
287         dcmd->header.data_len = bufsize;
288         dcmd->opcode = opcode;
289
290         ioc.buf = buf;
291         ioc.buf_size = bufsize;
292         r = ioctl(fd, MFIIO_PASSTHRU, &ioc);
293         if (r < 0)
294                 return (r);
295
296         if (statusp != NULL)
297                 *statusp = dcmd->header.cmd_status;
298         else if (dcmd->header.cmd_status != MFI_STAT_OK) {
299                 warnx("Command failed: %s",
300                     mfi_status(dcmd->header.cmd_status));
301                 errno = EIO;
302                 return (-1);
303         }
304         return (0);
305 }
306
307 int
308 mfi_ctrl_get_info(int fd, struct mfi_ctrl_info *info, uint8_t *statusp)
309 {
310
311         return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_GETINFO, info,
312             sizeof(struct mfi_ctrl_info), NULL, 0, statusp));
313 }
314
315 int
316 mfi_open(char *dev, int acs)
317 {
318         int ret;
319
320         ret = open(dev, acs);
321         if (ret < 0)
322                 warn("Couldn't open %s", dev);
323         return (ret);
324 }
325
326 static void
327 print_time_humanized(uint seconds)
328 {
329
330         if (seconds > 3600) {
331                 printf("%u:", seconds / 3600);
332         }
333         if (seconds > 60) {
334                 seconds %= 3600;
335                 printf("%02u:%02u", seconds / 60, seconds % 60);
336         } else {
337                 printf("%us", seconds);
338         }
339 }
340
341 void
342 mfi_display_progress(const char *label, struct mfi_progress *prog)
343 {
344         uint seconds;
345
346         printf("%s: %.2f%% complete after ", label,
347             (float)prog->progress * 100 / 0xffff);
348         print_time_humanized(prog->elapsed_seconds);
349         if (prog->progress != 0 && prog->elapsed_seconds > 10) {
350                 printf(" finished in ");
351                 seconds = (0x10000 * (uint32_t)prog->elapsed_seconds) /
352                     prog->progress - prog->elapsed_seconds;
353                 print_time_humanized(seconds);
354         }
355         printf("\n");
356 }
357
358 int
359 mfi_table_handler(struct mfiutil_command **start, struct mfiutil_command **end,
360     int ac, char **av)
361 {
362         struct mfiutil_command **cmd;
363
364         if (ac < 2) {
365                 warnx("The %s command requires a sub-command.", av[0]);
366                 return (EINVAL);
367         }
368         for (cmd = start; cmd < end; cmd++) {
369                 if (strcmp((*cmd)->name, av[1]) == 0)
370                         return ((*cmd)->handler(ac - 1, av + 1));
371         }
372
373         warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
374         return (ENOENT);
375 }