nrelease - fix/improve livecd
[dragonfly.git] / usr.sbin / mptutil / mpt_cmd.c
1 /*-
2  * Copyright (c) 2008 Yahoo!, Inc.
3  * All rights reserved.
4  * Written by: John Baldwin <jhb@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the author nor the names of any co-contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD: src/usr.sbin/mptutil/mpt_cmd.c,v 1.2 2010/11/09 19:28:06 jhb Exp $
31  */
32
33 #include <sys/param.h>
34 #include <sys/errno.h>
35 #include <sys/ioctl.h>
36 #include <sys/mpt_ioctl.h>
37 #include <sys/sysctl.h>
38 #include <sys/uio.h>
39
40 #include <err.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46
47 #include "mptutil.h"
48
49 static const char *mpt_ioc_status_codes[] = {
50         "Success",                              /* 0x0000 */
51         "Invalid function",
52         "Busy",
53         "Invalid scatter-gather list",
54         "Internal error",
55         "Reserved",
56         "Insufficient resources",
57         "Invalid field",
58         "Invalid state",                        /* 0x0008 */
59         "Operation state not supported",
60         NULL,
61         NULL,
62         NULL,
63         NULL,
64         NULL,
65         NULL,
66         NULL,                                   /* 0x0010 */
67         NULL,
68         NULL,
69         NULL,
70         NULL,
71         NULL,
72         NULL,
73         NULL,
74         NULL,                                   /* 0x0018 */
75         NULL,
76         NULL,
77         NULL,
78         NULL,
79         NULL,
80         NULL,
81         NULL,
82         "Invalid configuration action",         /* 0x0020 */
83         "Invalid configuration type",
84         "Invalid configuration page",
85         "Invalid configuration data",
86         "No configuration defaults",
87         "Unable to commit configuration change",
88         NULL,
89         NULL,
90         NULL,                                   /* 0x0028 */
91         NULL,
92         NULL,
93         NULL,
94         NULL,
95         NULL,
96         NULL,
97         NULL,
98         NULL,                                   /* 0x0030 */
99         NULL,
100         NULL,
101         NULL,
102         NULL,
103         NULL,
104         NULL,
105         NULL,
106         NULL,                                   /* 0x0038 */
107         NULL,
108         NULL,
109         NULL,
110         NULL,
111         NULL,
112         NULL,
113         NULL,
114         "Recovered SCSI error",                 /* 0x0040 */
115         "Invalid SCSI bus",
116         "Invalid SCSI target ID",
117         "SCSI device not there",
118         "SCSI data overrun",
119         "SCSI data underrun",
120         "SCSI I/O error",
121         "SCSI protocol error",
122         "SCSI task terminated",                 /* 0x0048 */
123         "SCSI residual mismatch",
124         "SCSI task management failed",
125         "SCSI I/O controller terminated",
126         "SCSI external controller terminated",
127         "EEDP guard error",
128         "EEDP reference tag error",
129         "EEDP application tag error",
130         NULL,                                   /* 0x0050 */
131         NULL,
132         NULL,
133         NULL,
134         NULL,
135         NULL,
136         NULL,
137         NULL,
138         NULL,                                   /* 0x0058 */
139         NULL,
140         NULL,
141         NULL,
142         NULL,
143         NULL,
144         NULL,
145         NULL,
146         "SCSI target priority I/O",             /* 0x0060 */
147         "Invalid SCSI target port",
148         "Invalid SCSI target I/O index",
149         "SCSI target aborted",
150         "No connection retryable",
151         "No connection",
152         "FC aborted",
153         "Invalid FC receive ID",
154         "FC did invalid",                       /* 0x0068 */
155         "FC node logged out",
156         "Transfer count mismatch",
157         "STS data not set",
158         "FC exchange canceled",
159         "Data offset error",
160         "Too much write data",
161         "IU too short",
162         "ACK NAK timeout",                      /* 0x0070 */
163         "NAK received",
164         NULL,
165         NULL,
166         NULL,
167         NULL,
168         NULL,
169         NULL,
170         NULL,                                   /* 0x0078 */
171         NULL,
172         NULL,
173         NULL,
174         NULL,
175         NULL,
176         NULL,
177         NULL,
178         "LAN device not found",                 /* 0x0080 */
179         "LAN device failure",
180         "LAN transmit error",
181         "LAN transmit aborted",
182         "LAN receive error",
183         "LAN receive aborted",
184         "LAN partial packet",
185         "LAN canceled",
186         NULL,                                   /* 0x0088 */
187         NULL,
188         NULL,
189         NULL,
190         NULL,
191         NULL,
192         NULL,
193         NULL,
194         "SAS SMP request failed",               /* 0x0090 */
195         "SAS SMP data overrun",
196         NULL,
197         NULL,
198         NULL,
199         NULL,
200         NULL,
201         NULL,
202         "Inband aborted",                       /* 0x0098 */
203         "No inband connection",
204         NULL,
205         NULL,
206         NULL,
207         NULL,
208         NULL,
209         NULL,
210         "Diagnostic released",                  /* 0x00A0 */
211 };
212
213 static const char *mpt_raid_action_status_codes[] = {
214         "Success",
215         "Invalid action",
216         "Failure",
217         "Operation in progress",
218 };
219
220 const char *
221 mpt_ioc_status(U16 IOCStatus)
222 {
223         static char buffer[16];
224
225         IOCStatus &= MPI_IOCSTATUS_MASK;
226         if (IOCStatus < sizeof(mpt_ioc_status_codes) / sizeof(char *) &&
227             mpt_ioc_status_codes[IOCStatus] != NULL)
228                 return (mpt_ioc_status_codes[IOCStatus]);
229         snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
230         return (buffer);
231 }
232
233 const char *
234 mpt_raid_status(U16 ActionStatus)
235 {
236         static char buffer[16];
237
238         if (ActionStatus < sizeof(mpt_raid_action_status_codes) /
239             sizeof(char *))
240                 return (mpt_raid_action_status_codes[ActionStatus]);
241         snprintf(buffer, sizeof(buffer), "Status: 0x%04x", ActionStatus);
242         return (buffer);
243 }
244
245 const char *
246 mpt_raid_level(U8 VolumeType)
247 {
248         static char buf[16];
249
250         switch (VolumeType) {
251         case MPI_RAID_VOL_TYPE_IS:
252                 return ("RAID-0");
253         case MPI_RAID_VOL_TYPE_IM:
254                 return ("RAID-1");
255         case MPI_RAID_VOL_TYPE_IME:
256                 return ("RAID-1E");
257         case MPI_RAID_VOL_TYPE_RAID_5:
258                 return ("RAID-5");
259         case MPI_RAID_VOL_TYPE_RAID_6:
260                 return ("RAID-6");
261         case MPI_RAID_VOL_TYPE_RAID_10:
262                 return ("RAID-10");
263         case MPI_RAID_VOL_TYPE_RAID_50:
264                 return ("RAID-50");
265         default:
266                 sprintf(buf, "LVL 0x%02x", VolumeType);
267                 return (buf);
268         }
269 }
270
271 const char *
272 mpt_volume_name(U8 VolumeBus, U8 VolumeID)
273 {
274         static struct mpt_query_disk info;
275         static char buf[16];
276
277         if (mpt_query_disk(VolumeBus, VolumeID, &info) != 0) {
278                 /*
279                  * We only print out the bus number if it is non-zero
280                  * since mpt(4) only supports devices on bus zero
281                  * anyway.
282                  */
283                 if (VolumeBus == 0)
284                         snprintf(buf, sizeof(buf), "%d", VolumeID);
285                 else
286                         snprintf(buf, sizeof(buf), "%d:%d", VolumeBus,
287                             VolumeID);
288                 return (buf);
289         }
290         return (info.devname);
291 }
292
293 int
294 mpt_lookup_volume(int fd, const char *name, U8 *VolumeBus, U8 *VolumeID)
295 {
296         CONFIG_PAGE_IOC_2 *ioc2;
297         CONFIG_PAGE_IOC_2_RAID_VOL *vol;
298         struct mpt_query_disk info;
299         char *cp;
300         long bus, id;
301         int i;
302
303         /*
304          * Check for a raw [<bus>:]<id> string.  If the bus is not
305          * specified, assume bus 0.
306          */
307         bus = strtol(name, &cp, 0);
308         if (*cp == ':') {
309                 id = strtol(cp + 1, &cp, 0);
310                 if (*cp == '\0') {
311                         if (bus < 0 || bus > 0xff || id < 0 || id > 0xff) {
312                                 return (EINVAL);
313                         }
314                         *VolumeBus = bus;
315                         *VolumeID = id;
316                         return (0);
317                 }
318         } else if (*cp == '\0') {
319                 if (bus < 0 || bus > 0xff)
320                         return (EINVAL);
321                 *VolumeBus = 0;
322                 *VolumeID = bus;
323                 return (0);
324         }
325
326         ioc2 = mpt_read_ioc_page(fd, 2, NULL);
327         if (ioc2 == NULL)
328                 return (errno);
329
330         vol = ioc2->RaidVolume;
331         for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
332                 if (mpt_query_disk(vol->VolumeBus, vol->VolumeID, &info) != 0)
333                         continue;
334                 if (strcmp(name, info.devname) == 0) {
335                         *VolumeBus = vol->VolumeBus;
336                         *VolumeID = vol->VolumeID;
337                         free(ioc2);
338                         return (0);
339                 }
340         }
341         free(ioc2);
342         return (EINVAL);
343 }
344
345 int
346 mpt_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
347     CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
348 {
349         struct mpt_cfg_page_req req;
350
351         if (IOCStatus != NULL)
352                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
353         bzero(&req, sizeof(req));
354         req.header.PageType = PageType;
355         req.header.PageNumber = PageNumber;
356         req.page_address = PageAddress;
357         if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
358                 return (errno);
359         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
360                 if (IOCStatus != NULL)
361                         *IOCStatus = req.ioc_status;
362                 else
363                         warnx("Reading config page header failed: %s",
364                             mpt_ioc_status(req.ioc_status));
365                 return (EIO);
366         }
367         *header = req.header;
368         return (0);
369 }
370
371 void *
372 mpt_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
373     U16 *IOCStatus)
374 {
375         struct mpt_cfg_page_req req;
376         void *buf;
377         int error;
378
379         if (IOCStatus != NULL)
380                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
381         bzero(&req, sizeof(req));
382         req.header.PageType = PageType;
383         req.header.PageNumber = PageNumber;
384         req.page_address = PageAddress;
385         if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
386                 return (NULL);
387         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
388                 if (IOCStatus != NULL)
389                         *IOCStatus = req.ioc_status;
390                 else
391                         warnx("Reading config page header failed: %s",
392                             mpt_ioc_status(req.ioc_status));
393                 errno = EIO;
394                 return (NULL);
395         }
396         req.len = req.header.PageLength * 4;
397         buf = malloc(req.len);
398         req.buf = buf;
399         bcopy(&req.header, buf, sizeof(req.header));
400         if (ioctl(fd, MPTIO_READ_CFG_PAGE, &req) < 0) {
401                 error = errno;
402                 free(buf);
403                 errno = error;
404                 return (NULL);
405         }
406         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
407                 if (IOCStatus != NULL)
408                         *IOCStatus = req.ioc_status;
409                 else
410                         warnx("Reading config page failed: %s",
411                             mpt_ioc_status(req.ioc_status));
412                 free(buf);
413                 errno = EIO;
414                 return (NULL);
415         }
416         return (buf);
417 }
418
419 void *
420 mpt_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
421     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
422 {
423         struct mpt_ext_cfg_page_req req;
424         void *buf;
425         int error;
426
427         if (IOCStatus != NULL)
428                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
429         bzero(&req, sizeof(req));
430         req.header.PageVersion = PageVersion;
431         req.header.PageNumber = PageNumber;
432         req.header.ExtPageType = ExtPageType;
433         req.page_address = PageAddress;
434         if (ioctl(fd, MPTIO_READ_EXT_CFG_HEADER, &req) < 0)
435                 return (NULL);
436         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
437                 if (IOCStatus != NULL)
438                         *IOCStatus = req.ioc_status;
439                 else
440                         warnx("Reading extended config page header failed: %s",
441                             mpt_ioc_status(req.ioc_status));
442                 errno = EIO;
443                 return (NULL);
444         }
445         req.len = req.header.ExtPageLength * 4;
446         buf = malloc(req.len);
447         req.buf = buf;
448         bcopy(&req.header, buf, sizeof(req.header));
449         if (ioctl(fd, MPTIO_READ_EXT_CFG_PAGE, &req) < 0) {
450                 error = errno;
451                 free(buf);
452                 errno = error;
453                 return (NULL);
454         }
455         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
456                 if (IOCStatus != NULL)
457                         *IOCStatus = req.ioc_status;
458                 else
459                         warnx("Reading extended config page failed: %s",
460                             mpt_ioc_status(req.ioc_status));
461                 free(buf);
462                 errno = EIO;
463                 return (NULL);
464         }
465         return (buf);
466 }
467
468 int
469 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
470 {
471         CONFIG_PAGE_HEADER *hdr;
472         struct mpt_cfg_page_req req;
473
474         if (IOCStatus != NULL)
475                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
476         bzero(&req, sizeof(req));
477         req.buf = buf;
478         hdr = buf;
479         req.len = hdr->PageLength * 4;
480         if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
481                 return (errno);
482         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
483                 if (IOCStatus != NULL) {
484                         *IOCStatus = req.ioc_status;
485                         return (0);
486                 }
487                 warnx("Writing config page failed: %s",
488                     mpt_ioc_status(req.ioc_status));
489                 return (EIO);
490         }
491         return (0);
492 }
493
494 int
495 mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
496     U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
497     U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write_act)
498 {
499         struct mpt_raid_action raid_act;
500
501         if (IOCStatus != NULL)
502                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
503         if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
504                 return (EINVAL);
505         bzero(&raid_act, sizeof(raid_act));
506         raid_act.action = Action;
507         raid_act.volume_bus = VolumeBus;
508         raid_act.volume_id = VolumeID;
509         raid_act.phys_disk_num = PhysDiskNum;
510         raid_act.action_data_word = ActionDataWord;
511         if (buf != NULL && len != 0) {
512                 raid_act.buf = buf;
513                 raid_act.len = len;
514                 raid_act.write = write_act;
515         }
516
517         if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
518                 return (errno);
519
520         if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
521                 if (IOCStatus != NULL) {
522                         *IOCStatus = raid_act.ioc_status;
523                         return (0);
524                 }
525                 warnx("RAID action failed: %s",
526                     mpt_ioc_status(raid_act.ioc_status));
527                 return (EIO);
528         }
529
530         if (ActionStatus != NULL)
531                 *ActionStatus = raid_act.action_status;
532         if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
533                 if (ActionStatus != NULL)
534                         return (0);
535                 warnx("RAID action failed: %s",
536                     mpt_raid_status(raid_act.action_status));
537                 return (EIO);
538         }
539
540         if (VolumeStatus != NULL)
541                 *((U32 *)VolumeStatus) = raid_act.volume_status;
542         if (ActionData != NULL)
543                 bcopy(raid_act.action_data, ActionData, datalen);
544         return (0);
545 }
546
547 int
548 mpt_open(int unit)
549 {
550         char path[MAXPATHLEN];
551
552         snprintf(path, sizeof(path), "/dev/mpt%d", unit);
553         return (open(path, O_RDWR));
554 }
555
556 int
557 mpt_table_handler(struct mptutil_command **start, struct mptutil_command **end,
558     int ac, char **av)
559 {
560         struct mptutil_command **cmd;
561
562         if (ac < 2) {
563                 warnx("The %s command requires a sub-command.", av[0]);
564                 return (EINVAL);
565         }
566         for (cmd = start; cmd < end; cmd++) {
567                 if (strcmp((*cmd)->name, av[1]) == 0)
568                         return ((*cmd)->handler(ac - 1, av + 1));
569         }
570
571         warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
572         return (ENOENT);
573 }
574
575 #ifdef DEBUG
576 void
577 hexdump(const void *ptr, int length, const char *hdr, int flags)
578 {
579         int i, j, k;
580         int cols;
581         const unsigned char *cp;
582         char delim;
583
584         if ((flags & HD_DELIM_MASK) != 0)
585                 delim = (flags & HD_DELIM_MASK) >> 8;
586         else
587                 delim = ' ';
588
589         if ((flags & HD_COLUMN_MASK) != 0)
590                 cols = flags & HD_COLUMN_MASK;
591         else
592                 cols = 16;
593
594         cp = ptr;
595         for (i = 0; i < length; i+= cols) {
596                 if (hdr != NULL)
597                         printf("%s", hdr);
598
599                 if ((flags & HD_OMIT_COUNT) == 0)
600                         printf("%04x  ", i);
601
602                 if ((flags & HD_OMIT_HEX) == 0) {
603                         for (j = 0; j < cols; j++) {
604                                 k = i + j;
605                                 if (k < length)
606                                         printf("%c%02x", delim, cp[k]);
607                                 else
608                                         printf("   ");
609                         }
610                 }
611
612                 if ((flags & HD_OMIT_CHARS) == 0) {
613                         printf("  |");
614                         for (j = 0; j < cols; j++) {
615                                 k = i + j;
616                                 if (k >= length)
617                                         printf(" ");
618                                 else if (cp[k] >= ' ' && cp[k] <= '~')
619                                         printf("%c", cp[k]);
620                                 else
621                                         printf(".");
622                         }
623                         printf("|");
624                 }
625                 printf("\n");
626         }
627 }
628 #endif