xref: /dragonfly/usr.sbin/mfiutil/mfi_volume.c (revision f0d8b1f2)
1249d29c8SSascha Wildner /*-
2249d29c8SSascha Wildner  * Copyright (c) 2008, 2009 Yahoo!, Inc.
3249d29c8SSascha Wildner  * All rights reserved.
4249d29c8SSascha Wildner  *
5249d29c8SSascha Wildner  * Redistribution and use in source and binary forms, with or without
6249d29c8SSascha Wildner  * modification, are permitted provided that the following conditions
7249d29c8SSascha Wildner  * are met:
8249d29c8SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9249d29c8SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10249d29c8SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11249d29c8SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12249d29c8SSascha Wildner  *    documentation and/or other materials provided with the distribution.
13249d29c8SSascha Wildner  * 3. The names of the authors may not be used to endorse or promote
14249d29c8SSascha Wildner  *    products derived from this software without specific prior written
15249d29c8SSascha Wildner  *    permission.
16249d29c8SSascha Wildner  *
17249d29c8SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18249d29c8SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19249d29c8SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20249d29c8SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21249d29c8SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22249d29c8SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23249d29c8SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24249d29c8SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25249d29c8SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26249d29c8SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27249d29c8SSascha Wildner  * SUCH DAMAGE.
28249d29c8SSascha Wildner  *
29*f0d8b1f2SSascha Wildner  * $FreeBSD: src/usr.sbin/mfiutil/mfi_volume.c,v 1.5 2011/09/02 16:00:51 jhb Exp $
30249d29c8SSascha Wildner  */
31249d29c8SSascha Wildner 
32249d29c8SSascha Wildner #include <sys/types.h>
33249d29c8SSascha Wildner #include <sys/errno.h>
34249d29c8SSascha Wildner #include <err.h>
35249d29c8SSascha Wildner #include <libutil.h>
36249d29c8SSascha Wildner #include <stdio.h>
37249d29c8SSascha Wildner #include <stdlib.h>
38249d29c8SSascha Wildner #include <string.h>
39249d29c8SSascha Wildner #include <unistd.h>
40249d29c8SSascha Wildner #include "mfiutil.h"
41249d29c8SSascha Wildner 
42249d29c8SSascha Wildner MFI_TABLE(top, volume);
43249d29c8SSascha Wildner 
44249d29c8SSascha Wildner const char *
mfi_ldstate(enum mfi_ld_state state)45249d29c8SSascha Wildner mfi_ldstate(enum mfi_ld_state state)
46249d29c8SSascha Wildner {
47249d29c8SSascha Wildner 	static char buf[16];
48249d29c8SSascha Wildner 
49249d29c8SSascha Wildner 	switch (state) {
50249d29c8SSascha Wildner 	case MFI_LD_STATE_OFFLINE:
51249d29c8SSascha Wildner 		return ("OFFLINE");
52249d29c8SSascha Wildner 	case MFI_LD_STATE_PARTIALLY_DEGRADED:
53249d29c8SSascha Wildner 		return ("PARTIALLY DEGRADED");
54249d29c8SSascha Wildner 	case MFI_LD_STATE_DEGRADED:
55249d29c8SSascha Wildner 		return ("DEGRADED");
56249d29c8SSascha Wildner 	case MFI_LD_STATE_OPTIMAL:
57249d29c8SSascha Wildner 		return ("OPTIMAL");
58249d29c8SSascha Wildner 	default:
59249d29c8SSascha Wildner 		sprintf(buf, "LSTATE 0x%02x", state);
60249d29c8SSascha Wildner 		return (buf);
61249d29c8SSascha Wildner 	}
62249d29c8SSascha Wildner }
63249d29c8SSascha Wildner 
64249d29c8SSascha Wildner void
mbox_store_ldref(uint8_t * mbox,union mfi_ld_ref * ref)65249d29c8SSascha Wildner mbox_store_ldref(uint8_t *mbox, union mfi_ld_ref *ref)
66249d29c8SSascha Wildner {
67249d29c8SSascha Wildner 
68249d29c8SSascha Wildner 	mbox[0] = ref->v.target_id;
69249d29c8SSascha Wildner 	mbox[1] = ref->v.reserved;
70249d29c8SSascha Wildner 	mbox[2] = ref->v.seq & 0xff;
71249d29c8SSascha Wildner 	mbox[3] = ref->v.seq >> 8;
72249d29c8SSascha Wildner }
73249d29c8SSascha Wildner 
74249d29c8SSascha Wildner int
mfi_ld_get_list(int fd,struct mfi_ld_list * list,uint8_t * statusp)75249d29c8SSascha Wildner mfi_ld_get_list(int fd, struct mfi_ld_list *list, uint8_t *statusp)
76249d29c8SSascha Wildner {
77249d29c8SSascha Wildner 
78249d29c8SSascha Wildner 	return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_LIST, list,
79249d29c8SSascha Wildner 		sizeof(struct mfi_ld_list), NULL, 0, statusp));
80249d29c8SSascha Wildner }
81249d29c8SSascha Wildner 
82249d29c8SSascha Wildner int
mfi_ld_get_info(int fd,uint8_t target_id,struct mfi_ld_info * info,uint8_t * statusp)83249d29c8SSascha Wildner mfi_ld_get_info(int fd, uint8_t target_id, struct mfi_ld_info *info,
84249d29c8SSascha Wildner     uint8_t *statusp)
85249d29c8SSascha Wildner {
86249d29c8SSascha Wildner 	uint8_t mbox[1];
87249d29c8SSascha Wildner 
88249d29c8SSascha Wildner 	mbox[0] = target_id;
89249d29c8SSascha Wildner 	return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_INFO, info,
90249d29c8SSascha Wildner 	    sizeof(struct mfi_ld_info), mbox, 1, statusp));
91249d29c8SSascha Wildner }
92249d29c8SSascha Wildner 
93249d29c8SSascha Wildner static int
mfi_ld_get_props(int fd,uint8_t target_id,struct mfi_ld_props * props)94249d29c8SSascha Wildner mfi_ld_get_props(int fd, uint8_t target_id, struct mfi_ld_props *props)
95249d29c8SSascha Wildner {
96249d29c8SSascha Wildner 	uint8_t mbox[1];
97249d29c8SSascha Wildner 
98249d29c8SSascha Wildner 	mbox[0] = target_id;
99249d29c8SSascha Wildner 	return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_PROP, props,
100249d29c8SSascha Wildner 	    sizeof(struct mfi_ld_props), mbox, 1, NULL));
101249d29c8SSascha Wildner }
102249d29c8SSascha Wildner 
103249d29c8SSascha Wildner static int
mfi_ld_set_props(int fd,struct mfi_ld_props * props)104249d29c8SSascha Wildner mfi_ld_set_props(int fd, struct mfi_ld_props *props)
105249d29c8SSascha Wildner {
106249d29c8SSascha Wildner 	uint8_t mbox[4];
107249d29c8SSascha Wildner 
108249d29c8SSascha Wildner 	mbox_store_ldref(mbox, &props->ld);
109249d29c8SSascha Wildner 	return (mfi_dcmd_command(fd, MFI_DCMD_LD_SET_PROP, props,
110249d29c8SSascha Wildner 	    sizeof(struct mfi_ld_props), mbox, 4, NULL));
111249d29c8SSascha Wildner }
112249d29c8SSascha Wildner 
113249d29c8SSascha Wildner static int
update_cache_policy(int fd,struct mfi_ld_props * old,struct mfi_ld_props * new)114*f0d8b1f2SSascha Wildner update_cache_policy(int fd, struct mfi_ld_props *old, struct mfi_ld_props *new)
115249d29c8SSascha Wildner {
116249d29c8SSascha Wildner 	int error;
117249d29c8SSascha Wildner 	uint8_t changes, policy;
118249d29c8SSascha Wildner 
119*f0d8b1f2SSascha Wildner 	if (old->default_cache_policy == new->default_cache_policy &&
120*f0d8b1f2SSascha Wildner 	    old->disk_cache_policy == new->disk_cache_policy)
121249d29c8SSascha Wildner 		return (0);
122*f0d8b1f2SSascha Wildner 	policy = new->default_cache_policy;
123*f0d8b1f2SSascha Wildner 	changes = policy ^ old->default_cache_policy;
124249d29c8SSascha Wildner 	if (changes & MR_LD_CACHE_ALLOW_WRITE_CACHE)
125249d29c8SSascha Wildner 		printf("%s caching of I/O writes\n",
126249d29c8SSascha Wildner 		    policy & MR_LD_CACHE_ALLOW_WRITE_CACHE ? "Enabling" :
127249d29c8SSascha Wildner 		    "Disabling");
128249d29c8SSascha Wildner 	if (changes & MR_LD_CACHE_ALLOW_READ_CACHE)
129249d29c8SSascha Wildner 		printf("%s caching of I/O reads\n",
130249d29c8SSascha Wildner 		    policy & MR_LD_CACHE_ALLOW_READ_CACHE ? "Enabling" :
131249d29c8SSascha Wildner 		    "Disabling");
132249d29c8SSascha Wildner 	if (changes & MR_LD_CACHE_WRITE_BACK)
133249d29c8SSascha Wildner 		printf("Setting write cache policy to %s\n",
134249d29c8SSascha Wildner 		    policy & MR_LD_CACHE_WRITE_BACK ? "write-back" :
135249d29c8SSascha Wildner 		    "write-through");
136249d29c8SSascha Wildner 	if (changes & (MR_LD_CACHE_READ_AHEAD | MR_LD_CACHE_READ_ADAPTIVE))
137249d29c8SSascha Wildner 		printf("Setting read ahead policy to %s\n",
138249d29c8SSascha Wildner 		    policy & MR_LD_CACHE_READ_AHEAD ?
139249d29c8SSascha Wildner 		    (policy & MR_LD_CACHE_READ_ADAPTIVE ?
140249d29c8SSascha Wildner 		    "adaptive" : "always") : "none");
141f26fa772SSascha Wildner 	if (changes & MR_LD_CACHE_WRITE_CACHE_BAD_BBU)
142f26fa772SSascha Wildner 		printf("%s write caching with bad BBU\n",
143f26fa772SSascha Wildner 		    policy & MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "Enabling" :
144f26fa772SSascha Wildner 		    "Disabling");
145*f0d8b1f2SSascha Wildner 	if (old->disk_cache_policy != new->disk_cache_policy) {
146*f0d8b1f2SSascha Wildner 		switch (new->disk_cache_policy) {
147*f0d8b1f2SSascha Wildner 		case MR_PD_CACHE_ENABLE:
148*f0d8b1f2SSascha Wildner 			printf("Enabling write-cache on physical drives\n");
149*f0d8b1f2SSascha Wildner 			break;
150*f0d8b1f2SSascha Wildner 		case MR_PD_CACHE_DISABLE:
151*f0d8b1f2SSascha Wildner 			printf("Disabling write-cache on physical drives\n");
152*f0d8b1f2SSascha Wildner 			break;
153*f0d8b1f2SSascha Wildner 		case MR_PD_CACHE_UNCHANGED:
154*f0d8b1f2SSascha Wildner 			printf("Using default write-cache setting on physical drives\n");
155*f0d8b1f2SSascha Wildner 			break;
156*f0d8b1f2SSascha Wildner 		}
157*f0d8b1f2SSascha Wildner 	}
158249d29c8SSascha Wildner 
159*f0d8b1f2SSascha Wildner 	if (mfi_ld_set_props(fd, new) < 0) {
160249d29c8SSascha Wildner 		error = errno;
161249d29c8SSascha Wildner 		warn("Failed to set volume properties");
162249d29c8SSascha Wildner 		return (error);
163249d29c8SSascha Wildner 	}
164249d29c8SSascha Wildner 	return (0);
165249d29c8SSascha Wildner }
166249d29c8SSascha Wildner 
167*f0d8b1f2SSascha Wildner static void
stage_cache_setting(struct mfi_ld_props * props,uint8_t new_policy,uint8_t mask)168*f0d8b1f2SSascha Wildner stage_cache_setting(struct mfi_ld_props *props, uint8_t new_policy,
169*f0d8b1f2SSascha Wildner     uint8_t mask)
170*f0d8b1f2SSascha Wildner {
171*f0d8b1f2SSascha Wildner 
172*f0d8b1f2SSascha Wildner 	props->default_cache_policy &= ~mask;
173*f0d8b1f2SSascha Wildner 	props->default_cache_policy |= new_policy;
174*f0d8b1f2SSascha Wildner }
175*f0d8b1f2SSascha Wildner 
176*f0d8b1f2SSascha Wildner /*
177*f0d8b1f2SSascha Wildner  * Parse a single cache directive modifying the passed in policy.
178*f0d8b1f2SSascha Wildner  * Returns -1 on a parse error and the number of arguments consumed
179*f0d8b1f2SSascha Wildner  * on success.
180*f0d8b1f2SSascha Wildner  */
181*f0d8b1f2SSascha Wildner static int
process_cache_command(int ac,char ** av,struct mfi_ld_props * props)182*f0d8b1f2SSascha Wildner process_cache_command(int ac, char **av, struct mfi_ld_props *props)
183*f0d8b1f2SSascha Wildner {
184*f0d8b1f2SSascha Wildner 	uint8_t policy;
185*f0d8b1f2SSascha Wildner 
186*f0d8b1f2SSascha Wildner 	/* I/O cache settings. */
187*f0d8b1f2SSascha Wildner 	if (strcmp(av[0], "all") == 0 || strcmp(av[0], "enable") == 0) {
188*f0d8b1f2SSascha Wildner 		stage_cache_setting(props, MR_LD_CACHE_ALLOW_READ_CACHE |
189*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_ALLOW_WRITE_CACHE,
190*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_ALLOW_READ_CACHE |
191*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_ALLOW_WRITE_CACHE);
192*f0d8b1f2SSascha Wildner 		return (1);
193*f0d8b1f2SSascha Wildner 	}
194*f0d8b1f2SSascha Wildner 	if (strcmp(av[0], "none") == 0 || strcmp(av[0], "disable") == 0) {
195*f0d8b1f2SSascha Wildner 		stage_cache_setting(props, 0, MR_LD_CACHE_ALLOW_READ_CACHE |
196*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_ALLOW_WRITE_CACHE);
197*f0d8b1f2SSascha Wildner 		return (1);
198*f0d8b1f2SSascha Wildner 	}
199*f0d8b1f2SSascha Wildner 	if (strcmp(av[0], "reads") == 0) {
200*f0d8b1f2SSascha Wildner 		stage_cache_setting(props, MR_LD_CACHE_ALLOW_READ_CACHE,
201*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_ALLOW_READ_CACHE |
202*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_ALLOW_WRITE_CACHE);
203*f0d8b1f2SSascha Wildner 		return (1);
204*f0d8b1f2SSascha Wildner 	}
205*f0d8b1f2SSascha Wildner 	if (strcmp(av[0], "writes") == 0) {
206*f0d8b1f2SSascha Wildner 		stage_cache_setting(props, MR_LD_CACHE_ALLOW_WRITE_CACHE,
207*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_ALLOW_READ_CACHE |
208*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_ALLOW_WRITE_CACHE);
209*f0d8b1f2SSascha Wildner 		return (1);
210*f0d8b1f2SSascha Wildner 	}
211*f0d8b1f2SSascha Wildner 
212*f0d8b1f2SSascha Wildner 	/* Write cache behavior. */
213*f0d8b1f2SSascha Wildner 	if (strcmp(av[0], "write-back") == 0) {
214*f0d8b1f2SSascha Wildner 		stage_cache_setting(props, MR_LD_CACHE_WRITE_BACK,
215*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_WRITE_BACK);
216*f0d8b1f2SSascha Wildner 		return (1);
217*f0d8b1f2SSascha Wildner 	}
218*f0d8b1f2SSascha Wildner 	if (strcmp(av[0], "write-through") == 0) {
219*f0d8b1f2SSascha Wildner 		stage_cache_setting(props, 0, MR_LD_CACHE_WRITE_BACK);
220*f0d8b1f2SSascha Wildner 		return (1);
221*f0d8b1f2SSascha Wildner 	}
222*f0d8b1f2SSascha Wildner 	if (strcmp(av[0], "bad-bbu-write-cache") == 0) {
223*f0d8b1f2SSascha Wildner 		if (ac < 2) {
224*f0d8b1f2SSascha Wildner 			warnx("cache: bad BBU setting required");
225*f0d8b1f2SSascha Wildner 			return (-1);
226*f0d8b1f2SSascha Wildner 		}
227*f0d8b1f2SSascha Wildner 		if (strcmp(av[1], "enable") == 0)
228*f0d8b1f2SSascha Wildner 			policy = MR_LD_CACHE_WRITE_CACHE_BAD_BBU;
229*f0d8b1f2SSascha Wildner 		else if (strcmp(av[1], "disable") == 0)
230*f0d8b1f2SSascha Wildner 			policy = 0;
231*f0d8b1f2SSascha Wildner 		else {
232*f0d8b1f2SSascha Wildner 			warnx("cache: invalid bad BBU setting");
233*f0d8b1f2SSascha Wildner 			return (-1);
234*f0d8b1f2SSascha Wildner 		}
235*f0d8b1f2SSascha Wildner 		stage_cache_setting(props, policy,
236*f0d8b1f2SSascha Wildner 		    MR_LD_CACHE_WRITE_CACHE_BAD_BBU);
237*f0d8b1f2SSascha Wildner 		return (2);
238*f0d8b1f2SSascha Wildner 	}
239*f0d8b1f2SSascha Wildner 
240*f0d8b1f2SSascha Wildner 	/* Read cache behavior. */
241*f0d8b1f2SSascha Wildner 	if (strcmp(av[0], "read-ahead") == 0) {
242*f0d8b1f2SSascha Wildner 		if (ac < 2) {
243*f0d8b1f2SSascha Wildner 			warnx("cache: read-ahead setting required");
244*f0d8b1f2SSascha Wildner 			return (-1);
245*f0d8b1f2SSascha Wildner 		}
246*f0d8b1f2SSascha Wildner 		if (strcmp(av[1], "none") == 0)
247*f0d8b1f2SSascha Wildner 			policy = 0;
248*f0d8b1f2SSascha Wildner 		else if (strcmp(av[1], "always") == 0)
249*f0d8b1f2SSascha Wildner 			policy = MR_LD_CACHE_READ_AHEAD;
250*f0d8b1f2SSascha Wildner 		else if (strcmp(av[1], "adaptive") == 0)
251*f0d8b1f2SSascha Wildner 			policy = MR_LD_CACHE_READ_AHEAD |
252*f0d8b1f2SSascha Wildner 			    MR_LD_CACHE_READ_ADAPTIVE;
253*f0d8b1f2SSascha Wildner 		else {
254*f0d8b1f2SSascha Wildner 			warnx("cache: invalid read-ahead setting");
255*f0d8b1f2SSascha Wildner 			return (-1);
256*f0d8b1f2SSascha Wildner 		}
257*f0d8b1f2SSascha Wildner 		stage_cache_setting(props, policy, MR_LD_CACHE_READ_AHEAD |
258*f0d8b1f2SSascha Wildner 			    MR_LD_CACHE_READ_ADAPTIVE);
259*f0d8b1f2SSascha Wildner 		return (2);
260*f0d8b1f2SSascha Wildner 	}
261*f0d8b1f2SSascha Wildner 
262*f0d8b1f2SSascha Wildner 	/* Drive write-cache behavior. */
263*f0d8b1f2SSascha Wildner 	if (strcmp(av[0], "write-cache") == 0) {
264*f0d8b1f2SSascha Wildner 		if (ac < 2) {
265*f0d8b1f2SSascha Wildner 			warnx("cache: write-cache setting required");
266*f0d8b1f2SSascha Wildner 			return (-1);
267*f0d8b1f2SSascha Wildner 		}
268*f0d8b1f2SSascha Wildner 		if (strcmp(av[1], "enable") == 0)
269*f0d8b1f2SSascha Wildner 			props->disk_cache_policy = MR_PD_CACHE_ENABLE;
270*f0d8b1f2SSascha Wildner 		else if (strcmp(av[1], "disable") == 0)
271*f0d8b1f2SSascha Wildner 			props->disk_cache_policy = MR_PD_CACHE_DISABLE;
272*f0d8b1f2SSascha Wildner 		else if (strcmp(av[1], "default") == 0)
273*f0d8b1f2SSascha Wildner 			props->disk_cache_policy = MR_PD_CACHE_UNCHANGED;
274*f0d8b1f2SSascha Wildner 		else {
275*f0d8b1f2SSascha Wildner 			warnx("cache: invalid write-cache setting");
276*f0d8b1f2SSascha Wildner 			return (-1);
277*f0d8b1f2SSascha Wildner 		}
278*f0d8b1f2SSascha Wildner 		return (2);
279*f0d8b1f2SSascha Wildner 	}
280*f0d8b1f2SSascha Wildner 
281*f0d8b1f2SSascha Wildner 	warnx("cache: Invalid command");
282*f0d8b1f2SSascha Wildner 	return (-1);
283*f0d8b1f2SSascha Wildner }
284*f0d8b1f2SSascha Wildner 
285249d29c8SSascha Wildner static int
volume_cache(int ac,char ** av)286249d29c8SSascha Wildner volume_cache(int ac, char **av)
287249d29c8SSascha Wildner {
288*f0d8b1f2SSascha Wildner 	struct mfi_ld_props props, new;
289*f0d8b1f2SSascha Wildner 	int error, fd, consumed;
290*f0d8b1f2SSascha Wildner 	uint8_t target_id;
291249d29c8SSascha Wildner 
292249d29c8SSascha Wildner 	if (ac < 2) {
293249d29c8SSascha Wildner 		warnx("cache: volume required");
294249d29c8SSascha Wildner 		return (EINVAL);
295249d29c8SSascha Wildner 	}
296249d29c8SSascha Wildner 
297249d29c8SSascha Wildner 	fd = mfi_open(mfi_unit);
298249d29c8SSascha Wildner 	if (fd < 0) {
299249d29c8SSascha Wildner 		error = errno;
300249d29c8SSascha Wildner 		warn("mfi_open");
301249d29c8SSascha Wildner 		return (error);
302249d29c8SSascha Wildner 	}
303249d29c8SSascha Wildner 
304249d29c8SSascha Wildner 	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
305249d29c8SSascha Wildner 		error = errno;
306249d29c8SSascha Wildner 		warn("Invalid volume: %s", av[1]);
307f26fa772SSascha Wildner 		close(fd);
308249d29c8SSascha Wildner 		return (error);
309249d29c8SSascha Wildner 	}
310249d29c8SSascha Wildner 
311249d29c8SSascha Wildner 	if (mfi_ld_get_props(fd, target_id, &props) < 0) {
312249d29c8SSascha Wildner 		error = errno;
313249d29c8SSascha Wildner 		warn("Failed to fetch volume properties");
314f26fa772SSascha Wildner 		close(fd);
315249d29c8SSascha Wildner 		return (error);
316249d29c8SSascha Wildner 	}
317249d29c8SSascha Wildner 
318249d29c8SSascha Wildner 	if (ac == 2) {
319249d29c8SSascha Wildner 		printf("mfi%u volume %s cache settings:\n", mfi_unit,
320249d29c8SSascha Wildner 		    mfi_volume_name(fd, target_id));
321249d29c8SSascha Wildner 		printf("             I/O caching: ");
322249d29c8SSascha Wildner 		switch (props.default_cache_policy &
323249d29c8SSascha Wildner 		    (MR_LD_CACHE_ALLOW_WRITE_CACHE |
324249d29c8SSascha Wildner 		    MR_LD_CACHE_ALLOW_READ_CACHE)) {
325249d29c8SSascha Wildner 		case 0:
326249d29c8SSascha Wildner 			printf("disabled\n");
327249d29c8SSascha Wildner 			break;
328249d29c8SSascha Wildner 		case MR_LD_CACHE_ALLOW_WRITE_CACHE:
329249d29c8SSascha Wildner 			printf("writes\n");
330249d29c8SSascha Wildner 			break;
331249d29c8SSascha Wildner 		case MR_LD_CACHE_ALLOW_READ_CACHE:
332249d29c8SSascha Wildner 			printf("reads\n");
333249d29c8SSascha Wildner 			break;
334249d29c8SSascha Wildner 		case MR_LD_CACHE_ALLOW_WRITE_CACHE |
335249d29c8SSascha Wildner 		    MR_LD_CACHE_ALLOW_READ_CACHE:
336249d29c8SSascha Wildner 			printf("writes and reads\n");
337249d29c8SSascha Wildner 			break;
338249d29c8SSascha Wildner 		}
339249d29c8SSascha Wildner 		printf("           write caching: %s\n",
340249d29c8SSascha Wildner 		    props.default_cache_policy & MR_LD_CACHE_WRITE_BACK ?
341249d29c8SSascha Wildner 		    "write-back" : "write-through");
342f26fa772SSascha Wildner 		printf("write cache with bad BBU: %s\n",
343f26fa772SSascha Wildner 		    props.default_cache_policy &
344f26fa772SSascha Wildner 		    MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "enabled" : "disabled");
345249d29c8SSascha Wildner 		printf("              read ahead: %s\n",
346249d29c8SSascha Wildner 		    props.default_cache_policy & MR_LD_CACHE_READ_AHEAD ?
347249d29c8SSascha Wildner 		    (props.default_cache_policy & MR_LD_CACHE_READ_ADAPTIVE ?
348249d29c8SSascha Wildner 		    "adaptive" : "always") : "none");
349249d29c8SSascha Wildner 		printf("       drive write cache: ");
350249d29c8SSascha Wildner 		switch (props.disk_cache_policy) {
351249d29c8SSascha Wildner 		case MR_PD_CACHE_UNCHANGED:
352249d29c8SSascha Wildner 			printf("default\n");
353249d29c8SSascha Wildner 			break;
354249d29c8SSascha Wildner 		case MR_PD_CACHE_ENABLE:
355249d29c8SSascha Wildner 			printf("enabled\n");
356249d29c8SSascha Wildner 			break;
357249d29c8SSascha Wildner 		case MR_PD_CACHE_DISABLE:
358249d29c8SSascha Wildner 			printf("disabled\n");
359249d29c8SSascha Wildner 			break;
360249d29c8SSascha Wildner 		default:
361249d29c8SSascha Wildner 			printf("??? %d\n", props.disk_cache_policy);
362249d29c8SSascha Wildner 			break;
363249d29c8SSascha Wildner 		}
364249d29c8SSascha Wildner 		if (props.default_cache_policy != props.current_cache_policy)
365249d29c8SSascha Wildner 			printf("Cache Disabled Due to Dead Battery\n");
366249d29c8SSascha Wildner 		error = 0;
367249d29c8SSascha Wildner 	} else {
368*f0d8b1f2SSascha Wildner 		new = props;
369*f0d8b1f2SSascha Wildner 		av += 2;
370*f0d8b1f2SSascha Wildner 		ac -= 2;
371*f0d8b1f2SSascha Wildner 		while (ac > 0) {
372*f0d8b1f2SSascha Wildner 			consumed = process_cache_command(ac, av, &new);
373*f0d8b1f2SSascha Wildner 			if (consumed < 0) {
374f26fa772SSascha Wildner 				close(fd);
375249d29c8SSascha Wildner 				return (EINVAL);
376249d29c8SSascha Wildner 			}
377*f0d8b1f2SSascha Wildner 			av += consumed;
378*f0d8b1f2SSascha Wildner 			ac -= consumed;
379249d29c8SSascha Wildner 		}
380*f0d8b1f2SSascha Wildner 		error = update_cache_policy(fd, &props, &new);
381249d29c8SSascha Wildner 	}
382249d29c8SSascha Wildner 	close(fd);
383249d29c8SSascha Wildner 
384249d29c8SSascha Wildner 	return (error);
385249d29c8SSascha Wildner }
386249d29c8SSascha Wildner MFI_COMMAND(top, cache, volume_cache);
387249d29c8SSascha Wildner 
388249d29c8SSascha Wildner static int
volume_name(int ac,char ** av)389249d29c8SSascha Wildner volume_name(int ac, char **av)
390249d29c8SSascha Wildner {
391249d29c8SSascha Wildner 	struct mfi_ld_props props;
392249d29c8SSascha Wildner 	int error, fd;
393249d29c8SSascha Wildner 	uint8_t target_id;
394249d29c8SSascha Wildner 
395249d29c8SSascha Wildner 	if (ac != 3) {
396249d29c8SSascha Wildner 		warnx("name: volume and name required");
397249d29c8SSascha Wildner 		return (EINVAL);
398249d29c8SSascha Wildner 	}
399249d29c8SSascha Wildner 
400249d29c8SSascha Wildner 	if (strlen(av[2]) >= sizeof(props.name)) {
401249d29c8SSascha Wildner 		warnx("name: new name is too long");
402249d29c8SSascha Wildner 		return (ENOSPC);
403249d29c8SSascha Wildner 	}
404249d29c8SSascha Wildner 
405249d29c8SSascha Wildner 	fd = mfi_open(mfi_unit);
406249d29c8SSascha Wildner 	if (fd < 0) {
407249d29c8SSascha Wildner 		error = errno;
408249d29c8SSascha Wildner 		warn("mfi_open");
409249d29c8SSascha Wildner 		return (error);
410249d29c8SSascha Wildner 	}
411249d29c8SSascha Wildner 
412249d29c8SSascha Wildner 	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
413249d29c8SSascha Wildner 		error = errno;
414249d29c8SSascha Wildner 		warn("Invalid volume: %s", av[1]);
415f26fa772SSascha Wildner 		close(fd);
416249d29c8SSascha Wildner 		return (error);
417249d29c8SSascha Wildner 	}
418249d29c8SSascha Wildner 
419249d29c8SSascha Wildner 	if (mfi_ld_get_props(fd, target_id, &props) < 0) {
420249d29c8SSascha Wildner 		error = errno;
421249d29c8SSascha Wildner 		warn("Failed to fetch volume properties");
422f26fa772SSascha Wildner 		close(fd);
423249d29c8SSascha Wildner 		return (error);
424249d29c8SSascha Wildner 	}
425249d29c8SSascha Wildner 
426249d29c8SSascha Wildner 	printf("mfi%u volume %s name changed from \"%s\" to \"%s\"\n", mfi_unit,
427249d29c8SSascha Wildner 	    mfi_volume_name(fd, target_id), props.name, av[2]);
428249d29c8SSascha Wildner 	bzero(props.name, sizeof(props.name));
429249d29c8SSascha Wildner 	strcpy(props.name, av[2]);
430249d29c8SSascha Wildner 	if (mfi_ld_set_props(fd, &props) < 0) {
431249d29c8SSascha Wildner 		error = errno;
432249d29c8SSascha Wildner 		warn("Failed to set volume properties");
433f26fa772SSascha Wildner 		close(fd);
434249d29c8SSascha Wildner 		return (error);
435249d29c8SSascha Wildner 	}
436249d29c8SSascha Wildner 
437249d29c8SSascha Wildner 	close(fd);
438249d29c8SSascha Wildner 
439249d29c8SSascha Wildner 	return (0);
440249d29c8SSascha Wildner }
441249d29c8SSascha Wildner MFI_COMMAND(top, name, volume_name);
442249d29c8SSascha Wildner 
443249d29c8SSascha Wildner static int
volume_progress(int ac,char ** av)444249d29c8SSascha Wildner volume_progress(int ac, char **av)
445249d29c8SSascha Wildner {
446249d29c8SSascha Wildner 	struct mfi_ld_info info;
447249d29c8SSascha Wildner 	int error, fd;
448249d29c8SSascha Wildner 	uint8_t target_id;
449249d29c8SSascha Wildner 
450249d29c8SSascha Wildner 	if (ac != 2) {
451249d29c8SSascha Wildner 		warnx("volume progress: %s", ac > 2 ? "extra arguments" :
452249d29c8SSascha Wildner 		    "volume required");
453249d29c8SSascha Wildner 		return (EINVAL);
454249d29c8SSascha Wildner 	}
455249d29c8SSascha Wildner 
456249d29c8SSascha Wildner 	fd = mfi_open(mfi_unit);
457249d29c8SSascha Wildner 	if (fd < 0) {
458249d29c8SSascha Wildner 		error = errno;
459249d29c8SSascha Wildner 		warn("mfi_open");
460249d29c8SSascha Wildner 		return (error);
461249d29c8SSascha Wildner 	}
462249d29c8SSascha Wildner 
463249d29c8SSascha Wildner 	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
464249d29c8SSascha Wildner 		error = errno;
465249d29c8SSascha Wildner 		warn("Invalid volume: %s", av[1]);
466f26fa772SSascha Wildner 		close(fd);
467249d29c8SSascha Wildner 		return (error);
468249d29c8SSascha Wildner 	}
469249d29c8SSascha Wildner 
470249d29c8SSascha Wildner 	/* Get the info for this drive. */
471249d29c8SSascha Wildner 	if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
472249d29c8SSascha Wildner 		error = errno;
473249d29c8SSascha Wildner 		warn("Failed to fetch info for volume %s",
474249d29c8SSascha Wildner 		    mfi_volume_name(fd, target_id));
475f26fa772SSascha Wildner 		close(fd);
476249d29c8SSascha Wildner 		return (error);
477249d29c8SSascha Wildner 	}
478249d29c8SSascha Wildner 
479249d29c8SSascha Wildner 	/* Display any of the active events. */
480249d29c8SSascha Wildner 	if (info.progress.active & MFI_LD_PROGRESS_CC)
481249d29c8SSascha Wildner 		mfi_display_progress("Consistency Check", &info.progress.cc);
482249d29c8SSascha Wildner 	if (info.progress.active & MFI_LD_PROGRESS_BGI)
483249d29c8SSascha Wildner 		mfi_display_progress("Background Init", &info.progress.bgi);
484249d29c8SSascha Wildner 	if (info.progress.active & MFI_LD_PROGRESS_FGI)
485249d29c8SSascha Wildner 		mfi_display_progress("Foreground Init", &info.progress.fgi);
486249d29c8SSascha Wildner 	if (info.progress.active & MFI_LD_PROGRESS_RECON)
487249d29c8SSascha Wildner 		mfi_display_progress("Reconstruction", &info.progress.recon);
488249d29c8SSascha Wildner 	if ((info.progress.active & (MFI_LD_PROGRESS_CC | MFI_LD_PROGRESS_BGI |
489249d29c8SSascha Wildner 	    MFI_LD_PROGRESS_FGI | MFI_LD_PROGRESS_RECON)) == 0)
490249d29c8SSascha Wildner 		printf("No activity in progress for volume %s.\n",
491249d29c8SSascha Wildner 		    mfi_volume_name(fd, target_id));
492249d29c8SSascha Wildner 	close(fd);
493249d29c8SSascha Wildner 
494249d29c8SSascha Wildner 	return (0);
495249d29c8SSascha Wildner }
496249d29c8SSascha Wildner MFI_COMMAND(volume, progress, volume_progress);
497