xref: /freebsd/usr.sbin/mptutil/mpt_volume.c (revision 5f4c09dd85bff675e0ca63c55ea3c517e0fddfcc)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2008 Yahoo!, Inc.
5  * All rights reserved.
6  * Written by: John Baldwin <jhb@FreeBSD.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 #include <sys/param.h>
35 #include <sys/errno.h>
36 #include <err.h>
37 #include <libutil.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <ctype.h>
43 #include "mptutil.h"
44 
45 MPT_TABLE(top, volume);
46 
47 const char *
48 mpt_volstate(U8 State)
49 {
50 	static char buf[16];
51 
52 	switch (State) {
53 	case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
54 		return ("OPTIMAL");
55 	case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
56 		return ("DEGRADED");
57 	case MPI_RAIDVOL0_STATUS_STATE_FAILED:
58 		return ("FAILED");
59 	case MPI_RAIDVOL0_STATUS_STATE_MISSING:
60 		return ("MISSING");
61 	default:
62 		sprintf(buf, "VSTATE 0x%02x", State);
63 		return (buf);
64 	}
65 }
66 
67 static int
68 volume_name(int ac, char **av)
69 {
70 	CONFIG_PAGE_RAID_VOL_1 *vnames;
71 	U8 VolumeBus, VolumeID;
72 	int error, fd;
73 
74 	if (ac != 3) {
75 		warnx("name: volume and name required");
76 		return (EINVAL);
77 	}
78 
79 	if (strlen(av[2]) >= sizeof(vnames->Name)) {
80 		warnx("name: new name is too long");
81 		return (ENOSPC);
82 	}
83 
84 	fd = mpt_open(mpt_unit);
85 	if (fd < 0) {
86 		error = errno;
87 		warn("mpt_open");
88 		return (error);
89 	}
90 
91 	error = mpt_lookup_volume(fd, av[1], &VolumeBus, &VolumeID);
92 	if (error) {
93 		warnc(error, "Invalid volume: %s", av[1]);
94 		return (error);
95 	}
96 
97 	vnames = mpt_vol_names(fd, VolumeBus, VolumeID, NULL);
98 	if (vnames == NULL) {
99 		error = errno;
100 		warn("Failed to fetch volume names");
101 		close(fd);
102 		return (error);
103 	}
104 
105 	if (vnames->Header.PageType != MPI_CONFIG_PAGEATTR_CHANGEABLE) {
106 		warnx("Volume name is read only");
107 		free(vnames);
108 		close(fd);
109 		return (EOPNOTSUPP);
110 	}
111 	printf("mpt%u changing volume %s name from \"%s\" to \"%s\"\n",
112 	    mpt_unit, mpt_volume_name(VolumeBus, VolumeID), vnames->Name,
113 	    av[2]);
114 	bzero(vnames->Name, sizeof(vnames->Name));
115 	strcpy(vnames->Name, av[2]);
116 
117 	if (mpt_write_config_page(fd, vnames, NULL) < 0) {
118 		error = errno;
119 		warn("Failed to set volume name");
120 		free(vnames);
121 		close(fd);
122 		return (error);
123 	}
124 
125 	free(vnames);
126 	close(fd);
127 
128 	return (0);
129 }
130 MPT_COMMAND(top, name, volume_name);
131 
132 static int
133 volume_status(int ac, char **av)
134 {
135 	MPI_RAID_VOL_INDICATOR prog;
136 	RAID_VOL0_STATUS VolumeStatus;
137 	uint64_t total, remaining;
138 	float pct;
139 	U8 VolumeBus, VolumeID;
140 	int error, fd;
141 
142 	if (ac != 2) {
143 		warnx("volume status: %s", ac > 2 ? "extra arguments" :
144 		    "volume required");
145 		return (EINVAL);
146 	}
147 
148 	fd = mpt_open(mpt_unit);
149 	if (fd < 0) {
150 		error = errno;
151 		warn("mpt_open");
152 		return (error);
153 	}
154 
155 	error = mpt_lookup_volume(fd, av[1], &VolumeBus, &VolumeID);
156 	if (error) {
157 		warnc(error, "Invalid volume: %s", av[1]);
158 		close(fd);
159 		return (error);
160 	}
161 
162 	error = mpt_raid_action(fd, MPI_RAID_ACTION_INDICATOR_STRUCT, VolumeBus,
163 	    VolumeID, 0, 0, NULL, 0, &VolumeStatus, (U32 *)&prog, sizeof(prog),
164 	    NULL, NULL, 0);
165 	if (error) {
166 		warnc(error, "Fetching volume status failed");
167 		close(fd);
168 		return (error);
169 	}
170 
171 	printf("Volume %s status:\n", mpt_volume_name(VolumeBus, VolumeID));
172 	printf("    state: %s\n", mpt_volstate(VolumeStatus.State));
173 	printf("    flags:");
174 	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)
175 		printf(" ENABLED");
176 	else
177 		printf(" DISABLED");
178 	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED)
179 		printf(", QUIESCED");
180 	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
181 		printf(", REBUILDING");
182 	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)
183 		printf(", INACTIVE");
184 	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL)
185 		printf(", BAD BLOCK TABLE FULL");
186 	printf("\n");
187 	if (VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
188 		total = (uint64_t)prog.TotalBlocks.High << 32 |
189 		    prog.TotalBlocks.Low;
190 		remaining = (uint64_t)prog.BlocksRemaining.High << 32 |
191 		    prog.BlocksRemaining.Low;
192 		pct = (float)(total - remaining) * 100 / total;
193 		printf("   resync: %.2f%% complete\n", pct);
194 	}
195 
196 	close(fd);
197 	return (0);
198 }
199 MPT_COMMAND(volume, status, volume_status);
200 
201 static int
202 volume_cache(int ac, char **av)
203 {
204 	CONFIG_PAGE_RAID_VOL_0 *volume;
205 	U32 Settings, NewSettings;
206 	U8 VolumeBus, VolumeID;
207 	char *s1;
208 	int error, fd;
209 
210 	if (ac != 3) {
211 		warnx("volume cache: %s", ac > 3 ? "extra arguments" :
212 		    "missing arguments");
213 		return (EINVAL);
214 	}
215 
216         for (s1 = av[2]; *s1 != '\0'; s1++)
217                 *s1 = tolower(*s1);
218 	if ((strcmp(av[2], "enable")) && (strcmp(av[2], "enabled")) &&
219 	    (strcmp(av[2], "disable")) && (strcmp(av[2], "disabled"))) {
220 		warnx("volume cache: invalid flag; "
221 		    "must be 'enable', 'enabled', 'disable', or 'disabled'");
222 		return (EINVAL);
223 	}
224 
225 	fd = mpt_open(mpt_unit);
226 	if (fd < 0) {
227 		error = errno;
228 		warn("mpt_open");
229 		return (error);
230 	}
231 
232 	error = mpt_lookup_volume(fd, av[1], &VolumeBus, &VolumeID);
233 	if (error) {
234 		warnc(error, "Invalid volume: %s", av[1]);
235 		close(fd);
236 		return (error);
237 	}
238 
239 	volume = mpt_vol_info(fd, VolumeBus, VolumeID, NULL);
240 	if (volume == NULL) {
241 		close(fd);
242 		return (errno);
243 	}
244 
245 	Settings = volume->VolumeSettings.Settings;
246 
247 	NewSettings = Settings;
248 	if (strncmp(av[2], "enable", strlen("enable")) == 0)
249 		NewSettings |= 0x01;
250 	else if (strncmp(av[2], "disable", strlen("disable")) == 0)
251 		NewSettings &= ~0x01;
252 
253 	if (NewSettings == Settings) {
254 		warnx("volume cache unchanged");
255 		free(volume);
256 		close(fd);
257 		return (0);
258 	}
259 
260 	volume->VolumeSettings.Settings = NewSettings;
261 	error = mpt_raid_action(fd, MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS,
262 	    VolumeBus, VolumeID, 0, *(U32 *)&volume->VolumeSettings, NULL, 0,
263 	    NULL, NULL, 0, NULL, NULL, 0);
264 	if (error)
265 		warnc(error, "volume cache change failed");
266 
267 	close(fd);
268 	return (error);
269 }
270 MPT_COMMAND(volume, cache, volume_cache);
271