Super User's BSD Cross Reference: /FreeBSD/usr.sbin/mfiutil/mfi_volume.c

1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2008, 2009 Yahoo!, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
17 * permission.
18 *
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
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD$
32 */
33
34#include <sys/types.h>
35#include <sys/errno.h>
36#include <err.h>
37#include <fcntl.h>
38#include <libutil.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43#include "mfiutil.h"
44
45 MFI_TABLE(top, volume);
46
47 const char *
48 mfi_ldstate(enum mfi_ld_state state)
49{
50 static char buf[16];
51
52 switch (state) {
53 case MFI_LD_STATE_OFFLINE:
54 return ("OFFLINE");
55 case MFI_LD_STATE_PARTIALLY_DEGRADED:
56 return ("PARTIALLY DEGRADED");
57 case MFI_LD_STATE_DEGRADED:
58 return ("DEGRADED");
59 case MFI_LD_STATE_OPTIMAL:
60 return ("OPTIMAL");
61 default:
62 sprintf(buf, "LSTATE 0x%02x", state);
63 return (buf);
64 }
65}
66
67 void
68 mbox_store_ldref(uint8_t *mbox, union mfi_ld_ref *ref)
69{
70
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;
75}
76
77 int
78 mfi_ld_get_list(int fd, struct mfi_ld_list *list, uint8_t *statusp)
79{
80
81 return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_LIST, list,
82 sizeof(struct mfi_ld_list), NULL, 0, statusp));
83}
84
85 int
86 mfi_ld_get_info(int fd, uint8_t target_id, struct mfi_ld_info *info,
87 uint8_t *statusp)
88{
89 uint8_t mbox[1];
90
91 mbox[0] = target_id;
92 return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_INFO, info,
93 sizeof(struct mfi_ld_info), mbox, 1, statusp));
94}
95
96 static int
97 mfi_ld_get_props(int fd, uint8_t target_id, struct mfi_ld_props *props)
98{
99 uint8_t mbox[1];
100
101 mbox[0] = target_id;
102 return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_PROP, props,
103 sizeof(struct mfi_ld_props), mbox, 1, NULL));
104}
105
106 static int
107 mfi_ld_set_props(int fd, struct mfi_ld_props *props)
108{
109 uint8_t mbox[4];
110
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));
114}
115
116 static int
117 update_cache_policy(int fd, struct mfi_ld_props *old, struct mfi_ld_props *new)
118{
119 int error;
120 uint8_t changes, policy;
121
122 if (old->default_cache_policy == new->default_cache_policy &&
123 old->disk_cache_policy == new->disk_cache_policy)
124 return (0);
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" :
130 "Disabling");
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" :
134 "Disabling");
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" :
138 "write-through");
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" :
147 "Disabling");
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");
152 break;
153 case MR_PD_CACHE_DISABLE:
154 printf("Disabling write-cache on physical drives\n");
155 break;
156 case MR_PD_CACHE_UNCHANGED:
157 printf("Using default write-cache setting on physical drives\n");
158 break;
159 }
160 }
161
162 if (mfi_ld_set_props(fd, new) < 0) {
163 error = errno;
164 warn("Failed to set volume properties");
165 return (error);
166 }
167 return (0);
168}
169
170 static void
171 stage_cache_setting(struct mfi_ld_props *props, uint8_t new_policy,
172 uint8_t mask)
173{
174
175 props->default_cache_policy &= ~mask;
176 props->default_cache_policy |= new_policy;
177}
178
179 /*
180 * Parse a single cache directive modifying the passed in policy.
181 * Returns -1 on a parse error and the number of arguments consumed
182 * on success.
183 */
184 static int
185 process_cache_command(int ac, char **av, struct mfi_ld_props *props)
186{
187 uint8_t policy;
188
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);
195 return (1);
196 }
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);
200 return (1);
201 }
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);
206 return (1);
207 }
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);
212 return (1);
213 }
214
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);
219 return (1);
220 }
221 if (strcmp(av[0], "write-through") == 0) {
222 stage_cache_setting(props, 0, MR_LD_CACHE_WRITE_BACK);
223 return (1);
224 }
225 if (strcmp(av[0], "bad-bbu-write-cache") == 0) {
226 if (ac < 2) {
227 warnx("cache: bad BBU setting required");
228 return (-1);
229 }
230 if (strcmp(av[1], "enable") == 0)
231 policy = MR_LD_CACHE_WRITE_CACHE_BAD_BBU;
232 else if (strcmp(av[1], "disable") == 0)
233 policy = 0;
234 else {
235 warnx("cache: invalid bad BBU setting");
236 return (-1);
237 }
238 stage_cache_setting(props, policy,
239 MR_LD_CACHE_WRITE_CACHE_BAD_BBU);
240 return (2);
241 }
242
243 /* Read cache behavior. */
244 if (strcmp(av[0], "read-ahead") == 0) {
245 if (ac < 2) {
246 warnx("cache: read-ahead setting required");
247 return (-1);
248 }
249 if (strcmp(av[1], "none") == 0)
250 policy = 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;
256 else {
257 warnx("cache: invalid read-ahead setting");
258 return (-1);
259 }
260 stage_cache_setting(props, policy, MR_LD_CACHE_READ_AHEAD |
261 MR_LD_CACHE_READ_ADAPTIVE);
262 return (2);
263 }
264
265 /* Drive write-cache behavior. */
266 if (strcmp(av[0], "write-cache") == 0) {
267 if (ac < 2) {
268 warnx("cache: write-cache setting required");
269 return (-1);
270 }
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;
277 else {
278 warnx("cache: invalid write-cache setting");
279 return (-1);
280 }
281 return (2);
282 }
283
284 warnx("cache: Invalid command");
285 return (-1);
286}
287
288 static int
289 volume_cache(int ac, char **av)
290{
291 struct mfi_ld_props props, new;
292 int error, fd, consumed;
293 uint8_t target_id;
294
295 if (ac < 2) {
296 warnx("cache: volume required");
297 return (EINVAL);
298 }
299
300 fd = mfi_open(mfi_unit, O_RDWR);
301 if (fd < 0) {
302 error = errno;
303 warn("mfi_open");
304 return (error);
305 }
306
307 if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
308 error = errno;
309 warn("Invalid volume: %s", av[1]);
310 close(fd);
311 return (error);
312 }
313
314 if (mfi_ld_get_props(fd, target_id, &props) < 0) {
315 error = errno;
316 warn("Failed to fetch volume properties");
317 close(fd);
318 return (error);
319 }
320
321 if (ac == 2) {
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)) {
328 case 0:
329 printf("disabled\n");
330 break;
331 case MR_LD_CACHE_ALLOW_WRITE_CACHE:
332 printf("writes\n");
333 break;
334 case MR_LD_CACHE_ALLOW_READ_CACHE:
335 printf("reads\n");
336 break;
337 case MR_LD_CACHE_ALLOW_WRITE_CACHE |
338 MR_LD_CACHE_ALLOW_READ_CACHE:
339 printf("writes and reads\n");
340 break;
341 }
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:
355 printf("default\n");
356 break;
357 case MR_PD_CACHE_ENABLE:
358 printf("enabled\n");
359 break;
360 case MR_PD_CACHE_DISABLE:
361 printf("disabled\n");
362 break;
363 default:
364 printf("??? %d\n", props.disk_cache_policy);
365 break;
366 }
367 if (props.default_cache_policy != props.current_cache_policy)
368 printf(
369 "Cache disabled due to dead battery or ongoing battery relearn\n");
370 error = 0;
371 } else {
372 new = props;
373 av += 2;
374 ac -= 2;
375 while (ac > 0) {
376 consumed = process_cache_command(ac, av, &new);
377 if (consumed < 0) {
378 close(fd);
379 return (EINVAL);
380 }
381 av += consumed;
382 ac -= consumed;
383 }
384 error = update_cache_policy(fd, &props, &new);
385 }
386 close(fd);
387
388 return (error);
389}
390 MFI_COMMAND(top, cache, volume_cache);
391
392 static int
393 volume_name(int ac, char **av)
394{
395 struct mfi_ld_props props;
396 int error, fd;
397 uint8_t target_id;
398
399 if (ac != 3) {
400 warnx("name: volume and name required");
401 return (EINVAL);
402 }
403
404 if (strlen(av[2]) >= sizeof(props.name)) {
405 warnx("name: new name is too long");
406 return (ENOSPC);
407 }
408
409 fd = mfi_open(mfi_unit, O_RDWR);
410 if (fd < 0) {
411 error = errno;
412 warn("mfi_open");
413 return (error);
414 }
415
416 if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
417 error = errno;
418 warn("Invalid volume: %s", av[1]);
419 close(fd);
420 return (error);
421 }
422
423 if (mfi_ld_get_props(fd, target_id, &props) < 0) {
424 error = errno;
425 warn("Failed to fetch volume properties");
426 close(fd);
427 return (error);
428 }
429
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) {
435 error = errno;
436 warn("Failed to set volume properties");
437 close(fd);
438 return (error);
439 }
440
441 close(fd);
442
443 return (0);
444}
445 MFI_COMMAND(top, name, volume_name);
446
447 static int
448 volume_progress(int ac, char **av)
449{
450 struct mfi_ld_info info;
451 int error, fd;
452 uint8_t target_id;
453
454 if (ac != 2) {
455 warnx("volume progress: %s", ac > 2 ? "extra arguments" :
456 "volume required");
457 return (EINVAL);
458 }
459
460 fd = mfi_open(mfi_unit, O_RDONLY);
461 if (fd < 0) {
462 error = errno;
463 warn("mfi_open");
464 return (error);
465 }
466
467 if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
468 error = errno;
469 warn("Invalid volume: %s", av[1]);
470 close(fd);
471 return (error);
472 }
473
474 /* Get the info for this drive. */
475 if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
476 error = errno;
477 warn("Failed to fetch info for volume %s",
478 mfi_volume_name(fd, target_id));
479 close(fd);
480 return (error);
481 }
482
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));
496 close(fd);
497
498 return (0);
499}
500 MFI_COMMAND(volume, progress, volume_progress);
501 

AltStyle によって変換されたページ (->オリジナル) /