1b6a7bef2SMike Smith /*- 2b6a7bef2SMike Smith * Copyright (c) 1999 Michael Smith 3b6a7bef2SMike Smith * All rights reserved. 4b6a7bef2SMike Smith * 5b6a7bef2SMike Smith * Redistribution and use in source and binary forms, with or without 6b6a7bef2SMike Smith * modification, are permitted provided that the following conditions 7b6a7bef2SMike Smith * are met: 8b6a7bef2SMike Smith * 1. Redistributions of source code must retain the above copyright 9b6a7bef2SMike Smith * notice, this list of conditions and the following disclaimer. 10b6a7bef2SMike Smith * 2. Redistributions in binary form must reproduce the above copyright 11b6a7bef2SMike Smith * notice, this list of conditions and the following disclaimer in the 12b6a7bef2SMike Smith * documentation and/or other materials provided with the distribution. 13b6a7bef2SMike Smith * 14b6a7bef2SMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15b6a7bef2SMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16b6a7bef2SMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17b6a7bef2SMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18b6a7bef2SMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19b6a7bef2SMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20b6a7bef2SMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21b6a7bef2SMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22b6a7bef2SMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23b6a7bef2SMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24b6a7bef2SMike Smith * SUCH DAMAGE. 25b6a7bef2SMike Smith * 26b6a7bef2SMike Smith * $FreeBSD$ 27b6a7bef2SMike Smith */ 28b6a7bef2SMike Smith 29b6a7bef2SMike Smith #include <fcntl.h> 30b6a7bef2SMike Smith #include <paths.h> 31b6a7bef2SMike Smith #include <stdio.h> 32b6a7bef2SMike Smith #include <stdlib.h> 33b6a7bef2SMike Smith #include <string.h> 34b6a7bef2SMike Smith #include <unistd.h> 35b6a7bef2SMike Smith #include <err.h> 36b6a7bef2SMike Smith 37b6a7bef2SMike Smith #if 0 38b6a7bef2SMike Smith #include <sys/mlxio.h> 39b6a7bef2SMike Smith #include <sys/mlxreg.h> 40b6a7bef2SMike Smith #else 41b6a7bef2SMike Smith #include "../sys/dev/mlx/mlxio.h" 42b6a7bef2SMike Smith #include "../sys/dev/mlx/mlxreg.h" 43b6a7bef2SMike Smith #endif 44b6a7bef2SMike Smith 45b6a7bef2SMike Smith #include "mlxcontrol.h" 46b6a7bef2SMike Smith 47b6a7bef2SMike Smith static int cmd_status(int argc, char *argv[]); 48b6a7bef2SMike Smith static int cmd_rescan(int argc, char *argv[]); 49b6a7bef2SMike Smith static int cmd_detach(int argc, char *argv[]); 50b6a7bef2SMike Smith static int cmd_check(int argc, char *argv[]); 51b6a7bef2SMike Smith static int cmd_rebuild(int argc, char *argv[]); 52b6a7bef2SMike Smith #ifdef SUPPORT_PAUSE 53b6a7bef2SMike Smith static int cmd_pause(int argc, char *argv[]); 54b6a7bef2SMike Smith #endif 55b6a7bef2SMike Smith static int cmd_help(int argc, char *argv[]); 56b6a7bef2SMike Smith 57b6a7bef2SMike Smith extern int cmd_config(int argc, char *argv[]); 58b6a7bef2SMike Smith 59b6a7bef2SMike Smith 60b6a7bef2SMike Smith struct 61b6a7bef2SMike Smith { 62b6a7bef2SMike Smith char *cmd; 63b6a7bef2SMike Smith int (*func)(int argc, char *argv[]); 64b6a7bef2SMike Smith char *desc; 65b6a7bef2SMike Smith char *text; 66b6a7bef2SMike Smith } commands[] = { 67b6a7bef2SMike Smith {"status", cmd_status, 68b6a7bef2SMike Smith "displays device status", 69b6a7bef2SMike Smith " status [-qv] [<drive>...]\n" 70b6a7bef2SMike Smith " Display status for <drive> or all drives if none is listed\n" 71b6a7bef2SMike Smith " -q Suppress output.\n" 72b6a7bef2SMike Smith " -v Display verbose information.\n" 73b6a7bef2SMike Smith " Returns 0 if all drives tested are online, 1 if one or more are\n" 74b6a7bef2SMike Smith " critical, and 2 if one or more are offline."}, 75b6a7bef2SMike Smith {"rescan", cmd_rescan, 76b6a7bef2SMike Smith "scan for new system drives", 77b6a7bef2SMike Smith " rescan <controller> [<controller>...]\n" 78b6a7bef2SMike Smith " Rescan <controller> for system drives.\n" 79b6a7bef2SMike Smith " rescan -a\n" 80b6a7bef2SMike Smith " Rescan all controllers for system drives."}, 81b6a7bef2SMike Smith {"detach", cmd_detach, 82b6a7bef2SMike Smith "detach system drives", 83b6a7bef2SMike Smith " detach <drive> [<drive>...]\n" 84b6a7bef2SMike Smith " Detaches <drive> from the controller.\n" 85b6a7bef2SMike Smith " detach -a <controller>\n" 86b6a7bef2SMike Smith " Detaches all drives on <controller>."}, 87b6a7bef2SMike Smith {"check", cmd_check, 88b6a7bef2SMike Smith "consistency-check a system drive", 89b6a7bef2SMike Smith " check <drive>\n" 90b6a7bef2SMike Smith " Requests a check and rebuild of the parity information on <drive>.\n" 91b6a7bef2SMike Smith " Note that each controller can only check one system drive at a time."}, 92b6a7bef2SMike Smith {"rebuild", cmd_rebuild, 93b6a7bef2SMike Smith "initiate a rebuild of a dead physical drive", 94b6a7bef2SMike Smith " rebuild <controller> <physdrive>\n" 95b6a7bef2SMike Smith " All system drives using space on the physical drive <physdrive>\n" 96b6a7bef2SMike Smith " are rebuilt, reconstructing all data on the drive.\n" 97b6a7bef2SMike Smith " Note that each controller can only perform one rebuild at a time."}, 98b6a7bef2SMike Smith #ifdef SUPPORT_PAUSE 99b6a7bef2SMike Smith {"pause", cmd_pause, 100b6a7bef2SMike Smith "pauses controller channels", 101b6a7bef2SMike Smith " pause [-t <howlong>] [-d <delay>] <controller> [<channel>...]\n" 102b6a7bef2SMike Smith " Pauses SCSI I/O on <channel> and <controller>. If no channel is specified,\n" 103b6a7bef2SMike Smith " all channels are paused.\n" 104b6a7bef2SMike Smith " <howlong> How long (seconds) to pause for (default 30).\n" 105b6a7bef2SMike Smith " <delay> How long (seconds) to wait before pausing (default 30).\n" 106b6a7bef2SMike Smith " pause <controller> -c\n" 107b6a7bef2SMike Smith " Cancels any pending pause operation on <controller>."}, 108b6a7bef2SMike Smith #endif 109b6a7bef2SMike Smith {"config", cmd_config, 110b6a7bef2SMike Smith "examine and update controller configuration", 111b6a7bef2SMike Smith " config <controller>\n" 112b6a7bef2SMike Smith " Print configuration for <controller>."}, 113b6a7bef2SMike Smith {"help", cmd_help, 114b6a7bef2SMike Smith "give help on usage", 115b6a7bef2SMike Smith ""}, 116b6a7bef2SMike Smith {NULL, NULL, NULL, NULL} 117b6a7bef2SMike Smith }; 118b6a7bef2SMike Smith 119b6a7bef2SMike Smith /******************************************************************************** 120b6a7bef2SMike Smith * Command dispatch and global options parsing. 121b6a7bef2SMike Smith */ 122b6a7bef2SMike Smith 123b6a7bef2SMike Smith int 124b6a7bef2SMike Smith main(int argc, char *argv[]) 125b6a7bef2SMike Smith { 126b6a7bef2SMike Smith int ch, i, oargc; 127b6a7bef2SMike Smith char **oargv; 128b6a7bef2SMike Smith 129b6a7bef2SMike Smith oargc = argc; 130b6a7bef2SMike Smith oargv = argv; 131b6a7bef2SMike Smith while ((ch = getopt(argc, argv, "")) != -1) 132b6a7bef2SMike Smith switch(ch) { 133b6a7bef2SMike Smith default: 134b6a7bef2SMike Smith return(cmd_help(0, NULL)); 135b6a7bef2SMike Smith } 136b6a7bef2SMike Smith 137b6a7bef2SMike Smith argc -= optind; 138b6a7bef2SMike Smith argv += optind; 139b6a7bef2SMike Smith 140b6a7bef2SMike Smith if (argc > 0) 141b6a7bef2SMike Smith for (i = 0; commands[i].cmd != NULL; i++) 142b6a7bef2SMike Smith if (!strcmp(argv[0], commands[i].cmd)) 143b6a7bef2SMike Smith return(commands[i].func(argc, argv)); 144b6a7bef2SMike Smith 145b6a7bef2SMike Smith return(cmd_help(oargc, oargv)); 146b6a7bef2SMike Smith } 147b6a7bef2SMike Smith 148b6a7bef2SMike Smith /******************************************************************************** 149b6a7bef2SMike Smith * Helptext output 150b6a7bef2SMike Smith */ 151b6a7bef2SMike Smith static int 152b6a7bef2SMike Smith cmd_help(int argc, char *argv[]) 153b6a7bef2SMike Smith { 154b6a7bef2SMike Smith int i; 155b6a7bef2SMike Smith 156b6a7bef2SMike Smith if (argc > 1) 157b6a7bef2SMike Smith for (i = 0; commands[i].cmd != NULL; i++) 158b6a7bef2SMike Smith if (!strcmp(argv[1], commands[i].cmd)) { 159b6a7bef2SMike Smith fprintf(stderr, "%s\n", commands[i].text); 160b6a7bef2SMike Smith fflush(stderr); 161b6a7bef2SMike Smith return(0); 162b6a7bef2SMike Smith } 163b6a7bef2SMike Smith 164b6a7bef2SMike Smith if (argv != NULL) 165b6a7bef2SMike Smith fprintf(stderr, "Unknown command '%s'.\n", argv[1]); 166b6a7bef2SMike Smith fprintf(stderr, "Valid commands are:\n"); 167b6a7bef2SMike Smith for (i = 0; commands[i].cmd != NULL; i++) 168b6a7bef2SMike Smith fprintf(stderr, " %-20s %s\n", commands[i].cmd, commands[i].desc); 169b6a7bef2SMike Smith fflush(stderr); 170b6a7bef2SMike Smith return(0); 171b6a7bef2SMike Smith } 172b6a7bef2SMike Smith 173b6a7bef2SMike Smith /******************************************************************************** 174b6a7bef2SMike Smith * Status output 175b6a7bef2SMike Smith * 176b6a7bef2SMike Smith * status [-qv] [<device> ...] 177b6a7bef2SMike Smith * Prints status for <device>, or all if none listed. 178b6a7bef2SMike Smith * 179b6a7bef2SMike Smith * -q Suppresses output, command returns 0 if devices are OK, 1 if one or 180b6a7bef2SMike Smith * more devices are critical, 2 if one or more devices are offline. 181b6a7bef2SMike Smith */ 182b6a7bef2SMike Smith static struct mlx_rebuild_status rs; 183b6a7bef2SMike Smith static int rs_ctrlr = -1; 184b6a7bef2SMike Smith static int status_result = 0; 185b6a7bef2SMike Smith 186b6a7bef2SMike Smith /* XXX more verbosity! */ 187b6a7bef2SMike Smith static void 188b6a7bef2SMike Smith status_print(int unit, void *arg) 189b6a7bef2SMike Smith { 190b6a7bef2SMike Smith int verbosity = *(int *)arg; 191b6a7bef2SMike Smith int fd, result, ctrlr, sysdrive, statvalid; 192b6a7bef2SMike Smith 193b6a7bef2SMike Smith /* Find which controller and what system drive we are */ 194b6a7bef2SMike Smith statvalid = 0; 195b6a7bef2SMike Smith if (mlxd_find_ctrlr(unit, &ctrlr, &sysdrive)) { 196b6a7bef2SMike Smith warnx("couldn't get controller/drive for %s", drivepath(unit)); 197b6a7bef2SMike Smith } else { 198b6a7bef2SMike Smith /* If we don't have rebuild stats for this controller, get them */ 199b6a7bef2SMike Smith if (rs_ctrlr == ctrlr) { 200b6a7bef2SMike Smith statvalid = 1; 201b6a7bef2SMike Smith } else { 202b6a7bef2SMike Smith if ((fd = open(ctrlrpath(ctrlr), 0)) < 0) { 203b6a7bef2SMike Smith warn("can't open %s", ctrlrpath(ctrlr)); 204b6a7bef2SMike Smith } else { 205b6a7bef2SMike Smith if (ioctl(fd, MLX_REBUILDSTAT, &rs) < 0) { 206b6a7bef2SMike Smith warn("ioctl MLX_REBUILDSTAT"); 207b6a7bef2SMike Smith } else { 208b6a7bef2SMike Smith rs_ctrlr = ctrlr; 209b6a7bef2SMike Smith statvalid = 1; 210b6a7bef2SMike Smith } 211b6a7bef2SMike Smith close(fd); 212b6a7bef2SMike Smith } 213b6a7bef2SMike Smith } 214b6a7bef2SMike Smith } 215b6a7bef2SMike Smith 216b6a7bef2SMike Smith /* Get the device */ 217b6a7bef2SMike Smith if ((fd = open(drivepath(unit), 0)) < 0) { 218b6a7bef2SMike Smith warn("can't open %s", drivepath(unit)); 219b6a7bef2SMike Smith return; 220b6a7bef2SMike Smith } 221b6a7bef2SMike Smith 222b6a7bef2SMike Smith /* Get its status */ 223b6a7bef2SMike Smith if (ioctl(fd, MLXD_STATUS, &result) < 0) { 224b6a7bef2SMike Smith warn("ioctl MLXD_STATUS"); 225b6a7bef2SMike Smith } else { 226b6a7bef2SMike Smith switch(result) { 227b6a7bef2SMike Smith case MLX_SYSD_ONLINE: 228b6a7bef2SMike Smith if (verbosity > 0) 229b6a7bef2SMike Smith printf("%s: online", drivename(unit)); 230b6a7bef2SMike Smith break; 231b6a7bef2SMike Smith case MLX_SYSD_CRITICAL: 232b6a7bef2SMike Smith if (verbosity > 0) 233b6a7bef2SMike Smith printf("%s: critical", drivename(unit)); 234b6a7bef2SMike Smith if (status_result < 1) 235b6a7bef2SMike Smith status_result = 1; 236b6a7bef2SMike Smith break; 237b6a7bef2SMike Smith case MLX_SYSD_OFFLINE: 238b6a7bef2SMike Smith if (verbosity > 0) 239b6a7bef2SMike Smith printf("%s: offline", drivename(unit)); 240b6a7bef2SMike Smith if (status_result < 2) 241b6a7bef2SMike Smith status_result = 2; 242b6a7bef2SMike Smith break; 243b6a7bef2SMike Smith default: 244b6a7bef2SMike Smith if (verbosity > 0) { 245b6a7bef2SMike Smith printf("%s: unknown status 0x%x", drivename(unit), result); 246b6a7bef2SMike Smith } 247b6a7bef2SMike Smith } 248b6a7bef2SMike Smith if (verbosity > 0) { 249b6a7bef2SMike Smith /* rebuild/check in progress on this drive? */ 250b6a7bef2SMike Smith if (statvalid && (rs_ctrlr == ctrlr) && 251b6a7bef2SMike Smith (rs.rs_drive == sysdrive) && (rs.rs_code != MLX_REBUILDSTAT_IDLE)) { 252b6a7bef2SMike Smith switch(rs.rs_code) { 253b6a7bef2SMike Smith case MLX_REBUILDSTAT_REBUILDCHECK: 254b6a7bef2SMike Smith printf(" [consistency check"); 255b6a7bef2SMike Smith break; 256b6a7bef2SMike Smith case MLX_REBUILDSTAT_ADDCAPACITY: 257b6a7bef2SMike Smith printf(" [add capacity"); 258b6a7bef2SMike Smith break; 259b6a7bef2SMike Smith case MLX_REBUILDSTAT_ADDCAPACITYINIT: 260b6a7bef2SMike Smith printf(" [add capacity init"); 261b6a7bef2SMike Smith break; 262b6a7bef2SMike Smith default: 263b6a7bef2SMike Smith printf(" [unknown operation"); 264b6a7bef2SMike Smith } 265b6a7bef2SMike Smith printf(": %d/%d, %d%% complete]", 266b6a7bef2SMike Smith rs.rs_remaining, rs.rs_size, 267b6a7bef2SMike Smith ((rs.rs_size - rs.rs_remaining) / (rs.rs_size / 100))); 268b6a7bef2SMike Smith } 269b6a7bef2SMike Smith printf("\n"); 270b6a7bef2SMike Smith } 271b6a7bef2SMike Smith } 272b6a7bef2SMike Smith close(fd); 273b6a7bef2SMike Smith } 274b6a7bef2SMike Smith 275b6a7bef2SMike Smith static struct 276b6a7bef2SMike Smith { 277b6a7bef2SMike Smith int hwid; 278b6a7bef2SMike Smith char *name; 279b6a7bef2SMike Smith } mlx_controller_names[] = { 280b6a7bef2SMike Smith {0x01, "960P/PD"}, 281b6a7bef2SMike Smith {0x02, "960PL"}, 282b6a7bef2SMike Smith {0x10, "960PG"}, 283b6a7bef2SMike Smith {0x11, "960PJ"}, 284b6a7bef2SMike Smith {0x12, "960PR"}, 285b6a7bef2SMike Smith {0x13, "960PT"}, 286b6a7bef2SMike Smith {0x14, "960PTL0"}, 287b6a7bef2SMike Smith {0x15, "960PRL"}, 288b6a7bef2SMike Smith {0x16, "960PTL1"}, 289b6a7bef2SMike Smith {0x20, "1100PVX"}, 290b6a7bef2SMike Smith {-1, NULL} 291b6a7bef2SMike Smith }; 292b6a7bef2SMike Smith 293b6a7bef2SMike Smith static void 294b6a7bef2SMike Smith controller_print(int unit, void *arg) 295b6a7bef2SMike Smith { 296b6a7bef2SMike Smith struct mlx_enquiry2 enq; 297b6a7bef2SMike Smith struct mlx_phys_drv pd; 298b6a7bef2SMike Smith int verbosity = *(int *)arg; 299b6a7bef2SMike Smith static char buf[80]; 300b6a7bef2SMike Smith char *model; 301b6a7bef2SMike Smith int i, channel, target; 302b6a7bef2SMike Smith 303b6a7bef2SMike Smith if (verbosity == 0) 304b6a7bef2SMike Smith return; 305b6a7bef2SMike Smith 306b6a7bef2SMike Smith /* fetch and print controller data */ 307b6a7bef2SMike Smith if (mlx_enquiry(unit, &enq)) { 308b6a7bef2SMike Smith printf("mlx%d: error submitting ENQUIRY2\n", unit); 309b6a7bef2SMike Smith } else { 310b6a7bef2SMike Smith 311b6a7bef2SMike Smith for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) { 312b6a7bef2SMike Smith if ((enq.me_hardware_id & 0xff) == mlx_controller_names[i].hwid) { 313b6a7bef2SMike Smith model = mlx_controller_names[i].name; 314b6a7bef2SMike Smith break; 315b6a7bef2SMike Smith } 316b6a7bef2SMike Smith } 317b6a7bef2SMike Smith if (model == NULL) { 318b6a7bef2SMike Smith sprintf(buf, " model 0x%x", enq.me_hardware_id & 0xff); 319b6a7bef2SMike Smith model = buf; 320b6a7bef2SMike Smith } 321b6a7bef2SMike Smith 322b6a7bef2SMike Smith printf("mlx%d: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n", 323b6a7bef2SMike Smith unit, model, 324b6a7bef2SMike Smith enq.me_actual_channels, 325b6a7bef2SMike Smith enq.me_actual_channels > 1 ? "s" : "", 326b6a7bef2SMike Smith enq.me_firmware_id & 0xff, 327b6a7bef2SMike Smith (enq.me_firmware_id >> 8) & 0xff, 328b6a7bef2SMike Smith (enq.me_firmware_id >> 16), 329b6a7bef2SMike Smith (enq.me_firmware_id >> 24) & 0xff, 330b6a7bef2SMike Smith enq.me_mem_size / (1024 * 1024)); 331b6a7bef2SMike Smith 332b6a7bef2SMike Smith if (verbosity > 1) { 333b6a7bef2SMike Smith printf(" Hardware ID 0x%08x\n", enq.me_hardware_id); 334b6a7bef2SMike Smith printf(" Firmware ID 0x%08x\n", enq.me_firmware_id); 335b6a7bef2SMike Smith printf(" Configured/Actual channels %d/%d\n", enq.me_configured_channels, 336b6a7bef2SMike Smith enq.me_actual_channels); 337b6a7bef2SMike Smith printf(" Max Targets %d\n", enq.me_max_targets); 338b6a7bef2SMike Smith printf(" Max Tags %d\n", enq.me_max_tags); 339b6a7bef2SMike Smith printf(" Max System Drives %d\n", enq.me_max_sys_drives); 340b6a7bef2SMike Smith printf(" Max Arms %d\n", enq.me_max_arms); 341b6a7bef2SMike Smith printf(" Max Spans %d\n", enq.me_max_spans); 342b6a7bef2SMike Smith printf(" DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", enq.me_mem_size, 343b6a7bef2SMike Smith enq.me_cache_size, enq.me_flash_size, enq.me_nvram_size); 344b6a7bef2SMike Smith printf(" DRAM type %d\n", enq.me_mem_type); 345b6a7bef2SMike Smith printf(" Clock Speed %dns\n", enq.me_clock_speed); 346b6a7bef2SMike Smith printf(" Hardware Speed %dns\n", enq.me_hardware_speed); 347b6a7bef2SMike Smith printf(" Max Commands %d\n", enq.me_max_commands); 348b6a7bef2SMike Smith printf(" Max SG Entries %d\n", enq.me_max_sg); 349b6a7bef2SMike Smith printf(" Max DP %d\n", enq.me_max_dp); 350b6a7bef2SMike Smith printf(" Max IOD %d\n", enq.me_max_iod); 351b6a7bef2SMike Smith printf(" Max Comb %d\n", enq.me_max_comb); 352b6a7bef2SMike Smith printf(" Latency %ds\n", enq.me_latency); 353b6a7bef2SMike Smith printf(" SCSI Timeout %ds\n", enq.me_scsi_timeout); 354b6a7bef2SMike Smith printf(" Min Free Lines %d\n", enq.me_min_freelines); 355b6a7bef2SMike Smith printf(" Rate Constant %d\n", enq.me_rate_const); 356b6a7bef2SMike Smith printf(" MAXBLK %d\n", enq.me_maxblk); 357b6a7bef2SMike Smith printf(" Blocking Factor %d sectors\n", enq.me_blocking_factor); 358b6a7bef2SMike Smith printf(" Cache Line Size %d blocks\n", enq.me_cacheline); 359b6a7bef2SMike Smith printf(" SCSI Capability %s%dMHz, %d bit\n", 360b6a7bef2SMike Smith enq.me_scsi_cap & (1<<4) ? "differential " : "", 361b6a7bef2SMike Smith (1 << ((enq.me_scsi_cap >> 2) & 3)) * 10, 362b6a7bef2SMike Smith 8 << (enq.me_scsi_cap & 0x3)); 363b6a7bef2SMike Smith printf(" Firmware Build Number %d\n", enq.me_firmware_build); 364b6a7bef2SMike Smith printf(" Fault Management Type %d\n", enq.me_fault_mgmt_type); 365b6a7bef2SMike Smith #if 0 366b6a7bef2SMike Smith printf(" Features %b\n", enq.me_firmware_features, 367b6a7bef2SMike Smith "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n"); 368b6a7bef2SMike Smith #endif 369b6a7bef2SMike Smith } 370b6a7bef2SMike Smith 371b6a7bef2SMike Smith /* fetch and print physical drive data */ 372b6a7bef2SMike Smith for (channel = 0; channel < enq.me_configured_channels; channel++) { 373b6a7bef2SMike Smith for (target = 0; target < enq.me_max_targets; target++) { 374b6a7bef2SMike Smith if ((mlx_get_device_state(unit, channel, target, &pd) == 0) && 375b6a7bef2SMike Smith (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT)) { 376b6a7bef2SMike Smith mlx_print_phys_drv(&pd, channel, target, " ", verbosity - 1); 377b6a7bef2SMike Smith if (verbosity > 1) { 378b6a7bef2SMike Smith /* XXX print device statistics? */ 379b6a7bef2SMike Smith } 380b6a7bef2SMike Smith } 381b6a7bef2SMike Smith } 382b6a7bef2SMike Smith } 383b6a7bef2SMike Smith } 384b6a7bef2SMike Smith } 385b6a7bef2SMike Smith 386b6a7bef2SMike Smith static int 387b6a7bef2SMike Smith cmd_status(int argc, char *argv[]) 388b6a7bef2SMike Smith { 389b6a7bef2SMike Smith int ch, verbosity = 1, i, unit; 390b6a7bef2SMike Smith 391b6a7bef2SMike Smith optreset = 1; 392b6a7bef2SMike Smith optind = 1; 393b6a7bef2SMike Smith while ((ch = getopt(argc, argv, "qv")) != -1) 394b6a7bef2SMike Smith switch(ch) { 395b6a7bef2SMike Smith case 'q': 396b6a7bef2SMike Smith verbosity = 0; 397b6a7bef2SMike Smith break; 398b6a7bef2SMike Smith case 'v': 399b6a7bef2SMike Smith verbosity = 2; 400b6a7bef2SMike Smith break; 401b6a7bef2SMike Smith default: 402b6a7bef2SMike Smith return(cmd_help(argc, argv)); 403b6a7bef2SMike Smith } 404b6a7bef2SMike Smith argc -= optind; 405b6a7bef2SMike Smith argv += optind; 406b6a7bef2SMike Smith 407b6a7bef2SMike Smith if (argc < 1) { 408b6a7bef2SMike Smith mlx_foreach(controller_print, &verbosity); 409b6a7bef2SMike Smith mlxd_foreach(status_print, &verbosity); 410b6a7bef2SMike Smith } else { 411b6a7bef2SMike Smith for (i = 0; i < argc; i++) { 412b6a7bef2SMike Smith if ((unit = driveunit(argv[i])) == -1) { 413b6a7bef2SMike Smith warnx("'%s' is not a valid drive", argv[i]); 414b6a7bef2SMike Smith } else { 415b6a7bef2SMike Smith status_print(unit, &verbosity); 416b6a7bef2SMike Smith } 417b6a7bef2SMike Smith } 418b6a7bef2SMike Smith } 419b6a7bef2SMike Smith return(status_result); 420b6a7bef2SMike Smith } 421b6a7bef2SMike Smith 422b6a7bef2SMike Smith /******************************************************************************** 423b6a7bef2SMike Smith * Recscan for system drives on one or more controllers. 424b6a7bef2SMike Smith * 425b6a7bef2SMike Smith * rescan <controller> [<controller>...] 426b6a7bef2SMike Smith * rescan -a 427b6a7bef2SMike Smith */ 428b6a7bef2SMike Smith static void 429b6a7bef2SMike Smith rescan_ctrlr(int unit, void *junk) 430b6a7bef2SMike Smith { 431b6a7bef2SMike Smith int fd; 432b6a7bef2SMike Smith 433b6a7bef2SMike Smith /* Get the device */ 434b6a7bef2SMike Smith if ((fd = open(ctrlrpath(unit), 0)) < 0) { 435b6a7bef2SMike Smith warn("can't open %s", ctrlrpath(unit)); 436b6a7bef2SMike Smith return; 437b6a7bef2SMike Smith } 438b6a7bef2SMike Smith 439b6a7bef2SMike Smith if (ioctl(fd, MLX_RESCAN_DRIVES) < 0) 440b6a7bef2SMike Smith warn("can't rescan %s", ctrlrname(unit)); 441b6a7bef2SMike Smith close(fd); 442b6a7bef2SMike Smith } 443b6a7bef2SMike Smith 444b6a7bef2SMike Smith static int 445b6a7bef2SMike Smith cmd_rescan(int argc, char *argv[]) 446b6a7bef2SMike Smith { 447b6a7bef2SMike Smith int all = 0, i, ch, unit; 448b6a7bef2SMike Smith 449b6a7bef2SMike Smith optreset = 1; 450b6a7bef2SMike Smith optind = 1; 451b6a7bef2SMike Smith while ((ch = getopt(argc, argv, "a")) != -1) 452b6a7bef2SMike Smith switch(ch) { 453b6a7bef2SMike Smith case 'a': 454b6a7bef2SMike Smith all = 1; 455b6a7bef2SMike Smith break; 456b6a7bef2SMike Smith default: 457b6a7bef2SMike Smith return(cmd_help(argc, argv)); 458b6a7bef2SMike Smith } 459b6a7bef2SMike Smith argc -= optind; 460b6a7bef2SMike Smith argv += optind; 461b6a7bef2SMike Smith 462b6a7bef2SMike Smith if (all) { 463b6a7bef2SMike Smith mlx_foreach(rescan_ctrlr, NULL); 464b6a7bef2SMike Smith } else { 465b6a7bef2SMike Smith for (i = 0; i < argc; i++) { 466b6a7bef2SMike Smith if ((unit = ctrlrunit(argv[i])) == -1) { 467b6a7bef2SMike Smith warnx("'%s' is not a valid controller", argv[i]); 468b6a7bef2SMike Smith } else { 469b6a7bef2SMike Smith rescan_ctrlr(unit, NULL); 470b6a7bef2SMike Smith } 471b6a7bef2SMike Smith } 472b6a7bef2SMike Smith } 473b6a7bef2SMike Smith return(0); 474b6a7bef2SMike Smith } 475b6a7bef2SMike Smith 476b6a7bef2SMike Smith /******************************************************************************** 477b6a7bef2SMike Smith * Detach one or more system drives from a controller. 478b6a7bef2SMike Smith * 479b6a7bef2SMike Smith * detach <drive> [<drive>...] 480b6a7bef2SMike Smith * Detach <drive>. 481b6a7bef2SMike Smith * 482b6a7bef2SMike Smith * detach -a <controller> [<controller>...] 483b6a7bef2SMike Smith * Detach all drives on <controller>. 484b6a7bef2SMike Smith * 485b6a7bef2SMike Smith */ 486b6a7bef2SMike Smith static void 487b6a7bef2SMike Smith detach_drive(int unit, void *arg) 488b6a7bef2SMike Smith { 489b6a7bef2SMike Smith int fd; 490b6a7bef2SMike Smith 491b6a7bef2SMike Smith /* Get the device */ 492b6a7bef2SMike Smith if ((fd = open(ctrlrpath(unit), 0)) < 0) { 493b6a7bef2SMike Smith warn("can't open %s", ctrlrpath(unit)); 494b6a7bef2SMike Smith return; 495b6a7bef2SMike Smith } 496b6a7bef2SMike Smith 497b6a7bef2SMike Smith if (ioctl(fd, MLX_DETACH_DRIVE, &unit) < 0) 498b6a7bef2SMike Smith warn("can't detach %s", drivename(unit)); 499b6a7bef2SMike Smith close(fd); 500b6a7bef2SMike Smith } 501b6a7bef2SMike Smith 502b6a7bef2SMike Smith static int 503b6a7bef2SMike Smith cmd_detach(int argc, char *argv[]) 504b6a7bef2SMike Smith { 505b6a7bef2SMike Smith struct mlxd_foreach_action ma; 506b6a7bef2SMike Smith int all = 0, i, ch, unit; 507b6a7bef2SMike Smith 508b6a7bef2SMike Smith optreset = 1; 509b6a7bef2SMike Smith optind = 1; 510b6a7bef2SMike Smith while ((ch = getopt(argc, argv, "a")) != -1) 511b6a7bef2SMike Smith switch(ch) { 512b6a7bef2SMike Smith case 'a': 513b6a7bef2SMike Smith all = 1; 514b6a7bef2SMike Smith break; 515b6a7bef2SMike Smith default: 516b6a7bef2SMike Smith return(cmd_help(argc, argv)); 517b6a7bef2SMike Smith } 518b6a7bef2SMike Smith argc -= optind; 519b6a7bef2SMike Smith argv += optind; 520b6a7bef2SMike Smith 521b6a7bef2SMike Smith if (all) { 522b6a7bef2SMike Smith ma.func = detach_drive; 523b6a7bef2SMike Smith ma.arg = &unit; 524b6a7bef2SMike Smith for (i = 0; i < argc; i++) { 525b6a7bef2SMike Smith if ((unit = ctrlrunit(argv[i])) == -1) { 526b6a7bef2SMike Smith warnx("'%s' is not a valid controller", argv[i]); 527b6a7bef2SMike Smith } else { 528b6a7bef2SMike Smith mlxd_foreach_ctrlr(unit, &ma); 529b6a7bef2SMike Smith } 530b6a7bef2SMike Smith } 531b6a7bef2SMike Smith } else { 532b6a7bef2SMike Smith for (i = 0; i < argc; i++) { 533b6a7bef2SMike Smith if ((unit = driveunit(argv[i])) == -1) { 534b6a7bef2SMike Smith warnx("'%s' is not a valid drive", argv[i]); 535b6a7bef2SMike Smith } else { 536b6a7bef2SMike Smith /* run across all controllers to find this drive */ 537b6a7bef2SMike Smith mlx_foreach(detach_drive, &unit); 538b6a7bef2SMike Smith } 539b6a7bef2SMike Smith } 540b6a7bef2SMike Smith } 541b6a7bef2SMike Smith return(0); 542b6a7bef2SMike Smith } 543b6a7bef2SMike Smith 544b6a7bef2SMike Smith /******************************************************************************** 545b6a7bef2SMike Smith * Initiate a consistency check on a system drive. 546b6a7bef2SMike Smith * 547b6a7bef2SMike Smith * check [<drive>] 548b6a7bef2SMike Smith * Start a check of <drive> 549b6a7bef2SMike Smith * 550b6a7bef2SMike Smith */ 551b6a7bef2SMike Smith static int 552b6a7bef2SMike Smith cmd_check(int argc, char *argv[]) 553b6a7bef2SMike Smith { 554b6a7bef2SMike Smith int unit, fd, result; 555b6a7bef2SMike Smith 556b6a7bef2SMike Smith if (argc != 2) 557b6a7bef2SMike Smith return(cmd_help(argc, argv)); 558b6a7bef2SMike Smith 559b6a7bef2SMike Smith if ((unit = driveunit(argv[1])) == -1) { 560b6a7bef2SMike Smith warnx("'%s' is not a valid drive", argv[1]); 561b6a7bef2SMike Smith } else { 562b6a7bef2SMike Smith 563b6a7bef2SMike Smith /* Get the device */ 564b6a7bef2SMike Smith if ((fd = open(drivepath(unit), 0)) < 0) { 565b6a7bef2SMike Smith warn("can't open %s", drivepath(unit)); 566b6a7bef2SMike Smith } else { 567b6a7bef2SMike Smith /* Try to start the check */ 568b6a7bef2SMike Smith if ((ioctl(fd, MLXD_CHECKASYNC, &result)) < 0) { 569b6a7bef2SMike Smith switch(result) { 570b6a7bef2SMike Smith case 0x0002: 571b6a7bef2SMike Smith warnx("one or more of the SCSI disks on which the drive '%s' depends is DEAD", argv[1]); 572b6a7bef2SMike Smith break; 573b6a7bef2SMike Smith case 0x0105: 574b6a7bef2SMike Smith warnx("drive %s is invalid, or not a drive which can be checked", argv[1]); 575b6a7bef2SMike Smith break; 576b6a7bef2SMike Smith case 0x0106: 577b6a7bef2SMike Smith warnx("drive rebuild or consistency check is already in progress on this controller"); 578b6a7bef2SMike Smith break; 579b6a7bef2SMike Smith default: 580b6a7bef2SMike Smith warn("ioctl MLXD_CHECKASYNC"); 581b6a7bef2SMike Smith } 582b6a7bef2SMike Smith } 583b6a7bef2SMike Smith } 584b6a7bef2SMike Smith } 585b6a7bef2SMike Smith return(0); 586b6a7bef2SMike Smith } 587b6a7bef2SMike Smith 588b6a7bef2SMike Smith /******************************************************************************** 589b6a7bef2SMike Smith * Initiate a physical drive rebuild 590b6a7bef2SMike Smith * 591b6a7bef2SMike Smith * rebuild <controller> <channel>:<target> 592b6a7bef2SMike Smith * Start a rebuild of <controller>:<channel>:<target> 593b6a7bef2SMike Smith * 594b6a7bef2SMike Smith */ 595b6a7bef2SMike Smith static int 596b6a7bef2SMike Smith cmd_rebuild(int argc, char *argv[]) 597b6a7bef2SMike Smith { 598b6a7bef2SMike Smith struct mlx_rebuild_request rb; 599b6a7bef2SMike Smith int unit, fd; 600b6a7bef2SMike Smith 601b6a7bef2SMike Smith if (argc != 3) 602b6a7bef2SMike Smith return(cmd_help(argc, argv)); 603b6a7bef2SMike Smith 604b6a7bef2SMike Smith /* parse arguments */ 605b6a7bef2SMike Smith if ((unit = ctrlrunit(argv[1])) == -1) { 606b6a7bef2SMike Smith warnx("'%s' is not a valid controller", argv[1]); 607b6a7bef2SMike Smith return(1); 608b6a7bef2SMike Smith } 609b6a7bef2SMike Smith /* try diskXXXX and unknownXXXX as we report the latter for a dead drive ... */ 610b6a7bef2SMike Smith if ((sscanf(argv[2], "disk%2d%2d", &rb.rr_channel, &rb.rr_target) != 2) && 611b6a7bef2SMike Smith (sscanf(argv[2], "unknown%2d%2d", &rb.rr_channel, &rb.rr_target) != 2)) { 612b6a7bef2SMike Smith warnx("'%s' is not a valid physical drive", argv[2]); 613b6a7bef2SMike Smith return(1); 614b6a7bef2SMike Smith } 615b6a7bef2SMike Smith /* get the device */ 616b6a7bef2SMike Smith if ((fd = open(ctrlrpath(unit), 0)) < 0) { 617b6a7bef2SMike Smith warn("can't open %s", ctrlrpath(unit)); 618b6a7bef2SMike Smith return(1); 619b6a7bef2SMike Smith } 620b6a7bef2SMike Smith /* try to start the rebuild */ 621b6a7bef2SMike Smith if ((ioctl(fd, MLX_REBUILDASYNC, &rb)) < 0) { 622b6a7bef2SMike Smith switch(rb.rr_status) { 623b6a7bef2SMike Smith case 0x0002: 624b6a7bef2SMike Smith warnx("the drive at %d:%d is already ONLINE", rb.rr_channel, rb.rr_target); 625b6a7bef2SMike Smith break; 626b6a7bef2SMike Smith case 0x0004: 627b6a7bef2SMike Smith warnx("drive failed during rebuild"); 628b6a7bef2SMike Smith break; 629b6a7bef2SMike Smith case 0x0105: 630b6a7bef2SMike Smith warnx("there is no drive at channel %d, target %d", rb.rr_channel, rb.rr_target); 631b6a7bef2SMike Smith break; 632b6a7bef2SMike Smith case 0x0106: 633b6a7bef2SMike Smith warnx("drive rebuild or consistency check is already in progress on this controller"); 634b6a7bef2SMike Smith break; 635b6a7bef2SMike Smith default: 636b6a7bef2SMike Smith warn("ioctl MLXD_CHECKASYNC"); 637b6a7bef2SMike Smith } 638b6a7bef2SMike Smith } 639b6a7bef2SMike Smith return(0); 640b6a7bef2SMike Smith } 641b6a7bef2SMike Smith 642b6a7bef2SMike Smith #ifdef SUPPORT_PAUSE 643b6a7bef2SMike Smith /******************************************************************************** 644b6a7bef2SMike Smith * Pause one or more channels on a controller 645b6a7bef2SMike Smith * 646b6a7bef2SMike Smith * pause [-d <delay>] [-t <time>] <controller> [<channel>...] 647b6a7bef2SMike Smith * Pauses <channel> (or all channels) for <time> seconds after a 648b6a7bef2SMike Smith * delay of <delay> seconds. 649b6a7bef2SMike Smith * pause <controller> -c 650b6a7bef2SMike Smith * Cancels pending pause 651b6a7bef2SMike Smith */ 652b6a7bef2SMike Smith static int 653b6a7bef2SMike Smith cmd_pause(int argc, char *argv[]) 654b6a7bef2SMike Smith { 655b6a7bef2SMike Smith struct mlx_pause mp; 656b6a7bef2SMike Smith int unit, i, ch, fd, cancel = 0; 657b6a7bef2SMike Smith char *cp; 658b6a7bef2SMike Smith int oargc = argc; 659b6a7bef2SMike Smith char **oargv = argv; 660b6a7bef2SMike Smith 661b6a7bef2SMike Smith mp.mp_which = 0; 662b6a7bef2SMike Smith mp.mp_when = 30; 663b6a7bef2SMike Smith mp.mp_howlong = 30; 664b6a7bef2SMike Smith optreset = 1; 665b6a7bef2SMike Smith optind = 1; 666b6a7bef2SMike Smith while ((ch = getopt(argc, argv, "cd:t:")) != -1) 667b6a7bef2SMike Smith switch(ch) { 668b6a7bef2SMike Smith case 'c': 669b6a7bef2SMike Smith cancel = 1; 670b6a7bef2SMike Smith break; 671b6a7bef2SMike Smith case 'd': 672b6a7bef2SMike Smith mp.mp_when = strtol(optarg, &cp, 0); 673b6a7bef2SMike Smith if (*cp != 0) 674b6a7bef2SMike Smith return(cmd_help(argc, argv)); 675b6a7bef2SMike Smith break; 676b6a7bef2SMike Smith case 't': 677b6a7bef2SMike Smith mp.mp_howlong = strtol(optarg, &cp, 0); 678b6a7bef2SMike Smith if (*cp != 0) 679b6a7bef2SMike Smith return(cmd_help(argc, argv)); 680b6a7bef2SMike Smith break; 681b6a7bef2SMike Smith default: 682b6a7bef2SMike Smith return(cmd_help(argc, argv)); 683b6a7bef2SMike Smith } 684b6a7bef2SMike Smith argc -= optind; 685b6a7bef2SMike Smith argv += optind; 686b6a7bef2SMike Smith 687b6a7bef2SMike Smith /* get controller unit number that we're working on */ 688b6a7bef2SMike Smith if ((argc < 1) || ((unit = ctrlrunit(argv[0])) == -1)) 689b6a7bef2SMike Smith return(cmd_help(oargc, oargv)); 690b6a7bef2SMike Smith 691b6a7bef2SMike Smith /* Get the device */ 692b6a7bef2SMike Smith if ((fd = open(ctrlrpath(unit), 0)) < 0) { 693b6a7bef2SMike Smith warn("can't open %s", ctrlrpath(unit)); 694b6a7bef2SMike Smith return(1); 695b6a7bef2SMike Smith } 696b6a7bef2SMike Smith 697b6a7bef2SMike Smith if (argc == 1) { 698b6a7bef2SMike Smith /* controller-wide pause/cancel */ 699b6a7bef2SMike Smith mp.mp_which = cancel ? MLX_PAUSE_CANCEL : MLX_PAUSE_ALL; 700b6a7bef2SMike Smith } else { 701b6a7bef2SMike Smith for (i = 1; i < argc; i++) { 702b6a7bef2SMike Smith ch = strtol(argv[i], &cp, 0); 703b6a7bef2SMike Smith if (*cp != 0) { 704b6a7bef2SMike Smith warnx("bad channel number '%s'", argv[i]); 705b6a7bef2SMike Smith continue; 706b6a7bef2SMike Smith } else { 707b6a7bef2SMike Smith mp.mp_which |= (1 << ch); 708b6a7bef2SMike Smith } 709b6a7bef2SMike Smith } 710b6a7bef2SMike Smith } 711b6a7bef2SMike Smith if ((ioctl(fd, MLX_PAUSE_CHANNEL, &mp)) < 0) 712b6a7bef2SMike Smith warn("couldn't %s %s", cancel ? "cancel pause on" : "pause", ctrlrname(unit)); 713b6a7bef2SMike Smith close(fd); 714b6a7bef2SMike Smith return(0); 715b6a7bef2SMike Smith } 716b6a7bef2SMike Smith #endif /* SUPPORT_PAUSE */ 717b6a7bef2SMike Smith 718