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
31 #include <sys/cdefs.h>
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>
50 static const char *mpt_ioc_status_codes[] = {
51 "Success", /* 0x0000 */
54 "Invalid scatter-gather list",
57 "Insufficient resources",
59 "Invalid state", /* 0x0008 */
60 "Operation state not supported",
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",
115 "Recovered SCSI error", /* 0x0040 */
117 "Invalid SCSI target ID",
118 "SCSI device not there",
120 "SCSI data underrun",
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",
129 "EEDP reference tag error",
130 "EEDP application tag error",
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",
154 "Invalid FC receive ID",
155 "FC did invalid", /* 0x0068 */
156 "FC node logged out",
157 "Transfer count mismatch",
159 "FC exchange canceled",
161 "Too much write data",
163 "ACK NAK timeout", /* 0x0070 */
179 "LAN device not found", /* 0x0080 */
180 "LAN device failure",
181 "LAN transmit error",
182 "LAN transmit aborted",
184 "LAN receive aborted",
185 "LAN partial packet",
195 "SAS SMP request failed", /* 0x0090 */
196 "SAS SMP data overrun",
203 "Inband aborted", /* 0x0098 */
204 "No inband connection",
211 "Diagnostic released", /* 0x00A0 */
214 static const char *mpt_raid_action_status_codes[] = {
218 "Operation in progress",
222 mpt_ioc_status(U16 IOCStatus)
224 static char buffer[16];
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);
235 mpt_raid_status(U16 ActionStatus)
237 static char buffer[16];
239 if (ActionStatus < sizeof(mpt_raid_action_status_codes) /
241 return (mpt_raid_action_status_codes[ActionStatus]);
242 snprintf(buffer, sizeof(buffer), "Status: 0x%04x", ActionStatus);
247 mpt_raid_level(U8 VolumeType)
251 switch (VolumeType) {
252 case MPI_RAID_VOL_TYPE_IS:
254 case MPI_RAID_VOL_TYPE_IM:
256 case MPI_RAID_VOL_TYPE_IME:
258 case MPI_RAID_VOL_TYPE_RAID_5:
260 case MPI_RAID_VOL_TYPE_RAID_6:
262 case MPI_RAID_VOL_TYPE_RAID_10:
264 case MPI_RAID_VOL_TYPE_RAID_50:
267 sprintf(buf, "LVL 0x%02x", VolumeType);
273 mpt_volume_name(U8 VolumeBus, U8 VolumeID)
275 static struct mpt_query_disk info;
278 if (mpt_query_disk(VolumeBus, VolumeID, &info) != 0) {
280 * We only print out the bus number if it is non-zero
281 * since mpt(4) only supports devices on bus zero
285 snprintf(buf, sizeof(buf), "%d", VolumeID);
287 snprintf(buf, sizeof(buf), "%d:%d", VolumeBus,
291 return (info.devname);
295 mpt_lookup_volume(int fd, const char *name, U8 *VolumeBus, U8 *VolumeID)
297 CONFIG_PAGE_IOC_2 *ioc2;
298 CONFIG_PAGE_IOC_2_RAID_VOL *vol;
299 struct mpt_query_disk info;
305 * Check for a raw [<bus>:]<id> string. If the bus is not
306 * specified, assume bus 0.
308 bus = strtol(name, &cp, 0);
310 id = strtol(cp + 1, &cp, 0);
312 if (bus < 0 || bus > 0xff || id < 0 || id > 0xff) {
320 } else if (*cp == '\0') {
321 if (bus < 0 || bus > 0xff) {
330 ioc2 = mpt_read_ioc_page(fd, 2, NULL);
334 vol = ioc2->RaidVolume;
335 for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
336 if (mpt_query_disk(vol->VolumeBus, vol->VolumeID, &info) != 0)
338 if (strcmp(name, info.devname) == 0) {
339 *VolumeBus = vol->VolumeBus;
340 *VolumeID = vol->VolumeID;
351 mpt_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
352 CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
354 struct mpt_cfg_page_req req;
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)
364 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
365 if (IOCStatus != NULL)
366 *IOCStatus = req.ioc_status;
368 warnx("Reading config page header failed: %s",
369 mpt_ioc_status(req.ioc_status));
373 *header = req.header;
378 mpt_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
381 struct mpt_cfg_page_req req;
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)
393 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
394 if (IOCStatus != NULL)
395 *IOCStatus = req.ioc_status;
397 warnx("Reading config page header failed: %s",
398 mpt_ioc_status(req.ioc_status));
402 req.len = req.header.PageLength * 4;
403 buf = malloc(req.len);
405 bcopy(&req.header, buf, sizeof(req.header));
406 if (ioctl(fd, MPTIO_READ_CFG_PAGE, &req) < 0) {
412 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
413 if (IOCStatus != NULL)
414 *IOCStatus = req.ioc_status;
416 warnx("Reading config page failed: %s",
417 mpt_ioc_status(req.ioc_status));
426 mpt_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
427 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
429 struct mpt_ext_cfg_page_req req;
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)
442 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
443 if (IOCStatus != NULL)
444 *IOCStatus = req.ioc_status;
446 warnx("Reading extended config page header failed: %s",
447 mpt_ioc_status(req.ioc_status));
451 req.len = req.header.ExtPageLength * 4;
452 buf = malloc(req.len);
454 bcopy(&req.header, buf, sizeof(req.header));
455 if (ioctl(fd, MPTIO_READ_EXT_CFG_PAGE, &req) < 0) {
461 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
462 if (IOCStatus != NULL)
463 *IOCStatus = req.ioc_status;
465 warnx("Reading extended config page failed: %s",
466 mpt_ioc_status(req.ioc_status));
475 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
477 CONFIG_PAGE_HEADER *hdr;
478 struct mpt_cfg_page_req req;
480 if (IOCStatus != NULL)
481 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
482 bzero(&req, sizeof(req));
485 req.len = hdr->PageLength * 4;
486 if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
488 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
489 if (IOCStatus != NULL) {
490 *IOCStatus = req.ioc_status;
493 warnx("Writing config page failed: %s",
494 mpt_ioc_status(req.ioc_status));
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)
506 struct mpt_raid_action raid_act;
508 if (IOCStatus != NULL)
509 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
510 if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data)) {
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) {
523 raid_act.write = write;
526 if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
529 if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
530 if (IOCStatus != NULL) {
531 *IOCStatus = raid_act.ioc_status;
534 warnx("RAID action failed: %s",
535 mpt_ioc_status(raid_act.ioc_status));
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)
545 warnx("RAID action failed: %s",
546 mpt_raid_status(raid_act.action_status));
551 if (VolumeStatus != NULL)
552 *((U32 *)VolumeStatus) = raid_act.volume_status;
553 if (ActionData != NULL)
554 bcopy(raid_act.action_data, ActionData, datalen);
561 char path[MAXPATHLEN];
563 snprintf(path, sizeof(path), "/dev/mpt%d", unit);
564 return (open(path, O_RDWR));
568 mpt_table_handler(struct mptutil_command **start, struct mptutil_command **end,
571 struct mptutil_command **cmd;
574 warnx("The %s command requires a sub-command.", av[0]);
577 for (cmd = start; cmd < end; cmd++) {
578 if (strcmp((*cmd)->name, av[1]) == 0)
579 return ((*cmd)->handler(ac - 1, av + 1));
582 warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
588 hexdump(const void *ptr, int length, const char *hdr, int flags)
592 const unsigned char *cp;
595 if ((flags & HD_DELIM_MASK) != 0)
596 delim = (flags & HD_DELIM_MASK) >> 8;
600 if ((flags & HD_COLUMN_MASK) != 0)
601 cols = flags & HD_COLUMN_MASK;
606 for (i = 0; i < length; i+= cols) {
610 if ((flags & HD_OMIT_COUNT) == 0)
613 if ((flags & HD_OMIT_HEX) == 0) {
614 for (j = 0; j < cols; j++) {
617 printf("%c%02x", delim, cp[k]);
623 if ((flags & HD_OMIT_CHARS) == 0) {
625 for (j = 0; j < cols; j++) {
629 else if (cp[k] >= ' ' && cp[k] <= '~')