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