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