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) {
319 } else if (*cp == '\0') {
320 if (bus < 0 || bus > 0xff)
327 ioc2 = mpt_read_ioc_page(fd, 2, NULL);
331 vol = ioc2->RaidVolume;
332 for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
333 if (mpt_query_disk(vol->VolumeBus, vol->VolumeID, &info) != 0)
335 if (strcmp(name, info.devname) == 0) {
336 *VolumeBus = vol->VolumeBus;
337 *VolumeID = vol->VolumeID;
347 mpt_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
348 CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
350 struct mpt_cfg_page_req req;
352 if (IOCStatus != NULL)
353 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
354 bzero(&req, sizeof(req));
355 req.header.PageType = PageType;
356 req.header.PageNumber = PageNumber;
357 req.page_address = PageAddress;
358 if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
360 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
361 if (IOCStatus != NULL)
362 *IOCStatus = req.ioc_status;
364 warnx("Reading config page header failed: %s",
365 mpt_ioc_status(req.ioc_status));
368 *header = req.header;
373 mpt_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
376 struct mpt_cfg_page_req req;
380 if (IOCStatus != NULL)
381 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
382 bzero(&req, sizeof(req));
383 req.header.PageType = PageType;
384 req.header.PageNumber = PageNumber;
385 req.page_address = PageAddress;
386 if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
388 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
389 if (IOCStatus != NULL)
390 *IOCStatus = req.ioc_status;
392 warnx("Reading config page header failed: %s",
393 mpt_ioc_status(req.ioc_status));
397 req.len = req.header.PageLength * 4;
398 buf = malloc(req.len);
400 bcopy(&req.header, buf, sizeof(req.header));
401 if (ioctl(fd, MPTIO_READ_CFG_PAGE, &req) < 0) {
407 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
408 if (IOCStatus != NULL)
409 *IOCStatus = req.ioc_status;
411 warnx("Reading config page failed: %s",
412 mpt_ioc_status(req.ioc_status));
421 mpt_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
422 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
424 struct mpt_ext_cfg_page_req req;
428 if (IOCStatus != NULL)
429 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
430 bzero(&req, sizeof(req));
431 req.header.PageVersion = PageVersion;
432 req.header.PageNumber = PageNumber;
433 req.header.ExtPageType = ExtPageType;
434 req.page_address = PageAddress;
435 if (ioctl(fd, MPTIO_READ_EXT_CFG_HEADER, &req) < 0)
437 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
438 if (IOCStatus != NULL)
439 *IOCStatus = req.ioc_status;
441 warnx("Reading extended config page header failed: %s",
442 mpt_ioc_status(req.ioc_status));
446 req.len = req.header.ExtPageLength * 4;
447 buf = malloc(req.len);
449 bcopy(&req.header, buf, sizeof(req.header));
450 if (ioctl(fd, MPTIO_READ_EXT_CFG_PAGE, &req) < 0) {
456 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
457 if (IOCStatus != NULL)
458 *IOCStatus = req.ioc_status;
460 warnx("Reading extended config page failed: %s",
461 mpt_ioc_status(req.ioc_status));
470 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
472 CONFIG_PAGE_HEADER *hdr;
473 struct mpt_cfg_page_req req;
475 if (IOCStatus != NULL)
476 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
477 bzero(&req, sizeof(req));
480 req.len = hdr->PageLength * 4;
481 if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
483 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
484 if (IOCStatus != NULL) {
485 *IOCStatus = req.ioc_status;
488 warnx("Writing config page failed: %s",
489 mpt_ioc_status(req.ioc_status));
496 mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
497 U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
498 U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
500 struct mpt_raid_action raid_act;
502 if (IOCStatus != NULL)
503 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
504 if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
506 bzero(&raid_act, sizeof(raid_act));
507 raid_act.action = Action;
508 raid_act.volume_bus = VolumeBus;
509 raid_act.volume_id = VolumeID;
510 raid_act.phys_disk_num = PhysDiskNum;
511 raid_act.action_data_word = ActionDataWord;
512 if (buf != NULL && len != 0) {
515 raid_act.write = write;
518 if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
521 if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
522 if (IOCStatus != NULL) {
523 *IOCStatus = raid_act.ioc_status;
526 warnx("RAID action failed: %s",
527 mpt_ioc_status(raid_act.ioc_status));
531 if (ActionStatus != NULL)
532 *ActionStatus = raid_act.action_status;
533 if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
534 if (ActionStatus != NULL)
536 warnx("RAID action failed: %s",
537 mpt_raid_status(raid_act.action_status));
541 if (VolumeStatus != NULL)
542 *((U32 *)VolumeStatus) = raid_act.volume_status;
543 if (ActionData != NULL)
544 bcopy(raid_act.action_data, ActionData, datalen);
551 char path[MAXPATHLEN];
553 snprintf(path, sizeof(path), "/dev/mpt%d", unit);
554 return (open(path, O_RDWR));
558 mpt_table_handler(struct mptutil_command **start, struct mptutil_command **end,
561 struct mptutil_command **cmd;
564 warnx("The %s command requires a sub-command.", av[0]);
567 for (cmd = start; cmd < end; cmd++) {
568 if (strcmp((*cmd)->name, av[1]) == 0)
569 return ((*cmd)->handler(ac - 1, av + 1));
572 warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
578 hexdump(const void *ptr, int length, const char *hdr, int flags)
582 const unsigned char *cp;
585 if ((flags & HD_DELIM_MASK) != 0)
586 delim = (flags & HD_DELIM_MASK) >> 8;
590 if ((flags & HD_COLUMN_MASK) != 0)
591 cols = flags & HD_COLUMN_MASK;
596 for (i = 0; i < length; i+= cols) {
600 if ((flags & HD_OMIT_COUNT) == 0)
603 if ((flags & HD_OMIT_HEX) == 0) {
604 for (j = 0; j < cols; j++) {
607 printf("%c%02x", delim, cp[k]);
613 if ((flags & HD_OMIT_CHARS) == 0) {
615 for (j = 0; j < cols; j++) {
619 else if (cp[k] >= ' ' && cp[k] <= '~')