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
] <= '~')