2 * Copyright (c) 2008, 2009 Yahoo!, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The names of the authors may not be used to endorse or promote
14 * products derived from this software without specific prior written
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: src/usr.sbin/mfiutil/mfi_cmd.c,v 1.3 2011/02/25 13:59:59 pluknet Exp $
32 #define _KERNEL_STRUCTURES
33 #include <sys/errno.h>
34 #include <sys/ioctl.h>
35 #include <sys/param.h>
37 #include <sys/sysctl.h>
48 #include <dev/raid/mfi/mfi_ioctl.h>
50 static const char *mfi_status_codes
[] = {
51 "Command completed successfully",
53 "Invalid DMCD opcode",
55 "Invalid Sequence Number",
56 "Abort isn't possible for the requested command",
57 "Application 'host' code not found",
59 "Application not initialized",
60 "Array index invalid",
61 "Array row not empty",
62 "Configuration resource conflict",
65 "Flash memory allocation failed",
66 "Flash download already in progress",
67 "Flash operation failed",
69 "Incomplete flash image",
73 "Specified application doesn't have host-resident code",
74 "Volume consistency check in progress",
75 "Volume initialization in progress",
76 "Volume LBA out of range",
77 "Maximum number of volumes are already configured",
78 "Volume is not OPTIMAL",
79 "Volume rebuild in progress",
80 "Volume reconstruction in progress",
81 "Volume RAID level is wrong for requested operation",
82 "Too many spares assigned",
83 "Scratch memory not available",
84 "Error writing MFC data to SEEPROM",
85 "Required hardware is missing",
87 "Volume drives are not within an enclosure",
88 "Drive clear in progress",
89 "Drive type mismatch (SATA vs SAS)",
90 "Patrol read disabled",
92 "SAS Config - Invalid action",
93 "SAS Config - Invalid data",
94 "SAS Config - Invalid page",
95 "SAS Config - Invalid type",
96 "SCSI command completed with error",
97 "SCSI I/O request failed",
98 "SCSI RESERVATION_CONFLICT",
99 "One or more flush operations during shutdown failed",
100 "Firmware time is not set",
101 "Wrong firmware or drive state",
103 "Peer controller rejected request",
104 "Unable to inform peer of communication changes",
105 "Volume reservation already in progress",
106 "I2C errors were detected",
107 "PCI errors occurred during XOR/DMA operation",
108 "Diagnostics failed",
109 "Unable to process command as boot messages are pending",
110 "Foreign configuration is incomplete"
114 mfi_status(u_int status_code
)
116 static char buffer
[16];
118 if (status_code
== MFI_STAT_INVALID_STATUS
)
119 return ("Invalid status");
120 if (status_code
< sizeof(mfi_status_codes
) / sizeof(char *))
121 return (mfi_status_codes
[status_code
]);
122 snprintf(buffer
, sizeof(buffer
), "Status: 0x%02x", status_code
);
127 mfi_raid_level(uint8_t primary_level
, uint8_t secondary_level
)
131 switch (primary_level
) {
135 if (secondary_level
!= 0)
144 if (secondary_level
!= 0)
153 if (secondary_level
!= 0)
162 sprintf(buf
, "LVL 0x%02x", primary_level
);
168 mfi_query_disk(int fd
, uint8_t target_id
, struct mfi_query_disk
*info
)
171 bzero(info
, sizeof(*info
));
172 info
->array_id
= target_id
;
173 if (ioctl(fd
, MFIIO_QUERY_DISK
, info
) < 0)
175 if (!info
->present
) {
183 mfi_volume_name(int fd
, uint8_t target_id
)
185 static struct mfi_query_disk info
;
188 if (mfi_query_disk(fd
, target_id
, &info
) < 0) {
189 snprintf(buf
, sizeof(buf
), "%d", target_id
);
192 return (info
.devname
);
196 mfi_volume_busy(int fd
, uint8_t target_id
)
198 struct mfi_query_disk info
;
200 /* Assume it isn't mounted if we can't get information. */
201 if (mfi_query_disk(fd
, target_id
, &info
) < 0)
203 return (info
.open
!= 0);
207 * Check if the running kernel supports changing the RAID
208 * configuration of the mfi controller.
211 mfi_reconfig_supported(void)
218 snprintf(mibname
, sizeof(mibname
), "hw.mfi%d.delete_busy_volumes",
220 return (sysctlbyname(mibname
, &dummy
, &len
, NULL
, 0) == 0);
224 mfi_lookup_volume(int fd
, const char *name
, uint8_t *target_id
)
226 struct mfi_query_disk info
;
227 struct mfi_ld_list list
;
232 /* If it's a valid number, treat it as a raw target ID. */
233 val
= strtol(name
, &cp
, 0);
239 if (mfi_dcmd_command(fd
, MFI_DCMD_LD_GET_LIST
, &list
, sizeof(list
),
243 for (i
= 0; i
< list
.ld_count
; i
++) {
244 if (mfi_query_disk(fd
, list
.ld_list
[i
].ld
.v
.target_id
,
247 if (strcmp(name
, info
.devname
) == 0) {
248 *target_id
= list
.ld_list
[i
].ld
.v
.target_id
;
257 mfi_dcmd_command(int fd
, uint32_t opcode
, void *buf
, size_t bufsize
,
258 uint8_t *mbox
, size_t mboxlen
, uint8_t *statusp
)
260 struct mfi_ioc_passthru ioc
;
261 struct mfi_dcmd_frame
*dcmd
;
264 if ((mbox
!= NULL
&& (mboxlen
== 0 || mboxlen
> MFI_MBOX_SIZE
)) ||
265 (mbox
== NULL
&& mboxlen
!= 0)) {
270 bzero(&ioc
, sizeof(ioc
));
271 dcmd
= &ioc
.ioc_frame
;
273 bcopy(mbox
, dcmd
->mbox
, mboxlen
);
274 dcmd
->header
.cmd
= MFI_CMD_DCMD
;
275 dcmd
->header
.timeout
= 0;
276 dcmd
->header
.flags
= 0;
277 dcmd
->header
.data_len
= bufsize
;
278 dcmd
->opcode
= opcode
;
281 ioc
.buf_size
= bufsize
;
282 r
= ioctl(fd
, MFIIO_PASSTHRU
, &ioc
);
287 *statusp
= dcmd
->header
.cmd_status
;
288 else if (dcmd
->header
.cmd_status
!= MFI_STAT_OK
) {
289 warnx("Command 0x%08x failed: %s", opcode
,
290 mfi_status(dcmd
->header
.cmd_status
));
298 mfi_ctrl_get_info(int fd
, struct mfi_ctrl_info
*info
, uint8_t *statusp
)
301 return (mfi_dcmd_command(fd
, MFI_DCMD_CTRL_GETINFO
, info
,
302 sizeof(struct mfi_ctrl_info
), NULL
, 0, statusp
));
308 char path
[MAXPATHLEN
];
310 snprintf(path
, sizeof(path
), "/dev/mfi%d", unit
);
311 return (open(path
, O_RDWR
));
315 mfi_display_progress(const char *label
, struct mfi_progress
*prog
)
319 printf("%s: %.2f%% complete, after %ds", label
,
320 (float)prog
->progress
* 100 / 0xffff, prog
->elapsed_seconds
);
321 if (prog
->progress
!= 0 && prog
->elapsed_seconds
> 10) {
322 printf(" finished in ");
323 seconds
= (0x10000 * (uint32_t)prog
->elapsed_seconds
) /
324 prog
->progress
- prog
->elapsed_seconds
;
326 printf("%u:", seconds
/ 3600);
329 printf("%02u:%02u", seconds
/ 60, seconds
% 60);
331 printf("%us", seconds
);
337 mfi_table_handler(struct mfiutil_command
**start
, struct mfiutil_command
**end
,
340 struct mfiutil_command
**cmd
;
343 warnx("The %s command requires a sub-command.", av
[0]);
346 for (cmd
= start
; cmd
< end
; cmd
++) {
347 if (strcmp((*cmd
)->name
, av
[1]) == 0)
348 return ((*cmd
)->handler(ac
- 1, av
+ 1));
351 warnx("%s is not a valid sub-command of %s.", av
[1], av
[0]);