]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/mptutil/mpt_cmd.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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                                 errno = EINVAL;
314                                 return (-1);
315                         }
316                         *VolumeBus = bus;
317                         *VolumeID = id;
318                         return (0);
319                 }
320         } else if (*cp == '\0') {
321                 if (bus < 0 || bus > 0xff) {
322                         errno = EINVAL;
323                         return (-1);
324                 }
325                 *VolumeBus = 0;
326                 *VolumeID = bus;
327                 return (0);
328         }
329
330         ioc2 = mpt_read_ioc_page(fd, 2, NULL);
331         if (ioc2 == NULL)
332                 return (-1);
333
334         vol = ioc2->RaidVolume;
335         for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
336                 if (mpt_query_disk(vol->VolumeBus, vol->VolumeID, &info) != 0)
337                         continue;
338                 if (strcmp(name, info.devname) == 0) {
339                         *VolumeBus = vol->VolumeBus;
340                         *VolumeID = vol->VolumeID;
341                         free(ioc2);
342                         return (0);
343                 }
344         }
345         free(ioc2);
346         errno = EINVAL;
347         return (-1);
348 }
349
350 int
351 mpt_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
352     CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
353 {
354         struct mpt_cfg_page_req req;
355
356         if (IOCStatus != NULL)
357                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
358         bzero(&req, sizeof(req));
359         req.header.PageType = PageType;
360         req.header.PageNumber = PageNumber;
361         req.page_address = PageAddress;
362         if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
363                 return (-1);
364         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
365                 if (IOCStatus != NULL)
366                         *IOCStatus = req.ioc_status;
367                 else
368                         warnx("Reading config page header failed: %s",
369                             mpt_ioc_status(req.ioc_status));
370                 errno = EIO;
371                 return (-1);
372         }
373         *header = req.header;
374         return (0);
375 }
376
377 void *
378 mpt_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
379     U16 *IOCStatus)
380 {
381         struct mpt_cfg_page_req req;
382         void *buf;
383         int save_errno;
384
385         if (IOCStatus != NULL)
386                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
387         bzero(&req, sizeof(req));
388         req.header.PageType = PageType;
389         req.header.PageNumber = PageNumber;
390         req.page_address = PageAddress;
391         if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
392                 return (NULL);
393         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
394                 if (IOCStatus != NULL)
395                         *IOCStatus = req.ioc_status;
396                 else
397                         warnx("Reading config page header failed: %s",
398                             mpt_ioc_status(req.ioc_status));
399                 errno = EIO;
400                 return (NULL);
401         }
402         req.len = req.header.PageLength * 4;
403         buf = malloc(req.len);
404         req.buf = buf;
405         bcopy(&req.header, buf, sizeof(req.header));
406         if (ioctl(fd, MPTIO_READ_CFG_PAGE, &req) < 0) {
407                 save_errno = errno;
408                 free(buf);
409                 errno = save_errno;
410                 return (NULL);
411         }
412         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
413                 if (IOCStatus != NULL)
414                         *IOCStatus = req.ioc_status;
415                 else
416                         warnx("Reading config page failed: %s",
417                             mpt_ioc_status(req.ioc_status));
418                 free(buf);
419                 errno = EIO;
420                 return (NULL);
421         }
422         return (buf);
423 }
424
425 void *
426 mpt_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
427     U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
428 {
429         struct mpt_ext_cfg_page_req req;
430         void *buf;
431         int save_errno;
432
433         if (IOCStatus != NULL)
434                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
435         bzero(&req, sizeof(req));
436         req.header.PageVersion = PageVersion;
437         req.header.PageNumber = PageNumber;
438         req.header.ExtPageType = ExtPageType;
439         req.page_address = PageAddress;
440         if (ioctl(fd, MPTIO_READ_EXT_CFG_HEADER, &req) < 0)
441                 return (NULL);
442         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
443                 if (IOCStatus != NULL)
444                         *IOCStatus = req.ioc_status;
445                 else
446                         warnx("Reading extended config page header failed: %s",
447                             mpt_ioc_status(req.ioc_status));
448                 errno = EIO;
449                 return (NULL);
450         }
451         req.len = req.header.ExtPageLength * 4;
452         buf = malloc(req.len);
453         req.buf = buf;
454         bcopy(&req.header, buf, sizeof(req.header));
455         if (ioctl(fd, MPTIO_READ_EXT_CFG_PAGE, &req) < 0) {
456                 save_errno = errno;
457                 free(buf);
458                 errno = save_errno;
459                 return (NULL);
460         }
461         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
462                 if (IOCStatus != NULL)
463                         *IOCStatus = req.ioc_status;
464                 else
465                         warnx("Reading extended config page failed: %s",
466                             mpt_ioc_status(req.ioc_status));
467                 free(buf);
468                 errno = EIO;
469                 return (NULL);
470         }
471         return (buf);
472 }
473
474 int
475 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
476 {
477         CONFIG_PAGE_HEADER *hdr;
478         struct mpt_cfg_page_req req;
479
480         if (IOCStatus != NULL)
481                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
482         bzero(&req, sizeof(req));
483         req.buf = buf;
484         hdr = buf;
485         req.len = hdr->PageLength * 4;
486         if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
487                 return (-1);
488         if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
489                 if (IOCStatus != NULL) {
490                         *IOCStatus = req.ioc_status;
491                         return (0);
492                 }
493                 warnx("Writing config page failed: %s",
494                     mpt_ioc_status(req.ioc_status));
495                 errno = EIO;
496                 return (-1);
497         }
498         return (0);
499 }
500
501 int
502 mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
503     U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
504     U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
505 {
506         struct mpt_raid_action raid_act;
507
508         if (IOCStatus != NULL)
509                 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
510         if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data)) {
511                 errno = EINVAL;
512                 return (-1);
513         }
514         bzero(&raid_act, sizeof(raid_act));
515         raid_act.action = Action;
516         raid_act.volume_bus = VolumeBus;
517         raid_act.volume_id = VolumeID;
518         raid_act.phys_disk_num = PhysDiskNum;
519         raid_act.action_data_word = ActionDataWord;
520         if (buf != NULL && len != 0) {
521                 raid_act.buf = buf;
522                 raid_act.len = len;
523                 raid_act.write = write;
524         }
525
526         if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
527                 return (-1);
528
529         if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
530                 if (IOCStatus != NULL) {
531                         *IOCStatus = raid_act.ioc_status;
532                         return (0);
533                 }
534                 warnx("RAID action failed: %s",
535                     mpt_ioc_status(raid_act.ioc_status));
536                 errno = EIO;
537                 return (-1);
538         }
539
540         if (ActionStatus != NULL)
541                 *ActionStatus = raid_act.action_status;
542         if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
543                 if (ActionStatus != NULL)
544                         return (0);
545                 warnx("RAID action failed: %s",
546                     mpt_raid_status(raid_act.action_status));
547                 errno = EIO;
548                 return (-1);
549         }
550
551         if (VolumeStatus != NULL)
552                 *((U32 *)VolumeStatus) = raid_act.volume_status;
553         if (ActionData != NULL)
554                 bcopy(raid_act.action_data, ActionData, datalen);
555         return (0);
556 }
557
558 int
559 mpt_open(int unit)
560 {
561         char path[MAXPATHLEN];
562
563         snprintf(path, sizeof(path), "/dev/mpt%d", unit);
564         return (open(path, O_RDWR));
565 }
566
567 int
568 mpt_table_handler(struct mptutil_command **start, struct mptutil_command **end,
569     int ac, char **av)
570 {
571         struct mptutil_command **cmd;
572
573         if (ac < 2) {
574                 warnx("The %s command requires a sub-command.", av[0]);
575                 return (EINVAL);
576         }
577         for (cmd = start; cmd < end; cmd++) {
578                 if (strcmp((*cmd)->name, av[1]) == 0)
579                         return ((*cmd)->handler(ac - 1, av + 1));
580         }
581
582         warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
583         return (ENOENT);
584 }
585
586 #ifdef DEBUG
587 void
588 hexdump(const void *ptr, int length, const char *hdr, int flags)
589 {
590         int i, j, k;
591         int cols;
592         const unsigned char *cp;
593         char delim;
594
595         if ((flags & HD_DELIM_MASK) != 0)
596                 delim = (flags & HD_DELIM_MASK) >> 8;
597         else
598                 delim = ' ';
599
600         if ((flags & HD_COLUMN_MASK) != 0)
601                 cols = flags & HD_COLUMN_MASK;
602         else
603                 cols = 16;
604
605         cp = ptr;
606         for (i = 0; i < length; i+= cols) {
607                 if (hdr != NULL)
608                         printf("%s", hdr);
609
610                 if ((flags & HD_OMIT_COUNT) == 0)
611                         printf("%04x  ", i);
612
613                 if ((flags & HD_OMIT_HEX) == 0) {
614                         for (j = 0; j < cols; j++) {
615                                 k = i + j;
616                                 if (k < length)
617                                         printf("%c%02x", delim, cp[k]);
618                                 else
619                                         printf("   ");
620                         }
621                 }
622
623                 if ((flags & HD_OMIT_CHARS) == 0) {
624                         printf("  |");
625                         for (j = 0; j < cols; j++) {
626                                 k = i + j;
627                                 if (k >= length)
628                                         printf(" ");
629                                 else if (cp[k] >= ' ' && cp[k] <= '~')
630                                         printf("%c", cp[k]);
631                                 else
632                                         printf(".");
633                         }
634                         printf("|");
635                 }
636                 printf("\n");
637         }
638 }
639 #endif