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