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