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/types.h>
35 #include <sys/errno.h>
45 MFI_TABLE(top, volume);
48 mfi_ldstate(enum mfi_ld_state state)
53 case MFI_LD_STATE_OFFLINE:
55 case MFI_LD_STATE_PARTIALLY_DEGRADED:
56 return ("PARTIALLY DEGRADED");
57 case MFI_LD_STATE_DEGRADED:
59 case MFI_LD_STATE_OPTIMAL:
62 sprintf(buf, "LSTATE 0x%02x", state);
68 mbox_store_ldref(uint8_t *mbox, union mfi_ld_ref *ref)
71 mbox[0] = ref->v.target_id;
72 mbox[1] = ref->v.reserved;
73 mbox[2] = ref->v.seq & 0xff;
74 mbox[3] = ref->v.seq >> 8;
78 mfi_ld_get_list(int fd, struct mfi_ld_list *list, uint8_t *statusp)
81 return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_LIST, list,
82 sizeof(struct mfi_ld_list), NULL, 0, statusp));
86 mfi_ld_get_info(int fd, uint8_t target_id, struct mfi_ld_info *info,
92 return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_INFO, info,
93 sizeof(struct mfi_ld_info), mbox, 1, statusp));
97 mfi_ld_get_props(int fd, uint8_t target_id, struct mfi_ld_props *props)
102 return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_PROP, props,
103 sizeof(struct mfi_ld_props), mbox, 1, NULL));
107 mfi_ld_set_props(int fd, struct mfi_ld_props *props)
111 mbox_store_ldref(mbox, &props->ld);
112 return (mfi_dcmd_command(fd, MFI_DCMD_LD_SET_PROP, props,
113 sizeof(struct mfi_ld_props), mbox, 4, NULL));
117 update_cache_policy(int fd, struct mfi_ld_props *old, struct mfi_ld_props *new)
120 uint8_t changes, policy;
122 if (old->default_cache_policy == new->default_cache_policy &&
123 old->disk_cache_policy == new->disk_cache_policy)
125 policy = new->default_cache_policy;
126 changes = policy ^ old->default_cache_policy;
127 if (changes & MR_LD_CACHE_ALLOW_WRITE_CACHE)
128 printf("%s caching of I/O writes\n",
129 policy & MR_LD_CACHE_ALLOW_WRITE_CACHE ? "Enabling" :
131 if (changes & MR_LD_CACHE_ALLOW_READ_CACHE)
132 printf("%s caching of I/O reads\n",
133 policy & MR_LD_CACHE_ALLOW_READ_CACHE ? "Enabling" :
135 if (changes & MR_LD_CACHE_WRITE_BACK)
136 printf("Setting write cache policy to %s\n",
137 policy & MR_LD_CACHE_WRITE_BACK ? "write-back" :
139 if (changes & (MR_LD_CACHE_READ_AHEAD | MR_LD_CACHE_READ_ADAPTIVE))
140 printf("Setting read ahead policy to %s\n",
141 policy & MR_LD_CACHE_READ_AHEAD ?
142 (policy & MR_LD_CACHE_READ_ADAPTIVE ?
143 "adaptive" : "always") : "none");
144 if (changes & MR_LD_CACHE_WRITE_CACHE_BAD_BBU)
145 printf("%s write caching with bad BBU\n",
146 policy & MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "Enabling" :
148 if (old->disk_cache_policy != new->disk_cache_policy) {
149 switch (new->disk_cache_policy) {
150 case MR_PD_CACHE_ENABLE:
151 printf("Enabling write-cache on physical drives\n");
153 case MR_PD_CACHE_DISABLE:
154 printf("Disabling write-cache on physical drives\n");
156 case MR_PD_CACHE_UNCHANGED:
157 printf("Using default write-cache setting on physical drives\n");
162 if (mfi_ld_set_props(fd, new) < 0) {
164 warn("Failed to set volume properties");
171 stage_cache_setting(struct mfi_ld_props *props, uint8_t new_policy,
175 props->default_cache_policy &= ~mask;
176 props->default_cache_policy |= new_policy;
180 * Parse a single cache directive modifying the passed in policy.
181 * Returns -1 on a parse error and the number of arguments consumed
185 process_cache_command(int ac, char **av, struct mfi_ld_props *props)
189 /* I/O cache settings. */
190 if (strcmp(av[0], "all") == 0 || strcmp(av[0], "enable") == 0) {
191 stage_cache_setting(props, MR_LD_CACHE_ALLOW_READ_CACHE |
192 MR_LD_CACHE_ALLOW_WRITE_CACHE,
193 MR_LD_CACHE_ALLOW_READ_CACHE |
194 MR_LD_CACHE_ALLOW_WRITE_CACHE);
197 if (strcmp(av[0], "none") == 0 || strcmp(av[0], "disable") == 0) {
198 stage_cache_setting(props, 0, MR_LD_CACHE_ALLOW_READ_CACHE |
199 MR_LD_CACHE_ALLOW_WRITE_CACHE);
202 if (strcmp(av[0], "reads") == 0) {
203 stage_cache_setting(props, MR_LD_CACHE_ALLOW_READ_CACHE,
204 MR_LD_CACHE_ALLOW_READ_CACHE |
205 MR_LD_CACHE_ALLOW_WRITE_CACHE);
208 if (strcmp(av[0], "writes") == 0) {
209 stage_cache_setting(props, MR_LD_CACHE_ALLOW_WRITE_CACHE,
210 MR_LD_CACHE_ALLOW_READ_CACHE |
211 MR_LD_CACHE_ALLOW_WRITE_CACHE);
215 /* Write cache behavior. */
216 if (strcmp(av[0], "write-back") == 0) {
217 stage_cache_setting(props, MR_LD_CACHE_WRITE_BACK,
218 MR_LD_CACHE_WRITE_BACK);
221 if (strcmp(av[0], "write-through") == 0) {
222 stage_cache_setting(props, 0, MR_LD_CACHE_WRITE_BACK);
225 if (strcmp(av[0], "bad-bbu-write-cache") == 0) {
227 warnx("cache: bad BBU setting required");
230 if (strcmp(av[1], "enable") == 0)
231 policy = MR_LD_CACHE_WRITE_CACHE_BAD_BBU;
232 else if (strcmp(av[1], "disable") == 0)
235 warnx("cache: invalid bad BBU setting");
238 stage_cache_setting(props, policy,
239 MR_LD_CACHE_WRITE_CACHE_BAD_BBU);
243 /* Read cache behavior. */
244 if (strcmp(av[0], "read-ahead") == 0) {
246 warnx("cache: read-ahead setting required");
249 if (strcmp(av[1], "none") == 0)
251 else if (strcmp(av[1], "always") == 0)
252 policy = MR_LD_CACHE_READ_AHEAD;
253 else if (strcmp(av[1], "adaptive") == 0)
254 policy = MR_LD_CACHE_READ_AHEAD |
255 MR_LD_CACHE_READ_ADAPTIVE;
257 warnx("cache: invalid read-ahead setting");
260 stage_cache_setting(props, policy, MR_LD_CACHE_READ_AHEAD |
261 MR_LD_CACHE_READ_ADAPTIVE);
265 /* Drive write-cache behavior. */
266 if (strcmp(av[0], "write-cache") == 0) {
268 warnx("cache: write-cache setting required");
271 if (strcmp(av[1], "enable") == 0)
272 props->disk_cache_policy = MR_PD_CACHE_ENABLE;
273 else if (strcmp(av[1], "disable") == 0)
274 props->disk_cache_policy = MR_PD_CACHE_DISABLE;
275 else if (strcmp(av[1], "default") == 0)
276 props->disk_cache_policy = MR_PD_CACHE_UNCHANGED;
278 warnx("cache: invalid write-cache setting");
284 warnx("cache: Invalid command");
289 volume_cache(int ac, char **av)
291 struct mfi_ld_props props, new;
292 int error, fd, consumed;
296 warnx("cache: volume required");
300 fd = mfi_open(mfi_unit, O_RDWR);
307 if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
309 warn("Invalid volume: %s", av[1]);
314 if (mfi_ld_get_props(fd, target_id, &props) < 0) {
316 warn("Failed to fetch volume properties");
322 printf("mfi%u volume %s cache settings:\n", mfi_unit,
323 mfi_volume_name(fd, target_id));
324 printf(" I/O caching: ");
325 switch (props.default_cache_policy &
326 (MR_LD_CACHE_ALLOW_WRITE_CACHE |
327 MR_LD_CACHE_ALLOW_READ_CACHE)) {
329 printf("disabled\n");
331 case MR_LD_CACHE_ALLOW_WRITE_CACHE:
334 case MR_LD_CACHE_ALLOW_READ_CACHE:
337 case MR_LD_CACHE_ALLOW_WRITE_CACHE |
338 MR_LD_CACHE_ALLOW_READ_CACHE:
339 printf("writes and reads\n");
342 printf(" write caching: %s\n",
343 props.default_cache_policy & MR_LD_CACHE_WRITE_BACK ?
344 "write-back" : "write-through");
345 printf("write cache with bad BBU: %s\n",
346 props.default_cache_policy &
347 MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "enabled" : "disabled");
348 printf(" read ahead: %s\n",
349 props.default_cache_policy & MR_LD_CACHE_READ_AHEAD ?
350 (props.default_cache_policy & MR_LD_CACHE_READ_ADAPTIVE ?
351 "adaptive" : "always") : "none");
352 printf(" drive write cache: ");
353 switch (props.disk_cache_policy) {
354 case MR_PD_CACHE_UNCHANGED:
357 case MR_PD_CACHE_ENABLE:
360 case MR_PD_CACHE_DISABLE:
361 printf("disabled\n");
364 printf("??? %d\n", props.disk_cache_policy);
367 if (props.default_cache_policy != props.current_cache_policy)
369 "Cache disabled due to dead battery or ongoing battery relearn\n");
376 consumed = process_cache_command(ac, av, &new);
384 error = update_cache_policy(fd, &props, &new);
390 MFI_COMMAND(top, cache, volume_cache);
393 volume_name(int ac, char **av)
395 struct mfi_ld_props props;
400 warnx("name: volume and name required");
404 if (strlen(av[2]) >= sizeof(props.name)) {
405 warnx("name: new name is too long");
409 fd = mfi_open(mfi_unit, O_RDWR);
416 if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
418 warn("Invalid volume: %s", av[1]);
423 if (mfi_ld_get_props(fd, target_id, &props) < 0) {
425 warn("Failed to fetch volume properties");
430 printf("mfi%u volume %s name changed from \"%s\" to \"%s\"\n", mfi_unit,
431 mfi_volume_name(fd, target_id), props.name, av[2]);
432 bzero(props.name, sizeof(props.name));
433 strcpy(props.name, av[2]);
434 if (mfi_ld_set_props(fd, &props) < 0) {
436 warn("Failed to set volume properties");
445 MFI_COMMAND(top, name, volume_name);
448 volume_progress(int ac, char **av)
450 struct mfi_ld_info info;
455 warnx("volume progress: %s", ac > 2 ? "extra arguments" :
460 fd = mfi_open(mfi_unit, O_RDONLY);
467 if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
469 warn("Invalid volume: %s", av[1]);
474 /* Get the info for this drive. */
475 if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
477 warn("Failed to fetch info for volume %s",
478 mfi_volume_name(fd, target_id));
483 /* Display any of the active events. */
484 if (info.progress.active & MFI_LD_PROGRESS_CC)
485 mfi_display_progress("Consistency Check", &info.progress.cc);
486 if (info.progress.active & MFI_LD_PROGRESS_BGI)
487 mfi_display_progress("Background Init", &info.progress.bgi);
488 if (info.progress.active & MFI_LD_PROGRESS_FGI)
489 mfi_display_progress("Foreground Init", &info.progress.fgi);
490 if (info.progress.active & MFI_LD_PROGRESS_RECON)
491 mfi_display_progress("Reconstruction", &info.progress.recon);
492 if ((info.progress.active & (MFI_LD_PROGRESS_CC | MFI_LD_PROGRESS_BGI |
493 MFI_LD_PROGRESS_FGI | MFI_LD_PROGRESS_RECON)) == 0)
494 printf("No activity in progress for volume %s.\n",
495 mfi_volume_name(fd, target_id));
500 MFI_COMMAND(volume, progress, volume_progress);