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_volume.c,v 1.5 2011/09/02 16:00:51 jhb Exp $
32 #include <sys/types.h>
33 #include <sys/errno.h>
42 MFI_TABLE(top
, volume
);
45 mfi_ldstate(enum mfi_ld_state state
)
50 case MFI_LD_STATE_OFFLINE
:
52 case MFI_LD_STATE_PARTIALLY_DEGRADED
:
53 return ("PARTIALLY DEGRADED");
54 case MFI_LD_STATE_DEGRADED
:
56 case MFI_LD_STATE_OPTIMAL
:
59 sprintf(buf
, "LSTATE 0x%02x", state
);
65 mbox_store_ldref(uint8_t *mbox
, union mfi_ld_ref
*ref
)
68 mbox
[0] = ref
->v
.target_id
;
69 mbox
[1] = ref
->v
.reserved
;
70 mbox
[2] = ref
->v
.seq
& 0xff;
71 mbox
[3] = ref
->v
.seq
>> 8;
75 mfi_ld_get_list(int fd
, struct mfi_ld_list
*list
, uint8_t *statusp
)
78 return (mfi_dcmd_command(fd
, MFI_DCMD_LD_GET_LIST
, list
,
79 sizeof(struct mfi_ld_list
), NULL
, 0, statusp
));
83 mfi_ld_get_info(int fd
, uint8_t target_id
, struct mfi_ld_info
*info
,
89 return (mfi_dcmd_command(fd
, MFI_DCMD_LD_GET_INFO
, info
,
90 sizeof(struct mfi_ld_info
), mbox
, 1, statusp
));
94 mfi_ld_get_props(int fd
, uint8_t target_id
, struct mfi_ld_props
*props
)
99 return (mfi_dcmd_command(fd
, MFI_DCMD_LD_GET_PROP
, props
,
100 sizeof(struct mfi_ld_props
), mbox
, 1, NULL
));
104 mfi_ld_set_props(int fd
, struct mfi_ld_props
*props
)
108 mbox_store_ldref(mbox
, &props
->ld
);
109 return (mfi_dcmd_command(fd
, MFI_DCMD_LD_SET_PROP
, props
,
110 sizeof(struct mfi_ld_props
), mbox
, 4, NULL
));
114 update_cache_policy(int fd
, struct mfi_ld_props
*old
, struct mfi_ld_props
*new)
117 uint8_t changes
, policy
;
119 if (old
->default_cache_policy
== new->default_cache_policy
&&
120 old
->disk_cache_policy
== new->disk_cache_policy
)
122 policy
= new->default_cache_policy
;
123 changes
= policy
^ old
->default_cache_policy
;
124 if (changes
& MR_LD_CACHE_ALLOW_WRITE_CACHE
)
125 printf("%s caching of I/O writes\n",
126 policy
& MR_LD_CACHE_ALLOW_WRITE_CACHE
? "Enabling" :
128 if (changes
& MR_LD_CACHE_ALLOW_READ_CACHE
)
129 printf("%s caching of I/O reads\n",
130 policy
& MR_LD_CACHE_ALLOW_READ_CACHE
? "Enabling" :
132 if (changes
& MR_LD_CACHE_WRITE_BACK
)
133 printf("Setting write cache policy to %s\n",
134 policy
& MR_LD_CACHE_WRITE_BACK
? "write-back" :
136 if (changes
& (MR_LD_CACHE_READ_AHEAD
| MR_LD_CACHE_READ_ADAPTIVE
))
137 printf("Setting read ahead policy to %s\n",
138 policy
& MR_LD_CACHE_READ_AHEAD
?
139 (policy
& MR_LD_CACHE_READ_ADAPTIVE
?
140 "adaptive" : "always") : "none");
141 if (changes
& MR_LD_CACHE_WRITE_CACHE_BAD_BBU
)
142 printf("%s write caching with bad BBU\n",
143 policy
& MR_LD_CACHE_WRITE_CACHE_BAD_BBU
? "Enabling" :
145 if (old
->disk_cache_policy
!= new->disk_cache_policy
) {
146 switch (new->disk_cache_policy
) {
147 case MR_PD_CACHE_ENABLE
:
148 printf("Enabling write-cache on physical drives\n");
150 case MR_PD_CACHE_DISABLE
:
151 printf("Disabling write-cache on physical drives\n");
153 case MR_PD_CACHE_UNCHANGED
:
154 printf("Using default write-cache setting on physical drives\n");
159 if (mfi_ld_set_props(fd
, new) < 0) {
161 warn("Failed to set volume properties");
168 stage_cache_setting(struct mfi_ld_props
*props
, uint8_t new_policy
,
172 props
->default_cache_policy
&= ~mask
;
173 props
->default_cache_policy
|= new_policy
;
177 * Parse a single cache directive modifying the passed in policy.
178 * Returns -1 on a parse error and the number of arguments consumed
182 process_cache_command(int ac
, char **av
, struct mfi_ld_props
*props
)
186 /* I/O cache settings. */
187 if (strcmp(av
[0], "all") == 0 || strcmp(av
[0], "enable") == 0) {
188 stage_cache_setting(props
, MR_LD_CACHE_ALLOW_READ_CACHE
|
189 MR_LD_CACHE_ALLOW_WRITE_CACHE
,
190 MR_LD_CACHE_ALLOW_READ_CACHE
|
191 MR_LD_CACHE_ALLOW_WRITE_CACHE
);
194 if (strcmp(av
[0], "none") == 0 || strcmp(av
[0], "disable") == 0) {
195 stage_cache_setting(props
, 0, MR_LD_CACHE_ALLOW_READ_CACHE
|
196 MR_LD_CACHE_ALLOW_WRITE_CACHE
);
199 if (strcmp(av
[0], "reads") == 0) {
200 stage_cache_setting(props
, MR_LD_CACHE_ALLOW_READ_CACHE
,
201 MR_LD_CACHE_ALLOW_READ_CACHE
|
202 MR_LD_CACHE_ALLOW_WRITE_CACHE
);
205 if (strcmp(av
[0], "writes") == 0) {
206 stage_cache_setting(props
, MR_LD_CACHE_ALLOW_WRITE_CACHE
,
207 MR_LD_CACHE_ALLOW_READ_CACHE
|
208 MR_LD_CACHE_ALLOW_WRITE_CACHE
);
212 /* Write cache behavior. */
213 if (strcmp(av
[0], "write-back") == 0) {
214 stage_cache_setting(props
, MR_LD_CACHE_WRITE_BACK
,
215 MR_LD_CACHE_WRITE_BACK
);
218 if (strcmp(av
[0], "write-through") == 0) {
219 stage_cache_setting(props
, 0, MR_LD_CACHE_WRITE_BACK
);
222 if (strcmp(av
[0], "bad-bbu-write-cache") == 0) {
224 warnx("cache: bad BBU setting required");
227 if (strcmp(av
[1], "enable") == 0)
228 policy
= MR_LD_CACHE_WRITE_CACHE_BAD_BBU
;
229 else if (strcmp(av
[1], "disable") == 0)
232 warnx("cache: invalid bad BBU setting");
235 stage_cache_setting(props
, policy
,
236 MR_LD_CACHE_WRITE_CACHE_BAD_BBU
);
240 /* Read cache behavior. */
241 if (strcmp(av
[0], "read-ahead") == 0) {
243 warnx("cache: read-ahead setting required");
246 if (strcmp(av
[1], "none") == 0)
248 else if (strcmp(av
[1], "always") == 0)
249 policy
= MR_LD_CACHE_READ_AHEAD
;
250 else if (strcmp(av
[1], "adaptive") == 0)
251 policy
= MR_LD_CACHE_READ_AHEAD
|
252 MR_LD_CACHE_READ_ADAPTIVE
;
254 warnx("cache: invalid read-ahead setting");
257 stage_cache_setting(props
, policy
, MR_LD_CACHE_READ_AHEAD
|
258 MR_LD_CACHE_READ_ADAPTIVE
);
262 /* Drive write-cache behavior. */
263 if (strcmp(av
[0], "write-cache") == 0) {
265 warnx("cache: write-cache setting required");
268 if (strcmp(av
[1], "enable") == 0)
269 props
->disk_cache_policy
= MR_PD_CACHE_ENABLE
;
270 else if (strcmp(av
[1], "disable") == 0)
271 props
->disk_cache_policy
= MR_PD_CACHE_DISABLE
;
272 else if (strcmp(av
[1], "default") == 0)
273 props
->disk_cache_policy
= MR_PD_CACHE_UNCHANGED
;
275 warnx("cache: invalid write-cache setting");
281 warnx("cache: Invalid command");
286 volume_cache(int ac
, char **av
)
288 struct mfi_ld_props props
, new;
289 int error
, fd
, consumed
;
293 warnx("cache: volume required");
297 fd
= mfi_open(mfi_unit
);
304 if (mfi_lookup_volume(fd
, av
[1], &target_id
) < 0) {
306 warn("Invalid volume: %s", av
[1]);
311 if (mfi_ld_get_props(fd
, target_id
, &props
) < 0) {
313 warn("Failed to fetch volume properties");
319 printf("mfi%u volume %s cache settings:\n", mfi_unit
,
320 mfi_volume_name(fd
, target_id
));
321 printf(" I/O caching: ");
322 switch (props
.default_cache_policy
&
323 (MR_LD_CACHE_ALLOW_WRITE_CACHE
|
324 MR_LD_CACHE_ALLOW_READ_CACHE
)) {
326 printf("disabled\n");
328 case MR_LD_CACHE_ALLOW_WRITE_CACHE
:
331 case MR_LD_CACHE_ALLOW_READ_CACHE
:
334 case MR_LD_CACHE_ALLOW_WRITE_CACHE
|
335 MR_LD_CACHE_ALLOW_READ_CACHE
:
336 printf("writes and reads\n");
339 printf(" write caching: %s\n",
340 props
.default_cache_policy
& MR_LD_CACHE_WRITE_BACK
?
341 "write-back" : "write-through");
342 printf("write cache with bad BBU: %s\n",
343 props
.default_cache_policy
&
344 MR_LD_CACHE_WRITE_CACHE_BAD_BBU
? "enabled" : "disabled");
345 printf(" read ahead: %s\n",
346 props
.default_cache_policy
& MR_LD_CACHE_READ_AHEAD
?
347 (props
.default_cache_policy
& MR_LD_CACHE_READ_ADAPTIVE
?
348 "adaptive" : "always") : "none");
349 printf(" drive write cache: ");
350 switch (props
.disk_cache_policy
) {
351 case MR_PD_CACHE_UNCHANGED
:
354 case MR_PD_CACHE_ENABLE
:
357 case MR_PD_CACHE_DISABLE
:
358 printf("disabled\n");
361 printf("??? %d\n", props
.disk_cache_policy
);
364 if (props
.default_cache_policy
!= props
.current_cache_policy
)
365 printf("Cache Disabled Due to Dead Battery\n");
372 consumed
= process_cache_command(ac
, av
, &new);
380 error
= update_cache_policy(fd
, &props
, &new);
386 MFI_COMMAND(top
, cache
, volume_cache
);
389 volume_name(int ac
, char **av
)
391 struct mfi_ld_props props
;
396 warnx("name: volume and name required");
400 if (strlen(av
[2]) >= sizeof(props
.name
)) {
401 warnx("name: new name is too long");
405 fd
= mfi_open(mfi_unit
);
412 if (mfi_lookup_volume(fd
, av
[1], &target_id
) < 0) {
414 warn("Invalid volume: %s", av
[1]);
419 if (mfi_ld_get_props(fd
, target_id
, &props
) < 0) {
421 warn("Failed to fetch volume properties");
426 printf("mfi%u volume %s name changed from \"%s\" to \"%s\"\n", mfi_unit
,
427 mfi_volume_name(fd
, target_id
), props
.name
, av
[2]);
428 bzero(props
.name
, sizeof(props
.name
));
429 strcpy(props
.name
, av
[2]);
430 if (mfi_ld_set_props(fd
, &props
) < 0) {
432 warn("Failed to set volume properties");
441 MFI_COMMAND(top
, name
, volume_name
);
444 volume_progress(int ac
, char **av
)
446 struct mfi_ld_info info
;
451 warnx("volume progress: %s", ac
> 2 ? "extra arguments" :
456 fd
= mfi_open(mfi_unit
);
463 if (mfi_lookup_volume(fd
, av
[1], &target_id
) < 0) {
465 warn("Invalid volume: %s", av
[1]);
470 /* Get the info for this drive. */
471 if (mfi_ld_get_info(fd
, target_id
, &info
, NULL
) < 0) {
473 warn("Failed to fetch info for volume %s",
474 mfi_volume_name(fd
, target_id
));
479 /* Display any of the active events. */
480 if (info
.progress
.active
& MFI_LD_PROGRESS_CC
)
481 mfi_display_progress("Consistency Check", &info
.progress
.cc
);
482 if (info
.progress
.active
& MFI_LD_PROGRESS_BGI
)
483 mfi_display_progress("Background Init", &info
.progress
.bgi
);
484 if (info
.progress
.active
& MFI_LD_PROGRESS_FGI
)
485 mfi_display_progress("Foreground Init", &info
.progress
.fgi
);
486 if (info
.progress
.active
& MFI_LD_PROGRESS_RECON
)
487 mfi_display_progress("Reconstruction", &info
.progress
.recon
);
488 if ((info
.progress
.active
& (MFI_LD_PROGRESS_CC
| MFI_LD_PROGRESS_BGI
|
489 MFI_LD_PROGRESS_FGI
| MFI_LD_PROGRESS_RECON
)) == 0)
490 printf("No activity in progress for volume %s.\n",
491 mfi_volume_name(fd
, target_id
));
496 MFI_COMMAND(volume
, progress
, volume_progress
);