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