1196200Sscottl/*-
2196200Sscottl * Copyright (c) 2008, 2009 Yahoo!, Inc.
3196200Sscottl * All rights reserved.
4196200Sscottl *
5196200Sscottl * Redistribution and use in source and binary forms, with or without
6196200Sscottl * modification, are permitted provided that the following conditions
7196200Sscottl * are met:
8196200Sscottl * 1. Redistributions of source code must retain the above copyright
9196200Sscottl *    notice, this list of conditions and the following disclaimer.
10196200Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11196200Sscottl *    notice, this list of conditions and the following disclaimer in the
12196200Sscottl *    documentation and/or other materials provided with the distribution.
13196200Sscottl * 3. The names of the authors may not be used to endorse or promote
14196200Sscottl *    products derived from this software without specific prior written
15196200Sscottl *    permission.
16196200Sscottl *
17196200Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18196200Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19196200Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20196200Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21196200Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22196200Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23196200Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24196200Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25196200Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26196200Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27196200Sscottl * SUCH DAMAGE.
28196200Sscottl *
29196200Sscottl * $FreeBSD: releng/11.0/usr.sbin/mfiutil/mfi_volume.c 249257 2013-04-08 17:46:45Z markj $
30196200Sscottl */
31196200Sscottl
32196200Sscottl#include <sys/types.h>
33196200Sscottl#include <sys/errno.h>
34196200Sscottl#include <err.h>
35237259Seadler#include <fcntl.h>
36196200Sscottl#include <libutil.h>
37196200Sscottl#include <stdio.h>
38196200Sscottl#include <stdlib.h>
39196200Sscottl#include <string.h>
40196200Sscottl#include <unistd.h>
41196200Sscottl#include "mfiutil.h"
42196200Sscottl
43196200SscottlMFI_TABLE(top, volume);
44196200Sscottl
45196200Sscottlconst char *
46196200Sscottlmfi_ldstate(enum mfi_ld_state state)
47196200Sscottl{
48196200Sscottl	static char buf[16];
49196200Sscottl
50196200Sscottl	switch (state) {
51196200Sscottl	case MFI_LD_STATE_OFFLINE:
52196200Sscottl		return ("OFFLINE");
53196200Sscottl	case MFI_LD_STATE_PARTIALLY_DEGRADED:
54196200Sscottl		return ("PARTIALLY DEGRADED");
55196200Sscottl	case MFI_LD_STATE_DEGRADED:
56196200Sscottl		return ("DEGRADED");
57196200Sscottl	case MFI_LD_STATE_OPTIMAL:
58196200Sscottl		return ("OPTIMAL");
59196200Sscottl	default:
60196200Sscottl		sprintf(buf, "LSTATE 0x%02x", state);
61196200Sscottl		return (buf);
62196200Sscottl	}
63196200Sscottl}
64196200Sscottl
65196200Sscottlvoid
66196200Sscottlmbox_store_ldref(uint8_t *mbox, union mfi_ld_ref *ref)
67196200Sscottl{
68196200Sscottl
69196200Sscottl	mbox[0] = ref->v.target_id;
70196200Sscottl	mbox[1] = ref->v.reserved;
71196200Sscottl	mbox[2] = ref->v.seq & 0xff;
72196200Sscottl	mbox[3] = ref->v.seq >> 8;
73196200Sscottl}
74196200Sscottl
75196200Sscottlint
76196200Sscottlmfi_ld_get_list(int fd, struct mfi_ld_list *list, uint8_t *statusp)
77196200Sscottl{
78196200Sscottl
79196200Sscottl	return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_LIST, list,
80196200Sscottl		sizeof(struct mfi_ld_list), NULL, 0, statusp));
81196200Sscottl}
82196200Sscottl
83196200Sscottlint
84196200Sscottlmfi_ld_get_info(int fd, uint8_t target_id, struct mfi_ld_info *info,
85196200Sscottl    uint8_t *statusp)
86196200Sscottl{
87196200Sscottl	uint8_t mbox[1];
88196200Sscottl
89196200Sscottl	mbox[0] = target_id;
90196200Sscottl	return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_INFO, info,
91196200Sscottl	    sizeof(struct mfi_ld_info), mbox, 1, statusp));
92196200Sscottl}
93196200Sscottl
94196200Sscottlstatic int
95196200Sscottlmfi_ld_get_props(int fd, uint8_t target_id, struct mfi_ld_props *props)
96196200Sscottl{
97196200Sscottl	uint8_t mbox[1];
98196200Sscottl
99196200Sscottl	mbox[0] = target_id;
100196200Sscottl	return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_PROP, props,
101196200Sscottl	    sizeof(struct mfi_ld_props), mbox, 1, NULL));
102196200Sscottl}
103196200Sscottl
104196200Sscottlstatic int
105196200Sscottlmfi_ld_set_props(int fd, struct mfi_ld_props *props)
106196200Sscottl{
107196200Sscottl	uint8_t mbox[4];
108196200Sscottl
109196200Sscottl	mbox_store_ldref(mbox, &props->ld);
110196200Sscottl	return (mfi_dcmd_command(fd, MFI_DCMD_LD_SET_PROP, props,
111196200Sscottl	    sizeof(struct mfi_ld_props), mbox, 4, NULL));
112196200Sscottl}
113196200Sscottl
114196200Sscottlstatic int
115225331Sjhbupdate_cache_policy(int fd, struct mfi_ld_props *old, struct mfi_ld_props *new)
116196200Sscottl{
117214396Sjhb	int error;
118196200Sscottl	uint8_t changes, policy;
119196200Sscottl
120225331Sjhb	if (old->default_cache_policy == new->default_cache_policy &&
121225331Sjhb	    old->disk_cache_policy == new->disk_cache_policy)
122196200Sscottl		return (0);
123225331Sjhb	policy = new->default_cache_policy;
124225331Sjhb	changes = policy ^ old->default_cache_policy;
125196200Sscottl	if (changes & MR_LD_CACHE_ALLOW_WRITE_CACHE)
126196200Sscottl		printf("%s caching of I/O writes\n",
127196200Sscottl		    policy & MR_LD_CACHE_ALLOW_WRITE_CACHE ? "Enabling" :
128196200Sscottl		    "Disabling");
129196200Sscottl	if (changes & MR_LD_CACHE_ALLOW_READ_CACHE)
130196200Sscottl		printf("%s caching of I/O reads\n",
131196200Sscottl		    policy & MR_LD_CACHE_ALLOW_READ_CACHE ? "Enabling" :
132196200Sscottl		    "Disabling");
133196200Sscottl	if (changes & MR_LD_CACHE_WRITE_BACK)
134196200Sscottl		printf("Setting write cache policy to %s\n",
135196200Sscottl		    policy & MR_LD_CACHE_WRITE_BACK ? "write-back" :
136196200Sscottl		    "write-through");
137196200Sscottl	if (changes & (MR_LD_CACHE_READ_AHEAD | MR_LD_CACHE_READ_ADAPTIVE))
138196200Sscottl		printf("Setting read ahead policy to %s\n",
139196200Sscottl		    policy & MR_LD_CACHE_READ_AHEAD ?
140196200Sscottl		    (policy & MR_LD_CACHE_READ_ADAPTIVE ?
141196200Sscottl		    "adaptive" : "always") : "none");
142220363Sjhb	if (changes & MR_LD_CACHE_WRITE_CACHE_BAD_BBU)
143220363Sjhb		printf("%s write caching with bad BBU\n",
144220363Sjhb		    policy & MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "Enabling" :
145220363Sjhb		    "Disabling");
146225331Sjhb	if (old->disk_cache_policy != new->disk_cache_policy) {
147225331Sjhb		switch (new->disk_cache_policy) {
148225331Sjhb		case MR_PD_CACHE_ENABLE:
149225331Sjhb			printf("Enabling write-cache on physical drives\n");
150225331Sjhb			break;
151225331Sjhb		case MR_PD_CACHE_DISABLE:
152225331Sjhb			printf("Disabling write-cache on physical drives\n");
153225331Sjhb			break;
154225331Sjhb		case MR_PD_CACHE_UNCHANGED:
155225331Sjhb			printf("Using default write-cache setting on physical drives\n");
156225331Sjhb			break;
157225331Sjhb		}
158225331Sjhb	}
159196200Sscottl
160225331Sjhb	if (mfi_ld_set_props(fd, new) < 0) {
161214396Sjhb		error = errno;
162196200Sscottl		warn("Failed to set volume properties");
163214396Sjhb		return (error);
164196200Sscottl	}
165196200Sscottl	return (0);
166196200Sscottl}
167196200Sscottl
168225331Sjhbstatic void
169225331Sjhbstage_cache_setting(struct mfi_ld_props *props, uint8_t new_policy,
170225331Sjhb    uint8_t mask)
171225331Sjhb{
172225331Sjhb
173225331Sjhb	props->default_cache_policy &= ~mask;
174225331Sjhb	props->default_cache_policy |= new_policy;
175225331Sjhb}
176225331Sjhb
177225331Sjhb/*
178225331Sjhb * Parse a single cache directive modifying the passed in policy.
179225331Sjhb * Returns -1 on a parse error and the number of arguments consumed
180225331Sjhb * on success.
181225331Sjhb */
182196200Sscottlstatic int
183225331Sjhbprocess_cache_command(int ac, char **av, struct mfi_ld_props *props)
184225331Sjhb{
185225331Sjhb	uint8_t policy;
186225331Sjhb
187225331Sjhb	/* I/O cache settings. */
188225331Sjhb	if (strcmp(av[0], "all") == 0 || strcmp(av[0], "enable") == 0) {
189225331Sjhb		stage_cache_setting(props, MR_LD_CACHE_ALLOW_READ_CACHE |
190225331Sjhb		    MR_LD_CACHE_ALLOW_WRITE_CACHE,
191225331Sjhb		    MR_LD_CACHE_ALLOW_READ_CACHE |
192225331Sjhb		    MR_LD_CACHE_ALLOW_WRITE_CACHE);
193225331Sjhb		return (1);
194225331Sjhb	}
195225331Sjhb	if (strcmp(av[0], "none") == 0 || strcmp(av[0], "disable") == 0) {
196225331Sjhb		stage_cache_setting(props, 0, MR_LD_CACHE_ALLOW_READ_CACHE |
197225331Sjhb		    MR_LD_CACHE_ALLOW_WRITE_CACHE);
198225331Sjhb		return (1);
199225331Sjhb	}
200225331Sjhb	if (strcmp(av[0], "reads") == 0) {
201225331Sjhb 		stage_cache_setting(props, MR_LD_CACHE_ALLOW_READ_CACHE,
202225331Sjhb		    MR_LD_CACHE_ALLOW_READ_CACHE |
203225331Sjhb		    MR_LD_CACHE_ALLOW_WRITE_CACHE);
204225331Sjhb		return (1);
205225331Sjhb	}
206225331Sjhb	if (strcmp(av[0], "writes") == 0) {
207225331Sjhb		stage_cache_setting(props, MR_LD_CACHE_ALLOW_WRITE_CACHE,
208225331Sjhb		    MR_LD_CACHE_ALLOW_READ_CACHE |
209225331Sjhb		    MR_LD_CACHE_ALLOW_WRITE_CACHE);
210225331Sjhb		return (1);
211225331Sjhb	}
212225331Sjhb
213225331Sjhb	/* Write cache behavior. */
214225331Sjhb	if (strcmp(av[0], "write-back") == 0) {
215225331Sjhb		stage_cache_setting(props, MR_LD_CACHE_WRITE_BACK,
216225331Sjhb		    MR_LD_CACHE_WRITE_BACK);
217225331Sjhb		return (1);
218225331Sjhb	}
219225331Sjhb	if (strcmp(av[0], "write-through") == 0) {
220225331Sjhb		stage_cache_setting(props, 0, MR_LD_CACHE_WRITE_BACK);
221225331Sjhb		return (1);
222225331Sjhb	}
223225331Sjhb	if (strcmp(av[0], "bad-bbu-write-cache") == 0) {
224225331Sjhb		if (ac < 2) {
225225331Sjhb			warnx("cache: bad BBU setting required");
226225331Sjhb			return (-1);
227225331Sjhb		}
228225331Sjhb		if (strcmp(av[1], "enable") == 0)
229225331Sjhb			policy = MR_LD_CACHE_WRITE_CACHE_BAD_BBU;
230225331Sjhb		else if (strcmp(av[1], "disable") == 0)
231225331Sjhb			policy = 0;
232225331Sjhb		else {
233225331Sjhb			warnx("cache: invalid bad BBU setting");
234225331Sjhb			return (-1);
235225331Sjhb		}
236225331Sjhb		stage_cache_setting(props, policy,
237225331Sjhb		    MR_LD_CACHE_WRITE_CACHE_BAD_BBU);
238225331Sjhb		return (2);
239225331Sjhb	}
240225331Sjhb
241225331Sjhb	/* Read cache behavior. */
242225331Sjhb	if (strcmp(av[0], "read-ahead") == 0) {
243225331Sjhb		if (ac < 2) {
244225331Sjhb			warnx("cache: read-ahead setting required");
245225331Sjhb			return (-1);
246225331Sjhb		}
247225331Sjhb		if (strcmp(av[1], "none") == 0)
248225331Sjhb			policy = 0;
249225331Sjhb		else if (strcmp(av[1], "always") == 0)
250225331Sjhb			policy = MR_LD_CACHE_READ_AHEAD;
251225331Sjhb		else if (strcmp(av[1], "adaptive") == 0)
252225331Sjhb			policy = MR_LD_CACHE_READ_AHEAD |
253225331Sjhb			    MR_LD_CACHE_READ_ADAPTIVE;
254225331Sjhb		else {
255225331Sjhb			warnx("cache: invalid read-ahead setting");
256225331Sjhb			return (-1);
257225331Sjhb		}
258225331Sjhb		stage_cache_setting(props, policy, MR_LD_CACHE_READ_AHEAD |
259225331Sjhb			    MR_LD_CACHE_READ_ADAPTIVE);
260225331Sjhb		return (2);
261225331Sjhb	}
262225331Sjhb
263225331Sjhb	/* Drive write-cache behavior. */
264225331Sjhb	if (strcmp(av[0], "write-cache") == 0) {
265225331Sjhb		if (ac < 2) {
266225331Sjhb			warnx("cache: write-cache setting required");
267225331Sjhb			return (-1);
268225331Sjhb		}
269225331Sjhb		if (strcmp(av[1], "enable") == 0)
270225331Sjhb			props->disk_cache_policy = MR_PD_CACHE_ENABLE;
271225331Sjhb		else if (strcmp(av[1], "disable") == 0)
272225331Sjhb			props->disk_cache_policy = MR_PD_CACHE_DISABLE;
273225331Sjhb		else if (strcmp(av[1], "default") == 0)
274225331Sjhb			props->disk_cache_policy = MR_PD_CACHE_UNCHANGED;
275225331Sjhb		else {
276225331Sjhb			warnx("cache: invalid write-cache setting");
277225331Sjhb			return (-1);
278225331Sjhb		}
279225331Sjhb		return (2);
280225331Sjhb	}
281225331Sjhb
282225331Sjhb	warnx("cache: Invalid command");
283225331Sjhb	return (-1);
284225331Sjhb}
285225331Sjhb
286225331Sjhbstatic int
287196200Sscottlvolume_cache(int ac, char **av)
288196200Sscottl{
289225331Sjhb	struct mfi_ld_props props, new;
290225331Sjhb	int error, fd, consumed;
291225331Sjhb	uint8_t target_id;
292196200Sscottl
293196200Sscottl	if (ac < 2) {
294196200Sscottl		warnx("cache: volume required");
295196200Sscottl		return (EINVAL);
296196200Sscottl	}
297196200Sscottl
298237259Seadler	fd = mfi_open(mfi_unit, O_RDWR);
299196200Sscottl	if (fd < 0) {
300214396Sjhb		error = errno;
301196200Sscottl		warn("mfi_open");
302214396Sjhb		return (error);
303196200Sscottl	}
304196200Sscottl
305196200Sscottl	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
306214396Sjhb		error = errno;
307196200Sscottl		warn("Invalid volume: %s", av[1]);
308222899Sbz		close(fd);
309214396Sjhb		return (error);
310196200Sscottl	}
311196200Sscottl
312196200Sscottl	if (mfi_ld_get_props(fd, target_id, &props) < 0) {
313214396Sjhb		error = errno;
314196200Sscottl		warn("Failed to fetch volume properties");
315222899Sbz		close(fd);
316214396Sjhb		return (error);
317196200Sscottl	}
318196200Sscottl
319196200Sscottl	if (ac == 2) {
320196200Sscottl		printf("mfi%u volume %s cache settings:\n", mfi_unit,
321196200Sscottl		    mfi_volume_name(fd, target_id));
322220363Sjhb		printf("             I/O caching: ");
323196200Sscottl		switch (props.default_cache_policy &
324196200Sscottl		    (MR_LD_CACHE_ALLOW_WRITE_CACHE |
325196200Sscottl		    MR_LD_CACHE_ALLOW_READ_CACHE)) {
326196200Sscottl		case 0:
327196200Sscottl			printf("disabled\n");
328196200Sscottl			break;
329196200Sscottl		case MR_LD_CACHE_ALLOW_WRITE_CACHE:
330196200Sscottl			printf("writes\n");
331196200Sscottl			break;
332196200Sscottl		case MR_LD_CACHE_ALLOW_READ_CACHE:
333196200Sscottl			printf("reads\n");
334196200Sscottl			break;
335196200Sscottl		case MR_LD_CACHE_ALLOW_WRITE_CACHE |
336196200Sscottl		    MR_LD_CACHE_ALLOW_READ_CACHE:
337196200Sscottl			printf("writes and reads\n");
338196200Sscottl			break;
339196200Sscottl		}
340220363Sjhb		printf("           write caching: %s\n",
341196200Sscottl		    props.default_cache_policy & MR_LD_CACHE_WRITE_BACK ?
342196200Sscottl		    "write-back" : "write-through");
343220363Sjhb		printf("write cache with bad BBU: %s\n",
344220363Sjhb		    props.default_cache_policy &
345220363Sjhb		    MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "enabled" : "disabled");
346220363Sjhb		printf("              read ahead: %s\n",
347196200Sscottl		    props.default_cache_policy & MR_LD_CACHE_READ_AHEAD ?
348196200Sscottl		    (props.default_cache_policy & MR_LD_CACHE_READ_ADAPTIVE ?
349196200Sscottl		    "adaptive" : "always") : "none");
350220363Sjhb		printf("       drive write cache: ");
351196200Sscottl		switch (props.disk_cache_policy) {
352196200Sscottl		case MR_PD_CACHE_UNCHANGED:
353196200Sscottl			printf("default\n");
354196200Sscottl			break;
355196200Sscottl		case MR_PD_CACHE_ENABLE:
356196200Sscottl			printf("enabled\n");
357196200Sscottl			break;
358196200Sscottl		case MR_PD_CACHE_DISABLE:
359196200Sscottl			printf("disabled\n");
360196200Sscottl			break;
361196200Sscottl		default:
362196200Sscottl			printf("??? %d\n", props.disk_cache_policy);
363196200Sscottl			break;
364196200Sscottl		}
365196200Sscottl		if (props.default_cache_policy != props.current_cache_policy)
366249257Smarkj			printf(
367249257Smarkj	"Cache disabled due to dead battery or ongoing battery relearn\n");
368196200Sscottl		error = 0;
369196200Sscottl	} else {
370225331Sjhb		new = props;
371225331Sjhb		av += 2;
372225331Sjhb		ac -= 2;
373225331Sjhb		while (ac > 0) {
374225331Sjhb			consumed = process_cache_command(ac, av, &new);
375225331Sjhb			if (consumed < 0) {
376222899Sbz				close(fd);
377196200Sscottl				return (EINVAL);
378196200Sscottl			}
379225331Sjhb			av += consumed;
380225331Sjhb			ac -= consumed;
381196200Sscottl		}
382225331Sjhb		error = update_cache_policy(fd, &props, &new);
383196200Sscottl	}
384196200Sscottl	close(fd);
385196200Sscottl
386196200Sscottl	return (error);
387196200Sscottl}
388196200SscottlMFI_COMMAND(top, cache, volume_cache);
389196200Sscottl
390196200Sscottlstatic int
391196200Sscottlvolume_name(int ac, char **av)
392196200Sscottl{
393196200Sscottl	struct mfi_ld_props props;
394214396Sjhb	int error, fd;
395196200Sscottl	uint8_t target_id;
396196200Sscottl
397196200Sscottl	if (ac != 3) {
398196200Sscottl		warnx("name: volume and name required");
399196200Sscottl		return (EINVAL);
400196200Sscottl	}
401196200Sscottl
402196200Sscottl	if (strlen(av[2]) >= sizeof(props.name)) {
403196200Sscottl		warnx("name: new name is too long");
404196200Sscottl		return (ENOSPC);
405196200Sscottl	}
406196200Sscottl
407237259Seadler	fd = mfi_open(mfi_unit, O_RDWR);
408196200Sscottl	if (fd < 0) {
409214396Sjhb		error = errno;
410196200Sscottl		warn("mfi_open");
411214396Sjhb		return (error);
412196200Sscottl	}
413196200Sscottl
414196200Sscottl	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
415214396Sjhb		error = errno;
416196200Sscottl		warn("Invalid volume: %s", av[1]);
417222899Sbz		close(fd);
418214396Sjhb		return (error);
419196200Sscottl	}
420196200Sscottl
421196200Sscottl	if (mfi_ld_get_props(fd, target_id, &props) < 0) {
422214396Sjhb		error = errno;
423196200Sscottl		warn("Failed to fetch volume properties");
424222899Sbz		close(fd);
425214396Sjhb		return (error);
426196200Sscottl	}
427196200Sscottl
428196200Sscottl	printf("mfi%u volume %s name changed from \"%s\" to \"%s\"\n", mfi_unit,
429196200Sscottl	    mfi_volume_name(fd, target_id), props.name, av[2]);
430196200Sscottl	bzero(props.name, sizeof(props.name));
431196200Sscottl	strcpy(props.name, av[2]);
432196200Sscottl	if (mfi_ld_set_props(fd, &props) < 0) {
433214396Sjhb		error = errno;
434196200Sscottl		warn("Failed to set volume properties");
435222899Sbz		close(fd);
436214396Sjhb		return (error);
437196200Sscottl	}
438196200Sscottl
439196200Sscottl	close(fd);
440196200Sscottl
441196200Sscottl	return (0);
442196200Sscottl}
443196200SscottlMFI_COMMAND(top, name, volume_name);
444196200Sscottl
445196200Sscottlstatic int
446196200Sscottlvolume_progress(int ac, char **av)
447196200Sscottl{
448196200Sscottl	struct mfi_ld_info info;
449214396Sjhb	int error, fd;
450196200Sscottl	uint8_t target_id;
451196200Sscottl
452196200Sscottl	if (ac != 2) {
453196200Sscottl		warnx("volume progress: %s", ac > 2 ? "extra arguments" :
454196200Sscottl		    "volume required");
455196200Sscottl		return (EINVAL);
456196200Sscottl	}
457196200Sscottl
458237259Seadler	fd = mfi_open(mfi_unit, O_RDONLY);
459196200Sscottl	if (fd < 0) {
460214396Sjhb		error = errno;
461196200Sscottl		warn("mfi_open");
462214396Sjhb		return (error);
463196200Sscottl	}
464196200Sscottl
465196200Sscottl	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
466214396Sjhb		error = errno;
467196200Sscottl		warn("Invalid volume: %s", av[1]);
468222899Sbz		close(fd);
469214396Sjhb		return (error);
470196200Sscottl	}
471196200Sscottl
472196200Sscottl	/* Get the info for this drive. */
473196200Sscottl	if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
474214396Sjhb		error = errno;
475196200Sscottl		warn("Failed to fetch info for volume %s",
476196200Sscottl		    mfi_volume_name(fd, target_id));
477222899Sbz		close(fd);
478214396Sjhb		return (error);
479196200Sscottl	}
480196200Sscottl
481196200Sscottl	/* Display any of the active events. */
482196200Sscottl	if (info.progress.active & MFI_LD_PROGRESS_CC)
483196200Sscottl		mfi_display_progress("Consistency Check", &info.progress.cc);
484196200Sscottl	if (info.progress.active & MFI_LD_PROGRESS_BGI)
485196200Sscottl		mfi_display_progress("Background Init", &info.progress.bgi);
486196200Sscottl	if (info.progress.active & MFI_LD_PROGRESS_FGI)
487196200Sscottl		mfi_display_progress("Foreground Init", &info.progress.fgi);
488196200Sscottl	if (info.progress.active & MFI_LD_PROGRESS_RECON)
489196200Sscottl		mfi_display_progress("Reconstruction", &info.progress.recon);
490196200Sscottl	if ((info.progress.active & (MFI_LD_PROGRESS_CC | MFI_LD_PROGRESS_BGI |
491196200Sscottl	    MFI_LD_PROGRESS_FGI | MFI_LD_PROGRESS_RECON)) == 0)
492196200Sscottl		printf("No activity in progress for volume %s.\n",
493196200Sscottl		    mfi_volume_name(fd, target_id));
494196200Sscottl	close(fd);
495196200Sscottl
496196200Sscottl	return (0);
497196200Sscottl}
498196200SscottlMFI_COMMAND(volume, progress, volume_progress);
499