diff options
author | msmith <msmith@FreeBSD.org> | 2000-04-11 03:01:45 +0000 |
---|---|---|
committer | msmith <msmith@FreeBSD.org> | 2000-04-11 03:01:45 +0000 |
commit | e9115d2df19df8d9a0db6c4e98f69f7d0b089a76 (patch) | |
tree | 3cc2441cf5076d6c3e51a83fb0ac66666d975085 | |
parent | adf731f0abaa675658ccf1c99ca1559e84334ca9 (diff) | |
download | FreeBSD-src-e9115d2df19df8d9a0db6c4e98f69f7d0b089a76.zip FreeBSD-src-e9115d2df19df8d9a0db6c4e98f69f7d0b089a76.tar.gz |
This is a command-line management tool for RAID controllers managed by the
mlx(4) driver.
-rw-r--r-- | usr.sbin/mlxcontrol/Makefile | 8 | ||||
-rw-r--r-- | usr.sbin/mlxcontrol/command.c | 717 | ||||
-rw-r--r-- | usr.sbin/mlxcontrol/config.c | 162 | ||||
-rw-r--r-- | usr.sbin/mlxcontrol/interface.c | 292 | ||||
-rw-r--r-- | usr.sbin/mlxcontrol/mlxcontrol.8 | 116 | ||||
-rw-r--r-- | usr.sbin/mlxcontrol/mlxcontrol.h | 89 | ||||
-rw-r--r-- | usr.sbin/mlxcontrol/util.c | 177 |
7 files changed, 1561 insertions, 0 deletions
diff --git a/usr.sbin/mlxcontrol/Makefile b/usr.sbin/mlxcontrol/Makefile new file mode 100644 index 0000000..3c16b51 --- /dev/null +++ b/usr.sbin/mlxcontrol/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +PROG= mlxcontrol +SRCS= command.c config.c interface.c util.c +MAN8= mlxcontrol.8 + +.include <bsd.prog.mk> + diff --git a/usr.sbin/mlxcontrol/command.c b/usr.sbin/mlxcontrol/command.c new file mode 100644 index 0000000..507f75a --- /dev/null +++ b/usr.sbin/mlxcontrol/command.c @@ -0,0 +1,717 @@ +/*- + * Copyright (c) 1999 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <err.h> + +#if 0 +#include <sys/mlxio.h> +#include <sys/mlxreg.h> +#else +#include "../sys/dev/mlx/mlxio.h" +#include "../sys/dev/mlx/mlxreg.h" +#endif + +#include "mlxcontrol.h" + +static int cmd_status(int argc, char *argv[]); +static int cmd_rescan(int argc, char *argv[]); +static int cmd_detach(int argc, char *argv[]); +static int cmd_check(int argc, char *argv[]); +static int cmd_rebuild(int argc, char *argv[]); +#ifdef SUPPORT_PAUSE +static int cmd_pause(int argc, char *argv[]); +#endif +static int cmd_help(int argc, char *argv[]); + +extern int cmd_config(int argc, char *argv[]); + + +struct +{ + char *cmd; + int (*func)(int argc, char *argv[]); + char *desc; + char *text; +} commands[] = { + {"status", cmd_status, + "displays device status", + " status [-qv] [<drive>...]\n" + " Display status for <drive> or all drives if none is listed\n" + " -q Suppress output.\n" + " -v Display verbose information.\n" + " Returns 0 if all drives tested are online, 1 if one or more are\n" + " critical, and 2 if one or more are offline."}, + {"rescan", cmd_rescan, + "scan for new system drives", + " rescan <controller> [<controller>...]\n" + " Rescan <controller> for system drives.\n" + " rescan -a\n" + " Rescan all controllers for system drives."}, + {"detach", cmd_detach, + "detach system drives", + " detach <drive> [<drive>...]\n" + " Detaches <drive> from the controller.\n" + " detach -a <controller>\n" + " Detaches all drives on <controller>."}, + {"check", cmd_check, + "consistency-check a system drive", + " check <drive>\n" + " Requests a check and rebuild of the parity information on <drive>.\n" + " Note that each controller can only check one system drive at a time."}, + {"rebuild", cmd_rebuild, + "initiate a rebuild of a dead physical drive", + " rebuild <controller> <physdrive>\n" + " All system drives using space on the physical drive <physdrive>\n" + " are rebuilt, reconstructing all data on the drive.\n" + " Note that each controller can only perform one rebuild at a time."}, +#ifdef SUPPORT_PAUSE + {"pause", cmd_pause, + "pauses controller channels", + " pause [-t <howlong>] [-d <delay>] <controller> [<channel>...]\n" + " Pauses SCSI I/O on <channel> and <controller>. If no channel is specified,\n" + " all channels are paused.\n" + " <howlong> How long (seconds) to pause for (default 30).\n" + " <delay> How long (seconds) to wait before pausing (default 30).\n" + " pause <controller> -c\n" + " Cancels any pending pause operation on <controller>."}, +#endif + {"config", cmd_config, + "examine and update controller configuration", + " config <controller>\n" + " Print configuration for <controller>."}, + {"help", cmd_help, + "give help on usage", + ""}, + {NULL, NULL, NULL, NULL} +}; + +/******************************************************************************** + * Command dispatch and global options parsing. + */ + +int +main(int argc, char *argv[]) +{ + int ch, i, oargc; + char **oargv; + + oargc = argc; + oargv = argv; + while ((ch = getopt(argc, argv, "")) != -1) + switch(ch) { + default: + return(cmd_help(0, NULL)); + } + + argc -= optind; + argv += optind; + + if (argc > 0) + for (i = 0; commands[i].cmd != NULL; i++) + if (!strcmp(argv[0], commands[i].cmd)) + return(commands[i].func(argc, argv)); + + return(cmd_help(oargc, oargv)); +} + +/******************************************************************************** + * Helptext output + */ +static int +cmd_help(int argc, char *argv[]) +{ + int i; + + if (argc > 1) + for (i = 0; commands[i].cmd != NULL; i++) + if (!strcmp(argv[1], commands[i].cmd)) { + fprintf(stderr, "%s\n", commands[i].text); + fflush(stderr); + return(0); + } + + if (argv != NULL) + fprintf(stderr, "Unknown command '%s'.\n", argv[1]); + fprintf(stderr, "Valid commands are:\n"); + for (i = 0; commands[i].cmd != NULL; i++) + fprintf(stderr, " %-20s %s\n", commands[i].cmd, commands[i].desc); + fflush(stderr); + return(0); +} + +/******************************************************************************** + * Status output + * + * status [-qv] [<device> ...] + * Prints status for <device>, or all if none listed. + * + * -q Suppresses output, command returns 0 if devices are OK, 1 if one or + * more devices are critical, 2 if one or more devices are offline. + */ +static struct mlx_rebuild_status rs; +static int rs_ctrlr = -1; +static int status_result = 0; + +/* XXX more verbosity! */ +static void +status_print(int unit, void *arg) +{ + int verbosity = *(int *)arg; + int fd, result, ctrlr, sysdrive, statvalid; + + /* Find which controller and what system drive we are */ + statvalid = 0; + if (mlxd_find_ctrlr(unit, &ctrlr, &sysdrive)) { + warnx("couldn't get controller/drive for %s", drivepath(unit)); + } else { + /* If we don't have rebuild stats for this controller, get them */ + if (rs_ctrlr == ctrlr) { + statvalid = 1; + } else { + if ((fd = open(ctrlrpath(ctrlr), 0)) < 0) { + warn("can't open %s", ctrlrpath(ctrlr)); + } else { + if (ioctl(fd, MLX_REBUILDSTAT, &rs) < 0) { + warn("ioctl MLX_REBUILDSTAT"); + } else { + rs_ctrlr = ctrlr; + statvalid = 1; + } + close(fd); + } + } + } + + /* Get the device */ + if ((fd = open(drivepath(unit), 0)) < 0) { + warn("can't open %s", drivepath(unit)); + return; + } + + /* Get its status */ + if (ioctl(fd, MLXD_STATUS, &result) < 0) { + warn("ioctl MLXD_STATUS"); + } else { + switch(result) { + case MLX_SYSD_ONLINE: + if (verbosity > 0) + printf("%s: online", drivename(unit)); + break; + case MLX_SYSD_CRITICAL: + if (verbosity > 0) + printf("%s: critical", drivename(unit)); + if (status_result < 1) + status_result = 1; + break; + case MLX_SYSD_OFFLINE: + if (verbosity > 0) + printf("%s: offline", drivename(unit)); + if (status_result < 2) + status_result = 2; + break; + default: + if (verbosity > 0) { + printf("%s: unknown status 0x%x", drivename(unit), result); + } + } + if (verbosity > 0) { + /* rebuild/check in progress on this drive? */ + if (statvalid && (rs_ctrlr == ctrlr) && + (rs.rs_drive == sysdrive) && (rs.rs_code != MLX_REBUILDSTAT_IDLE)) { + switch(rs.rs_code) { + case MLX_REBUILDSTAT_REBUILDCHECK: + printf(" [consistency check"); + break; + case MLX_REBUILDSTAT_ADDCAPACITY: + printf(" [add capacity"); + break; + case MLX_REBUILDSTAT_ADDCAPACITYINIT: + printf(" [add capacity init"); + break; + default: + printf(" [unknown operation"); + } + printf(": %d/%d, %d%% complete]", + rs.rs_remaining, rs.rs_size, + ((rs.rs_size - rs.rs_remaining) / (rs.rs_size / 100))); + } + printf("\n"); + } + } + close(fd); +} + +static struct +{ + int hwid; + char *name; +} mlx_controller_names[] = { + {0x01, "960P/PD"}, + {0x02, "960PL"}, + {0x10, "960PG"}, + {0x11, "960PJ"}, + {0x12, "960PR"}, + {0x13, "960PT"}, + {0x14, "960PTL0"}, + {0x15, "960PRL"}, + {0x16, "960PTL1"}, + {0x20, "1100PVX"}, + {-1, NULL} +}; + +static void +controller_print(int unit, void *arg) +{ + struct mlx_enquiry2 enq; + struct mlx_phys_drv pd; + int verbosity = *(int *)arg; + static char buf[80]; + char *model; + int i, channel, target; + + if (verbosity == 0) + return; + + /* fetch and print controller data */ + if (mlx_enquiry(unit, &enq)) { + printf("mlx%d: error submitting ENQUIRY2\n", unit); + } else { + + for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) { + if ((enq.me_hardware_id & 0xff) == mlx_controller_names[i].hwid) { + model = mlx_controller_names[i].name; + break; + } + } + if (model == NULL) { + sprintf(buf, " model 0x%x", enq.me_hardware_id & 0xff); + model = buf; + } + + printf("mlx%d: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n", + unit, model, + enq.me_actual_channels, + enq.me_actual_channels > 1 ? "s" : "", + enq.me_firmware_id & 0xff, + (enq.me_firmware_id >> 8) & 0xff, + (enq.me_firmware_id >> 16), + (enq.me_firmware_id >> 24) & 0xff, + enq.me_mem_size / (1024 * 1024)); + + if (verbosity > 1) { + printf(" Hardware ID 0x%08x\n", enq.me_hardware_id); + printf(" Firmware ID 0x%08x\n", enq.me_firmware_id); + printf(" Configured/Actual channels %d/%d\n", enq.me_configured_channels, + enq.me_actual_channels); + printf(" Max Targets %d\n", enq.me_max_targets); + printf(" Max Tags %d\n", enq.me_max_tags); + printf(" Max System Drives %d\n", enq.me_max_sys_drives); + printf(" Max Arms %d\n", enq.me_max_arms); + printf(" Max Spans %d\n", enq.me_max_spans); + printf(" DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", enq.me_mem_size, + enq.me_cache_size, enq.me_flash_size, enq.me_nvram_size); + printf(" DRAM type %d\n", enq.me_mem_type); + printf(" Clock Speed %dns\n", enq.me_clock_speed); + printf(" Hardware Speed %dns\n", enq.me_hardware_speed); + printf(" Max Commands %d\n", enq.me_max_commands); + printf(" Max SG Entries %d\n", enq.me_max_sg); + printf(" Max DP %d\n", enq.me_max_dp); + printf(" Max IOD %d\n", enq.me_max_iod); + printf(" Max Comb %d\n", enq.me_max_comb); + printf(" Latency %ds\n", enq.me_latency); + printf(" SCSI Timeout %ds\n", enq.me_scsi_timeout); + printf(" Min Free Lines %d\n", enq.me_min_freelines); + printf(" Rate Constant %d\n", enq.me_rate_const); + printf(" MAXBLK %d\n", enq.me_maxblk); + printf(" Blocking Factor %d sectors\n", enq.me_blocking_factor); + printf(" Cache Line Size %d blocks\n", enq.me_cacheline); + printf(" SCSI Capability %s%dMHz, %d bit\n", + enq.me_scsi_cap & (1<<4) ? "differential " : "", + (1 << ((enq.me_scsi_cap >> 2) & 3)) * 10, + 8 << (enq.me_scsi_cap & 0x3)); + printf(" Firmware Build Number %d\n", enq.me_firmware_build); + printf(" Fault Management Type %d\n", enq.me_fault_mgmt_type); +#if 0 + printf(" Features %b\n", enq.me_firmware_features, + "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n"); +#endif + } + + /* fetch and print physical drive data */ + for (channel = 0; channel < enq.me_configured_channels; channel++) { + for (target = 0; target < enq.me_max_targets; target++) { + if ((mlx_get_device_state(unit, channel, target, &pd) == 0) && + (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT)) { + mlx_print_phys_drv(&pd, channel, target, " ", verbosity - 1); + if (verbosity > 1) { + /* XXX print device statistics? */ + } + } + } + } + } +} + +static int +cmd_status(int argc, char *argv[]) +{ + int ch, verbosity = 1, i, unit; + + optreset = 1; + optind = 1; + while ((ch = getopt(argc, argv, "qv")) != -1) + switch(ch) { + case 'q': + verbosity = 0; + break; + case 'v': + verbosity = 2; + break; + default: + return(cmd_help(argc, argv)); + } + argc -= optind; + argv += optind; + + if (argc < 1) { + mlx_foreach(controller_print, &verbosity); + mlxd_foreach(status_print, &verbosity); + } else { + for (i = 0; i < argc; i++) { + if ((unit = driveunit(argv[i])) == -1) { + warnx("'%s' is not a valid drive", argv[i]); + } else { + status_print(unit, &verbosity); + } + } + } + return(status_result); +} + +/******************************************************************************** + * Recscan for system drives on one or more controllers. + * + * rescan <controller> [<controller>...] + * rescan -a + */ +static void +rescan_ctrlr(int unit, void *junk) +{ + int fd; + + /* Get the device */ + if ((fd = open(ctrlrpath(unit), 0)) < 0) { + warn("can't open %s", ctrlrpath(unit)); + return; + } + + if (ioctl(fd, MLX_RESCAN_DRIVES) < 0) + warn("can't rescan %s", ctrlrname(unit)); + close(fd); +} + +static int +cmd_rescan(int argc, char *argv[]) +{ + int all = 0, i, ch, unit; + + optreset = 1; + optind = 1; + while ((ch = getopt(argc, argv, "a")) != -1) + switch(ch) { + case 'a': + all = 1; + break; + default: + return(cmd_help(argc, argv)); + } + argc -= optind; + argv += optind; + + if (all) { + mlx_foreach(rescan_ctrlr, NULL); + } else { + for (i = 0; i < argc; i++) { + if ((unit = ctrlrunit(argv[i])) == -1) { + warnx("'%s' is not a valid controller", argv[i]); + } else { + rescan_ctrlr(unit, NULL); + } + } + } + return(0); +} + +/******************************************************************************** + * Detach one or more system drives from a controller. + * + * detach <drive> [<drive>...] + * Detach <drive>. + * + * detach -a <controller> [<controller>...] + * Detach all drives on <controller>. + * + */ +static void +detach_drive(int unit, void *arg) +{ + int fd; + + /* Get the device */ + if ((fd = open(ctrlrpath(unit), 0)) < 0) { + warn("can't open %s", ctrlrpath(unit)); + return; + } + + if (ioctl(fd, MLX_DETACH_DRIVE, &unit) < 0) + warn("can't detach %s", drivename(unit)); + close(fd); +} + +static int +cmd_detach(int argc, char *argv[]) +{ + struct mlxd_foreach_action ma; + int all = 0, i, ch, unit; + + optreset = 1; + optind = 1; + while ((ch = getopt(argc, argv, "a")) != -1) + switch(ch) { + case 'a': + all = 1; + break; + default: + return(cmd_help(argc, argv)); + } + argc -= optind; + argv += optind; + + if (all) { + ma.func = detach_drive; + ma.arg = &unit; + for (i = 0; i < argc; i++) { + if ((unit = ctrlrunit(argv[i])) == -1) { + warnx("'%s' is not a valid controller", argv[i]); + } else { + mlxd_foreach_ctrlr(unit, &ma); + } + } + } else { + for (i = 0; i < argc; i++) { + if ((unit = driveunit(argv[i])) == -1) { + warnx("'%s' is not a valid drive", argv[i]); + } else { + /* run across all controllers to find this drive */ + mlx_foreach(detach_drive, &unit); + } + } + } + return(0); +} + +/******************************************************************************** + * Initiate a consistency check on a system drive. + * + * check [<drive>] + * Start a check of <drive> + * + */ +static int +cmd_check(int argc, char *argv[]) +{ + int unit, fd, result; + + if (argc != 2) + return(cmd_help(argc, argv)); + + if ((unit = driveunit(argv[1])) == -1) { + warnx("'%s' is not a valid drive", argv[1]); + } else { + + /* Get the device */ + if ((fd = open(drivepath(unit), 0)) < 0) { + warn("can't open %s", drivepath(unit)); + } else { + /* Try to start the check */ + if ((ioctl(fd, MLXD_CHECKASYNC, &result)) < 0) { + switch(result) { + case 0x0002: + warnx("one or more of the SCSI disks on which the drive '%s' depends is DEAD", argv[1]); + break; + case 0x0105: + warnx("drive %s is invalid, or not a drive which can be checked", argv[1]); + break; + case 0x0106: + warnx("drive rebuild or consistency check is already in progress on this controller"); + break; + default: + warn("ioctl MLXD_CHECKASYNC"); + } + } + } + } + return(0); +} + +/******************************************************************************** + * Initiate a physical drive rebuild + * + * rebuild <controller> <channel>:<target> + * Start a rebuild of <controller>:<channel>:<target> + * + */ +static int +cmd_rebuild(int argc, char *argv[]) +{ + struct mlx_rebuild_request rb; + int unit, fd; + + if (argc != 3) + return(cmd_help(argc, argv)); + + /* parse arguments */ + if ((unit = ctrlrunit(argv[1])) == -1) { + warnx("'%s' is not a valid controller", argv[1]); + return(1); + } + /* try diskXXXX and unknownXXXX as we report the latter for a dead drive ... */ + if ((sscanf(argv[2], "disk%2d%2d", &rb.rr_channel, &rb.rr_target) != 2) && + (sscanf(argv[2], "unknown%2d%2d", &rb.rr_channel, &rb.rr_target) != 2)) { + warnx("'%s' is not a valid physical drive", argv[2]); + return(1); + } + /* get the device */ + if ((fd = open(ctrlrpath(unit), 0)) < 0) { + warn("can't open %s", ctrlrpath(unit)); + return(1); + } + /* try to start the rebuild */ + if ((ioctl(fd, MLX_REBUILDASYNC, &rb)) < 0) { + switch(rb.rr_status) { + case 0x0002: + warnx("the drive at %d:%d is already ONLINE", rb.rr_channel, rb.rr_target); + break; + case 0x0004: + warnx("drive failed during rebuild"); + break; + case 0x0105: + warnx("there is no drive at channel %d, target %d", rb.rr_channel, rb.rr_target); + break; + case 0x0106: + warnx("drive rebuild or consistency check is already in progress on this controller"); + break; + default: + warn("ioctl MLXD_CHECKASYNC"); + } + } + return(0); +} + +#ifdef SUPPORT_PAUSE +/******************************************************************************** + * Pause one or more channels on a controller + * + * pause [-d <delay>] [-t <time>] <controller> [<channel>...] + * Pauses <channel> (or all channels) for <time> seconds after a + * delay of <delay> seconds. + * pause <controller> -c + * Cancels pending pause + */ +static int +cmd_pause(int argc, char *argv[]) +{ + struct mlx_pause mp; + int unit, i, ch, fd, cancel = 0; + char *cp; + int oargc = argc; + char **oargv = argv; + + mp.mp_which = 0; + mp.mp_when = 30; + mp.mp_howlong = 30; + optreset = 1; + optind = 1; + while ((ch = getopt(argc, argv, "cd:t:")) != -1) + switch(ch) { + case 'c': + cancel = 1; + break; + case 'd': + mp.mp_when = strtol(optarg, &cp, 0); + if (*cp != 0) + return(cmd_help(argc, argv)); + break; + case 't': + mp.mp_howlong = strtol(optarg, &cp, 0); + if (*cp != 0) + return(cmd_help(argc, argv)); + break; + default: + return(cmd_help(argc, argv)); + } + argc -= optind; + argv += optind; + + /* get controller unit number that we're working on */ + if ((argc < 1) || ((unit = ctrlrunit(argv[0])) == -1)) + return(cmd_help(oargc, oargv)); + + /* Get the device */ + if ((fd = open(ctrlrpath(unit), 0)) < 0) { + warn("can't open %s", ctrlrpath(unit)); + return(1); + } + + if (argc == 1) { + /* controller-wide pause/cancel */ + mp.mp_which = cancel ? MLX_PAUSE_CANCEL : MLX_PAUSE_ALL; + } else { + for (i = 1; i < argc; i++) { + ch = strtol(argv[i], &cp, 0); + if (*cp != 0) { + warnx("bad channel number '%s'", argv[i]); + continue; + } else { + mp.mp_which |= (1 << ch); + } + } + } + if ((ioctl(fd, MLX_PAUSE_CHANNEL, &mp)) < 0) + warn("couldn't %s %s", cancel ? "cancel pause on" : "pause", ctrlrname(unit)); + close(fd); + return(0); +} +#endif /* SUPPORT_PAUSE */ + diff --git a/usr.sbin/mlxcontrol/config.c b/usr.sbin/mlxcontrol/config.c new file mode 100644 index 0000000..3f5ba59 --- /dev/null +++ b/usr.sbin/mlxcontrol/config.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 1999 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <err.h> + +#if 0 +#include <sys/mlxio.h> +#include <sys/mlxreg.h> +#else +#include "../sys/dev/mlx/mlxio.h" +#include "../sys/dev/mlx/mlxreg.h" +#endif + +#include "mlxcontrol.h" + +static void print_span(struct mlx_sys_drv_span *span, int arms); +static void print_sys_drive(struct conf_config *conf, int drvno); +static void print_phys_drive(struct conf_config *conf, int chn, int targ); + +/******************************************************************************** + * Get the configuration from the selected controller. + * + * config <controller> + * Print the configuration for <controller> + * + * XXX update to support adding/deleting drives. + */ + +int +cmd_config(int argc, char *argv[]) +{ + struct conf_config conf; + int unit = 0; /* XXX */ + int i, j; + + bzero(&conf.cc_cfg, sizeof(conf.cc_cfg)); + if (mlx_read_configuration(unit, &conf.cc_cfg)) { + printf("mlx%d: error submitting READ CONFIGURATION\n", unit); + } else { + + printf("# Controller <INSERT DETAILS HERE>\n"); + printf("#\n# Physical devices connected:\n"); + for (i = 0; i < 5; i++) + for (j = 0; j < 16; j++) + print_phys_drive(&conf, i, j); + printf("#\n# System Drives defined:\n"); + + for (i = 0; i < conf.cc_cfg.cc_num_sys_drives; i++) + print_sys_drive(&conf, i); + } + return(0); +} + + +/******************************************************************************** + * Print details for the system drive (drvno) in a format that we will be + * able to parse later. + * + * drive?? <raidlevel> <writemode> + * span? 0x????????-0x???????? ????MB on <disk> [...] + * ... + */ +static void +print_span(struct mlx_sys_drv_span *span, int arms) +{ + int i; + + printf("0x%08x-0x%08x %uMB on", span->sp_start_lba, span->sp_start_lba + span->sp_nblks, span->sp_nblks / 2048); + for (i = 0; i < arms; i++) + printf(" disk%02d%02d", span->sp_arm[i] >> 4, span->sp_arm[i] & 0x0f); + printf("\n"); +} + +static void +print_sys_drive(struct conf_config *conf, int drvno) +{ + struct mlx_sys_drv *drv = &conf->cc_cfg.cc_sys_drives[drvno]; + int i; + + printf("drive%02d ", drvno); + switch(drv->sd_raidlevel & 0xf) { + case MLX_SYS_DRV_RAID0: + printf("RAID0"); + break; + case MLX_SYS_DRV_RAID1: + printf("RAID1"); + break; + case MLX_SYS_DRV_RAID3: + printf("RAID3"); + break; + case MLX_SYS_DRV_RAID5: + printf("RAID5"); + break; + case MLX_SYS_DRV_RAID6: + printf("RAID6"); + break; + case MLX_SYS_DRV_JBOD: + printf("JBOD"); + break; + default: + printf("RAID?"); + } + printf(" write%s\n", drv->sd_raidlevel & MLX_SYS_DRV_WRITEBACK ? "back" : "through"); + + for (i = 0; i < drv->sd_valid_spans; i++) { + printf(" span%d ", i); + print_span(&drv->sd_span[i], drv->sd_valid_arms); + } +} + +/******************************************************************************** + * Print details for the physical drive at chn/targ in a format suitable for + * human consumption. + * + * <type>CCTT (<state>) "<vendor>/<model>" + * ????MB <features> + * + */ +static void +print_phys_drive(struct conf_config *conf, int chn, int targ) +{ + struct mlx_phys_drv *drv = &conf->cc_cfg.cc_phys_drives[chn * 16 + targ]; + + /* if the drive isn't present, don't print it */ + if (!(drv->pd_flags1 & MLX_PHYS_DRV_PRESENT)) + return; + + mlx_print_phys_drv(drv, chn, targ, "# ", 1); +} + + diff --git a/usr.sbin/mlxcontrol/interface.c b/usr.sbin/mlxcontrol/interface.c new file mode 100644 index 0000000..a2c5dfa --- /dev/null +++ b/usr.sbin/mlxcontrol/interface.c @@ -0,0 +1,292 @@ +/*- + * Copyright (c) 1999 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <cam/scsi/scsi_all.h> + +#if 0 +#include <sys/mlxio.h> +#include <sys/mlxreg.h> +#else +#include "../sys/dev/mlx/mlxio.h" +#include "../sys/dev/mlx/mlxreg.h" +#endif + +#include "mlxcontrol.h" + +/******************************************************************************** + * Iterate over all mlx devices, call (func) with each ones' path and (arg) + */ +void +mlx_foreach(void (*func)(int unit, void *arg), void *arg) +{ + int i, fd; + + /* limit total count for sanity */ + for (i = 0; i < 64; i++) { + /* verify we can open it */ + if ((fd = open(ctrlrpath(i), 0)) >= 0) + close(fd); + /* if we can, do */ + if (fd >= 0) { + func(i, arg); + } + } +} + +/******************************************************************************** + * Open the controller (unit) and give the fd to (func) along with (arg) + */ +void +mlx_perform(int unit, void (*func)(int fd, void *arg), void *arg) +{ + int fd; + + if ((fd = open(ctrlrpath(unit), 0)) >= 0) { + func(fd, arg); + close(fd); + } +} + +/******************************************************************************** + * Iterate over all mlxd devices, call (func) with each ones' path and (arg) + */ +void +mlxd_foreach_ctrlr(int unit, void *arg) +{ + struct mlxd_foreach_action *ma = (struct mlxd_foreach_action *)arg; + int i, fd; + + /* Get the device */ + if ((fd = open(ctrlrpath(unit), 0)) < 0) + return; + + for (i = -1; ;) { + /* Get the unit number of the next child device */ + if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0) + return; + + /* check that we can open this unit */ + if ((fd = open(drivepath(i), 0)) >= 0) + close(fd); + /* if we can, do */ + if (fd >= 0) { + ma->func(i, ma->arg); + } + } +} + +void +mlxd_foreach(void (*func)(int unit, void *arg), void *arg) +{ + struct mlxd_foreach_action ma; + + ma.func = func; + ma.arg = arg; + mlx_foreach(mlxd_foreach_ctrlr, &ma); +} + +/******************************************************************************** + * Find the controller that manages the drive (unit), return controller number + * and system drive number on that controller. + */ +static struct +{ + int unit; + int ctrlr; + int sysdrive; +} mlxd_find_ctrlr_param; + +static void +mlxd_find_ctrlr_search(int unit, void *arg) +{ + int i, fd; + + /* Get the device */ + if ((fd = open(ctrlrpath(unit), 0)) >= 0) { + for (i = -1; ;) { + /* Get the unit number of the next child device */ + if (ioctl(fd, MLX_NEXT_CHILD, &i) < 0) + break; + + /* is this child the unit we want? */ + if (i == mlxd_find_ctrlr_param.unit) { + mlxd_find_ctrlr_param.ctrlr = unit; + if (ioctl(fd, MLX_GET_SYSDRIVE, &i) == 0) + mlxd_find_ctrlr_param.sysdrive = i; + } + } + close(fd); + } +} + +int +mlxd_find_ctrlr(int unit, int *ctrlr, int *sysdrive) +{ + mlxd_find_ctrlr_param.unit = unit; + mlxd_find_ctrlr_param.ctrlr = -1; + mlxd_find_ctrlr_param.sysdrive = -1; + + mlx_foreach(mlxd_find_ctrlr_search, NULL); + if ((mlxd_find_ctrlr_param.ctrlr != -1) && (mlxd_find_ctrlr_param.sysdrive != -1)) { + *ctrlr = mlxd_find_ctrlr_param.ctrlr; + *sysdrive = mlxd_find_ctrlr_param.sysdrive; + return(0); + } + return(1); +} + + +/******************************************************************************** + * Send a command to the controller on (fd) + */ + +void +mlx_command(int fd, void *arg) +{ + struct mlx_usercommand *cmd = (struct mlx_usercommand *)arg; + int error; + + error = ioctl(fd, MLX_COMMAND, cmd); + if (error != 0) + cmd->mu_error = error; +} + +/******************************************************************************** + * Perform an ENQUIRY2 command and return information related to the controller + * (unit) + */ +int +mlx_enquiry(int unit, struct mlx_enquiry2 *enq) +{ + struct mlx_usercommand cmd; + + /* build the command */ + cmd.mu_datasize = sizeof(*enq); + cmd.mu_buf = enq; + cmd.mu_bufptr = 8; + cmd.mu_command[0] = MLX_CMD_ENQUIRY2; + + /* hand it off for processing */ + mlx_perform(unit, mlx_command, (void *)&cmd); + + return(cmd.mu_status != 0); +} + + +/******************************************************************************** + * Perform a READ CONFIGURATION command and return information related to the controller + * (unit) + */ +int +mlx_read_configuration(int unit, struct mlx_core_cfg *cfg) +{ + struct mlx_usercommand cmd; + + /* build the command */ + cmd.mu_datasize = sizeof(*cfg); + cmd.mu_buf = cfg; + cmd.mu_bufptr = 8; + cmd.mu_command[0] = MLX_CMD_READ_CONFIG; + + /* hand it off for processing */ + mlx_perform(unit, mlx_command, (void *)&cmd); + + return(cmd.mu_status != 0); +} + +/******************************************************************************** + * Perform a SCSI INQUIRY command and return pointers to the relevant data. + */ +int +mlx_scsi_inquiry(int unit, int channel, int target, char **vendor, char **device, char **revision) +{ + struct mlx_usercommand cmd; + static struct { + struct mlx_dcdb dcdb; + union { + struct scsi_inquiry_data inq; + u_int8_t pad[SHORT_INQUIRY_LENGTH]; + } d; + } __attribute__ ((packed)) dcdb_cmd; + struct scsi_inquiry *inq_cmd = (struct scsi_inquiry *)&dcdb_cmd.dcdb.dcdb_cdb[0]; + + /* build the command */ + cmd.mu_datasize = sizeof(dcdb_cmd); + cmd.mu_buf = &dcdb_cmd; + cmd.mu_command[0] = MLX_CMD_DIRECT_CDB; + + /* build the DCDB */ + bzero(&dcdb_cmd, sizeof(dcdb_cmd)); + dcdb_cmd.dcdb.dcdb_channel = channel; + dcdb_cmd.dcdb.dcdb_target = target; + dcdb_cmd.dcdb.dcdb_flags = MLX_DCDB_DATA_IN | MLX_DCDB_TIMEOUT_10S; + dcdb_cmd.dcdb.dcdb_datasize = SHORT_INQUIRY_LENGTH; + dcdb_cmd.dcdb.dcdb_cdb_length = 6; + dcdb_cmd.dcdb.dcdb_sense_length = SSD_FULL_SIZE; + + /* build the cdb */ + inq_cmd->opcode = INQUIRY; + inq_cmd->length = SHORT_INQUIRY_LENGTH; + + /* hand it off for processing */ + mlx_perform(unit, mlx_command, &cmd); + + if (cmd.mu_status == 0) { + *vendor = &dcdb_cmd.d.inq.vendor[0]; + *device = &dcdb_cmd.d.inq.product[0]; + *revision = &dcdb_cmd.d.inq.revision[0]; + } + return(cmd.mu_status); +} + +/******************************************************************************** + * Perform a GET DEVICE STATE command and return pointers to the relevant data. + */ +int +mlx_get_device_state(int unit, int channel, int target, struct mlx_phys_drv *drv) +{ + struct mlx_usercommand cmd; + + /* build the command */ + cmd.mu_datasize = sizeof(*drv); + cmd.mu_buf = drv; + cmd.mu_bufptr = 8; + cmd.mu_command[0] = MLX_CMD_DEVICE_STATE; + cmd.mu_command[2] = channel; + cmd.mu_command[3] = target; + + /* hand it off for processing */ + mlx_perform(unit, mlx_command, (void *)&cmd); + + return(cmd.mu_status != 0); +} diff --git a/usr.sbin/mlxcontrol/mlxcontrol.8 b/usr.sbin/mlxcontrol/mlxcontrol.8 new file mode 100644 index 0000000..267decf --- /dev/null +++ b/usr.sbin/mlxcontrol/mlxcontrol.8 @@ -0,0 +1,116 @@ +.\" +.\" Copyright (c) 2000 Michael Smith +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 10, 2000 +.Dt MLXCONTROL 8 +.Os +.Sh NAME +.Nm mlxcontrol +.Nd Mylex DAC-family RAID management utility +.Sh SYNOPSIS +.Nm mlxcontrol +.Aq command +.Op args +.Nm mlxcontrol +status +.Op Fl qv +.Op Ar drive +.Nm mlxcontrol +rescan +.Ar controller +.Op Ar controller ... +.Nm mlxcontrol +detach +.Ar drive +.Op Ar drive ... +.Nm mlxcontrol +detach +.Fl a +.Nm mlxcontrol +check +.Ar drive +.Nm mlxcontrol +config +.Ar controller +.Nm mlxcontrol +help +.Ar command +.Sh DESCRIPTION +The +.Nm +utility provides status monitoring and management functions for devices attached +to the +.Xr mlx 4 +driver. +.Pp +Controller names are of the form "mlxN" where N is the unit number of the controller. +Drive names are of the form "mlxdN" where N is the unit number of the drive. Do not +specify the path to a device node. +.Pp +.Bl -tag -width status +.It status +Print the status of controllers and system drives. If one or more drives are specified, +only print information about these drives, otherwise print information about all controllers +and drives in the system. With the +.Fl v +flag, display much more verbose information. +With the +.Fl q +flag, do not print any output. This command returns 0 if all drives tested are online, 1 +if one or more drives are critical and 2 if one or more are offline. +.It rescan +Rescan one or more controllers for non-attached system drives (eg. drives that have been +detached or created subsequent to driver initialisation). If the +.Fl a +flag is supplied, rescan all controllers in the system. +.It detach +Detach one or more system drives. Drives must be unmounted and not opened by any other +utility for this command to succeed. If the +.Fl a +flag is supplied, detach all system drives from the nominated controller. +.It check +Initiate a consistency check and repair pass on a redundant system drive (eg. RAID1 or RAID5). +The controller will scan the system drive and repair any inconsistencies. This command +returns immediately; use the +.Ar status +command to monitor the progress of the check. +.It config +Print the current configuration from the nominated controller. This command will be +updated to allow addition/deletion of system drives from a configuration in a future +release. +.It help +Print usage information for +.Ar command. +.Sh BUGS +The +.Ar config +command does not yet support modifying system drive configuration. +.Pp +Error log extraction is not yet supported. +.Sh AUTHORS +The mlxcontrol utility was written by +.An Michael Smith +.Aq msmith@FreeBSD.org . + diff --git a/usr.sbin/mlxcontrol/mlxcontrol.h b/usr.sbin/mlxcontrol/mlxcontrol.h new file mode 100644 index 0000000..f0225b5 --- /dev/null +++ b/usr.sbin/mlxcontrol/mlxcontrol.h @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 1999 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/queue.h> + +#define debug(fmt, args...) printf("%s: " fmt "\n", __FUNCTION__ , ##args) + +struct mlxd_foreach_action +{ + void (*func)(int unit, void *arg); + void *arg; +}; + +extern void mlx_foreach(void (*func)(int unit, void *arg), void *arg); +void mlxd_foreach_ctrlr(int unit, void *arg); +extern void mlxd_foreach(void (*func)(int unit, void *arg), void *arg); +extern int mlxd_find_ctrlr(int unit, int *ctrlr, int *sysdrive); +extern void mlx_perform(int unit, void (*func)(int fd, void *arg), void *arg); +extern void mlx_command(int fd, void *arg); +extern int mlx_enquiry(int unit, struct mlx_enquiry2 *enq); +extern int mlx_read_configuration(int unit, struct mlx_core_cfg *cfg); +extern int mlx_scsi_inquiry(int unit, int bus, int target, char **vendor, char **device, char **revision); +extern int mlx_get_device_state(int fd, int channel, int target, struct mlx_phys_drv *drv); + +extern char *ctrlrpath(int unit); +extern char *ctrlrname(int unit); +extern char *drivepath(int unit); +extern char *drivename(int unit); +extern int ctrlrunit(char *str); +extern int driveunit(char *str); + +extern void mlx_print_phys_drv(struct mlx_phys_drv *drv, int channel, int target, char *prefix, int verbose); + +struct conf_phys_drv +{ + TAILQ_ENTRY(conf_phys_drv) pd_link; + int pd_bus; + int pd_target; + struct mlx_phys_drv pd_drv; +}; + +struct conf_span +{ + TAILQ_ENTRY(conf_span) s_link; + struct conf_phys_drv *s_drvs[8]; + struct mlx_sys_drv_span s_span; +}; + +struct conf_sys_drv +{ + TAILQ_ENTRY(conf_sys_drv) sd_link; + struct conf_span *sd_spans[4]; + struct mlx_sys_drv sd_drv; +}; + +struct conf_config +{ + TAILQ_HEAD(,conf_phys_drv) cc_phys_drvs; + TAILQ_HEAD(,conf_span) cc_spans; + TAILQ_HEAD(,conf_sys_drv) cc_sys_drvs; + struct conf_sys_drv *cc_drives[32]; + struct mlx_core_cfg cc_cfg; +}; + diff --git a/usr.sbin/mlxcontrol/util.c b/usr.sbin/mlxcontrol/util.c new file mode 100644 index 0000000..9431a20 --- /dev/null +++ b/usr.sbin/mlxcontrol/util.c @@ -0,0 +1,177 @@ +/*- + * Copyright (c) 1999 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <stdio.h> +#include <paths.h> +#include <string.h> + +#if 0 +#include <sys/mlxio.h> +#include <sys/mlxreg.h> +#else +#include "../sys/dev/mlx/mlxio.h" +#include "../sys/dev/mlx/mlxreg.h" +#endif + +#include "mlxcontrol.h" + +/******************************************************************************** + * Various name-producing and -parsing functions + */ + +/* return path of controller (unit) */ +char * +ctrlrpath(int unit) +{ + static char buf[32]; + + sprintf(buf, "%s%s", _PATH_DEV, ctrlrname(unit)); + return(buf); +} + +/* return name of controller (unit) */ +char * +ctrlrname(int unit) +{ + static char buf[32]; + + sprintf(buf, "mlx%d", unit); + return(buf); +} + +/* return path of drive (unit) */ +char * +drivepath(int unit) +{ + static char buf[32]; + + sprintf(buf, "%s%s", _PATH_DEV, drivename(unit)); + return(buf); +} + +/* return name of drive (unit) */ +char * +drivename(int unit) +{ + static char buf[32]; + + sprintf(buf, "mlxd%d", unit); + return(buf); +} + +/* get controller unit number from name in (str) */ +int +ctrlrunit(char *str) +{ + int unit; + + if (sscanf(str, "mlx%d", &unit) == 1) + return(unit); + return(-1); +} + +/* get drive unit number from name in (str) */ +int +driveunit(char *str) +{ + int unit; + + if (sscanf(str, "mlxd%d", &unit) == 1) + return(unit); + return(-1); +} + +/******************************************************************************** + * Standardised output of various data structures. + */ + +void +mlx_print_phys_drv(struct mlx_phys_drv *drv, int chn, int targ, char *prefix, int verbose) +{ + char *type, *device, *vendor, *revision; + + switch(drv->pd_flags2 & 0x03) { + case MLX_PHYS_DRV_DISK: + type = "disk"; + break; + case MLX_PHYS_DRV_SEQUENTIAL: + type = "tape"; + break; + case MLX_PHYS_DRV_CDROM: + type= "cdrom"; + break; + case MLX_PHYS_DRV_OTHER: + default: + type = "unknown"; + break; + } + printf("%s%s%02d%02d ", prefix, type, chn, targ); + switch(drv->pd_status) { + case MLX_PHYS_DRV_DEAD: + printf(" (dead) "); + break; + case MLX_PHYS_DRV_WRONLY: + printf(" (write-only) "); + break; + case MLX_PHYS_DRV_ONLINE: + printf(" (online) "); + break; + case MLX_PHYS_DRV_STANDBY: + printf(" (standby) "); + break; + default: + printf(" (0x%02x) ", drv->pd_status); + } + printf("\n"); + + if (verbose) { + + printf("%s ", prefix); + if (!mlx_scsi_inquiry(0, chn, targ, &vendor, &device, &revision)) { + printf("'%8.8s' '%16.16s' '%4.4s'", vendor, device, revision); + } else { + printf("<IDENTIFY FAILED>"); + } + + printf(" %dMB ", drv->pd_config_size / 2048); + + if (drv->pd_flags2 & MLX_PHYS_DRV_FAST20) { + printf(" fast20"); + } else if (drv->pd_flags2 & MLX_PHYS_DRV_FAST) { + printf(" fast"); + } + if (drv->pd_flags2 & MLX_PHYS_DRV_WIDE) + printf(" wide"); + if (drv->pd_flags2 & MLX_PHYS_DRV_SYNC) + printf(" sync"); + if (drv->pd_flags2 & MLX_PHYS_DRV_TAG) + printf(" tag-enabled"); + printf("\n"); + } +} |