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: releng/11.0/usr.sbin/mfiutil/mfi_volume.c 249257 2013-04-08 17:46:45Z markj $ 30196200Sscottl */ 31196200Sscottl 32196200Sscottl#include <sys/types.h> 33196200Sscottl#include <sys/errno.h> 34196200Sscottl#include <err.h> 35237259Seadler#include <fcntl.h> 36196200Sscottl#include <libutil.h> 37196200Sscottl#include <stdio.h> 38196200Sscottl#include <stdlib.h> 39196200Sscottl#include <string.h> 40196200Sscottl#include <unistd.h> 41196200Sscottl#include "mfiutil.h" 42196200Sscottl 43196200SscottlMFI_TABLE(top, volume); 44196200Sscottl 45196200Sscottlconst char * 46196200Sscottlmfi_ldstate(enum mfi_ld_state state) 47196200Sscottl{ 48196200Sscottl static char buf[16]; 49196200Sscottl 50196200Sscottl switch (state) { 51196200Sscottl case MFI_LD_STATE_OFFLINE: 52196200Sscottl return ("OFFLINE"); 53196200Sscottl case MFI_LD_STATE_PARTIALLY_DEGRADED: 54196200Sscottl return ("PARTIALLY DEGRADED"); 55196200Sscottl case MFI_LD_STATE_DEGRADED: 56196200Sscottl return ("DEGRADED"); 57196200Sscottl case MFI_LD_STATE_OPTIMAL: 58196200Sscottl return ("OPTIMAL"); 59196200Sscottl default: 60196200Sscottl sprintf(buf, "LSTATE 0x%02x", state); 61196200Sscottl return (buf); 62196200Sscottl } 63196200Sscottl} 64196200Sscottl 65196200Sscottlvoid 66196200Sscottlmbox_store_ldref(uint8_t *mbox, union mfi_ld_ref *ref) 67196200Sscottl{ 68196200Sscottl 69196200Sscottl mbox[0] = ref->v.target_id; 70196200Sscottl mbox[1] = ref->v.reserved; 71196200Sscottl mbox[2] = ref->v.seq & 0xff; 72196200Sscottl mbox[3] = ref->v.seq >> 8; 73196200Sscottl} 74196200Sscottl 75196200Sscottlint 76196200Sscottlmfi_ld_get_list(int fd, struct mfi_ld_list *list, uint8_t *statusp) 77196200Sscottl{ 78196200Sscottl 79196200Sscottl return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_LIST, list, 80196200Sscottl sizeof(struct mfi_ld_list), NULL, 0, statusp)); 81196200Sscottl} 82196200Sscottl 83196200Sscottlint 84196200Sscottlmfi_ld_get_info(int fd, uint8_t target_id, struct mfi_ld_info *info, 85196200Sscottl uint8_t *statusp) 86196200Sscottl{ 87196200Sscottl uint8_t mbox[1]; 88196200Sscottl 89196200Sscottl mbox[0] = target_id; 90196200Sscottl return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_INFO, info, 91196200Sscottl sizeof(struct mfi_ld_info), mbox, 1, statusp)); 92196200Sscottl} 93196200Sscottl 94196200Sscottlstatic int 95196200Sscottlmfi_ld_get_props(int fd, uint8_t target_id, struct mfi_ld_props *props) 96196200Sscottl{ 97196200Sscottl uint8_t mbox[1]; 98196200Sscottl 99196200Sscottl mbox[0] = target_id; 100196200Sscottl return (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_PROP, props, 101196200Sscottl sizeof(struct mfi_ld_props), mbox, 1, NULL)); 102196200Sscottl} 103196200Sscottl 104196200Sscottlstatic int 105196200Sscottlmfi_ld_set_props(int fd, struct mfi_ld_props *props) 106196200Sscottl{ 107196200Sscottl uint8_t mbox[4]; 108196200Sscottl 109196200Sscottl mbox_store_ldref(mbox, &props->ld); 110196200Sscottl return (mfi_dcmd_command(fd, MFI_DCMD_LD_SET_PROP, props, 111196200Sscottl sizeof(struct mfi_ld_props), mbox, 4, NULL)); 112196200Sscottl} 113196200Sscottl 114196200Sscottlstatic int 115225331Sjhbupdate_cache_policy(int fd, struct mfi_ld_props *old, struct mfi_ld_props *new) 116196200Sscottl{ 117214396Sjhb int error; 118196200Sscottl uint8_t changes, policy; 119196200Sscottl 120225331Sjhb if (old->default_cache_policy == new->default_cache_policy && 121225331Sjhb old->disk_cache_policy == new->disk_cache_policy) 122196200Sscottl return (0); 123225331Sjhb policy = new->default_cache_policy; 124225331Sjhb changes = policy ^ old->default_cache_policy; 125196200Sscottl if (changes & MR_LD_CACHE_ALLOW_WRITE_CACHE) 126196200Sscottl printf("%s caching of I/O writes\n", 127196200Sscottl policy & MR_LD_CACHE_ALLOW_WRITE_CACHE ? "Enabling" : 128196200Sscottl "Disabling"); 129196200Sscottl if (changes & MR_LD_CACHE_ALLOW_READ_CACHE) 130196200Sscottl printf("%s caching of I/O reads\n", 131196200Sscottl policy & MR_LD_CACHE_ALLOW_READ_CACHE ? "Enabling" : 132196200Sscottl "Disabling"); 133196200Sscottl if (changes & MR_LD_CACHE_WRITE_BACK) 134196200Sscottl printf("Setting write cache policy to %s\n", 135196200Sscottl policy & MR_LD_CACHE_WRITE_BACK ? "write-back" : 136196200Sscottl "write-through"); 137196200Sscottl if (changes & (MR_LD_CACHE_READ_AHEAD | MR_LD_CACHE_READ_ADAPTIVE)) 138196200Sscottl printf("Setting read ahead policy to %s\n", 139196200Sscottl policy & MR_LD_CACHE_READ_AHEAD ? 140196200Sscottl (policy & MR_LD_CACHE_READ_ADAPTIVE ? 141196200Sscottl "adaptive" : "always") : "none"); 142220363Sjhb if (changes & MR_LD_CACHE_WRITE_CACHE_BAD_BBU) 143220363Sjhb printf("%s write caching with bad BBU\n", 144220363Sjhb policy & MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "Enabling" : 145220363Sjhb "Disabling"); 146225331Sjhb if (old->disk_cache_policy != new->disk_cache_policy) { 147225331Sjhb switch (new->disk_cache_policy) { 148225331Sjhb case MR_PD_CACHE_ENABLE: 149225331Sjhb printf("Enabling write-cache on physical drives\n"); 150225331Sjhb break; 151225331Sjhb case MR_PD_CACHE_DISABLE: 152225331Sjhb printf("Disabling write-cache on physical drives\n"); 153225331Sjhb break; 154225331Sjhb case MR_PD_CACHE_UNCHANGED: 155225331Sjhb printf("Using default write-cache setting on physical drives\n"); 156225331Sjhb break; 157225331Sjhb } 158225331Sjhb } 159196200Sscottl 160225331Sjhb if (mfi_ld_set_props(fd, new) < 0) { 161214396Sjhb error = errno; 162196200Sscottl warn("Failed to set volume properties"); 163214396Sjhb return (error); 164196200Sscottl } 165196200Sscottl return (0); 166196200Sscottl} 167196200Sscottl 168225331Sjhbstatic void 169225331Sjhbstage_cache_setting(struct mfi_ld_props *props, uint8_t new_policy, 170225331Sjhb uint8_t mask) 171225331Sjhb{ 172225331Sjhb 173225331Sjhb props->default_cache_policy &= ~mask; 174225331Sjhb props->default_cache_policy |= new_policy; 175225331Sjhb} 176225331Sjhb 177225331Sjhb/* 178225331Sjhb * Parse a single cache directive modifying the passed in policy. 179225331Sjhb * Returns -1 on a parse error and the number of arguments consumed 180225331Sjhb * on success. 181225331Sjhb */ 182196200Sscottlstatic int 183225331Sjhbprocess_cache_command(int ac, char **av, struct mfi_ld_props *props) 184225331Sjhb{ 185225331Sjhb uint8_t policy; 186225331Sjhb 187225331Sjhb /* I/O cache settings. */ 188225331Sjhb if (strcmp(av[0], "all") == 0 || strcmp(av[0], "enable") == 0) { 189225331Sjhb stage_cache_setting(props, MR_LD_CACHE_ALLOW_READ_CACHE | 190225331Sjhb MR_LD_CACHE_ALLOW_WRITE_CACHE, 191225331Sjhb MR_LD_CACHE_ALLOW_READ_CACHE | 192225331Sjhb MR_LD_CACHE_ALLOW_WRITE_CACHE); 193225331Sjhb return (1); 194225331Sjhb } 195225331Sjhb if (strcmp(av[0], "none") == 0 || strcmp(av[0], "disable") == 0) { 196225331Sjhb stage_cache_setting(props, 0, MR_LD_CACHE_ALLOW_READ_CACHE | 197225331Sjhb MR_LD_CACHE_ALLOW_WRITE_CACHE); 198225331Sjhb return (1); 199225331Sjhb } 200225331Sjhb if (strcmp(av[0], "reads") == 0) { 201225331Sjhb stage_cache_setting(props, MR_LD_CACHE_ALLOW_READ_CACHE, 202225331Sjhb MR_LD_CACHE_ALLOW_READ_CACHE | 203225331Sjhb MR_LD_CACHE_ALLOW_WRITE_CACHE); 204225331Sjhb return (1); 205225331Sjhb } 206225331Sjhb if (strcmp(av[0], "writes") == 0) { 207225331Sjhb stage_cache_setting(props, MR_LD_CACHE_ALLOW_WRITE_CACHE, 208225331Sjhb MR_LD_CACHE_ALLOW_READ_CACHE | 209225331Sjhb MR_LD_CACHE_ALLOW_WRITE_CACHE); 210225331Sjhb return (1); 211225331Sjhb } 212225331Sjhb 213225331Sjhb /* Write cache behavior. */ 214225331Sjhb if (strcmp(av[0], "write-back") == 0) { 215225331Sjhb stage_cache_setting(props, MR_LD_CACHE_WRITE_BACK, 216225331Sjhb MR_LD_CACHE_WRITE_BACK); 217225331Sjhb return (1); 218225331Sjhb } 219225331Sjhb if (strcmp(av[0], "write-through") == 0) { 220225331Sjhb stage_cache_setting(props, 0, MR_LD_CACHE_WRITE_BACK); 221225331Sjhb return (1); 222225331Sjhb } 223225331Sjhb if (strcmp(av[0], "bad-bbu-write-cache") == 0) { 224225331Sjhb if (ac < 2) { 225225331Sjhb warnx("cache: bad BBU setting required"); 226225331Sjhb return (-1); 227225331Sjhb } 228225331Sjhb if (strcmp(av[1], "enable") == 0) 229225331Sjhb policy = MR_LD_CACHE_WRITE_CACHE_BAD_BBU; 230225331Sjhb else if (strcmp(av[1], "disable") == 0) 231225331Sjhb policy = 0; 232225331Sjhb else { 233225331Sjhb warnx("cache: invalid bad BBU setting"); 234225331Sjhb return (-1); 235225331Sjhb } 236225331Sjhb stage_cache_setting(props, policy, 237225331Sjhb MR_LD_CACHE_WRITE_CACHE_BAD_BBU); 238225331Sjhb return (2); 239225331Sjhb } 240225331Sjhb 241225331Sjhb /* Read cache behavior. */ 242225331Sjhb if (strcmp(av[0], "read-ahead") == 0) { 243225331Sjhb if (ac < 2) { 244225331Sjhb warnx("cache: read-ahead setting required"); 245225331Sjhb return (-1); 246225331Sjhb } 247225331Sjhb if (strcmp(av[1], "none") == 0) 248225331Sjhb policy = 0; 249225331Sjhb else if (strcmp(av[1], "always") == 0) 250225331Sjhb policy = MR_LD_CACHE_READ_AHEAD; 251225331Sjhb else if (strcmp(av[1], "adaptive") == 0) 252225331Sjhb policy = MR_LD_CACHE_READ_AHEAD | 253225331Sjhb MR_LD_CACHE_READ_ADAPTIVE; 254225331Sjhb else { 255225331Sjhb warnx("cache: invalid read-ahead setting"); 256225331Sjhb return (-1); 257225331Sjhb } 258225331Sjhb stage_cache_setting(props, policy, MR_LD_CACHE_READ_AHEAD | 259225331Sjhb MR_LD_CACHE_READ_ADAPTIVE); 260225331Sjhb return (2); 261225331Sjhb } 262225331Sjhb 263225331Sjhb /* Drive write-cache behavior. */ 264225331Sjhb if (strcmp(av[0], "write-cache") == 0) { 265225331Sjhb if (ac < 2) { 266225331Sjhb warnx("cache: write-cache setting required"); 267225331Sjhb return (-1); 268225331Sjhb } 269225331Sjhb if (strcmp(av[1], "enable") == 0) 270225331Sjhb props->disk_cache_policy = MR_PD_CACHE_ENABLE; 271225331Sjhb else if (strcmp(av[1], "disable") == 0) 272225331Sjhb props->disk_cache_policy = MR_PD_CACHE_DISABLE; 273225331Sjhb else if (strcmp(av[1], "default") == 0) 274225331Sjhb props->disk_cache_policy = MR_PD_CACHE_UNCHANGED; 275225331Sjhb else { 276225331Sjhb warnx("cache: invalid write-cache setting"); 277225331Sjhb return (-1); 278225331Sjhb } 279225331Sjhb return (2); 280225331Sjhb } 281225331Sjhb 282225331Sjhb warnx("cache: Invalid command"); 283225331Sjhb return (-1); 284225331Sjhb} 285225331Sjhb 286225331Sjhbstatic int 287196200Sscottlvolume_cache(int ac, char **av) 288196200Sscottl{ 289225331Sjhb struct mfi_ld_props props, new; 290225331Sjhb int error, fd, consumed; 291225331Sjhb uint8_t target_id; 292196200Sscottl 293196200Sscottl if (ac < 2) { 294196200Sscottl warnx("cache: volume required"); 295196200Sscottl return (EINVAL); 296196200Sscottl } 297196200Sscottl 298237259Seadler fd = mfi_open(mfi_unit, O_RDWR); 299196200Sscottl if (fd < 0) { 300214396Sjhb error = errno; 301196200Sscottl warn("mfi_open"); 302214396Sjhb return (error); 303196200Sscottl } 304196200Sscottl 305196200Sscottl if (mfi_lookup_volume(fd, av[1], &target_id) < 0) { 306214396Sjhb error = errno; 307196200Sscottl warn("Invalid volume: %s", av[1]); 308222899Sbz close(fd); 309214396Sjhb return (error); 310196200Sscottl } 311196200Sscottl 312196200Sscottl if (mfi_ld_get_props(fd, target_id, &props) < 0) { 313214396Sjhb error = errno; 314196200Sscottl warn("Failed to fetch volume properties"); 315222899Sbz close(fd); 316214396Sjhb return (error); 317196200Sscottl } 318196200Sscottl 319196200Sscottl if (ac == 2) { 320196200Sscottl printf("mfi%u volume %s cache settings:\n", mfi_unit, 321196200Sscottl mfi_volume_name(fd, target_id)); 322220363Sjhb printf(" I/O caching: "); 323196200Sscottl switch (props.default_cache_policy & 324196200Sscottl (MR_LD_CACHE_ALLOW_WRITE_CACHE | 325196200Sscottl MR_LD_CACHE_ALLOW_READ_CACHE)) { 326196200Sscottl case 0: 327196200Sscottl printf("disabled\n"); 328196200Sscottl break; 329196200Sscottl case MR_LD_CACHE_ALLOW_WRITE_CACHE: 330196200Sscottl printf("writes\n"); 331196200Sscottl break; 332196200Sscottl case MR_LD_CACHE_ALLOW_READ_CACHE: 333196200Sscottl printf("reads\n"); 334196200Sscottl break; 335196200Sscottl case MR_LD_CACHE_ALLOW_WRITE_CACHE | 336196200Sscottl MR_LD_CACHE_ALLOW_READ_CACHE: 337196200Sscottl printf("writes and reads\n"); 338196200Sscottl break; 339196200Sscottl } 340220363Sjhb printf(" write caching: %s\n", 341196200Sscottl props.default_cache_policy & MR_LD_CACHE_WRITE_BACK ? 342196200Sscottl "write-back" : "write-through"); 343220363Sjhb printf("write cache with bad BBU: %s\n", 344220363Sjhb props.default_cache_policy & 345220363Sjhb MR_LD_CACHE_WRITE_CACHE_BAD_BBU ? "enabled" : "disabled"); 346220363Sjhb printf(" read ahead: %s\n", 347196200Sscottl props.default_cache_policy & MR_LD_CACHE_READ_AHEAD ? 348196200Sscottl (props.default_cache_policy & MR_LD_CACHE_READ_ADAPTIVE ? 349196200Sscottl "adaptive" : "always") : "none"); 350220363Sjhb printf(" drive write cache: "); 351196200Sscottl switch (props.disk_cache_policy) { 352196200Sscottl case MR_PD_CACHE_UNCHANGED: 353196200Sscottl printf("default\n"); 354196200Sscottl break; 355196200Sscottl case MR_PD_CACHE_ENABLE: 356196200Sscottl printf("enabled\n"); 357196200Sscottl break; 358196200Sscottl case MR_PD_CACHE_DISABLE: 359196200Sscottl printf("disabled\n"); 360196200Sscottl break; 361196200Sscottl default: 362196200Sscottl printf("??? %d\n", props.disk_cache_policy); 363196200Sscottl break; 364196200Sscottl } 365196200Sscottl if (props.default_cache_policy != props.current_cache_policy) 366249257Smarkj printf( 367249257Smarkj "Cache disabled due to dead battery or ongoing battery relearn\n"); 368196200Sscottl error = 0; 369196200Sscottl } else { 370225331Sjhb new = props; 371225331Sjhb av += 2; 372225331Sjhb ac -= 2; 373225331Sjhb while (ac > 0) { 374225331Sjhb consumed = process_cache_command(ac, av, &new); 375225331Sjhb if (consumed < 0) { 376222899Sbz close(fd); 377196200Sscottl return (EINVAL); 378196200Sscottl } 379225331Sjhb av += consumed; 380225331Sjhb ac -= consumed; 381196200Sscottl } 382225331Sjhb error = update_cache_policy(fd, &props, &new); 383196200Sscottl } 384196200Sscottl close(fd); 385196200Sscottl 386196200Sscottl return (error); 387196200Sscottl} 388196200SscottlMFI_COMMAND(top, cache, volume_cache); 389196200Sscottl 390196200Sscottlstatic int 391196200Sscottlvolume_name(int ac, char **av) 392196200Sscottl{ 393196200Sscottl struct mfi_ld_props props; 394214396Sjhb int error, fd; 395196200Sscottl uint8_t target_id; 396196200Sscottl 397196200Sscottl if (ac != 3) { 398196200Sscottl warnx("name: volume and name required"); 399196200Sscottl return (EINVAL); 400196200Sscottl } 401196200Sscottl 402196200Sscottl if (strlen(av[2]) >= sizeof(props.name)) { 403196200Sscottl warnx("name: new name is too long"); 404196200Sscottl return (ENOSPC); 405196200Sscottl } 406196200Sscottl 407237259Seadler fd = mfi_open(mfi_unit, O_RDWR); 408196200Sscottl if (fd < 0) { 409214396Sjhb error = errno; 410196200Sscottl warn("mfi_open"); 411214396Sjhb return (error); 412196200Sscottl } 413196200Sscottl 414196200Sscottl if (mfi_lookup_volume(fd, av[1], &target_id) < 0) { 415214396Sjhb error = errno; 416196200Sscottl warn("Invalid volume: %s", av[1]); 417222899Sbz close(fd); 418214396Sjhb return (error); 419196200Sscottl } 420196200Sscottl 421196200Sscottl if (mfi_ld_get_props(fd, target_id, &props) < 0) { 422214396Sjhb error = errno; 423196200Sscottl warn("Failed to fetch volume properties"); 424222899Sbz close(fd); 425214396Sjhb return (error); 426196200Sscottl } 427196200Sscottl 428196200Sscottl printf("mfi%u volume %s name changed from \"%s\" to \"%s\"\n", mfi_unit, 429196200Sscottl mfi_volume_name(fd, target_id), props.name, av[2]); 430196200Sscottl bzero(props.name, sizeof(props.name)); 431196200Sscottl strcpy(props.name, av[2]); 432196200Sscottl if (mfi_ld_set_props(fd, &props) < 0) { 433214396Sjhb error = errno; 434196200Sscottl warn("Failed to set volume properties"); 435222899Sbz close(fd); 436214396Sjhb return (error); 437196200Sscottl } 438196200Sscottl 439196200Sscottl close(fd); 440196200Sscottl 441196200Sscottl return (0); 442196200Sscottl} 443196200SscottlMFI_COMMAND(top, name, volume_name); 444196200Sscottl 445196200Sscottlstatic int 446196200Sscottlvolume_progress(int ac, char **av) 447196200Sscottl{ 448196200Sscottl struct mfi_ld_info info; 449214396Sjhb int error, fd; 450196200Sscottl uint8_t target_id; 451196200Sscottl 452196200Sscottl if (ac != 2) { 453196200Sscottl warnx("volume progress: %s", ac > 2 ? "extra arguments" : 454196200Sscottl "volume required"); 455196200Sscottl return (EINVAL); 456196200Sscottl } 457196200Sscottl 458237259Seadler fd = mfi_open(mfi_unit, O_RDONLY); 459196200Sscottl if (fd < 0) { 460214396Sjhb error = errno; 461196200Sscottl warn("mfi_open"); 462214396Sjhb return (error); 463196200Sscottl } 464196200Sscottl 465196200Sscottl if (mfi_lookup_volume(fd, av[1], &target_id) < 0) { 466214396Sjhb error = errno; 467196200Sscottl warn("Invalid volume: %s", av[1]); 468222899Sbz close(fd); 469214396Sjhb return (error); 470196200Sscottl } 471196200Sscottl 472196200Sscottl /* Get the info for this drive. */ 473196200Sscottl if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) { 474214396Sjhb error = errno; 475196200Sscottl warn("Failed to fetch info for volume %s", 476196200Sscottl mfi_volume_name(fd, target_id)); 477222899Sbz close(fd); 478214396Sjhb return (error); 479196200Sscottl } 480196200Sscottl 481196200Sscottl /* Display any of the active events. */ 482196200Sscottl if (info.progress.active & MFI_LD_PROGRESS_CC) 483196200Sscottl mfi_display_progress("Consistency Check", &info.progress.cc); 484196200Sscottl if (info.progress.active & MFI_LD_PROGRESS_BGI) 485196200Sscottl mfi_display_progress("Background Init", &info.progress.bgi); 486196200Sscottl if (info.progress.active & MFI_LD_PROGRESS_FGI) 487196200Sscottl mfi_display_progress("Foreground Init", &info.progress.fgi); 488196200Sscottl if (info.progress.active & MFI_LD_PROGRESS_RECON) 489196200Sscottl mfi_display_progress("Reconstruction", &info.progress.recon); 490196200Sscottl if ((info.progress.active & (MFI_LD_PROGRESS_CC | MFI_LD_PROGRESS_BGI | 491196200Sscottl MFI_LD_PROGRESS_FGI | MFI_LD_PROGRESS_RECON)) == 0) 492196200Sscottl printf("No activity in progress for volume %s.\n", 493196200Sscottl mfi_volume_name(fd, target_id)); 494196200Sscottl close(fd); 495196200Sscottl 496196200Sscottl return (0); 497196200Sscottl} 498196200SscottlMFI_COMMAND(volume, progress, volume_progress); 499