159138Smsmith/*- 259138Smsmith * Copyright (c) 1999 Michael Smith 359138Smsmith * All rights reserved. 459138Smsmith * 559138Smsmith * Redistribution and use in source and binary forms, with or without 659138Smsmith * modification, are permitted provided that the following conditions 759138Smsmith * are met: 859138Smsmith * 1. Redistributions of source code must retain the above copyright 959138Smsmith * notice, this list of conditions and the following disclaimer. 1059138Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1159138Smsmith * notice, this list of conditions and the following disclaimer in the 1259138Smsmith * documentation and/or other materials provided with the distribution. 1359138Smsmith * 1459138Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1559138Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1659138Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1759138Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1859138Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1959138Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2059138Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2159138Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2259138Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2359138Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2459138Smsmith * SUCH DAMAGE. 2559138Smsmith * 2659138Smsmith * $FreeBSD$ 2759138Smsmith */ 2859138Smsmith 2959138Smsmith#include <fcntl.h> 3059138Smsmith#include <paths.h> 3159138Smsmith#include <stdio.h> 3259138Smsmith#include <stdlib.h> 3359138Smsmith#include <string.h> 3459138Smsmith#include <unistd.h> 3559138Smsmith#include <err.h> 3659138Smsmith 3759159Smsmith#include <dev/mlx/mlxio.h> 3859159Smsmith#include <dev/mlx/mlxreg.h> 3959138Smsmith 4059138Smsmith#include "mlxcontrol.h" 4159138Smsmith 4259138Smsmithstatic int cmd_status(int argc, char *argv[]); 4359138Smsmithstatic int cmd_rescan(int argc, char *argv[]); 4459138Smsmithstatic int cmd_detach(int argc, char *argv[]); 4559138Smsmithstatic int cmd_check(int argc, char *argv[]); 4659138Smsmithstatic int cmd_rebuild(int argc, char *argv[]); 4759138Smsmith#ifdef SUPPORT_PAUSE 4859138Smsmithstatic int cmd_pause(int argc, char *argv[]); 4959138Smsmith#endif 5059138Smsmithstatic int cmd_help(int argc, char *argv[]); 5159138Smsmith 5259138Smsmithextern int cmd_config(int argc, char *argv[]); 5359138Smsmith 5459138Smsmith 5559138Smsmithstruct 5659138Smsmith{ 5759138Smsmith char *cmd; 5859138Smsmith int (*func)(int argc, char *argv[]); 5959138Smsmith char *desc; 6059138Smsmith char *text; 6159138Smsmith} commands[] = { 6259138Smsmith {"status", cmd_status, 6359138Smsmith "displays device status", 6459138Smsmith " status [-qv] [<drive>...]\n" 6559138Smsmith " Display status for <drive> or all drives if none is listed\n" 6659138Smsmith " -q Suppress output.\n" 6759138Smsmith " -v Display verbose information.\n" 6859138Smsmith " Returns 0 if all drives tested are online, 1 if one or more are\n" 6959138Smsmith " critical, and 2 if one or more are offline."}, 7059138Smsmith {"rescan", cmd_rescan, 7159138Smsmith "scan for new system drives", 7259138Smsmith " rescan <controller> [<controller>...]\n" 7359138Smsmith " Rescan <controller> for system drives.\n" 7459138Smsmith " rescan -a\n" 7559138Smsmith " Rescan all controllers for system drives."}, 7659138Smsmith {"detach", cmd_detach, 7759138Smsmith "detach system drives", 7859138Smsmith " detach <drive> [<drive>...]\n" 7959138Smsmith " Detaches <drive> from the controller.\n" 8059138Smsmith " detach -a <controller>\n" 8159138Smsmith " Detaches all drives on <controller>."}, 8259138Smsmith {"check", cmd_check, 8359138Smsmith "consistency-check a system drive", 8459138Smsmith " check <drive>\n" 8559138Smsmith " Requests a check and rebuild of the parity information on <drive>.\n" 8659138Smsmith " Note that each controller can only check one system drive at a time."}, 8759138Smsmith {"rebuild", cmd_rebuild, 8859138Smsmith "initiate a rebuild of a dead physical drive", 8959138Smsmith " rebuild <controller> <physdrive>\n" 9059138Smsmith " All system drives using space on the physical drive <physdrive>\n" 9159138Smsmith " are rebuilt, reconstructing all data on the drive.\n" 9259138Smsmith " Note that each controller can only perform one rebuild at a time."}, 9359138Smsmith#ifdef SUPPORT_PAUSE 9459138Smsmith {"pause", cmd_pause, 9559138Smsmith "pauses controller channels", 9659138Smsmith " pause [-t <howlong>] [-d <delay>] <controller> [<channel>...]\n" 9759138Smsmith " Pauses SCSI I/O on <channel> and <controller>. If no channel is specified,\n" 9859138Smsmith " all channels are paused.\n" 9959138Smsmith " <howlong> How long (seconds) to pause for (default 30).\n" 10059138Smsmith " <delay> How long (seconds) to wait before pausing (default 30).\n" 10159138Smsmith " pause <controller> -c\n" 10259138Smsmith " Cancels any pending pause operation on <controller>."}, 10359138Smsmith#endif 10459138Smsmith {"config", cmd_config, 10559138Smsmith "examine and update controller configuration", 10659138Smsmith " config <controller>\n" 10759138Smsmith " Print configuration for <controller>."}, 10859138Smsmith {"help", cmd_help, 10959138Smsmith "give help on usage", 11059138Smsmith ""}, 11159138Smsmith {NULL, NULL, NULL, NULL} 11259138Smsmith}; 11359138Smsmith 11459138Smsmith/******************************************************************************** 11559138Smsmith * Command dispatch and global options parsing. 11659138Smsmith */ 11759138Smsmith 11859138Smsmithint 11959138Smsmithmain(int argc, char *argv[]) 12059138Smsmith{ 12159138Smsmith int ch, i, oargc; 12259138Smsmith char **oargv; 12359138Smsmith 12459138Smsmith oargc = argc; 12559138Smsmith oargv = argv; 12659138Smsmith while ((ch = getopt(argc, argv, "")) != -1) 12759138Smsmith switch(ch) { 12859138Smsmith default: 12959138Smsmith return(cmd_help(0, NULL)); 13059138Smsmith } 13159138Smsmith 13259138Smsmith argc -= optind; 13359138Smsmith argv += optind; 13459138Smsmith 13559138Smsmith if (argc > 0) 13659138Smsmith for (i = 0; commands[i].cmd != NULL; i++) 13759138Smsmith if (!strcmp(argv[0], commands[i].cmd)) 13859138Smsmith return(commands[i].func(argc, argv)); 13959138Smsmith 14059138Smsmith return(cmd_help(oargc, oargv)); 14159138Smsmith} 14259138Smsmith 14359138Smsmith/******************************************************************************** 14459138Smsmith * Helptext output 14559138Smsmith */ 14659138Smsmithstatic int 14759138Smsmithcmd_help(int argc, char *argv[]) 14859138Smsmith{ 14959138Smsmith int i; 15059138Smsmith 15159138Smsmith if (argc > 1) 15259138Smsmith for (i = 0; commands[i].cmd != NULL; i++) 15359138Smsmith if (!strcmp(argv[1], commands[i].cmd)) { 15459138Smsmith fprintf(stderr, "%s\n", commands[i].text); 15559138Smsmith fflush(stderr); 15659138Smsmith return(0); 15759138Smsmith } 15859138Smsmith 15959138Smsmith if (argv != NULL) 16059138Smsmith fprintf(stderr, "Unknown command '%s'.\n", argv[1]); 16159138Smsmith fprintf(stderr, "Valid commands are:\n"); 16259138Smsmith for (i = 0; commands[i].cmd != NULL; i++) 16359138Smsmith fprintf(stderr, " %-20s %s\n", commands[i].cmd, commands[i].desc); 16459138Smsmith fflush(stderr); 16559138Smsmith return(0); 16659138Smsmith} 16759138Smsmith 16859138Smsmith/******************************************************************************** 16959138Smsmith * Status output 17059138Smsmith * 17159138Smsmith * status [-qv] [<device> ...] 17259138Smsmith * Prints status for <device>, or all if none listed. 17359138Smsmith * 17459138Smsmith * -q Suppresses output, command returns 0 if devices are OK, 1 if one or 17559138Smsmith * more devices are critical, 2 if one or more devices are offline. 17659138Smsmith */ 17759138Smsmithstatic struct mlx_rebuild_status rs; 17859138Smsmithstatic int rs_ctrlr = -1; 17959138Smsmithstatic int status_result = 0; 18059138Smsmith 18159138Smsmith/* XXX more verbosity! */ 18259138Smsmithstatic void 18359138Smsmithstatus_print(int unit, void *arg) 18459138Smsmith{ 18559138Smsmith int verbosity = *(int *)arg; 18659138Smsmith int fd, result, ctrlr, sysdrive, statvalid; 18759138Smsmith 18859138Smsmith /* Find which controller and what system drive we are */ 18959138Smsmith statvalid = 0; 19059138Smsmith if (mlxd_find_ctrlr(unit, &ctrlr, &sysdrive)) { 19159138Smsmith warnx("couldn't get controller/drive for %s", drivepath(unit)); 19259138Smsmith } else { 19359138Smsmith /* If we don't have rebuild stats for this controller, get them */ 19459138Smsmith if (rs_ctrlr == ctrlr) { 19559138Smsmith statvalid = 1; 19659138Smsmith } else { 19759138Smsmith if ((fd = open(ctrlrpath(ctrlr), 0)) < 0) { 19859138Smsmith warn("can't open %s", ctrlrpath(ctrlr)); 19959138Smsmith } else { 20059138Smsmith if (ioctl(fd, MLX_REBUILDSTAT, &rs) < 0) { 20159138Smsmith warn("ioctl MLX_REBUILDSTAT"); 20259138Smsmith } else { 20359138Smsmith rs_ctrlr = ctrlr; 20459138Smsmith statvalid = 1; 20559138Smsmith } 20659138Smsmith close(fd); 20759138Smsmith } 20859138Smsmith } 20959138Smsmith } 21059138Smsmith 21159138Smsmith /* Get the device */ 21259138Smsmith if ((fd = open(drivepath(unit), 0)) < 0) { 21359138Smsmith warn("can't open %s", drivepath(unit)); 21459138Smsmith return; 21559138Smsmith } 21659138Smsmith 21759138Smsmith /* Get its status */ 21859138Smsmith if (ioctl(fd, MLXD_STATUS, &result) < 0) { 21959138Smsmith warn("ioctl MLXD_STATUS"); 22059138Smsmith } else { 22159138Smsmith switch(result) { 22259138Smsmith case MLX_SYSD_ONLINE: 22359138Smsmith if (verbosity > 0) 22459138Smsmith printf("%s: online", drivename(unit)); 22559138Smsmith break; 22659138Smsmith case MLX_SYSD_CRITICAL: 22759138Smsmith if (verbosity > 0) 22859138Smsmith printf("%s: critical", drivename(unit)); 22959138Smsmith if (status_result < 1) 23059138Smsmith status_result = 1; 23159138Smsmith break; 23259138Smsmith case MLX_SYSD_OFFLINE: 23359138Smsmith if (verbosity > 0) 23459138Smsmith printf("%s: offline", drivename(unit)); 23559138Smsmith if (status_result < 2) 23659138Smsmith status_result = 2; 23759138Smsmith break; 23859138Smsmith default: 23959138Smsmith if (verbosity > 0) { 24059138Smsmith printf("%s: unknown status 0x%x", drivename(unit), result); 24159138Smsmith } 24259138Smsmith } 24359138Smsmith if (verbosity > 0) { 24459138Smsmith /* rebuild/check in progress on this drive? */ 24559138Smsmith if (statvalid && (rs_ctrlr == ctrlr) && 24659138Smsmith (rs.rs_drive == sysdrive) && (rs.rs_code != MLX_REBUILDSTAT_IDLE)) { 24759138Smsmith switch(rs.rs_code) { 24859138Smsmith case MLX_REBUILDSTAT_REBUILDCHECK: 24959138Smsmith printf(" [consistency check"); 25059138Smsmith break; 25159138Smsmith case MLX_REBUILDSTAT_ADDCAPACITY: 25259138Smsmith printf(" [add capacity"); 25359138Smsmith break; 25459138Smsmith case MLX_REBUILDSTAT_ADDCAPACITYINIT: 25559138Smsmith printf(" [add capacity init"); 25659138Smsmith break; 25759138Smsmith default: 25859138Smsmith printf(" [unknown operation"); 25959138Smsmith } 26059138Smsmith printf(": %d/%d, %d%% complete]", 26159138Smsmith rs.rs_remaining, rs.rs_size, 26259138Smsmith ((rs.rs_size - rs.rs_remaining) / (rs.rs_size / 100))); 26359138Smsmith } 26459138Smsmith printf("\n"); 26559138Smsmith } 26659138Smsmith } 26759138Smsmith close(fd); 26859138Smsmith} 26959138Smsmith 27059138Smsmithstatic struct 27159138Smsmith{ 27259138Smsmith int hwid; 27359138Smsmith char *name; 27459138Smsmith} mlx_controller_names[] = { 27559138Smsmith {0x01, "960P/PD"}, 27659138Smsmith {0x02, "960PL"}, 27759138Smsmith {0x10, "960PG"}, 27859138Smsmith {0x11, "960PJ"}, 27959138Smsmith {0x12, "960PR"}, 28059138Smsmith {0x13, "960PT"}, 28159138Smsmith {0x14, "960PTL0"}, 28259138Smsmith {0x15, "960PRL"}, 28359138Smsmith {0x16, "960PTL1"}, 28459138Smsmith {0x20, "1100PVX"}, 28559138Smsmith {-1, NULL} 28659138Smsmith}; 28759138Smsmith 28859138Smsmithstatic void 28959138Smsmithcontroller_print(int unit, void *arg) 29059138Smsmith{ 29159138Smsmith struct mlx_enquiry2 enq; 29259138Smsmith struct mlx_phys_drv pd; 29359138Smsmith int verbosity = *(int *)arg; 29459138Smsmith static char buf[80]; 29559138Smsmith char *model; 29659138Smsmith int i, channel, target; 29759138Smsmith 29859138Smsmith if (verbosity == 0) 29959138Smsmith return; 30059138Smsmith 30159138Smsmith /* fetch and print controller data */ 30259138Smsmith if (mlx_enquiry(unit, &enq)) { 30359138Smsmith printf("mlx%d: error submitting ENQUIRY2\n", unit); 30459138Smsmith } else { 30559138Smsmith 30659138Smsmith for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) { 30759138Smsmith if ((enq.me_hardware_id & 0xff) == mlx_controller_names[i].hwid) { 30859138Smsmith model = mlx_controller_names[i].name; 30959138Smsmith break; 31059138Smsmith } 31159138Smsmith } 31259138Smsmith if (model == NULL) { 31359138Smsmith sprintf(buf, " model 0x%x", enq.me_hardware_id & 0xff); 31459138Smsmith model = buf; 31559138Smsmith } 31659138Smsmith 31759138Smsmith printf("mlx%d: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n", 31859138Smsmith unit, model, 31959138Smsmith enq.me_actual_channels, 32059138Smsmith enq.me_actual_channels > 1 ? "s" : "", 32159138Smsmith enq.me_firmware_id & 0xff, 32259138Smsmith (enq.me_firmware_id >> 8) & 0xff, 32359138Smsmith (enq.me_firmware_id >> 16), 32459138Smsmith (enq.me_firmware_id >> 24) & 0xff, 32559138Smsmith enq.me_mem_size / (1024 * 1024)); 32659138Smsmith 32759138Smsmith if (verbosity > 1) { 32859138Smsmith printf(" Hardware ID 0x%08x\n", enq.me_hardware_id); 32959138Smsmith printf(" Firmware ID 0x%08x\n", enq.me_firmware_id); 33059138Smsmith printf(" Configured/Actual channels %d/%d\n", enq.me_configured_channels, 33159138Smsmith enq.me_actual_channels); 33259138Smsmith printf(" Max Targets %d\n", enq.me_max_targets); 33359138Smsmith printf(" Max Tags %d\n", enq.me_max_tags); 33459138Smsmith printf(" Max System Drives %d\n", enq.me_max_sys_drives); 33559138Smsmith printf(" Max Arms %d\n", enq.me_max_arms); 33659138Smsmith printf(" Max Spans %d\n", enq.me_max_spans); 33759138Smsmith printf(" DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", enq.me_mem_size, 33859138Smsmith enq.me_cache_size, enq.me_flash_size, enq.me_nvram_size); 33959138Smsmith printf(" DRAM type %d\n", enq.me_mem_type); 34059138Smsmith printf(" Clock Speed %dns\n", enq.me_clock_speed); 34159138Smsmith printf(" Hardware Speed %dns\n", enq.me_hardware_speed); 34259138Smsmith printf(" Max Commands %d\n", enq.me_max_commands); 34359138Smsmith printf(" Max SG Entries %d\n", enq.me_max_sg); 34459138Smsmith printf(" Max DP %d\n", enq.me_max_dp); 34559138Smsmith printf(" Max IOD %d\n", enq.me_max_iod); 34659138Smsmith printf(" Max Comb %d\n", enq.me_max_comb); 34759138Smsmith printf(" Latency %ds\n", enq.me_latency); 34859138Smsmith printf(" SCSI Timeout %ds\n", enq.me_scsi_timeout); 34959138Smsmith printf(" Min Free Lines %d\n", enq.me_min_freelines); 35059138Smsmith printf(" Rate Constant %d\n", enq.me_rate_const); 35159138Smsmith printf(" MAXBLK %d\n", enq.me_maxblk); 35259138Smsmith printf(" Blocking Factor %d sectors\n", enq.me_blocking_factor); 35359138Smsmith printf(" Cache Line Size %d blocks\n", enq.me_cacheline); 35459138Smsmith printf(" SCSI Capability %s%dMHz, %d bit\n", 35559138Smsmith enq.me_scsi_cap & (1<<4) ? "differential " : "", 35659138Smsmith (1 << ((enq.me_scsi_cap >> 2) & 3)) * 10, 35759138Smsmith 8 << (enq.me_scsi_cap & 0x3)); 35859138Smsmith printf(" Firmware Build Number %d\n", enq.me_firmware_build); 35959138Smsmith printf(" Fault Management Type %d\n", enq.me_fault_mgmt_type); 36059138Smsmith#if 0 36159138Smsmith printf(" Features %b\n", enq.me_firmware_features, 36259138Smsmith "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n"); 36359138Smsmith#endif 36459138Smsmith } 36559138Smsmith 36659138Smsmith /* fetch and print physical drive data */ 36759138Smsmith for (channel = 0; channel < enq.me_configured_channels; channel++) { 36859138Smsmith for (target = 0; target < enq.me_max_targets; target++) { 36959138Smsmith if ((mlx_get_device_state(unit, channel, target, &pd) == 0) && 37059138Smsmith (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT)) { 37159138Smsmith mlx_print_phys_drv(&pd, channel, target, " ", verbosity - 1); 37259138Smsmith if (verbosity > 1) { 37359138Smsmith /* XXX print device statistics? */ 37459138Smsmith } 37559138Smsmith } 37659138Smsmith } 37759138Smsmith } 37859138Smsmith } 37959138Smsmith} 38059138Smsmith 38159138Smsmithstatic int 38259138Smsmithcmd_status(int argc, char *argv[]) 38359138Smsmith{ 38459138Smsmith int ch, verbosity = 1, i, unit; 38559138Smsmith 38659138Smsmith optreset = 1; 38759138Smsmith optind = 1; 38859138Smsmith while ((ch = getopt(argc, argv, "qv")) != -1) 38959138Smsmith switch(ch) { 39059138Smsmith case 'q': 39159138Smsmith verbosity = 0; 39259138Smsmith break; 39359138Smsmith case 'v': 39459138Smsmith verbosity = 2; 39559138Smsmith break; 39659138Smsmith default: 39759138Smsmith return(cmd_help(argc, argv)); 39859138Smsmith } 39959138Smsmith argc -= optind; 40059138Smsmith argv += optind; 40159138Smsmith 40259138Smsmith if (argc < 1) { 40359138Smsmith mlx_foreach(controller_print, &verbosity); 40459138Smsmith mlxd_foreach(status_print, &verbosity); 40559138Smsmith } else { 40659138Smsmith for (i = 0; i < argc; i++) { 40759138Smsmith if ((unit = driveunit(argv[i])) == -1) { 40859138Smsmith warnx("'%s' is not a valid drive", argv[i]); 40959138Smsmith } else { 41059138Smsmith status_print(unit, &verbosity); 41159138Smsmith } 41259138Smsmith } 41359138Smsmith } 41459138Smsmith return(status_result); 41559138Smsmith} 41659138Smsmith 41759138Smsmith/******************************************************************************** 41859138Smsmith * Recscan for system drives on one or more controllers. 41959138Smsmith * 42059138Smsmith * rescan <controller> [<controller>...] 42159138Smsmith * rescan -a 42259138Smsmith */ 42359138Smsmithstatic void 42459138Smsmithrescan_ctrlr(int unit, void *junk) 42559138Smsmith{ 42659138Smsmith int fd; 42759138Smsmith 42859138Smsmith /* Get the device */ 42959138Smsmith if ((fd = open(ctrlrpath(unit), 0)) < 0) { 43059138Smsmith warn("can't open %s", ctrlrpath(unit)); 43159138Smsmith return; 43259138Smsmith } 43359138Smsmith 43459138Smsmith if (ioctl(fd, MLX_RESCAN_DRIVES) < 0) 43559138Smsmith warn("can't rescan %s", ctrlrname(unit)); 43659138Smsmith close(fd); 43759138Smsmith} 43859138Smsmith 43959138Smsmithstatic int 44059138Smsmithcmd_rescan(int argc, char *argv[]) 44159138Smsmith{ 44259138Smsmith int all = 0, i, ch, unit; 44359138Smsmith 44459138Smsmith optreset = 1; 44559138Smsmith optind = 1; 44659138Smsmith while ((ch = getopt(argc, argv, "a")) != -1) 44759138Smsmith switch(ch) { 44859138Smsmith case 'a': 44959138Smsmith all = 1; 45059138Smsmith break; 45159138Smsmith default: 45259138Smsmith return(cmd_help(argc, argv)); 45359138Smsmith } 45459138Smsmith argc -= optind; 45559138Smsmith argv += optind; 45659138Smsmith 45759138Smsmith if (all) { 45859138Smsmith mlx_foreach(rescan_ctrlr, NULL); 45959138Smsmith } else { 46059138Smsmith for (i = 0; i < argc; i++) { 46159138Smsmith if ((unit = ctrlrunit(argv[i])) == -1) { 46259138Smsmith warnx("'%s' is not a valid controller", argv[i]); 46359138Smsmith } else { 46459138Smsmith rescan_ctrlr(unit, NULL); 46559138Smsmith } 46659138Smsmith } 46759138Smsmith } 46859138Smsmith return(0); 46959138Smsmith} 47059138Smsmith 47159138Smsmith/******************************************************************************** 47259138Smsmith * Detach one or more system drives from a controller. 47359138Smsmith * 47459138Smsmith * detach <drive> [<drive>...] 47559138Smsmith * Detach <drive>. 47659138Smsmith * 47759138Smsmith * detach -a <controller> [<controller>...] 47859138Smsmith * Detach all drives on <controller>. 47959138Smsmith * 48059138Smsmith */ 48159138Smsmithstatic void 48259138Smsmithdetach_drive(int unit, void *arg) 48359138Smsmith{ 48459138Smsmith int fd; 48559138Smsmith 48659138Smsmith /* Get the device */ 48759138Smsmith if ((fd = open(ctrlrpath(unit), 0)) < 0) { 48859138Smsmith warn("can't open %s", ctrlrpath(unit)); 48959138Smsmith return; 49059138Smsmith } 49159138Smsmith 49259138Smsmith if (ioctl(fd, MLX_DETACH_DRIVE, &unit) < 0) 49359138Smsmith warn("can't detach %s", drivename(unit)); 49459138Smsmith close(fd); 49559138Smsmith} 49659138Smsmith 49759138Smsmithstatic int 49859138Smsmithcmd_detach(int argc, char *argv[]) 49959138Smsmith{ 50059138Smsmith struct mlxd_foreach_action ma; 50159138Smsmith int all = 0, i, ch, unit; 50259138Smsmith 50359138Smsmith optreset = 1; 50459138Smsmith optind = 1; 50559138Smsmith while ((ch = getopt(argc, argv, "a")) != -1) 50659138Smsmith switch(ch) { 50759138Smsmith case 'a': 50859138Smsmith all = 1; 50959138Smsmith break; 51059138Smsmith default: 51159138Smsmith return(cmd_help(argc, argv)); 51259138Smsmith } 51359138Smsmith argc -= optind; 51459138Smsmith argv += optind; 51559138Smsmith 51659138Smsmith if (all) { 51759138Smsmith ma.func = detach_drive; 51859138Smsmith ma.arg = &unit; 51959138Smsmith for (i = 0; i < argc; i++) { 52059138Smsmith if ((unit = ctrlrunit(argv[i])) == -1) { 52159138Smsmith warnx("'%s' is not a valid controller", argv[i]); 52259138Smsmith } else { 52359138Smsmith mlxd_foreach_ctrlr(unit, &ma); 52459138Smsmith } 52559138Smsmith } 52659138Smsmith } else { 52759138Smsmith for (i = 0; i < argc; i++) { 52859138Smsmith if ((unit = driveunit(argv[i])) == -1) { 52959138Smsmith warnx("'%s' is not a valid drive", argv[i]); 53059138Smsmith } else { 53159138Smsmith /* run across all controllers to find this drive */ 53259138Smsmith mlx_foreach(detach_drive, &unit); 53359138Smsmith } 53459138Smsmith } 53559138Smsmith } 53659138Smsmith return(0); 53759138Smsmith} 53859138Smsmith 53959138Smsmith/******************************************************************************** 54059138Smsmith * Initiate a consistency check on a system drive. 54159138Smsmith * 54259138Smsmith * check [<drive>] 54359138Smsmith * Start a check of <drive> 54459138Smsmith * 54559138Smsmith */ 54659138Smsmithstatic int 54759138Smsmithcmd_check(int argc, char *argv[]) 54859138Smsmith{ 54959138Smsmith int unit, fd, result; 55059138Smsmith 55159138Smsmith if (argc != 2) 55259138Smsmith return(cmd_help(argc, argv)); 55359138Smsmith 55459138Smsmith if ((unit = driveunit(argv[1])) == -1) { 55559138Smsmith warnx("'%s' is not a valid drive", argv[1]); 55659138Smsmith } else { 55759138Smsmith 55859138Smsmith /* Get the device */ 55959138Smsmith if ((fd = open(drivepath(unit), 0)) < 0) { 56059138Smsmith warn("can't open %s", drivepath(unit)); 56159138Smsmith } else { 56259138Smsmith /* Try to start the check */ 56359138Smsmith if ((ioctl(fd, MLXD_CHECKASYNC, &result)) < 0) { 56459138Smsmith switch(result) { 56559138Smsmith case 0x0002: 56659138Smsmith warnx("one or more of the SCSI disks on which the drive '%s' depends is DEAD", argv[1]); 56759138Smsmith break; 56859138Smsmith case 0x0105: 56959138Smsmith warnx("drive %s is invalid, or not a drive which can be checked", argv[1]); 57059138Smsmith break; 57159138Smsmith case 0x0106: 57259138Smsmith warnx("drive rebuild or consistency check is already in progress on this controller"); 57359138Smsmith break; 57459138Smsmith default: 57559138Smsmith warn("ioctl MLXD_CHECKASYNC"); 57659138Smsmith } 57759138Smsmith } 57859138Smsmith } 57959138Smsmith } 58059138Smsmith return(0); 58159138Smsmith} 58259138Smsmith 58359138Smsmith/******************************************************************************** 58459138Smsmith * Initiate a physical drive rebuild 58559138Smsmith * 58659138Smsmith * rebuild <controller> <channel>:<target> 58759138Smsmith * Start a rebuild of <controller>:<channel>:<target> 58859138Smsmith * 58959138Smsmith */ 59059138Smsmithstatic int 59159138Smsmithcmd_rebuild(int argc, char *argv[]) 59259138Smsmith{ 59359138Smsmith struct mlx_rebuild_request rb; 59459138Smsmith int unit, fd; 59559138Smsmith 59659138Smsmith if (argc != 3) 59759138Smsmith return(cmd_help(argc, argv)); 59859138Smsmith 59959138Smsmith /* parse arguments */ 60059138Smsmith if ((unit = ctrlrunit(argv[1])) == -1) { 60159138Smsmith warnx("'%s' is not a valid controller", argv[1]); 60259138Smsmith return(1); 60359138Smsmith } 60459138Smsmith /* try diskXXXX and unknownXXXX as we report the latter for a dead drive ... */ 60559138Smsmith if ((sscanf(argv[2], "disk%2d%2d", &rb.rr_channel, &rb.rr_target) != 2) && 60659138Smsmith (sscanf(argv[2], "unknown%2d%2d", &rb.rr_channel, &rb.rr_target) != 2)) { 60759138Smsmith warnx("'%s' is not a valid physical drive", argv[2]); 60859138Smsmith return(1); 60959138Smsmith } 61059138Smsmith /* get the device */ 61159138Smsmith if ((fd = open(ctrlrpath(unit), 0)) < 0) { 61259138Smsmith warn("can't open %s", ctrlrpath(unit)); 61359138Smsmith return(1); 61459138Smsmith } 61559138Smsmith /* try to start the rebuild */ 61659138Smsmith if ((ioctl(fd, MLX_REBUILDASYNC, &rb)) < 0) { 61759138Smsmith switch(rb.rr_status) { 61859138Smsmith case 0x0002: 61959138Smsmith warnx("the drive at %d:%d is already ONLINE", rb.rr_channel, rb.rr_target); 62059138Smsmith break; 62159138Smsmith case 0x0004: 62259138Smsmith warnx("drive failed during rebuild"); 62359138Smsmith break; 62459138Smsmith case 0x0105: 62559138Smsmith warnx("there is no drive at channel %d, target %d", rb.rr_channel, rb.rr_target); 62659138Smsmith break; 62759138Smsmith case 0x0106: 62859138Smsmith warnx("drive rebuild or consistency check is already in progress on this controller"); 62959138Smsmith break; 63059138Smsmith default: 631182965Ssepotvin warn("ioctl MLXD_REBUILDASYNC"); 63259138Smsmith } 63359138Smsmith } 63459138Smsmith return(0); 63559138Smsmith} 63659138Smsmith 63759138Smsmith#ifdef SUPPORT_PAUSE 63859138Smsmith/******************************************************************************** 63959138Smsmith * Pause one or more channels on a controller 64059138Smsmith * 64159138Smsmith * pause [-d <delay>] [-t <time>] <controller> [<channel>...] 64259138Smsmith * Pauses <channel> (or all channels) for <time> seconds after a 64359138Smsmith * delay of <delay> seconds. 64459138Smsmith * pause <controller> -c 64559138Smsmith * Cancels pending pause 64659138Smsmith */ 64759138Smsmithstatic int 64859138Smsmithcmd_pause(int argc, char *argv[]) 64959138Smsmith{ 65059138Smsmith struct mlx_pause mp; 65159138Smsmith int unit, i, ch, fd, cancel = 0; 65259138Smsmith char *cp; 65359138Smsmith int oargc = argc; 65459138Smsmith char **oargv = argv; 65559138Smsmith 65659138Smsmith mp.mp_which = 0; 65759138Smsmith mp.mp_when = 30; 65859138Smsmith mp.mp_howlong = 30; 65959138Smsmith optreset = 1; 66059138Smsmith optind = 1; 66159138Smsmith while ((ch = getopt(argc, argv, "cd:t:")) != -1) 66259138Smsmith switch(ch) { 66359138Smsmith case 'c': 66459138Smsmith cancel = 1; 66559138Smsmith break; 66659138Smsmith case 'd': 66759138Smsmith mp.mp_when = strtol(optarg, &cp, 0); 66859138Smsmith if (*cp != 0) 66959138Smsmith return(cmd_help(argc, argv)); 67059138Smsmith break; 67159138Smsmith case 't': 67259138Smsmith mp.mp_howlong = strtol(optarg, &cp, 0); 67359138Smsmith if (*cp != 0) 67459138Smsmith return(cmd_help(argc, argv)); 67559138Smsmith break; 67659138Smsmith default: 67759138Smsmith return(cmd_help(argc, argv)); 67859138Smsmith } 67959138Smsmith argc -= optind; 68059138Smsmith argv += optind; 68159138Smsmith 68259138Smsmith /* get controller unit number that we're working on */ 68359138Smsmith if ((argc < 1) || ((unit = ctrlrunit(argv[0])) == -1)) 68459138Smsmith return(cmd_help(oargc, oargv)); 68559138Smsmith 68659138Smsmith /* Get the device */ 68759138Smsmith if ((fd = open(ctrlrpath(unit), 0)) < 0) { 68859138Smsmith warn("can't open %s", ctrlrpath(unit)); 68959138Smsmith return(1); 69059138Smsmith } 69159138Smsmith 69259138Smsmith if (argc == 1) { 69359138Smsmith /* controller-wide pause/cancel */ 69459138Smsmith mp.mp_which = cancel ? MLX_PAUSE_CANCEL : MLX_PAUSE_ALL; 69559138Smsmith } else { 69659138Smsmith for (i = 1; i < argc; i++) { 69759138Smsmith ch = strtol(argv[i], &cp, 0); 69859138Smsmith if (*cp != 0) { 69959138Smsmith warnx("bad channel number '%s'", argv[i]); 70059138Smsmith continue; 70159138Smsmith } else { 70259138Smsmith mp.mp_which |= (1 << ch); 70359138Smsmith } 70459138Smsmith } 70559138Smsmith } 70659138Smsmith if ((ioctl(fd, MLX_PAUSE_CHANNEL, &mp)) < 0) 70759138Smsmith warn("couldn't %s %s", cancel ? "cancel pause on" : "pause", ctrlrname(unit)); 70859138Smsmith close(fd); 70959138Smsmith return(0); 71059138Smsmith} 71159138Smsmith#endif /* SUPPORT_PAUSE */ 71259138Smsmith 713