2 * Copyright (c) 2008 Yahoo!, Inc.
4 * Written by: John Baldwin <jhb@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
30 * $FreeBSD: src/usr.sbin/mptutil/mpt_cmd.c,v 1.1 2009/08/14 13:13:12 scottl Exp $
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>
49 static const char *mpt_ioc_status_codes[] = {
50 "Success", /* 0x0000 */
53 "Invalid scatter-gather list",
56 "Insufficient resources",
58 "Invalid state", /* 0x0008 */
59 "Operation state not supported",
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",
114 "Recovered SCSI error", /* 0x0040 */
116 "Invalid SCSI target ID",
117 "SCSI device not there",
119 "SCSI data underrun",
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",
128 "EEDP reference tag error",
129 "EEDP application tag error",
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",
153 "Invalid FC receive ID",
154 "FC did invalid", /* 0x0068 */
155 "FC node logged out",
156 "Transfer count mismatch",
158 "FC exchange canceled",
160 "Too much write data",
162 "ACK NAK timeout", /* 0x0070 */
178 "LAN device not found", /* 0x0080 */
179 "LAN device failure",
180 "LAN transmit error",
181 "LAN transmit aborted",
183 "LAN receive aborted",
184 "LAN partial packet",
194 "SAS SMP request failed", /* 0x0090 */
195 "SAS SMP data overrun",
202 "Inband aborted", /* 0x0098 */
203 "No inband connection",
210 "Diagnostic released", /* 0x00A0 */
213 static const char *mpt_raid_action_status_codes[] = {
217 "Operation in progress",
221 mpt_ioc_status(U16 IOCStatus)
223 static char buffer[16];
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);
234 mpt_raid_status(U16 ActionStatus)
236 static char buffer[16];
238 if (ActionStatus < sizeof(mpt_raid_action_status_codes) /
240 return (mpt_raid_action_status_codes[ActionStatus]);
241 snprintf(buffer, sizeof(buffer), "Status: 0x%04x", ActionStatus);
246 mpt_raid_level(U8 VolumeType)
250 switch (VolumeType) {
251 case MPI_RAID_VOL_TYPE_IS:
253 case MPI_RAID_VOL_TYPE_IM:
255 case MPI_RAID_VOL_TYPE_IME:
257 case MPI_RAID_VOL_TYPE_RAID_5:
259 case MPI_RAID_VOL_TYPE_RAID_6:
261 case MPI_RAID_VOL_TYPE_RAID_10:
263 case MPI_RAID_VOL_TYPE_RAID_50:
266 sprintf(buf, "LVL 0x%02x", VolumeType);
272 mpt_volume_name(U8 VolumeBus, U8 VolumeID)
274 static struct mpt_query_disk info;
277 if (mpt_query_disk(VolumeBus, VolumeID, &info) != 0) {
279 * We only print out the bus number if it is non-zero
280 * since mpt(4) only supports devices on bus zero
284 snprintf(buf, sizeof(buf), "%d", VolumeID);
286 snprintf(buf, sizeof(buf), "%d:%d", VolumeBus,
290 return (info.devname);
294 mpt_lookup_volume(int fd, const char *name, U8 *VolumeBus, U8 *VolumeID)
296 CONFIG_PAGE_IOC_2 *ioc2;
297 CONFIG_PAGE_IOC_2_RAID_VOL *vol;
298 struct mpt_query_disk info;
304 * Check for a raw [<bus>:]<id> string. If the bus is not
305 * specified, assume bus 0.
307 bus = strtol(name, &cp, 0);
309 id = strtol(cp + 1, &cp, 0);
311 if (bus < 0 || bus > 0xff || id < 0 || id > 0xff) {
319 } else if (*cp == '\0') {
320 if (bus < 0 || bus > 0xff) {
329 ioc2 = mpt_read_ioc_page(fd, 2, NULL);
333 vol = ioc2->RaidVolume;
334 for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
335 if (mpt_query_disk(vol->VolumeBus, vol->VolumeID, &info) != 0)
337 if (strcmp(name, info.devname) == 0) {
338 *VolumeBus = vol->VolumeBus;
339 *VolumeID = vol->VolumeID;
350 mpt_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
351 CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
353 struct mpt_cfg_page_req req;
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)
363 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
364 if (IOCStatus != NULL)
365 *IOCStatus = req.ioc_status;
367 warnx("Reading config page header failed: %s",
368 mpt_ioc_status(req.ioc_status));
372 *header = req.header;
377 mpt_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
380 struct mpt_cfg_page_req req;
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)
392 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
393 if (IOCStatus != NULL)
394 *IOCStatus = req.ioc_status;
396 warnx("Reading config page header failed: %s",
397 mpt_ioc_status(req.ioc_status));
401 req.len = req.header.PageLength * 4;
402 buf = malloc(req.len);
404 bcopy(&req.header, buf, sizeof(req.header));
405 if (ioctl(fd, MPTIO_READ_CFG_PAGE, &req) < 0) {
411 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
412 if (IOCStatus != NULL)
413 *IOCStatus = req.ioc_status;
415 warnx("Reading config page failed: %s",
416 mpt_ioc_status(req.ioc_status));
425 mpt_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
426 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
428 struct mpt_ext_cfg_page_req req;
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)
441 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
442 if (IOCStatus != NULL)
443 *IOCStatus = req.ioc_status;
445 warnx("Reading extended config page header failed: %s",
446 mpt_ioc_status(req.ioc_status));
450 req.len = req.header.ExtPageLength * 4;
451 buf = malloc(req.len);
453 bcopy(&req.header, buf, sizeof(req.header));
454 if (ioctl(fd, MPTIO_READ_EXT_CFG_PAGE, &req) < 0) {
460 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
461 if (IOCStatus != NULL)
462 *IOCStatus = req.ioc_status;
464 warnx("Reading extended config page failed: %s",
465 mpt_ioc_status(req.ioc_status));
474 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
476 CONFIG_PAGE_HEADER *hdr;
477 struct mpt_cfg_page_req req;
479 if (IOCStatus != NULL)
480 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
481 bzero(&req, sizeof(req));
484 req.len = hdr->PageLength * 4;
485 if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
487 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
488 if (IOCStatus != NULL) {
489 *IOCStatus = req.ioc_status;
492 warnx("Writing config page failed: %s",
493 mpt_ioc_status(req.ioc_status));
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)
505 struct mpt_raid_action raid_act;
507 if (IOCStatus != NULL)
508 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
509 if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data)) {
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) {
522 raid_act.write = write_act;
525 if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
528 if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
529 if (IOCStatus != NULL) {
530 *IOCStatus = raid_act.ioc_status;
533 warnx("RAID action failed: %s",
534 mpt_ioc_status(raid_act.ioc_status));
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)
544 warnx("RAID action failed: %s",
545 mpt_raid_status(raid_act.action_status));
550 if (VolumeStatus != NULL)
551 *((U32 *)VolumeStatus) = raid_act.volume_status;
552 if (ActionData != NULL)
553 bcopy(raid_act.action_data, ActionData, datalen);
560 char path[MAXPATHLEN];
562 snprintf(path, sizeof(path), "/dev/mpt%d", unit);
563 return (open(path, O_RDWR));
567 mpt_table_handler(struct mptutil_command **start, struct mptutil_command **end,
570 struct mptutil_command **cmd;
573 warnx("The %s command requires a sub-command.", av[0]);
576 for (cmd = start; cmd < end; cmd++) {
577 if (strcmp((*cmd)->name, av[1]) == 0)
578 return ((*cmd)->handler(ac - 1, av + 1));
581 warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
587 hexdump(const void *ptr, int length, const char *hdr, int flags)
591 const unsigned char *cp;
594 if ((flags & HD_DELIM_MASK) != 0)
595 delim = (flags & HD_DELIM_MASK) >> 8;
599 if ((flags & HD_COLUMN_MASK) != 0)
600 cols = flags & HD_COLUMN_MASK;
605 for (i = 0; i < length; i+= cols) {
609 if ((flags & HD_OMIT_COUNT) == 0)
612 if ((flags & HD_OMIT_HEX) == 0) {
613 for (j = 0; j < cols; j++) {
616 printf("%c%02x", delim, cp[k]);
622 if ((flags & HD_OMIT_CHARS) == 0) {
624 for (j = 0; j < cols; j++) {
628 else if (cp[k] >= ' ' && cp[k] <= '~')