mfi_volume.c revision 214396
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: head/usr.sbin/mfiutil/mfi_volume.c 214396 2010-10-26 19:11:09Z jhb $
30196200Sscottl */
31196200Sscottl
32196200Sscottl#include <sys/types.h>
33196200Sscottl#include <sys/errno.h>
34196200Sscottl#include <err.h>
35196200Sscottl#include <libutil.h>
36196200Sscottl#include <stdio.h>
37196200Sscottl#include <stdlib.h>
38196200Sscottl#include <string.h>
39196200Sscottl#include <unistd.h>
40196200Sscottl#include "mfiutil.h"
41196200Sscottl
42196200SscottlMFI_TABLE(top, volume);
43196200Sscottl
44196200Sscottlconst char *
45196200Sscottlmfi_ldstate(enum mfi_ld_state state)
46196200Sscottl{
47196200Sscottl	static char buf[16];
48196200Sscottl
49196200Sscottl	switch (state) {
50196200Sscottl	case MFI_LD_STATE_OFFLINE:
51196200Sscottl		return ("OFFLINE");
52196200Sscottl	case MFI_LD_STATE_PARTIALLY_DEGRADED:
53196200Sscottl		return ("PARTIALLY DEGRADED");
54196200Sscottl	case MFI_LD_STATE_DEGRADED:
55196200Sscottl		return ("DEGRADED");
56196200Sscottl	case MFI_LD_STATE_OPTIMAL:
57196200Sscottl		return ("OPTIMAL");
58196200Sscottl	default:
59196200Sscottl		sprintf(buf, "LSTATE 0x%02x", state);
60196200Sscottl		return (buf);
61196200Sscottl	}
62196200Sscottl}
63196200Sscottl
64196200Sscottlvoid
65196200Sscottlmbox_store_ldref(uint8_t *mbox, union mfi_ld_ref *ref)
66196200Sscottl{
67196200Sscottl
68196200Sscottl	mbox[0] = ref->v.target_id;
69196200Sscottl	mbox[1] = ref->v.reserved;
70196200Sscottl	mbox[2] = ref->v.seq & 0xff;
71196200Sscottl	mbox[3] = ref->v.seq >> 8;
72196200Sscottl}
73196200Sscottl
74196200Sscottlint
75196200Sscottlmfi_ld_get_list(int fd, struct mfi_ld_list *list, uint8_t *statusp)
76196200Sscottl{
77196200Sscottl
78196200Sscottl	return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_LIST, list,
79196200Sscottl		sizeof(struct mfi_ld_list), NULL, 0, statusp));
80196200Sscottl}
81196200Sscottl
82196200Sscottlint
83196200Sscottlmfi_ld_get_info(int fd, uint8_t target_id, struct mfi_ld_info *info,
84196200Sscottl    uint8_t *statusp)
85196200Sscottl{
86196200Sscottl	uint8_t mbox[1];
87196200Sscottl
88196200Sscottl	mbox[0] = target_id;
89196200Sscottl	return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_INFO, info,
90196200Sscottl	    sizeof(struct mfi_ld_info), mbox, 1, statusp));
91196200Sscottl}
92196200Sscottl
93196200Sscottlstatic int
94196200Sscottlmfi_ld_get_props(int fd, uint8_t target_id, struct mfi_ld_props *props)
95196200Sscottl{
96196200Sscottl	uint8_t mbox[1];
97196200Sscottl
98196200Sscottl	mbox[0] = target_id;
99196200Sscottl	return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_PROP, props,
100196200Sscottl	    sizeof(struct mfi_ld_props), mbox, 1, NULL));
101196200Sscottl}
102196200Sscottl
103196200Sscottlstatic int
104196200Sscottlmfi_ld_set_props(int fd, struct mfi_ld_props *props)
105196200Sscottl{
106196200Sscottl	uint8_t mbox[4];
107196200Sscottl
108196200Sscottl	mbox_store_ldref(mbox, &props->ld);
109196200Sscottl	return (mfi_dcmd_command(fd, MFI_DCMD_LD_SET_PROP, props,
110196200Sscottl	    sizeof(struct mfi_ld_props), mbox, 4, NULL));
111196200Sscottl}
112196200Sscottl
113196200Sscottlstatic int
114196200Sscottlupdate_cache_policy(int fd, struct mfi_ld_props *props, uint8_t new_policy,
115196200Sscottl    uint8_t mask)
116196200Sscottl{
117214396Sjhb	int error;
118196200Sscottl	uint8_t changes, policy;
119196200Sscottl
120196200Sscottl	policy = (props->default_cache_policy & ~mask) | new_policy;
121196200Sscottl	if (policy == props->default_cache_policy)
122196200Sscottl		return (0);
123196200Sscottl	changes = policy ^ props->default_cache_policy;
124196200Sscottl	if (changes & MR_LD_CACHE_ALLOW_WRITE_CACHE)
125196200Sscottl		printf("%s caching of I/O writes\n",
126196200Sscottl		    policy & MR_LD_CACHE_ALLOW_WRITE_CACHE ? "Enabling" :
127196200Sscottl		    "Disabling");
128196200Sscottl	if (changes & MR_LD_CACHE_ALLOW_READ_CACHE)
129196200Sscottl		printf("%s caching of I/O reads\n",
130196200Sscottl		    policy & MR_LD_CACHE_ALLOW_READ_CACHE ? "Enabling" :
131196200Sscottl		    "Disabling");
132196200Sscottl	if (changes & MR_LD_CACHE_WRITE_BACK)
133196200Sscottl		printf("Setting write cache policy to %s\n",
134196200Sscottl		    policy & MR_LD_CACHE_WRITE_BACK ? "write-back" :
135196200Sscottl		    "write-through");
136196200Sscottl	if (changes & (MR_LD_CACHE_READ_AHEAD | MR_LD_CACHE_READ_ADAPTIVE))
137196200Sscottl		printf("Setting read ahead policy to %s\n",
138196200Sscottl		    policy & MR_LD_CACHE_READ_AHEAD ?
139196200Sscottl		    (policy & MR_LD_CACHE_READ_ADAPTIVE ?
140196200Sscottl		    "adaptive" : "always") : "none");
141196200Sscottl
142196200Sscottl	props->default_cache_policy = policy;
143196200Sscottl	if (mfi_ld_set_props(fd, props) < 0) {
144214396Sjhb		error = errno;
145196200Sscottl		warn("Failed to set volume properties");
146214396Sjhb		return (error);
147196200Sscottl	}
148196200Sscottl	return (0);
149196200Sscottl}
150196200Sscottl
151196200Sscottlstatic int
152196200Sscottlvolume_cache(int ac, char **av)
153196200Sscottl{
154196200Sscottl	struct mfi_ld_props props;
155196200Sscottl	int error, fd;
156196200Sscottl	uint8_t target_id, policy;
157196200Sscottl
158196200Sscottl	if (ac < 2) {
159196200Sscottl		warnx("cache: volume required");
160196200Sscottl		return (EINVAL);
161196200Sscottl	}
162196200Sscottl
163196200Sscottl	fd = mfi_open(mfi_unit);
164196200Sscottl	if (fd < 0) {
165214396Sjhb		error = errno;
166196200Sscottl		warn("mfi_open");
167214396Sjhb		return (error);
168196200Sscottl	}
169196200Sscottl
170196200Sscottl	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
171214396Sjhb		error = errno;
172196200Sscottl		warn("Invalid volume: %s", av[1]);
173214396Sjhb		return (error);
174196200Sscottl	}
175196200Sscottl
176196200Sscottl	if (mfi_ld_get_props(fd, target_id, &props) < 0) {
177214396Sjhb		error = errno;
178196200Sscottl		warn("Failed to fetch volume properties");
179214396Sjhb		return (error);
180196200Sscottl	}
181196200Sscottl
182196200Sscottl	if (ac == 2) {
183196200Sscottl		printf("mfi%u volume %s cache settings:\n", mfi_unit,
184196200Sscottl		    mfi_volume_name(fd, target_id));
185196200Sscottl		printf("      I/O caching: ");
186196200Sscottl		switch (props.default_cache_policy &
187196200Sscottl		    (MR_LD_CACHE_ALLOW_WRITE_CACHE |
188196200Sscottl		    MR_LD_CACHE_ALLOW_READ_CACHE)) {
189196200Sscottl		case 0:
190196200Sscottl			printf("disabled\n");
191196200Sscottl			break;
192196200Sscottl		case MR_LD_CACHE_ALLOW_WRITE_CACHE:
193196200Sscottl			printf("writes\n");
194196200Sscottl			break;
195196200Sscottl		case MR_LD_CACHE_ALLOW_READ_CACHE:
196196200Sscottl			printf("reads\n");
197196200Sscottl			break;
198196200Sscottl		case MR_LD_CACHE_ALLOW_WRITE_CACHE |
199196200Sscottl		    MR_LD_CACHE_ALLOW_READ_CACHE:
200196200Sscottl			printf("writes and reads\n");
201196200Sscottl			break;
202196200Sscottl		}
203196200Sscottl		printf("    write caching: %s\n",
204196200Sscottl		    props.default_cache_policy & MR_LD_CACHE_WRITE_BACK ?
205196200Sscottl		    "write-back" : "write-through");
206196200Sscottl		printf("       read ahead: %s\n",
207196200Sscottl		    props.default_cache_policy & MR_LD_CACHE_READ_AHEAD ?
208196200Sscottl		    (props.default_cache_policy & MR_LD_CACHE_READ_ADAPTIVE ?
209196200Sscottl		    "adaptive" : "always") : "none");
210196200Sscottl		printf("drive write cache: ");
211196200Sscottl		switch (props.disk_cache_policy) {
212196200Sscottl		case MR_PD_CACHE_UNCHANGED:
213196200Sscottl			printf("default\n");
214196200Sscottl			break;
215196200Sscottl		case MR_PD_CACHE_ENABLE:
216196200Sscottl			printf("enabled\n");
217196200Sscottl			break;
218196200Sscottl		case MR_PD_CACHE_DISABLE:
219196200Sscottl			printf("disabled\n");
220196200Sscottl			break;
221196200Sscottl		default:
222196200Sscottl			printf("??? %d\n", props.disk_cache_policy);
223196200Sscottl			break;
224196200Sscottl		}
225196200Sscottl		if (props.default_cache_policy != props.current_cache_policy)
226196200Sscottl			printf("Cache Disabled Due to Dead Battery\n");
227196200Sscottl		error = 0;
228196200Sscottl	} else {
229196200Sscottl		if (strcmp(av[2], "all") == 0 || strcmp(av[2], "enable") == 0)
230196200Sscottl			error = update_cache_policy(fd, &props,
231196200Sscottl			    MR_LD_CACHE_ALLOW_READ_CACHE |
232196200Sscottl			    MR_LD_CACHE_ALLOW_WRITE_CACHE,
233196200Sscottl			    MR_LD_CACHE_ALLOW_READ_CACHE |
234196200Sscottl			    MR_LD_CACHE_ALLOW_WRITE_CACHE);
235196200Sscottl		else if (strcmp(av[2], "none") == 0 ||
236196200Sscottl		    strcmp(av[2], "disable") == 0)
237196200Sscottl			error = update_cache_policy(fd, &props, 0,
238196200Sscottl			    MR_LD_CACHE_ALLOW_READ_CACHE |
239196200Sscottl			    MR_LD_CACHE_ALLOW_WRITE_CACHE);
240196200Sscottl		else if (strcmp(av[2], "reads") == 0)
241196200Sscottl			error = update_cache_policy(fd, &props,
242196200Sscottl			    MR_LD_CACHE_ALLOW_READ_CACHE,
243196200Sscottl			    MR_LD_CACHE_ALLOW_READ_CACHE |
244196200Sscottl			    MR_LD_CACHE_ALLOW_WRITE_CACHE);
245196200Sscottl		else if (strcmp(av[2], "writes") == 0)
246196200Sscottl			error = update_cache_policy(fd, &props,
247196200Sscottl			    MR_LD_CACHE_ALLOW_WRITE_CACHE,
248196200Sscottl			    MR_LD_CACHE_ALLOW_READ_CACHE |
249196200Sscottl			    MR_LD_CACHE_ALLOW_WRITE_CACHE);
250196200Sscottl		else if (strcmp(av[2], "write-back") == 0)
251196200Sscottl			error = update_cache_policy(fd, &props,
252196200Sscottl			    MR_LD_CACHE_WRITE_BACK,
253196200Sscottl			    MR_LD_CACHE_WRITE_BACK);
254196200Sscottl		else if (strcmp(av[2], "write-through") == 0)
255196200Sscottl			error = update_cache_policy(fd, &props, 0,
256196200Sscottl			    MR_LD_CACHE_WRITE_BACK);
257196200Sscottl		else if (strcmp(av[2], "read-ahead") == 0) {
258196200Sscottl			if (ac < 4) {
259196200Sscottl				warnx("cache: read-ahead setting required");
260196200Sscottl				return (EINVAL);
261196200Sscottl			}
262196200Sscottl			if (strcmp(av[3], "none") == 0)
263196200Sscottl				policy = 0;
264196200Sscottl			else if (strcmp(av[3], "always") == 0)
265196200Sscottl				policy = MR_LD_CACHE_READ_AHEAD;
266196200Sscottl			else if (strcmp(av[3], "adaptive") == 0)
267196200Sscottl				policy = MR_LD_CACHE_READ_AHEAD |
268196200Sscottl				    MR_LD_CACHE_READ_ADAPTIVE;
269196200Sscottl			else {
270196200Sscottl				warnx("cache: invalid read-ahead setting");
271196200Sscottl				return (EINVAL);
272196200Sscottl			}
273196200Sscottl			error = update_cache_policy(fd, &props, policy,
274196200Sscottl			    MR_LD_CACHE_READ_AHEAD |
275196200Sscottl			    MR_LD_CACHE_READ_ADAPTIVE);
276196200Sscottl		} else if (strcmp(av[2], "write-cache") == 0) {
277196200Sscottl			if (ac < 4) {
278196200Sscottl				warnx("cache: write-cache setting required");
279196200Sscottl				return (EINVAL);
280196200Sscottl			}
281196200Sscottl			if (strcmp(av[3], "enable") == 0)
282196200Sscottl				policy = MR_PD_CACHE_ENABLE;
283196200Sscottl			else if (strcmp(av[3], "disable") == 0)
284196200Sscottl				policy = MR_PD_CACHE_DISABLE;
285196200Sscottl			else if (strcmp(av[3], "default") == 0)
286196200Sscottl				policy = MR_PD_CACHE_UNCHANGED;
287196200Sscottl			else {
288196200Sscottl				warnx("cache: invalid write-cache setting");
289196200Sscottl				return (EINVAL);
290196200Sscottl			}
291196200Sscottl			error = 0;
292196200Sscottl			if (policy != props.disk_cache_policy) {
293196200Sscottl				switch (policy) {
294196200Sscottl				case MR_PD_CACHE_ENABLE:
295196200Sscottl					printf("Enabling write-cache on physical drives\n");
296196200Sscottl					break;
297196200Sscottl				case MR_PD_CACHE_DISABLE:
298196200Sscottl					printf("Disabling write-cache on physical drives\n");
299196200Sscottl					break;
300196200Sscottl				case MR_PD_CACHE_UNCHANGED:
301196200Sscottl					printf("Using default write-cache setting on physical drives\n");
302196200Sscottl					break;
303196200Sscottl				}
304196200Sscottl				props.disk_cache_policy = policy;
305196200Sscottl				if (mfi_ld_set_props(fd, &props) < 0) {
306214396Sjhb					error = errno;
307196200Sscottl					warn("Failed to set volume properties");
308196200Sscottl				}
309196200Sscottl			}
310196200Sscottl		} else {
311196200Sscottl			warnx("cache: Invalid command");
312196200Sscottl			return (EINVAL);
313196200Sscottl		}
314196200Sscottl	}
315196200Sscottl	close(fd);
316196200Sscottl
317196200Sscottl	return (error);
318196200Sscottl}
319196200SscottlMFI_COMMAND(top, cache, volume_cache);
320196200Sscottl
321196200Sscottlstatic int
322196200Sscottlvolume_name(int ac, char **av)
323196200Sscottl{
324196200Sscottl	struct mfi_ld_props props;
325214396Sjhb	int error, fd;
326196200Sscottl	uint8_t target_id;
327196200Sscottl
328196200Sscottl	if (ac != 3) {
329196200Sscottl		warnx("name: volume and name required");
330196200Sscottl		return (EINVAL);
331196200Sscottl	}
332196200Sscottl
333196200Sscottl	if (strlen(av[2]) >= sizeof(props.name)) {
334196200Sscottl		warnx("name: new name is too long");
335196200Sscottl		return (ENOSPC);
336196200Sscottl	}
337196200Sscottl
338196200Sscottl	fd = mfi_open(mfi_unit);
339196200Sscottl	if (fd < 0) {
340214396Sjhb		error = errno;
341196200Sscottl		warn("mfi_open");
342214396Sjhb		return (error);
343196200Sscottl	}
344196200Sscottl
345196200Sscottl	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
346214396Sjhb		error = errno;
347196200Sscottl		warn("Invalid volume: %s", av[1]);
348214396Sjhb		return (error);
349196200Sscottl	}
350196200Sscottl
351196200Sscottl	if (mfi_ld_get_props(fd, target_id, &props) < 0) {
352214396Sjhb		error = errno;
353196200Sscottl		warn("Failed to fetch volume properties");
354214396Sjhb		return (error);
355196200Sscottl	}
356196200Sscottl
357196200Sscottl	printf("mfi%u volume %s name changed from \"%s\" to \"%s\"\n", mfi_unit,
358196200Sscottl	    mfi_volume_name(fd, target_id), props.name, av[2]);
359196200Sscottl	bzero(props.name, sizeof(props.name));
360196200Sscottl	strcpy(props.name, av[2]);
361196200Sscottl	if (mfi_ld_set_props(fd, &props) < 0) {
362214396Sjhb		error = errno;
363196200Sscottl		warn("Failed to set volume properties");
364214396Sjhb		return (error);
365196200Sscottl	}
366196200Sscottl
367196200Sscottl	close(fd);
368196200Sscottl
369196200Sscottl	return (0);
370196200Sscottl}
371196200SscottlMFI_COMMAND(top, name, volume_name);
372196200Sscottl
373196200Sscottlstatic int
374196200Sscottlvolume_progress(int ac, char **av)
375196200Sscottl{
376196200Sscottl	struct mfi_ld_info info;
377214396Sjhb	int error, fd;
378196200Sscottl	uint8_t target_id;
379196200Sscottl
380196200Sscottl	if (ac != 2) {
381196200Sscottl		warnx("volume progress: %s", ac > 2 ? "extra arguments" :
382196200Sscottl		    "volume required");
383196200Sscottl		return (EINVAL);
384196200Sscottl	}
385196200Sscottl
386196200Sscottl	fd = mfi_open(mfi_unit);
387196200Sscottl	if (fd < 0) {
388214396Sjhb		error = errno;
389196200Sscottl		warn("mfi_open");
390214396Sjhb		return (error);
391196200Sscottl	}
392196200Sscottl
393196200Sscottl	if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
394214396Sjhb		error = errno;
395196200Sscottl		warn("Invalid volume: %s", av[1]);
396214396Sjhb		return (error);
397196200Sscottl	}
398196200Sscottl
399196200Sscottl	/* Get the info for this drive. */
400196200Sscottl	if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
401214396Sjhb		error = errno;
402196200Sscottl		warn("Failed to fetch info for volume %s",
403196200Sscottl		    mfi_volume_name(fd, target_id));
404214396Sjhb		return (error);
405196200Sscottl	}
406196200Sscottl
407196200Sscottl	/* Display any of the active events. */
408196200Sscottl	if (info.progress.active & MFI_LD_PROGRESS_CC)
409196200Sscottl		mfi_display_progress("Consistency Check", &info.progress.cc);
410196200Sscottl	if (info.progress.active & MFI_LD_PROGRESS_BGI)
411196200Sscottl		mfi_display_progress("Background Init", &info.progress.bgi);
412196200Sscottl	if (info.progress.active & MFI_LD_PROGRESS_FGI)
413196200Sscottl		mfi_display_progress("Foreground Init", &info.progress.fgi);
414196200Sscottl	if (info.progress.active & MFI_LD_PROGRESS_RECON)
415196200Sscottl		mfi_display_progress("Reconstruction", &info.progress.recon);
416196200Sscottl	if ((info.progress.active & (MFI_LD_PROGRESS_CC | MFI_LD_PROGRESS_BGI |
417196200Sscottl	    MFI_LD_PROGRESS_FGI | MFI_LD_PROGRESS_RECON)) == 0)
418196200Sscottl		printf("No activity in progress for volume %s.\n",
419196200Sscottl		    mfi_volume_name(fd, target_id));
420196200Sscottl	close(fd);
421196200Sscottl
422196200Sscottl	return (0);
423196200Sscottl}
424196200SscottlMFI_COMMAND(volume, progress, volume_progress);
425