Unify BTL parsing for camcontrol debug
and reset
.
This makes `camcontrol debug` also allow peripheral device specification. While there, make BTL parser more strict and switch from strtok() to strsep(). MFC after: 2 weeks
This commit is contained in:
parent
e8e90fef03
commit
512efccf6d
@ -27,7 +27,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 19, 2019
|
||||
.Dd July 22, 2019
|
||||
.Dt CAMCONTROL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -185,7 +185,7 @@
|
||||
.Op Fl X
|
||||
.Op Fl c
|
||||
.Op Fl p
|
||||
.Aq all|off|bus Ns Op :target Ns Op :lun
|
||||
.Aq all | off | device id | bus Ns Op :target Ns Op :lun
|
||||
.Nm
|
||||
.Ic tags
|
||||
.Op device id
|
||||
|
@ -3534,6 +3534,66 @@ atasecurity(struct cam_device *device, int retry_count, int timeout,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert periph name into a bus, target and lun.
|
||||
*
|
||||
* Returns the number of parsed components, or 0.
|
||||
*/
|
||||
static int
|
||||
parse_btl_name(char *tstr, path_id_t *bus, target_id_t *target, lun_id_t *lun,
|
||||
cam_argmask *arglst)
|
||||
{
|
||||
int fd;
|
||||
union ccb ccb;
|
||||
|
||||
bzero(&ccb, sizeof(ccb));
|
||||
ccb.ccb_h.func_code = XPT_GDEVLIST;
|
||||
if (cam_get_device(tstr, ccb.cgdl.periph_name,
|
||||
sizeof(ccb.cgdl.periph_name), &ccb.cgdl.unit_number) == -1) {
|
||||
warnx("%s", cam_errbuf);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to get the passthrough device. This ioctl will
|
||||
* fail if the device name is null, if the device doesn't
|
||||
* exist, or if the passthrough driver isn't in the kernel.
|
||||
*/
|
||||
if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
|
||||
warn("Unable to open %s", XPT_DEVICE);
|
||||
return (0);
|
||||
}
|
||||
if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
|
||||
warn("Unable to find bus:target:lun for device %s%d",
|
||||
ccb.cgdl.periph_name, ccb.cgdl.unit_number);
|
||||
close(fd);
|
||||
return (0);
|
||||
}
|
||||
close(fd);
|
||||
if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
const struct cam_status_entry *entry;
|
||||
|
||||
entry = cam_fetch_status_entry(ccb.ccb_h.status);
|
||||
warnx("Unable to find bus:target_lun for device %s%d, "
|
||||
"CAM status: %s (%#x)",
|
||||
ccb.cgdl.periph_name, ccb.cgdl.unit_number,
|
||||
entry ? entry->status_text : "Unknown",
|
||||
ccb.ccb_h.status);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The kernel fills in the bus/target/lun. We don't
|
||||
* need the passthrough device name and unit number since
|
||||
* we aren't going to open it.
|
||||
*/
|
||||
*bus = ccb.ccb_h.path_id;
|
||||
*target = ccb.ccb_h.target_id;
|
||||
*lun = ccb.ccb_h.target_lun;
|
||||
*arglst |= CAM_ARG_BUS | CAM_ARG_TARGET | CAM_ARG_LUN;
|
||||
return (3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse out a bus, or a bus, target and lun in the following
|
||||
* format:
|
||||
@ -3547,25 +3607,43 @@ static int
|
||||
parse_btl(char *tstr, path_id_t *bus, target_id_t *target, lun_id_t *lun,
|
||||
cam_argmask *arglst)
|
||||
{
|
||||
char *tmpstr;
|
||||
char *tmpstr, *end;
|
||||
int convs = 0;
|
||||
|
||||
*bus = CAM_BUS_WILDCARD;
|
||||
*target = CAM_TARGET_WILDCARD;
|
||||
*lun = CAM_LUN_WILDCARD;
|
||||
|
||||
while (isspace(*tstr) && (*tstr != '\0'))
|
||||
tstr++;
|
||||
|
||||
tmpstr = (char *)strtok(tstr, ":");
|
||||
if (strncasecmp(tstr, "all", strlen("all")) == 0) {
|
||||
arglist |= CAM_ARG_BUS;
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (!isdigit(*tstr))
|
||||
return (parse_btl_name(tstr, bus, target, lun, arglst));
|
||||
|
||||
tmpstr = strsep(&tstr, ":");
|
||||
if ((tmpstr != NULL) && (*tmpstr != '\0')) {
|
||||
*bus = strtol(tmpstr, NULL, 0);
|
||||
*bus = strtol(tmpstr, &end, 0);
|
||||
if (*end != '\0')
|
||||
return (0);
|
||||
*arglst |= CAM_ARG_BUS;
|
||||
convs++;
|
||||
tmpstr = (char *)strtok(NULL, ":");
|
||||
tmpstr = strsep(&tstr, ":");
|
||||
if ((tmpstr != NULL) && (*tmpstr != '\0')) {
|
||||
*target = strtol(tmpstr, NULL, 0);
|
||||
*target = strtol(tmpstr, &end, 0);
|
||||
if (*end != '\0')
|
||||
return (0);
|
||||
*arglst |= CAM_ARG_TARGET;
|
||||
convs++;
|
||||
tmpstr = (char *)strtok(NULL, ":");
|
||||
tmpstr = strsep(&tstr, ":");
|
||||
if ((tmpstr != NULL) && (*tmpstr != '\0')) {
|
||||
*lun = strtol(tmpstr, NULL, 0);
|
||||
*lun = strtoll(tmpstr, &end, 0);
|
||||
if (*end != '\0')
|
||||
return (0);
|
||||
*arglst |= CAM_ARG_LUN;
|
||||
convs++;
|
||||
}
|
||||
@ -3579,7 +3657,7 @@ static int
|
||||
dorescan_or_reset(int argc, char **argv, int rescan)
|
||||
{
|
||||
static const char must[] =
|
||||
"you must specify \"all\", a bus, or a bus:target:lun to %s";
|
||||
"you must specify \"all\", a bus, a bus:target:lun or periph to %s";
|
||||
int rv, error = 0;
|
||||
path_id_t bus = CAM_BUS_WILDCARD;
|
||||
target_id_t target = CAM_TARGET_WILDCARD;
|
||||
@ -3596,118 +3674,19 @@ dorescan_or_reset(int argc, char **argv, int rescan)
|
||||
tstr++;
|
||||
if (strncasecmp(tstr, "all", strlen("all")) == 0)
|
||||
arglist |= CAM_ARG_BUS;
|
||||
else if (isdigit(*tstr)) {
|
||||
else {
|
||||
rv = parse_btl(argv[optind], &bus, &target, &lun, &arglist);
|
||||
if (rv != 1 && rv != 3) {
|
||||
warnx(must, rescan? "rescan" : "reset");
|
||||
warnx(must, rescan ? "rescan" : "reset");
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
char name[30];
|
||||
int unit;
|
||||
int fd = -1;
|
||||
union ccb ccb;
|
||||
|
||||
/*
|
||||
* Note that resetting or rescanning a device used to
|
||||
* require a bus or bus:target:lun. This is because the
|
||||
* device in question may not exist and you're trying to
|
||||
* get the controller to rescan to find it. It may also be
|
||||
* because the device is hung / unresponsive, and opening
|
||||
* an unresponsive device is not desireable.
|
||||
*
|
||||
* It can be more convenient to reference a device by
|
||||
* peripheral name and unit number, though, and it is
|
||||
* possible to get the bus:target:lun for devices that
|
||||
* currently exist in the EDT. So this can work for
|
||||
* devices that we want to reset, or devices that exist
|
||||
* that we want to rescan, but not devices that do not
|
||||
* exist yet.
|
||||
*
|
||||
* So, we are careful here to look up the bus/target/lun
|
||||
* for the device the user wants to operate on, specified
|
||||
* by peripheral instance (e.g. da0, pass32) without
|
||||
* actually opening that device. The process is similar to
|
||||
* what cam_lookup_pass() does, except that we don't
|
||||
* actually open the passthrough driver instance in the end.
|
||||
*/
|
||||
|
||||
if (cam_get_device(tstr, name, sizeof(name), &unit) == -1) {
|
||||
warnx("%s", cam_errbuf);
|
||||
error = 1;
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
|
||||
warn("Unable to open %s", XPT_DEVICE);
|
||||
error = 1;
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
bzero(&ccb, sizeof(ccb));
|
||||
|
||||
/*
|
||||
* The function code isn't strictly necessary for the
|
||||
* GETPASSTHRU ioctl.
|
||||
*/
|
||||
ccb.ccb_h.func_code = XPT_GDEVLIST;
|
||||
|
||||
/*
|
||||
* These two are necessary for the GETPASSTHRU ioctl to
|
||||
* work.
|
||||
*/
|
||||
strlcpy(ccb.cgdl.periph_name, name,
|
||||
sizeof(ccb.cgdl.periph_name));
|
||||
ccb.cgdl.unit_number = unit;
|
||||
|
||||
/*
|
||||
* Attempt to get the passthrough device. This ioctl will
|
||||
* fail if the device name is null, if the device doesn't
|
||||
* exist, or if the passthrough driver isn't in the kernel.
|
||||
*/
|
||||
if (ioctl(fd, CAMGETPASSTHRU, &ccb) == -1) {
|
||||
warn("Unable to find bus:target:lun for device %s%d",
|
||||
name, unit);
|
||||
error = 1;
|
||||
close(fd);
|
||||
goto bailout;
|
||||
}
|
||||
if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
const struct cam_status_entry *entry;
|
||||
|
||||
entry = cam_fetch_status_entry(ccb.ccb_h.status);
|
||||
warnx("Unable to find bus:target_lun for device %s%d, "
|
||||
"CAM status: %s (%#x)", name, unit,
|
||||
entry ? entry->status_text : "Unknown",
|
||||
ccb.ccb_h.status);
|
||||
error = 1;
|
||||
close(fd);
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
/*
|
||||
* The kernel fills in the bus/target/lun. We don't
|
||||
* need the passthrough device name and unit number since
|
||||
* we aren't going to open it.
|
||||
*/
|
||||
bus = ccb.ccb_h.path_id;
|
||||
target = ccb.ccb_h.target_id;
|
||||
lun = ccb.ccb_h.target_lun;
|
||||
|
||||
arglist |= CAM_ARG_BUS | CAM_ARG_TARGET | CAM_ARG_LUN;
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if ((arglist & CAM_ARG_BUS)
|
||||
&& (arglist & CAM_ARG_TARGET)
|
||||
&& (arglist & CAM_ARG_LUN))
|
||||
if (arglist & CAM_ARG_LUN)
|
||||
error = scanlun_or_reset_dev(bus, target, lun, rescan);
|
||||
else
|
||||
error = rescan_or_reset_bus(bus, rescan);
|
||||
|
||||
bailout:
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -5091,9 +5070,9 @@ camdebug(int argc, char **argv, char *combinedopt)
|
||||
path_id_t bus = CAM_BUS_WILDCARD;
|
||||
target_id_t target = CAM_TARGET_WILDCARD;
|
||||
lun_id_t lun = CAM_LUN_WILDCARD;
|
||||
char *tstr, *tmpstr = NULL;
|
||||
char *tstr;
|
||||
union ccb ccb;
|
||||
int error = 0;
|
||||
int error = 0, rv;
|
||||
|
||||
bzero(&ccb, sizeof(union ccb));
|
||||
|
||||
@ -5132,23 +5111,16 @@ camdebug(int argc, char **argv, char *combinedopt)
|
||||
}
|
||||
}
|
||||
|
||||
if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
|
||||
warnx("error opening transport layer device %s", XPT_DEVICE);
|
||||
warn("%s", XPT_DEVICE);
|
||||
return (1);
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc <= 0) {
|
||||
warnx("you must specify \"off\", \"all\" or a bus,");
|
||||
warnx("bus:target, or bus:target:lun");
|
||||
close(fd);
|
||||
warnx("bus:target, bus:target:lun or periph");
|
||||
return (1);
|
||||
}
|
||||
|
||||
tstr = *argv;
|
||||
|
||||
while (isspace(*tstr) && (*tstr != '\0'))
|
||||
tstr++;
|
||||
|
||||
@ -5157,66 +5129,54 @@ camdebug(int argc, char **argv, char *combinedopt)
|
||||
arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH|
|
||||
CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE|
|
||||
CAM_ARG_DEBUG_XPT|CAM_ARG_DEBUG_PROBE);
|
||||
} else if (strncmp(tstr, "all", 3) != 0) {
|
||||
tmpstr = (char *)strtok(tstr, ":");
|
||||
if ((tmpstr != NULL) && (*tmpstr != '\0')){
|
||||
bus = strtol(tmpstr, NULL, 0);
|
||||
arglist |= CAM_ARG_BUS;
|
||||
tmpstr = (char *)strtok(NULL, ":");
|
||||
if ((tmpstr != NULL) && (*tmpstr != '\0')){
|
||||
target = strtol(tmpstr, NULL, 0);
|
||||
arglist |= CAM_ARG_TARGET;
|
||||
tmpstr = (char *)strtok(NULL, ":");
|
||||
if ((tmpstr != NULL) && (*tmpstr != '\0')){
|
||||
lun = strtol(tmpstr, NULL, 0);
|
||||
arglist |= CAM_ARG_LUN;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error = 1;
|
||||
} else {
|
||||
rv = parse_btl(tstr, &bus, &target, &lun, &arglist);
|
||||
if (rv < 1) {
|
||||
warnx("you must specify \"all\", \"off\", or a bus,");
|
||||
warnx("bus:target, or bus:target:lun to debug");
|
||||
warnx("bus:target, bus:target:lun or periph to debug");
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (error == 0) {
|
||||
if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) {
|
||||
warnx("error opening transport layer device %s", XPT_DEVICE);
|
||||
warn("%s", XPT_DEVICE);
|
||||
return (1);
|
||||
}
|
||||
|
||||
ccb.ccb_h.func_code = XPT_DEBUG;
|
||||
ccb.ccb_h.path_id = bus;
|
||||
ccb.ccb_h.target_id = target;
|
||||
ccb.ccb_h.target_lun = lun;
|
||||
ccb.ccb_h.func_code = XPT_DEBUG;
|
||||
ccb.ccb_h.path_id = bus;
|
||||
ccb.ccb_h.target_id = target;
|
||||
ccb.ccb_h.target_lun = lun;
|
||||
|
||||
if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
|
||||
warn("CAMIOCOMMAND ioctl failed");
|
||||
if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
|
||||
warn("CAMIOCOMMAND ioctl failed");
|
||||
error = 1;
|
||||
} else {
|
||||
if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_FUNC_NOTAVAIL) {
|
||||
warnx("CAM debugging not available");
|
||||
warnx("you need to put options CAMDEBUG in"
|
||||
" your kernel config file!");
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if (error == 0) {
|
||||
if ((ccb.ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_FUNC_NOTAVAIL) {
|
||||
warnx("CAM debugging not available");
|
||||
warnx("you need to put options CAMDEBUG in"
|
||||
" your kernel config file!");
|
||||
error = 1;
|
||||
} else if ((ccb.ccb_h.status & CAM_STATUS_MASK) !=
|
||||
CAM_REQ_CMP) {
|
||||
warnx("XPT_DEBUG CCB failed with status %#x",
|
||||
ccb.ccb_h.status);
|
||||
error = 1;
|
||||
} else if ((ccb.ccb_h.status & CAM_STATUS_MASK) !=
|
||||
CAM_REQ_CMP) {
|
||||
warnx("XPT_DEBUG CCB failed with status %#x",
|
||||
ccb.ccb_h.status);
|
||||
error = 1;
|
||||
} else {
|
||||
if (ccb.cdbg.flags == CAM_DEBUG_NONE) {
|
||||
fprintf(stderr,
|
||||
"Debugging turned off\n");
|
||||
} else {
|
||||
if (ccb.cdbg.flags == CAM_DEBUG_NONE) {
|
||||
fprintf(stderr,
|
||||
"Debugging turned off\n");
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Debugging enabled for "
|
||||
"%d:%d:%jx\n",
|
||||
bus, target, (uintmax_t)lun);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"Debugging enabled for "
|
||||
"%d:%d:%jx\n",
|
||||
bus, target, (uintmax_t)lun);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -9887,7 +9847,7 @@ usage(int printlong)
|
||||
" camcontrol smpphylist [dev_id][generic args][-l][-q]\n"
|
||||
" camcontrol smpmaninfo [dev_id][generic args][-l]\n"
|
||||
" camcontrol debug [-I][-P][-T][-S][-X][-c]\n"
|
||||
" <all|bus[:target[:lun]]|off>\n"
|
||||
" <all|dev_id|bus[:target[:lun]]|off>\n"
|
||||
" camcontrol tags [dev_id][generic args] [-N tags] [-q] [-v]\n"
|
||||
" camcontrol negotiate [dev_id][generic args] [-a][-c]\n"
|
||||
" [-D <enable|disable>][-M mode][-O offset]\n"
|
||||
|
Loading…
Reference in New Issue
Block a user