This is a command-line management tool for RAID controllers managed by the
mlx(4) driver.
This commit is contained in:
parent
9b58ae8693
commit
b6a7bef2be
8
usr.sbin/mlxcontrol/Makefile
Normal file
8
usr.sbin/mlxcontrol/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= mlxcontrol
|
||||
SRCS= command.c config.c interface.c util.c
|
||||
MAN8= mlxcontrol.8
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
717
usr.sbin/mlxcontrol/command.c
Normal file
717
usr.sbin/mlxcontrol/command.c
Normal file
@ -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 */
|
||||
|
162
usr.sbin/mlxcontrol/config.c
Normal file
162
usr.sbin/mlxcontrol/config.c
Normal file
@ -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);
|
||||
}
|
||||
|
||||
|
292
usr.sbin/mlxcontrol/interface.c
Normal file
292
usr.sbin/mlxcontrol/interface.c
Normal file
@ -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);
|
||||
}
|
116
usr.sbin/mlxcontrol/mlxcontrol.8
Normal file
116
usr.sbin/mlxcontrol/mlxcontrol.8
Normal file
@ -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 .
|
||||
|
89
usr.sbin/mlxcontrol/mlxcontrol.h
Normal file
89
usr.sbin/mlxcontrol/mlxcontrol.h
Normal file
@ -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;
|
||||
};
|
||||
|
177
usr.sbin/mlxcontrol/util.c
Normal file
177
usr.sbin/mlxcontrol/util.c
Normal file
@ -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");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user