2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 2008 Yahoo!, Inc.
6 * Written by: John Baldwin <jhb@FreeBSD.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
36 #include <sys/param.h>
37 #include <sys/errno.h>
38 #include <sys/ioctl.h>
39 #include <sys/mpt_ioctl.h>
40 #include <sys/sysctl.h>
52 static const char *mpt_ioc_status_codes[] = {
53 "Success", /* 0x0000 */
56 "Invalid scatter-gather list",
59 "Insufficient resources",
61 "Invalid state", /* 0x0008 */
62 "Operation state not supported",
85 "Invalid configuration action", /* 0x0020 */
86 "Invalid configuration type",
87 "Invalid configuration page",
88 "Invalid configuration data",
89 "No configuration defaults",
90 "Unable to commit configuration change",
117 "Recovered SCSI error", /* 0x0040 */
119 "Invalid SCSI target ID",
120 "SCSI device not there",
122 "SCSI data underrun",
124 "SCSI protocol error",
125 "SCSI task terminated", /* 0x0048 */
126 "SCSI residual mismatch",
127 "SCSI task management failed",
128 "SCSI I/O controller terminated",
129 "SCSI external controller terminated",
131 "EEDP reference tag error",
132 "EEDP application tag error",
149 "SCSI target priority I/O", /* 0x0060 */
150 "Invalid SCSI target port",
151 "Invalid SCSI target I/O index",
152 "SCSI target aborted",
153 "No connection retryable",
156 "Invalid FC receive ID",
157 "FC did invalid", /* 0x0068 */
158 "FC node logged out",
159 "Transfer count mismatch",
161 "FC exchange canceled",
163 "Too much write data",
165 "ACK NAK timeout", /* 0x0070 */
181 "LAN device not found", /* 0x0080 */
182 "LAN device failure",
183 "LAN transmit error",
184 "LAN transmit aborted",
186 "LAN receive aborted",
187 "LAN partial packet",
197 "SAS SMP request failed", /* 0x0090 */
198 "SAS SMP data overrun",
205 "Inband aborted", /* 0x0098 */
206 "No inband connection",
213 "Diagnostic released", /* 0x00A0 */
216 static const char *mpt_raid_action_status_codes[] = {
220 "Operation in progress",
224 mpt_ioc_status(U16 IOCStatus)
226 static char buffer[16];
228 IOCStatus &= MPI_IOCSTATUS_MASK;
229 if (IOCStatus < sizeof(mpt_ioc_status_codes) / sizeof(char *) &&
230 mpt_ioc_status_codes[IOCStatus] != NULL)
231 return (mpt_ioc_status_codes[IOCStatus]);
232 snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
237 mpt_raid_status(U16 ActionStatus)
239 static char buffer[16];
241 if (ActionStatus < sizeof(mpt_raid_action_status_codes) /
243 return (mpt_raid_action_status_codes[ActionStatus]);
244 snprintf(buffer, sizeof(buffer), "Status: 0x%04x", ActionStatus);
249 mpt_raid_level(U8 VolumeType)
253 switch (VolumeType) {
254 case MPI_RAID_VOL_TYPE_IS:
256 case MPI_RAID_VOL_TYPE_IM:
258 case MPI_RAID_VOL_TYPE_IME:
260 case MPI_RAID_VOL_TYPE_RAID_5:
262 case MPI_RAID_VOL_TYPE_RAID_6:
264 case MPI_RAID_VOL_TYPE_RAID_10:
266 case MPI_RAID_VOL_TYPE_RAID_50:
269 sprintf(buf, "LVL 0x%02x", VolumeType);
275 mpt_volume_name(U8 VolumeBus, U8 VolumeID)
277 static struct mpt_query_disk info;
280 if (mpt_query_disk(VolumeBus, VolumeID, &info) != 0) {
282 * We only print out the bus number if it is non-zero
283 * since mpt(4) only supports devices on bus zero
287 snprintf(buf, sizeof(buf), "%d", VolumeID);
289 snprintf(buf, sizeof(buf), "%d:%d", VolumeBus,
293 return (info.devname);
297 mpt_lookup_volume(int fd, const char *name, U8 *VolumeBus, U8 *VolumeID)
299 CONFIG_PAGE_IOC_2 *ioc2;
300 CONFIG_PAGE_IOC_2_RAID_VOL *vol;
301 struct mpt_query_disk info;
307 * Check for a raw [<bus>:]<id> string. If the bus is not
308 * specified, assume bus 0.
310 bus = strtol(name, &cp, 0);
312 id = strtol(cp + 1, &cp, 0);
314 if (bus < 0 || bus > 0xff || id < 0 || id > 0xff) {
321 } else if (*cp == '\0') {
322 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;
349 mpt_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
350 CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
352 struct mpt_cfg_page_req req;
354 if (IOCStatus != NULL)
355 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
356 bzero(&req, sizeof(req));
357 req.header.PageType = PageType;
358 req.header.PageNumber = PageNumber;
359 req.page_address = PageAddress;
360 if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
362 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
363 if (IOCStatus != NULL)
364 *IOCStatus = req.ioc_status;
366 warnx("Reading config page header failed: %s",
367 mpt_ioc_status(req.ioc_status));
370 *header = req.header;
375 mpt_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
378 struct mpt_cfg_page_req req;
382 if (IOCStatus != NULL)
383 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
384 bzero(&req, sizeof(req));
385 req.header.PageType = PageType;
386 req.header.PageNumber = PageNumber;
387 req.page_address = PageAddress;
388 if (ioctl(fd, MPTIO_READ_CFG_HEADER, &req) < 0)
390 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
391 if (IOCStatus != NULL)
392 *IOCStatus = req.ioc_status;
394 warnx("Reading config page header failed: %s",
395 mpt_ioc_status(req.ioc_status));
399 req.len = req.header.PageLength * 4;
400 buf = malloc(req.len);
402 bcopy(&req.header, buf, sizeof(req.header));
403 if (ioctl(fd, MPTIO_READ_CFG_PAGE, &req) < 0) {
409 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
410 if (IOCStatus != NULL)
411 *IOCStatus = req.ioc_status;
413 warnx("Reading config page failed: %s",
414 mpt_ioc_status(req.ioc_status));
423 mpt_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
424 U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
426 struct mpt_ext_cfg_page_req req;
430 if (IOCStatus != NULL)
431 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
432 bzero(&req, sizeof(req));
433 req.header.PageVersion = PageVersion;
434 req.header.PageNumber = PageNumber;
435 req.header.ExtPageType = ExtPageType;
436 req.page_address = PageAddress;
437 if (ioctl(fd, MPTIO_READ_EXT_CFG_HEADER, &req) < 0)
439 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
440 if (IOCStatus != NULL)
441 *IOCStatus = req.ioc_status;
443 warnx("Reading extended config page header failed: %s",
444 mpt_ioc_status(req.ioc_status));
448 req.len = req.header.ExtPageLength * 4;
449 buf = malloc(req.len);
451 bcopy(&req.header, buf, sizeof(req.header));
452 if (ioctl(fd, MPTIO_READ_EXT_CFG_PAGE, &req) < 0) {
458 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
459 if (IOCStatus != NULL)
460 *IOCStatus = req.ioc_status;
462 warnx("Reading extended config page failed: %s",
463 mpt_ioc_status(req.ioc_status));
472 mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
474 CONFIG_PAGE_HEADER *hdr;
475 struct mpt_cfg_page_req req;
477 if (IOCStatus != NULL)
478 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
479 bzero(&req, sizeof(req));
482 req.len = hdr->PageLength * 4;
483 if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
485 if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
486 if (IOCStatus != NULL) {
487 *IOCStatus = req.ioc_status;
490 warnx("Writing config page failed: %s",
491 mpt_ioc_status(req.ioc_status));
498 mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
499 U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
500 U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
502 struct mpt_raid_action raid_act;
504 if (IOCStatus != NULL)
505 *IOCStatus = MPI_IOCSTATUS_SUCCESS;
506 if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
508 bzero(&raid_act, sizeof(raid_act));
509 raid_act.action = Action;
510 raid_act.volume_bus = VolumeBus;
511 raid_act.volume_id = VolumeID;
512 raid_act.phys_disk_num = PhysDiskNum;
513 raid_act.action_data_word = ActionDataWord;
514 if (buf != NULL && len != 0) {
517 raid_act.write = write;
520 if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
523 if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
524 if (IOCStatus != NULL) {
525 *IOCStatus = raid_act.ioc_status;
528 warnx("RAID action failed: %s",
529 mpt_ioc_status(raid_act.ioc_status));
533 if (ActionStatus != NULL)
534 *ActionStatus = raid_act.action_status;
535 if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
536 if (ActionStatus != NULL)
538 warnx("RAID action failed: %s",
539 mpt_raid_status(raid_act.action_status));
543 if (VolumeStatus != NULL)
544 *((U32 *)VolumeStatus) = raid_act.volume_status;
545 if (ActionData != NULL)
546 bcopy(raid_act.action_data, ActionData, datalen);
553 char path[MAXPATHLEN];
555 snprintf(path, sizeof(path), "/dev/mpt%d", unit);
556 return (open(path, O_RDWR));
560 mpt_table_handler(struct mptutil_command **start, struct mptutil_command **end,
563 struct mptutil_command **cmd;
566 warnx("The %s command requires a sub-command.", av[0]);
569 for (cmd = start; cmd < end; cmd++) {
570 if (strcmp((*cmd)->name, av[1]) == 0)
571 return ((*cmd)->handler(ac - 1, av + 1));
574 warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
580 hexdump(const void *ptr, int length, const char *hdr, int flags)
584 const unsigned char *cp;
587 if ((flags & HD_DELIM_MASK) != 0)
588 delim = (flags & HD_DELIM_MASK) >> 8;
592 if ((flags & HD_COLUMN_MASK) != 0)
593 cols = flags & HD_COLUMN_MASK;
598 for (i = 0; i < length; i+= cols) {
602 if ((flags & HD_OMIT_COUNT) == 0)
605 if ((flags & HD_OMIT_HEX) == 0) {
606 for (j = 0; j < cols; j++) {
609 printf("%c%02x", delim, cp[k]);
615 if ((flags & HD_OMIT_CHARS) == 0) {
617 for (j = 0; j < cols; j++) {
621 else if (cp[k] >= ' ' && cp[k] <= '~')