summaryrefslogtreecommitdiffstats
path: root/sbin/camcontrol/camcontrol.c
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/camcontrol/camcontrol.c
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/camcontrol/camcontrol.c')
-rw-r--r--sbin/camcontrol/camcontrol.c208
1 files changed, 169 insertions, 39 deletions
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