]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/mfiutil/mfi_volume.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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(
367         "Cache disabled due to dead battery or ongoing battery relearn\n");
368                 error = 0;
369         } else {
370                 new = props;
371                 av += 2;
372                 ac -= 2;
373                 while (ac > 0) {
374                         consumed = process_cache_command(ac, av, &new);
375                         if (consumed < 0) {
376                                 close(fd);
377                                 return (EINVAL);
378                         }
379                         av += consumed;
380                         ac -= consumed;
381                 }
382                 error = update_cache_policy(fd, &props, &new);
383         }
384         close(fd);
385
386         return (error);
387 }
388 MFI_COMMAND(top, cache, volume_cache);
389
390 static int
391 volume_name(int ac, char **av)
392 {
393         struct mfi_ld_props props;
394         int error, fd;
395         uint8_t target_id;
396
397         if (ac != 3) {
398                 warnx("name: volume and name required");
399                 return (EINVAL);
400         }
401
402         if (strlen(av[2]) >= sizeof(props.name)) {
403                 warnx("name: new name is too long");
404                 return (ENOSPC);
405         }
406
407         fd = mfi_open(mfi_unit, O_RDWR);
408         if (fd < 0) {
409                 error = errno;
410                 warn("mfi_open");
411                 return (error);
412         }
413
414         if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
415                 error = errno;
416                 warn("Invalid volume: %s", av[1]);
417                 close(fd);
418                 return (error);
419         }
420
421         if (mfi_ld_get_props(fd, target_id, &props) < 0) {
422                 error = errno;
423                 warn("Failed to fetch volume properties");
424                 close(fd);
425                 return (error);
426         }
427
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) {
433                 error = errno;
434                 warn("Failed to set volume properties");
435                 close(fd);
436                 return (error);
437         }
438
439         close(fd);
440
441         return (0);
442 }
443 MFI_COMMAND(top, name, volume_name);
444
445 static int
446 volume_progress(int ac, char **av)
447 {
448         struct mfi_ld_info info;
449         int error, fd;
450         uint8_t target_id;
451
452         if (ac != 2) {
453                 warnx("volume progress: %s", ac > 2 ? "extra arguments" :
454                     "volume required");
455                 return (EINVAL);
456         }
457
458         fd = mfi_open(mfi_unit, O_RDONLY);
459         if (fd < 0) {
460                 error = errno;
461                 warn("mfi_open");
462                 return (error);
463         }
464
465         if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
466                 error = errno;
467                 warn("Invalid volume: %s", av[1]);
468                 close(fd);
469                 return (error);
470         }
471
472         /* Get the info for this drive. */
473         if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
474                 error = errno;
475                 warn("Failed to fetch info for volume %s",
476                     mfi_volume_name(fd, target_id));
477                 close(fd);
478                 return (error);
479         }
480
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));
494         close(fd);
495
496         return (0);
497 }
498 MFI_COMMAND(volume, progress, volume_progress);