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