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.2 2010/11/09 19:28:06 jhb 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) {
318 } else if (*cp == '\0') {
319 if (bus < 0 || bus > 0xff)
326 ioc2 = mpt_read_ioc_page(fd, 2, NULL);
330 vol = ioc2->RaidVolume;
331 for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
332 if (mpt_query_disk(vol->VolumeBus, vol->VolumeID, &info) != 0)
334 if (strcmp(name, info.devname) == 0) {
335 *VolumeBus = vol->VolumeBus;
336 *VolumeID = vol->VolumeID;
346 mpt_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
347 CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
349 struct mpt_cfg_page_req req;
351 if (IOCStatus != NULL)
352 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
353 bzero(&req, sizeof(req));
354 req.header.PageType = PageType;
355 req.header.PageNumber = PageNumber;
356 req.page_address = PageAddress;
357 if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
359 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
360 if (IOCStatus != NULL)
361 *IOCStatus = req.ioc_status;
363 warnx("Reading config page header failed: %s",
364 mpt_ioc_status(req.ioc_status));
367 *header = req.header;
372 mpt_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
375 struct mpt_cfg_page_req req;
379 if (IOCStatus != NULL)
380 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
381 bzero(&req, sizeof(req));
382 req.header.PageType = PageType;
383 req.header.PageNumber = PageNumber;
384 req.page_address = PageAddress;
385 if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
387 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
388 if (IOCStatus != NULL)
389 *IOCStatus = req.ioc_status;
391 warnx("Reading config page header failed: %s",
392 mpt_ioc_status(req.ioc_status));
396 req.len = req.header.PageLength * 4;
397 buf = malloc(req.len);
399 bcopy(&req.header, buf, sizeof(req.header));
400 if (ioctl(fd, MPTIO_READ_CFG_PAGE, &req) < 0) {
406 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
407 if (IOCStatus != NULL)
408 *IOCStatus = req.ioc_status;
410 warnx("Reading config page failed: %s",
411 mpt_ioc_status(req.ioc_status));
420 mpt_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
421 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
423 struct mpt_ext_cfg_page_req req;
427 if (IOCStatus != NULL)
428 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
429 bzero(&req, sizeof(req));
430 req.header.PageVersion = PageVersion;
431 req.header.PageNumber = PageNumber;
432 req.header.ExtPageType = ExtPageType;
433 req.page_address = PageAddress;
434 if (ioctl(fd, MPTIO_READ_EXT_CFG_HEADER, &req) < 0)
436 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
437 if (IOCStatus != NULL)
438 *IOCStatus = req.ioc_status;
440 warnx("Reading extended config page header failed: %s",
441 mpt_ioc_status(req.ioc_status));
445 req.len = req.header.ExtPageLength * 4;
446 buf = malloc(req.len);
448 bcopy(&req.header, buf, sizeof(req.header));
449 if (ioctl(fd, MPTIO_READ_EXT_CFG_PAGE, &req) < 0) {
455 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
456 if (IOCStatus != NULL)
457 *IOCStatus = req.ioc_status;
459 warnx("Reading extended config page failed: %s",
460 mpt_ioc_status(req.ioc_status));
469 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
471 CONFIG_PAGE_HEADER *hdr;
472 struct mpt_cfg_page_req req;
474 if (IOCStatus != NULL)
475 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
476 bzero(&req, sizeof(req));
479 req.len = hdr->PageLength * 4;
480 if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
482 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
483 if (IOCStatus != NULL) {
484 *IOCStatus = req.ioc_status;
487 warnx("Writing config page failed: %s",
488 mpt_ioc_status(req.ioc_status));
495 mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
496 U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
497 U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write_act)
499 struct mpt_raid_action raid_act;
501 if (IOCStatus != NULL)
502 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
503 if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
505 bzero(&raid_act, sizeof(raid_act));
506 raid_act.action = Action;
507 raid_act.volume_bus = VolumeBus;
508 raid_act.volume_id = VolumeID;
509 raid_act.phys_disk_num = PhysDiskNum;
510 raid_act.action_data_word = ActionDataWord;
511 if (buf != NULL && len != 0) {
514 raid_act.write = write_act;
517 if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
520 if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
521 if (IOCStatus != NULL) {
522 *IOCStatus = raid_act.ioc_status;
525 warnx("RAID action failed: %s",
526 mpt_ioc_status(raid_act.ioc_status));
530 if (ActionStatus != NULL)
531 *ActionStatus = raid_act.action_status;
532 if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
533 if (ActionStatus != NULL)
535 warnx("RAID action failed: %s",
536 mpt_raid_status(raid_act.action_status));
540 if (VolumeStatus != NULL)
541 *((U32 *)VolumeStatus) = raid_act.volume_status;
542 if (ActionData != NULL)
543 bcopy(raid_act.action_data, ActionData, datalen);
550 char path[MAXPATHLEN];
552 snprintf(path, sizeof(path), "/dev/mpt%d", unit);
553 return (open(path, O_RDWR));
557 mpt_table_handler(struct mptutil_command **start, struct mptutil_command **end,
560 struct mptutil_command **cmd;
563 warnx("The %s command requires a sub-command.", av[0]);
566 for (cmd = start; cmd < end; cmd++) {
567 if (strcmp((*cmd)->name, av[1]) == 0)
568 return ((*cmd)->handler(ac - 1, av + 1));
571 warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
577 hexdump(const void *ptr, int length, const char *hdr, int flags)
581 const unsigned char *cp;
584 if ((flags & HD_DELIM_MASK) != 0)
585 delim = (flags & HD_DELIM_MASK) >> 8;
589 if ((flags & HD_COLUMN_MASK) != 0)
590 cols = flags & HD_COLUMN_MASK;
595 for (i = 0; i < length; i+= cols) {
599 if ((flags & HD_OMIT_COUNT) == 0)
602 if ((flags & HD_OMIT_HEX) == 0) {
603 for (j = 0; j < cols; j++) {
606 printf("%c%02x", delim, cp[k]);
612 if ((flags & HD_OMIT_CHARS) == 0) {
614 for (j = 0; j < cols; j++) {
618 else if (cp[k] >= ' ' && cp[k] <= '~')