]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mfiutil/mfi_volume.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / 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);