1196212Sscottl/*-
2196212Sscottl * Copyright (c) 2008 Yahoo!, Inc.
3196212Sscottl * All rights reserved.
4196212Sscottl * Written by: John Baldwin <jhb@FreeBSD.org>
5196212Sscottl *
6196212Sscottl * Redistribution and use in source and binary forms, with or without
7196212Sscottl * modification, are permitted provided that the following conditions
8196212Sscottl * are met:
9196212Sscottl * 1. Redistributions of source code must retain the above copyright
10196212Sscottl *    notice, this list of conditions and the following disclaimer.
11196212Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12196212Sscottl *    notice, this list of conditions and the following disclaimer in the
13196212Sscottl *    documentation and/or other materials provided with the distribution.
14196212Sscottl * 3. Neither the name of the author nor the names of any co-contributors
15196212Sscottl *    may be used to endorse or promote products derived from this software
16196212Sscottl *    without specific prior written permission.
17196212Sscottl *
18196212Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19196212Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20196212Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21196212Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22196212Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23196212Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24196212Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25196212Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26196212Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27196212Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28196212Sscottl * SUCH DAMAGE.
29196212Sscottl */
30196212Sscottl
31196212Sscottl#include <sys/cdefs.h>
32196212Sscottl__RCSID("$FreeBSD$");
33196212Sscottl
34196212Sscottl#include <sys/param.h>
35196212Sscottl#include <sys/errno.h>
36196212Sscottl#include <err.h>
37196212Sscottl#include <libutil.h>
38196212Sscottl#include <stdio.h>
39196212Sscottl#include <stdlib.h>
40196212Sscottl#include <string.h>
41196212Sscottl#include <unistd.h>
42196212Sscottl#include <ctype.h>
43196212Sscottl#include "mptutil.h"
44196212Sscottl
45196212SscottlMPT_TABLE(top, volume);
46196212Sscottl
47196212Sscottlconst char *
48196212Sscottlmpt_volstate(U8 State)
49196212Sscottl{
50196212Sscottl	static char buf[16];
51196212Sscottl
52196212Sscottl	switch (State) {
53196212Sscottl	case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
54196212Sscottl		return ("OPTIMAL");
55196212Sscottl	case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
56196212Sscottl		return ("DEGRADED");
57196212Sscottl	case MPI_RAIDVOL0_STATUS_STATE_FAILED:
58196212Sscottl		return ("FAILED");
59196212Sscottl	case MPI_RAIDVOL0_STATUS_STATE_MISSING:
60196212Sscottl		return ("MISSING");
61196212Sscottl	default:
62196212Sscottl		sprintf(buf, "VSTATE 0x%02x", State);
63196212Sscottl		return (buf);
64196212Sscottl	}
65196212Sscottl}
66196212Sscottl
67196212Sscottlstatic int
68196212Sscottlvolume_name(int ac, char **av)
69196212Sscottl{
70196212Sscottl	CONFIG_PAGE_RAID_VOL_1 *vnames;
71196212Sscottl	U8 VolumeBus, VolumeID;
72215046Sjhb	int error, fd;
73196212Sscottl
74196212Sscottl	if (ac != 3) {
75196212Sscottl		warnx("name: volume and name required");
76196212Sscottl		return (EINVAL);
77196212Sscottl	}
78196212Sscottl
79196212Sscottl	if (strlen(av[2]) >= sizeof(vnames->Name)) {
80196212Sscottl		warnx("name: new name is too long");
81196212Sscottl		return (ENOSPC);
82196212Sscottl	}
83196212Sscottl
84196212Sscottl	fd = mpt_open(mpt_unit);
85196212Sscottl	if (fd < 0) {
86215046Sjhb		error = errno;
87196212Sscottl		warn("mpt_open");
88215046Sjhb		return (error);
89196212Sscottl	}
90196212Sscottl
91215046Sjhb	error = mpt_lookup_volume(fd, av[1], &VolumeBus, &VolumeID);
92215046Sjhb	if (error) {
93215046Sjhb		warnc(error, "Invalid volume: %s", av[1]);
94215046Sjhb		return (error);
95196212Sscottl	}
96196212Sscottl
97196212Sscottl	vnames = mpt_vol_names(fd, VolumeBus, VolumeID, NULL);
98196212Sscottl	if (vnames == NULL) {
99215046Sjhb		error = errno;
100196212Sscottl		warn("Failed to fetch volume names");
101215046Sjhb		return (error);
102196212Sscottl	}
103196212Sscottl
104196212Sscottl	if (vnames->Header.PageType != MPI_CONFIG_PAGEATTR_CHANGEABLE) {
105196212Sscottl		warnx("Volume name is read only");
106196212Sscottl		return (EOPNOTSUPP);
107196212Sscottl	}
108196212Sscottl	printf("mpt%u changing volume %s name from \"%s\" to \"%s\"\n",
109196212Sscottl	    mpt_unit, mpt_volume_name(VolumeBus, VolumeID), vnames->Name,
110196212Sscottl	    av[2]);
111196212Sscottl	bzero(vnames->Name, sizeof(vnames->Name));
112196212Sscottl	strcpy(vnames->Name, av[2]);
113196212Sscottl
114196212Sscottl	if (mpt_write_config_page(fd, vnames, NULL) < 0) {
115215046Sjhb		error = errno;
116196212Sscottl		warn("Failed to set volume name");
117215046Sjhb		return (error);
118196212Sscottl	}
119196212Sscottl
120196212Sscottl	free(vnames);
121196212Sscottl	close(fd);
122196212Sscottl
123196212Sscottl	return (0);
124196212Sscottl}
125196212SscottlMPT_COMMAND(top, name, volume_name);
126196212Sscottl
127196212Sscottlstatic int
128196212Sscottlvolume_status(int ac, char **av)
129196212Sscottl{
130196212Sscottl	MPI_RAID_VOL_INDICATOR prog;
131196212Sscottl	RAID_VOL0_STATUS VolumeStatus;
132196212Sscottl	uint64_t total, remaining;
133196212Sscottl	float pct;
134196212Sscottl	U8 VolumeBus, VolumeID;
135215046Sjhb	int error, fd;
136196212Sscottl
137196212Sscottl	if (ac != 2) {
138196212Sscottl		warnx("volume status: %s", ac > 2 ? "extra arguments" :
139196212Sscottl		    "volume required");
140196212Sscottl		return (EINVAL);
141196212Sscottl	}
142196212Sscottl
143196212Sscottl	fd = mpt_open(mpt_unit);
144196212Sscottl	if (fd < 0) {
145215046Sjhb		error = errno;
146196212Sscottl		warn("mpt_open");
147215046Sjhb		return (error);
148196212Sscottl	}
149196212Sscottl
150215046Sjhb	error = mpt_lookup_volume(fd, av[1], &VolumeBus, &VolumeID);
151215046Sjhb	if (error) {
152215046Sjhb		warnc(error, "Invalid volume: %s", av[1]);
153215046Sjhb		return (error);
154196212Sscottl	}
155196212Sscottl
156215046Sjhb	error = mpt_raid_action(fd, MPI_RAID_ACTION_INDICATOR_STRUCT, VolumeBus,
157196212Sscottl	    VolumeID, 0, 0, NULL, 0, &VolumeStatus, (U32 *)&prog, sizeof(prog),
158215046Sjhb	    NULL, NULL, 0);
159215046Sjhb	if (error) {
160215046Sjhb		warnc(error, "Fetching volume status failed");
161215046Sjhb		return (error);
162196212Sscottl	}
163196212Sscottl
164196212Sscottl	printf("Volume %s status:\n", mpt_volume_name(VolumeBus, VolumeID));
165196212Sscottl	printf("    state: %s\n", mpt_volstate(VolumeStatus.State));
166196212Sscottl	printf("    flags:");
167196212Sscottl	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)
168196212Sscottl		printf(" ENABLED");
169196212Sscottl	else
170196212Sscottl		printf(" DISABLED");
171196212Sscottl	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED)
172196212Sscottl		printf(", QUIESCED");
173196212Sscottl	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
174196212Sscottl		printf(", REBUILDING");
175196212Sscottl	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)
176196212Sscottl		printf(", INACTIVE");
177196212Sscottl	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL)
178196212Sscottl		printf(", BAD BLOCK TABLE FULL");
179196212Sscottl	printf("\n");
180196212Sscottl	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
181196212Sscottl		total = (uint64_t)prog.TotalBlocks.High << 32 |
182196212Sscottl		    prog.TotalBlocks.Low;
183196212Sscottl		remaining = (uint64_t)prog.BlocksRemaining.High << 32 |
184196212Sscottl		    prog.BlocksRemaining.Low;
185196212Sscottl		pct = (float)(total - remaining) * 100 / total;
186196212Sscottl		printf("   resync: %.2f%% complete\n", pct);
187196212Sscottl	}
188196212Sscottl
189196212Sscottl	close(fd);
190196212Sscottl	return (0);
191196212Sscottl}
192196212SscottlMPT_COMMAND(volume, status, volume_status);
193196212Sscottl
194196212Sscottlstatic int
195196212Sscottlvolume_cache(int ac, char **av)
196196212Sscottl{
197196212Sscottl	CONFIG_PAGE_RAID_VOL_0 *volume;
198196212Sscottl	U32 Settings, NewSettings;
199196212Sscottl	U8 VolumeBus, VolumeID;
200196212Sscottl	char *s1;
201215046Sjhb	int error, fd;
202196212Sscottl
203196212Sscottl	if (ac != 3) {
204196212Sscottl		warnx("volume cache: %s", ac > 3 ? "extra arguments" :
205215046Sjhb		    "missing arguments");
206196212Sscottl		return (EINVAL);
207196212Sscottl	}
208196212Sscottl
209196212Sscottl        for (s1 = av[2]; *s1 != '\0'; s1++)
210196212Sscottl                *s1 = tolower(*s1);
211196212Sscottl	if ((strcmp(av[2], "enable")) && (strcmp(av[2], "enabled")) &&
212196212Sscottl	    (strcmp(av[2], "disable")) && (strcmp(av[2], "disabled"))) {
213196212Sscottl		warnx("volume cache: invalid flag, must be 'enable' or 'disable'\n");
214196212Sscottl		return (EINVAL);
215196212Sscottl	}
216196212Sscottl
217196212Sscottl	fd = mpt_open(mpt_unit);
218196212Sscottl	if (fd < 0) {
219215046Sjhb		error = errno;
220196212Sscottl		warn("mpt_open");
221215046Sjhb		return (error);
222196212Sscottl	}
223196212Sscottl
224215046Sjhb	error = mpt_lookup_volume(fd, av[1], &VolumeBus, &VolumeID);
225215046Sjhb	if (error) {
226215046Sjhb		warnc(error, "Invalid volume: %s", av[1]);
227215046Sjhb		return (error);
228196212Sscottl	}
229196212Sscottl
230196212Sscottl	volume = mpt_vol_info(fd, VolumeBus, VolumeID, NULL);
231196212Sscottl	if (volume == NULL)
232215046Sjhb		return (errno);
233196212Sscottl
234196212Sscottl	Settings = volume->VolumeSettings.Settings;
235196212Sscottl
236196212Sscottl	NewSettings = Settings;
237196212Sscottl	if (strncmp(av[2], "enable", sizeof("enable")) == 0)
238196212Sscottl		NewSettings |= 0x01;
239196212Sscottl	if (strncmp(av[2], "disable", sizeof("disable")) == 0)
240196212Sscottl		NewSettings &= ~0x01;
241196212Sscottl
242196212Sscottl	if (NewSettings == Settings) {
243215046Sjhb		warnx("volume cache unchanged");
244196212Sscottl		close(fd);
245196212Sscottl		return (0);
246196212Sscottl	}
247196212Sscottl
248196212Sscottl	volume->VolumeSettings.Settings = NewSettings;
249215046Sjhb	error = mpt_raid_action(fd, MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS,
250196212Sscottl	    VolumeBus, VolumeID, 0, *(U32 *)&volume->VolumeSettings, NULL, 0,
251215046Sjhb	    NULL, NULL, 0, NULL, NULL, 0);
252215046Sjhb	if (error)
253215046Sjhb		warnc(error, "volume cache change failed");
254196212Sscottl
255196212Sscottl	close(fd);
256215046Sjhb	return (error);
257196212Sscottl}
258196212SscottlMPT_COMMAND(volume, cache, volume_cache);
259