summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authorken <ken@FreeBSD.org>2002-01-18 18:00:00 +0000
committerken <ken@FreeBSD.org>2002-01-18 18:00:00 +0000
commit1a5d09da65396eea992b33aa6d0253aecf4c1c41 (patch)
treece5b9acf24e775bf7a6575e54988c0c82c2bef1b /sbin
parent56895f2d6564a42dbff013892ab2f59c9c31b3c2 (diff)
downloadFreeBSD-src-1a5d09da65396eea992b33aa6d0253aecf4c1c41.zip
FreeBSD-src-1a5d09da65396eea992b33aa6d0253aecf4c1c41.tar.gz
Add 'camcontrol rescan all' and 'camcontrol reset all' functionality to
camcontrol. This enables rescanning all busses or resetting all busses in a system. The current implementation is not the ideal way to do it -- the ideal way to do it would be for the transport layer to handle wildcarded busses on bus rescan and reset operations. The current implementation enumerates all the busses and sends a rescan or reset CCB individually. Handling this behavior in the transport layer will happen later. Reviewed by: imp Tested by: joerg MFC after: 1 week
Diffstat (limited to 'sbin')
-rw-r--r--sbin/camcontrol/camcontrol.823
-rw-r--r--sbin/camcontrol/camcontrol.c208
2 files changed, 185 insertions, 46 deletions
diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index c01c07e..de37cf9 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -1,5 +1,5 @@
.\"
-.\" Copyright (c) 1998, 1999, 2000 Kenneth D. Merry.
+.\" Copyright (c) 1998, 1999, 2000, 2002 Kenneth D. Merry.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -72,10 +72,10 @@
.Op generic args
.Nm
.Ic rescan
-.Aq bus Ns Op :target:lun
+.Aq all | bus Ns Op :target:lun
.Nm
.Ic reset
-.Aq bus Ns Op :target:lun
+.Aq all | bus Ns Op :target:lun
.Nm
.Ic defects
.Op device id
@@ -251,12 +251,16 @@ start bit cleared.
Send the SCSI Start/Stop Unit (0x1B) command to the given device with the
start bit cleared and the eject bit set.
.It Ic rescan
-Tell the kernel to scan the given bus (XPT_SCAN_BUS), or bus:target:lun
+Tell the kernel to scan all busses in the system (with the
+.Ar all
+argument), the given bus (XPT_SCAN_BUS), or bus:target:lun
(XPT_SCAN_LUN) for new devices or devices that have gone away. The user
-may only specify a bus to scan, or a lun. Scanning all luns on a target
-isn't supported.
+may specify a scan of all busses, a single bus, or a lun. Scanning all luns
+on a target isn't supported.
.It Ic reset
-Tell the kernel to reset the given bus (XPT_RESET_BUS) by issuing a SCSI bus
+Tell the kernel to reset all busses in the system (with the
+.Ar all
+argument) or the given bus (XPT_RESET_BUS) by issuing a SCSI bus
reset for that bus, or to reset the given bus:target:lun
(XPT_RESET_DEV), typically by issuing a BUS DEVICE RESET message after
connecting to that device.
@@ -673,6 +677,11 @@ Edit mode page 1 (the Read-Write Error Recover page) for da3, and save the
settings on the drive. Mode page 1 contains a disk drive's auto read and
write reallocation settings, among other things.
.Pp
+.Dl camcontrol rescan all
+.Pp
+Rescan all SCSI busses in the system for devices that have been added,
+removed or changed.
+.Pp
.Dl camcontrol rescan 0
.Pp
Rescan SCSI bus 0 for devices that have been added, removed or changed.
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 639e7fd..5ca2e5b 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 1998, 1999, 2000, 2001 Kenneth D. Merry
+ * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002 Kenneth D. Merry
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -321,14 +321,14 @@ getdevtree(void)
if ((ccb.ccb_h.status != CAM_REQ_CMP)
|| ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
&& (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
- fprintf(stderr, "got CAM error %#x, CDM error %d\n",
- ccb.ccb_h.status, ccb.cdm.status);
+ warnx("got CAM error %#x, CDM error %d\n",
+ ccb.ccb_h.status, ccb.cdm.status);
error = 1;
break;
}
for (i = 0; i < ccb.cdm.num_matches; i++) {
- switch(ccb.cdm.matches[i].type) {
+ switch (ccb.cdm.matches[i].type) {
case DEV_MATCH_BUS: {
struct bus_match_result *bus_result;
@@ -968,18 +968,27 @@ static int
dorescan_or_reset(int argc, char **argv, int rescan)
{
static const char must[] =
- "you must specify a bus, or a bus:target:lun to %s";
+ "you must specify \"all\", a bus, or a bus:target:lun to %s";
int rv, error = 0;
int bus = -1, target = -1, lun = -1;
+ char *tstr;
if (argc < 3) {
warnx(must, rescan? "rescan" : "reset");
return(1);
}
- rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist);
- if (rv != 1 && rv != 3) {
- warnx(must, rescan? "rescan" : "reset");
- return(1);
+
+ tstr = argv[optind];
+ while (isspace(*tstr) && (*tstr != '\0'))
+ tstr++;
+ if (strncasecmp(tstr, "all", strlen("all")) == 0)
+ arglist |= CAM_ARG_BUS;
+ else {
+ rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist);
+ if (rv != 1 && rv != 3) {
+ warnx(must, rescan? "rescan" : "reset");
+ return(1);
+ }
}
if ((arglist & CAM_ARG_BUS)
@@ -995,13 +1004,12 @@ dorescan_or_reset(int argc, char **argv, int rescan)
static int
rescan_or_reset_bus(int bus, int rescan)
{
- union ccb ccb;
- int fd;
+ union ccb ccb, matchccb;
+ int curbus;
+ int fd, retval;
+ int bufsize;
- if (bus < 0) {
- warnx("invalid bus number %d", bus);
- return(1);
- }
+ retval = 0;
if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
warnx("error opening tranport layer device %s", XPT_DEVICE);
@@ -1009,33 +1017,155 @@ rescan_or_reset_bus(int bus, int rescan)
return(1);
}
- ccb.ccb_h.func_code = rescan? XPT_SCAN_BUS : XPT_RESET_BUS;
- ccb.ccb_h.path_id = bus;
- ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
- ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
- ccb.crcn.flags = CAM_FLAG_NONE;
+ if (bus != -1) {
+ ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS;
+ ccb.ccb_h.path_id = bus;
+ ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
+ ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
+ ccb.crcn.flags = CAM_FLAG_NONE;
- /* run this at a low priority */
- ccb.ccb_h.pinfo.priority = 5;
+ /* run this at a low priority */
+ ccb.ccb_h.pinfo.priority = 5;
+
+ if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
+ warn("CAMIOCOMMAND ioctl failed");
+ close(fd);
+ return(1);
+ }
+
+ if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+ fprintf(stdout, "%s of bus %d was successful\n",
+ rescan ? "Re-scan" : "Reset", bus);
+ } else {
+ fprintf(stdout, "%s of bus %d returned error %#x\n",
+ rescan ? "Re-scan" : "Reset", bus,
+ ccb.ccb_h.status & CAM_STATUS_MASK);
+ retval = 1;
+ }
- if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
- warn("CAMIOCOMMAND ioctl failed");
close(fd);
- return(1);
+ return(retval);
+
}
- close(fd);
- if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
- fprintf(stdout, "%s of bus %d was successful\n",
- rescan? "Re-scan" : "Reset", bus);
- return(0);
- } else {
- fprintf(stdout, "%s of bus %d returned error %#x\n",
- rescan? "Re-scan" : "Reset", bus,
- ccb.ccb_h.status & CAM_STATUS_MASK);
- return(1);
+ /*
+ * The right way to handle this is to modify the xpt so that it can
+ * handle a wildcarded bus in a rescan or reset CCB. At the moment
+ * that isn't implemented, so instead we enumerate the busses and
+ * send the rescan or reset to those busses in the case where the
+ * given bus is -1 (wildcard). We don't send a rescan or reset
+ * to the xpt bus; sending a rescan to the xpt bus is effectively a
+ * no-op, sending a rescan to the xpt bus would result in a status of
+ * CAM_REQ_INVALID.
+ */
+ bzero(&(&matchccb.ccb_h)[1],
+ sizeof(struct ccb_dev_match) - sizeof(struct ccb_hdr));
+ matchccb.ccb_h.func_code = XPT_DEV_MATCH;
+ bufsize = sizeof(struct dev_match_result) * 20;
+ matchccb.cdm.match_buf_len = bufsize;
+ matchccb.cdm.matches=(struct dev_match_result *)malloc(bufsize);
+ if (matchccb.cdm.matches == NULL) {
+ warnx("can't malloc memory for matches");
+ retval = 1;
+ goto bailout;
+ }
+ matchccb.cdm.num_matches = 0;
+
+ matchccb.cdm.num_patterns = 1;
+ matchccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern);
+
+ matchccb.cdm.patterns = (struct dev_match_pattern *)malloc(
+ matchccb.cdm.pattern_buf_len);
+ if (matchccb.cdm.patterns == NULL) {
+ warnx("can't malloc memory for patterns");
+ retval = 1;
+ goto bailout;
}
+ matchccb.cdm.patterns[0].type = DEV_MATCH_BUS;
+ matchccb.cdm.patterns[0].pattern.bus_pattern.flags = BUS_MATCH_ANY;
+
+ do {
+ int i;
+
+ if (ioctl(fd, CAMIOCOMMAND, &matchccb) == -1) {
+ warn("CAMIOCOMMAND ioctl failed");
+ retval = 1;
+ goto bailout;
+ }
+
+ if ((matchccb.ccb_h.status != CAM_REQ_CMP)
+ || ((matchccb.cdm.status != CAM_DEV_MATCH_LAST)
+ && (matchccb.cdm.status != CAM_DEV_MATCH_MORE))) {
+ warnx("got CAM error %#x, CDM error %d\n",
+ matchccb.ccb_h.status, matchccb.cdm.status);
+ retval = 1;
+ goto bailout;
+ }
+
+ for (i = 0; i < matchccb.cdm.num_matches; i++) {
+ struct bus_match_result *bus_result;
+
+ /* This shouldn't happen. */
+ if (matchccb.cdm.matches[i].type != DEV_MATCH_BUS)
+ continue;
+
+ bus_result = &matchccb.cdm.matches[i].result.bus_result;
+
+ /*
+ * We don't want to rescan or reset the xpt bus.
+ * See above.
+ */
+ if (bus_result->path_id == -1)
+ continue;
+
+ ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS :
+ XPT_RESET_BUS;
+ ccb.ccb_h.path_id = bus_result->path_id;
+ ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
+ ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
+ ccb.crcn.flags = CAM_FLAG_NONE;
+
+ /* run this at a low priority */
+ ccb.ccb_h.pinfo.priority = 5;
+
+ if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
+ warn("CAMIOCOMMAND ioctl failed");
+ retval = 1;
+ goto bailout;
+ }
+
+ if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==CAM_REQ_CMP){
+ fprintf(stdout, "%s of bus %d was successful\n",
+ rescan? "Re-scan" : "Reset",
+ bus_result->path_id);
+ } else {
+ /*
+ * Don't bail out just yet, maybe the other
+ * rescan or reset commands will complete
+ * successfully.
+ */
+ fprintf(stderr, "%s of bus %d returned error "
+ "%#x\n", rescan? "Re-scan" : "Reset",
+ bus_result->path_id,
+ ccb.ccb_h.status & CAM_STATUS_MASK);
+ retval = 1;
+ }
+ }
+ } while ((matchccb.ccb_h.status == CAM_REQ_CMP)
+ && (matchccb.cdm.status == CAM_DEV_MATCH_MORE));
+
+bailout:
+
+ if (fd != -1)
+ close(fd);
+
+ if (matchccb.cdm.patterns != NULL)
+ free(matchccb.cdm.patterns);
+ if (matchccb.cdm.matches != NULL)
+ free(matchccb.cdm.matches);
+
+ return(retval);
}
static int
@@ -2997,8 +3127,8 @@ usage(int verbose)
" camcontrol stop [dev_id][generic args]\n"
" camcontrol eject [dev_id][generic args]\n"
#endif /* MINIMALISTIC */
-" camcontrol rescan <bus[:target:lun]>\n"
-" camcontrol reset <bus[:target:lun]>\n"
+" camcontrol rescan <all | bus[:target:lun]>\n"
+" camcontrol reset <all | bus[:target:lun]>\n"
#ifndef MINIMALISTIC
" camcontrol defects [dev_id][generic args] <-f format> [-P][-G]\n"
" camcontrol modepage [dev_id][generic args] <-m page | -l>\n"
@@ -3026,8 +3156,8 @@ usage(int verbose)
"start send a Start Unit command to the device\n"
"stop send a Stop Unit command to the device\n"
"eject send a Stop Unit command to the device with the eject bit set\n"
-"rescan rescan the given bus, or bus:target:lun\n"
-"reset reset the given bus, or bus:target:lun\n"
+"rescan rescan all busses, the given bus, or bus:target:lun\n"
+"reset reset all busses, the given bus, or bus:target:lun\n"
"defects read the defect list of the specified device\n"
"modepage display or edit (-e) the given mode page\n"
"cmd send the given scsi command, may need -i or -o as well\n"
OpenPOWER on IntegriCloud