2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 2008, 2009 Yahoo!, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The names of the authors may not be used to endorse or promote
16 * products derived from this software without specific prior written
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/param.h>
35 #include <sys/ioctl.h>
36 #include <sys/sysctl.h>
50 #include <dev/mfi/mfi_ioctl.h>
52 static const char *mfi_status_codes[] = {
53 "Command completed successfully",
55 "Invalid DMCD opcode",
57 "Invalid Sequence Number",
58 "Abort isn't possible for the requested command",
59 "Application 'host' code not found",
61 "Application not initialized",
62 "Array index invalid",
63 "Array row not empty",
64 "Configuration resource conflict",
67 "Flash memory allocation failed",
68 "Flash download already in progress",
69 "Flash operation failed",
71 "Incomplete flash image",
75 "Specified application doesn't have host-resident code",
76 "Volume consistency check in progress",
77 "Volume initialization in progress",
78 "Volume LBA out of range",
79 "Maximum number of volumes are already configured",
80 "Volume is not OPTIMAL",
81 "Volume rebuild in progress",
82 "Volume reconstruction in progress",
83 "Volume RAID level is wrong for requested operation",
84 "Too many spares assigned",
85 "Scratch memory not available",
86 "Error writing MFC data to SEEPROM",
87 "Required hardware is missing",
89 "Volume drives are not within an enclosure",
90 "Drive clear in progress",
91 "Drive type mismatch (SATA vs SAS)",
92 "Patrol read disabled",
94 "SAS Config - Invalid action",
95 "SAS Config - Invalid data",
96 "SAS Config - Invalid page",
97 "SAS Config - Invalid type",
98 "SCSI command completed with error",
99 "SCSI I/O request failed",
100 "SCSI RESERVATION_CONFLICT",
101 "One or more flush operations during shutdown failed",
102 "Firmware time is not set",
103 "Wrong firmware or drive state",
105 "Peer controller rejected request",
106 "Unable to inform peer of communication changes",
107 "Volume reservation already in progress",
108 "I2C errors were detected",
109 "PCI errors occurred during XOR/DMA operation",
110 "Diagnostics failed",
111 "Unable to process command as boot messages are pending",
112 "Foreign configuration is incomplete"
116 mfi_status(u_int status_code)
118 static char buffer[16];
120 if (status_code == MFI_STAT_INVALID_STATUS)
121 return ("Invalid status");
122 if (status_code < sizeof(mfi_status_codes) / sizeof(char *))
123 return (mfi_status_codes[status_code]);
124 snprintf(buffer, sizeof(buffer), "Status: 0x%02x", status_code);
129 mfi_raid_level(uint8_t primary_level, uint8_t secondary_level)
133 switch (primary_level) {
137 if (secondary_level != 0)
146 if (secondary_level != 0)
155 if (secondary_level != 0)
164 sprintf(buf, "LVL 0x%02x", primary_level);
170 mfi_query_disk(int fd, uint8_t target_id, struct mfi_query_disk *info)
173 bzero(info, sizeof(*info));
174 info->array_id = target_id;
175 if (ioctl(fd, MFIIO_QUERY_DISK, info) < 0)
177 if (!info->present) {
185 mfi_volume_name(int fd, uint8_t target_id)
187 static struct mfi_query_disk info;
190 if (mfi_query_disk(fd, target_id, &info) < 0) {
191 snprintf(buf, sizeof(buf), "%d", target_id);
194 return (info.devname);
198 mfi_volume_busy(int fd, uint8_t target_id)
200 struct mfi_query_disk info;
202 /* Assume it isn't mounted if we can't get information. */
203 if (mfi_query_disk(fd, target_id, &info) < 0)
205 return (info.open != 0);
209 * Check if the running kernel supports changing the RAID
210 * configuration of the mfi controller.
213 mfi_reconfig_supported(const char *dev)
220 cp = dev + strlen(_PATH_DEV);
221 if (strncmp(cp, MRSAS_TYPE, strlen(MRSAS_TYPE)) == 0)
224 cp += strlen(MFI_TYPE);
225 mfi_unit = strtol(cp, NULL, 10);;
228 snprintf(mibname, sizeof(mibname),
229 "dev.mfi.%d.delete_busy_volumes", mfi_unit);
230 return (sysctlbyname(mibname, &dummy, &len, NULL, 0) == 0);
234 mfi_lookup_volume(int fd, const char *name, uint8_t *target_id)
236 struct mfi_query_disk info;
237 struct mfi_ld_list list;
242 /* If it's a valid number, treat it as a raw target ID. */
243 val = strtol(name, &cp, 0);
249 if (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_LIST, &list, sizeof(list),
253 for (i = 0; i < list.ld_count; i++) {
254 if (mfi_query_disk(fd, list.ld_list[i].ld.v.target_id,
257 if (strcmp(name, info.devname) == 0) {
258 *target_id = list.ld_list[i].ld.v.target_id;
267 mfi_dcmd_command(int fd, uint32_t opcode, void *buf, size_t bufsize,
268 uint8_t *mbox, size_t mboxlen, uint8_t *statusp)
270 struct mfi_ioc_passthru ioc;
271 struct mfi_dcmd_frame *dcmd;
274 if ((mbox != NULL && (mboxlen == 0 || mboxlen > MFI_MBOX_SIZE)) ||
275 (mbox == NULL && mboxlen != 0)) {
280 bzero(&ioc, sizeof(ioc));
281 dcmd = &ioc.ioc_frame;
283 bcopy(mbox, dcmd->mbox, mboxlen);
284 dcmd->header.cmd = MFI_CMD_DCMD;
285 dcmd->header.timeout = 0;
286 dcmd->header.flags = 0;
287 dcmd->header.data_len = bufsize;
288 dcmd->opcode = opcode;
291 ioc.buf_size = bufsize;
292 r = ioctl(fd, MFIIO_PASSTHRU, &ioc);
297 *statusp = dcmd->header.cmd_status;
298 else if (dcmd->header.cmd_status != MFI_STAT_OK) {
299 warnx("Command failed: %s",
300 mfi_status(dcmd->header.cmd_status));
308 mfi_ctrl_get_info(int fd, struct mfi_ctrl_info *info, uint8_t *statusp)
311 return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_GETINFO, info,
312 sizeof(struct mfi_ctrl_info), NULL, 0, statusp));
316 mfi_open(char *dev, int acs)
320 ret = open(dev, acs);
322 warn("Couldn't open %s", dev);
327 print_time_humanized(uint seconds)
330 if (seconds > 3600) {
331 printf("%u:", seconds / 3600);
335 printf("%02u:%02u", seconds / 60, seconds % 60);
337 printf("%us", seconds);
342 mfi_display_progress(const char *label, struct mfi_progress *prog)
346 printf("%s: %.2f%% complete after ", label,
347 (float)prog->progress * 100 / 0xffff);
348 print_time_humanized(prog->elapsed_seconds);
349 if (prog->progress != 0 && prog->elapsed_seconds > 10) {
350 printf(" finished in ");
351 seconds = (0x10000 * (uint32_t)prog->elapsed_seconds) /
352 prog->progress - prog->elapsed_seconds;
353 print_time_humanized(seconds);
359 mfi_table_handler(struct mfiutil_command **start, struct mfiutil_command **end,
362 struct mfiutil_command **cmd;
365 warnx("The %s command requires a sub-command.", av[0]);
368 for (cmd = start; cmd < end; cmd++) {
369 if (strcmp((*cmd)->name, av[1]) == 0)
370 return ((*cmd)->handler(ac - 1, av + 1));
373 warnx("%s is not a valid sub-command of %s.", av[1], av[0]);