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