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