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
32 #include <sys/types.h>
33 #include <sys/errno.h>
43 MFI_TABLE(top
, volume
);
46 mfi_ldstate(enum mfi_ld_state state
)
51 case MFI_LD_STATE_OFFLINE
:
53 case MFI_LD_STATE_PARTIALLY_DEGRADED
:
54 return ("PARTIALLY DEGRADED");
55 case MFI_LD_STATE_DEGRADED
:
57 case MFI_LD_STATE_OPTIMAL
:
60 sprintf(buf
, "LSTATE 0x%02x", state
);
66 mbox_store_ldref(uint8_t *mbox
, union mfi_ld_ref
*ref
)
69 mbox
[0] = ref
->v
.target_id
;
70 mbox
[1] = ref
->v
.reserved
;
71 mbox
[2] = ref
->v
.seq
& 0xff;
72 mbox
[3] = ref
->v
.seq
>> 8;
76 mfi_ld_get_list(int fd
, struct mfi_ld_list
*list
, uint8_t *statusp
)
79 return (mfi_dcmd_command(fd
, MFI_DCMD_LD_GET_LIST
, list
,
80 sizeof(struct mfi_ld_list
), NULL
, 0, statusp
));
84 mfi_ld_get_info(int fd
, uint8_t target_id
, struct mfi_ld_info
*info
,
90 return (mfi_dcmd_command(fd
, MFI_DCMD_LD_GET_INFO
, info
,
91 sizeof(struct mfi_ld_info
), mbox
, 1, statusp
));
95 mfi_ld_get_props(int fd
, uint8_t target_id
, struct mfi_ld_props
*props
)
100 return (mfi_dcmd_command(fd
, MFI_DCMD_LD_GET_PROP
, props
,
101 sizeof(struct mfi_ld_props
), mbox
, 1, NULL
));
105 mfi_ld_set_props(int fd
, struct mfi_ld_props
*props
)
109 mbox_store_ldref(mbox
, &props
->ld
);
110 return (mfi_dcmd_command(fd
, MFI_DCMD_LD_SET_PROP
, props
,
111 sizeof(struct mfi_ld_props
), mbox
, 4, NULL
));
115 update_cache_policy(int fd
, struct mfi_ld_props
*old
, struct mfi_ld_props
*new)
118 uint8_t changes
, policy
;
120 if (old
->default_cache_policy
== new->default_cache_policy
&&
121 old
->disk_cache_policy
== new->disk_cache_policy
)
123 policy
= new->default_cache_policy
;
124 changes
= policy
^ old
->default_cache_policy
;
125 if (changes
& MR_LD_CACHE_ALLOW_WRITE_CACHE
)
126 printf("%s caching of I/O writes\n",
127 policy
& MR_LD_CACHE_ALLOW_WRITE_CACHE
? "Enabling" :
129 if (changes
& MR_LD_CACHE_ALLOW_READ_CACHE
)
130 printf("%s caching of I/O reads\n",
131 policy
& MR_LD_CACHE_ALLOW_READ_CACHE
? "Enabling" :
133 if (changes
& MR_LD_CACHE_WRITE_BACK
)
134 printf("Setting write cache policy to %s\n",
135 policy
& MR_LD_CACHE_WRITE_BACK
? "write-back" :
137 if (changes
& (MR_LD_CACHE_READ_AHEAD
| MR_LD_CACHE_READ_ADAPTIVE
))
138 printf("Setting read ahead policy to %s\n",
139 policy
& MR_LD_CACHE_READ_AHEAD
?
140 (policy
& MR_LD_CACHE_READ_ADAPTIVE
?
141 "adaptive" : "always") : "none");
142 if (changes
& MR_LD_CACHE_WRITE_CACHE_BAD_BBU
)
143 printf("%s write caching with bad BBU\n",
144 policy
& MR_LD_CACHE_WRITE_CACHE_BAD_BBU
? "Enabling" :
146 if (old
->disk_cache_policy
!= new->disk_cache_policy
) {
147 switch (new->disk_cache_policy
) {
148 case MR_PD_CACHE_ENABLE
:
149 printf("Enabling write-cache on physical drives\n");
151 case MR_PD_CACHE_DISABLE
:
152 printf("Disabling write-cache on physical drives\n");
154 case MR_PD_CACHE_UNCHANGED
:
155 printf("Using default write-cache setting on physical drives\n");
160 if (mfi_ld_set_props(fd
, new) < 0) {
162 warn("Failed to set volume properties");
169 stage_cache_setting(struct mfi_ld_props
*props
, uint8_t new_policy
,
173 props
->default_cache_policy
&= ~mask
;
174 props
->default_cache_policy
|= new_policy
;
178 * Parse a single cache directive modifying the passed in policy.
179 * Returns -1 on a parse error and the number of arguments consumed
183 process_cache_command(int ac
, char **av
, struct mfi_ld_props
*props
)
187 /* I/O cache settings. */
188 if (strcmp(av
[0], "all") == 0 || strcmp(av
[0], "enable") == 0) {
189 stage_cache_setting(props
, MR_LD_CACHE_ALLOW_READ_CACHE
|
190 MR_LD_CACHE_ALLOW_WRITE_CACHE
,
191 MR_LD_CACHE_ALLOW_READ_CACHE
|
192 MR_LD_CACHE_ALLOW_WRITE_CACHE
);
195 if (strcmp(av
[0], "none") == 0 || strcmp(av
[0], "disable") == 0) {
196 stage_cache_setting(props
, 0, MR_LD_CACHE_ALLOW_READ_CACHE
|
197 MR_LD_CACHE_ALLOW_WRITE_CACHE
);
200 if (strcmp(av
[0], "reads") == 0) {
201 stage_cache_setting(props
, MR_LD_CACHE_ALLOW_READ_CACHE
,
202 MR_LD_CACHE_ALLOW_READ_CACHE
|
203 MR_LD_CACHE_ALLOW_WRITE_CACHE
);
206 if (strcmp(av
[0], "writes") == 0) {
207 stage_cache_setting(props
, MR_LD_CACHE_ALLOW_WRITE_CACHE
,
208 MR_LD_CACHE_ALLOW_READ_CACHE
|
209 MR_LD_CACHE_ALLOW_WRITE_CACHE
);
213 /* Write cache behavior. */
214 if (strcmp(av
[0], "write-back") == 0) {
215 stage_cache_setting(props
, MR_LD_CACHE_WRITE_BACK
,
216 MR_LD_CACHE_WRITE_BACK
);
219 if (strcmp(av
[0], "write-through") == 0) {
220 stage_cache_setting(props
, 0, MR_LD_CACHE_WRITE_BACK
);
223 if (strcmp(av
[0], "bad-bbu-write-cache") == 0) {
225 warnx("cache: bad BBU setting required");
228 if (strcmp(av
[1], "enable") == 0)
229 policy
= MR_LD_CACHE_WRITE_CACHE_BAD_BBU
;
230 else if (strcmp(av
[1], "disable") == 0)
233 warnx("cache: invalid bad BBU setting");
236 stage_cache_setting(props
, policy
,
237 MR_LD_CACHE_WRITE_CACHE_BAD_BBU
);
241 /* Read cache behavior. */
242 if (strcmp(av
[0], "read-ahead") == 0) {
244 warnx("cache: read-ahead setting required");
247 if (strcmp(av
[1], "none") == 0)
249 else if (strcmp(av
[1], "always") == 0)
250 policy
= MR_LD_CACHE_READ_AHEAD
;
251 else if (strcmp(av
[1], "adaptive") == 0)
252 policy
= MR_LD_CACHE_READ_AHEAD
|
253 MR_LD_CACHE_READ_ADAPTIVE
;
255 warnx("cache: invalid read-ahead setting");
258 stage_cache_setting(props
, policy
, MR_LD_CACHE_READ_AHEAD
|
259 MR_LD_CACHE_READ_ADAPTIVE
);
263 /* Drive write-cache behavior. */
264 if (strcmp(av
[0], "write-cache") == 0) {
266 warnx("cache: write-cache setting required");
269 if (strcmp(av
[1], "enable") == 0)
270 props
->disk_cache_policy
= MR_PD_CACHE_ENABLE
;
271 else if (strcmp(av
[1], "disable") == 0)
272 props
->disk_cache_policy
= MR_PD_CACHE_DISABLE
;
273 else if (strcmp(av
[1], "default") == 0)
274 props
->disk_cache_policy
= MR_PD_CACHE_UNCHANGED
;
276 warnx("cache: invalid write-cache setting");
282 warnx("cache: Invalid command");
287 volume_cache(int ac
, char **av
)
289 struct mfi_ld_props props
, new;
290 int error
, fd
, consumed
;
294 warnx("cache: volume required");
298 fd
= mfi_open(mfi_unit
, O_RDWR
);
305 if (mfi_lookup_volume(fd
, av
[1], &target_id
) < 0) {
307 warn("Invalid volume: %s", av
[1]);
312 if (mfi_ld_get_props(fd
, target_id
, &props
) < 0) {
314 warn("Failed to fetch volume properties");
320 printf("mfi%u volume %s cache settings:\n", mfi_unit
,
321 mfi_volume_name(fd
, target_id
));
322 printf(" I/O caching: ");
323 switch (props
.default_cache_policy
&
324 (MR_LD_CACHE_ALLOW_WRITE_CACHE
|
325 MR_LD_CACHE_ALLOW_READ_CACHE
)) {
327 printf("disabled\n");
329 case MR_LD_CACHE_ALLOW_WRITE_CACHE
:
332 case MR_LD_CACHE_ALLOW_READ_CACHE
:
335 case MR_LD_CACHE_ALLOW_WRITE_CACHE
|
336 MR_LD_CACHE_ALLOW_READ_CACHE
:
337 printf("writes and reads\n");
340 printf(" write caching: %s\n",
341 props
.default_cache_policy
& MR_LD_CACHE_WRITE_BACK
?
342 "write-back" : "write-through");
343 printf("write cache with bad BBU: %s\n",
344 props
.default_cache_policy
&
345 MR_LD_CACHE_WRITE_CACHE_BAD_BBU
? "enabled" : "disabled");
346 printf(" read ahead: %s\n",
347 props
.default_cache_policy
& MR_LD_CACHE_READ_AHEAD
?
348 (props
.default_cache_policy
& MR_LD_CACHE_READ_ADAPTIVE
?
349 "adaptive" : "always") : "none");
350 printf(" drive write cache: ");
351 switch (props
.disk_cache_policy
) {
352 case MR_PD_CACHE_UNCHANGED
:
355 case MR_PD_CACHE_ENABLE
:
358 case MR_PD_CACHE_DISABLE
:
359 printf("disabled\n");
362 printf("??? %d\n", props
.disk_cache_policy
);
365 if (props
.default_cache_policy
!= props
.current_cache_policy
)
367 "Cache disabled due to dead battery or ongoing battery relearn\n");
374 consumed
= process_cache_command(ac
, av
, &new);
382 error
= update_cache_policy(fd
, &props
, &new);
388 MFI_COMMAND(top
, cache
, volume_cache
);
391 volume_name(int ac
, char **av
)
393 struct mfi_ld_props props
;
398 warnx("name: volume and name required");
402 if (strlen(av
[2]) >= sizeof(props
.name
)) {
403 warnx("name: new name is too long");
407 fd
= mfi_open(mfi_unit
, O_RDWR
);
414 if (mfi_lookup_volume(fd
, av
[1], &target_id
) < 0) {
416 warn("Invalid volume: %s", av
[1]);
421 if (mfi_ld_get_props(fd
, target_id
, &props
) < 0) {
423 warn("Failed to fetch volume properties");
428 printf("mfi%u volume %s name changed from \"%s\" to \"%s\"\n", mfi_unit
,
429 mfi_volume_name(fd
, target_id
), props
.name
, av
[2]);
430 bzero(props
.name
, sizeof(props
.name
));
431 strcpy(props
.name
, av
[2]);
432 if (mfi_ld_set_props(fd
, &props
) < 0) {
434 warn("Failed to set volume properties");
443 MFI_COMMAND(top
, name
, volume_name
);
446 volume_progress(int ac
, char **av
)
448 struct mfi_ld_info info
;
453 warnx("volume progress: %s", ac
> 2 ? "extra arguments" :
458 fd
= mfi_open(mfi_unit
, O_RDONLY
);
465 if (mfi_lookup_volume(fd
, av
[1], &target_id
) < 0) {
467 warn("Invalid volume: %s", av
[1]);
472 /* Get the info for this drive. */
473 if (mfi_ld_get_info(fd
, target_id
, &info
, NULL
) < 0) {
475 warn("Failed to fetch info for volume %s",
476 mfi_volume_name(fd
, target_id
));
481 /* Display any of the active events. */
482 if (info
.progress
.active
& MFI_LD_PROGRESS_CC
)
483 mfi_display_progress("Consistency Check", &info
.progress
.cc
);
484 if (info
.progress
.active
& MFI_LD_PROGRESS_BGI
)
485 mfi_display_progress("Background Init", &info
.progress
.bgi
);
486 if (info
.progress
.active
& MFI_LD_PROGRESS_FGI
)
487 mfi_display_progress("Foreground Init", &info
.progress
.fgi
);
488 if (info
.progress
.active
& MFI_LD_PROGRESS_RECON
)
489 mfi_display_progress("Reconstruction", &info
.progress
.recon
);
490 if ((info
.progress
.active
& (MFI_LD_PROGRESS_CC
| MFI_LD_PROGRESS_BGI
|
491 MFI_LD_PROGRESS_FGI
| MFI_LD_PROGRESS_RECON
)) == 0)
492 printf("No activity in progress for volume %s.\n",
493 mfi_volume_name(fd
, target_id
));
498 MFI_COMMAND(volume
, progress
, volume_progress
);