1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-11-28 08:02:54 +00:00

Add a new device specification syntax to camcontrol. It is now possible to

do things like:

camcontrol tur da5
or
camcontrol tur 1:2:0
or
camcontrol tur 1:2

These changes are fully backwards compatible with the original device
specification syntax (-n dev -u unit), so it is possible to use either
method to specify a device now.

The device specification changes do not affect the rescan, reset or debug
commands, since by design, those commands work on a bus or bus:target:lun
basis only.

Also, shorten the default usage statement so that it fits in a 24 column
terminal.  The full usage statement is still available by using the "help"
"-h" or "-?" arguments to camcontrol.

Submitted by:	Joerg Wunsch <joerg_wunsch@interface-business.de>
This commit is contained in:
Kenneth D. Merry 1999-05-10 23:30:04 +00:00
parent 58f28f6089
commit c60e19a83b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=46938
5 changed files with 204 additions and 91 deletions

View File

@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id: camcontrol.8,v 1.10 1999/02/27 07:55:58 ken Exp $
.\" $Id: camcontrol.8,v 1.11 1999/05/06 20:15:37 ken Exp $
.\"
.Dd September 14, 1998
.Dt CAMCONTROL 8
@ -36,6 +36,7 @@
.Sh SYNOPSIS
.Nm camcontrol
.Aq command
.Op device id
.Op generic args
.Op command args
.Nm camcontrol
@ -43,25 +44,31 @@ devlist
.Op Fl v
.Nm camcontrol
periphlist
.Op device id
.Op Fl n Ar dev_name
.Op Fl u Ar unit_number
.Nm camcontrol
tur
.Op device id
.Op generic args
.Nm camcontrol
inquiry
.Op device id
.Op generic args
.Op Fl D
.Op Fl S
.Op Fl R
.Nm camcontrol
start
.Op device id
.Op generic args
.Nm camcontrol
stop
.Op device id
.Op generic args
.Nm camcontrol
eject
.Op device id
.Op generic args
.Nm camcontrol
rescan
@ -71,12 +78,14 @@ reset
.Aq bus Ns Op :target:lun
.Nm camcontrol
defects
.Op device id
.Op generic args
.Aq Fl f Ar format
.Op Fl P
.Op Fl G
.Nm camcontrol
modepage
.Op device id
.Op generic args
.Aq Fl m Ar page
.Op Fl P Ar pgctl
@ -84,6 +93,7 @@ modepage
.Op Fl d
.Nm camcontrol
cmd
.Op device id
.Op generic args
.Aq Fl c Ar cmd Op args
.Op Fl i Ar len Ar fmt
@ -99,12 +109,14 @@ debug
.Aq all|off|bus Ns Op :target Ns Op :lun
.Nm camcontrol
tags
.Op device id
.Op generic args
.Op Fl N Ar tags
.Op Fl q
.Op Fl v
.Nm camcontrol
negotiate
.Op device id
.Op generic args
.Op Fl c
.Op Fl D Ar enable|disable
@ -115,6 +127,8 @@ negotiate
.Op Fl U
.Op Fl W Ar bus_width
.Op Fl v
.Nm camcontrol
help
.Sh DESCRIPTION
.Nm camcontrol
is a utility designed to provide a way for users to access and control the
@ -127,8 +141,42 @@ expert users are encouraged to exercise caution when using this command.
Novice users should stay away from this utility.
.Pp
.Nm camcontrol
has a number of primary functions, most of which take some generic
arguments:
has a number of primary functions, many of which support an optional
device identifier. A device identifier can take one of three forms:
.Bl -tag -width 01234567890123
.It deviceUNIT
Specify a device name and unit number combination, like "da5" or "cd3".
Note that character device node names (e.g. /dev/rsd0.ctl) are
.Em not
allowed here.
.It bus:target
Specify a bus number and target id. The bus number can be determined from
the output of
.Dq camcontrol devlist .
The lun defaults to 0.
.It bus:target:lun
Specify the bus, target and lun for a device. (e.g. 1:2:0)
.El
.Pp
The device identifier, if it is specified,
.Em must
come immediately after the function name, and before any generic or
function-specific arguments. Note that the
.Fl n
and
.Fl u
arguments described below will override any device name or unit number
specified beforehand. The
.Fl n
and
.Fl u
arguments will
.Em not
override a specified bus:target or bus:target:lun, howevever.
.Pp
Most of the
.Nm camcontrol
primary functions support these generic arguments:
.Bl -tag -width 01234567890123
.It Fl C Ar count
SCSI command retry count. In order for this to work, error recovery
@ -461,6 +509,8 @@ device until a command has been sent to the device. The
.Fl a
switch above will automatically send a Test Unit Ready to the device so
negotiation parameters will take effect.
.It help
Print out a verbose usage information.
.El
.Sh ENVIRONMENT
The
@ -497,7 +547,7 @@ information if the command fails since the
switch was not specified.
.Pp
.Bd -literal -offset foobar
camcontrol tur -n da -u 1 -E -C 4 -t 50 -v
camcontrol tur da1 -E -C 4 -t 50 -v
.Ed
.Pp
Send a test unit ready command to da1. Enable kernel error recovery.
@ -528,7 +578,7 @@ the command fails. Be very careful with this command, improper use may
cause data corruption.
.Pp
.Bd -literal -offset foobar
camcontrol modepage -n da -u 3 -m 1 -e -P 3
camcontrol modepage da3 -m 1 -e -P 3
.Ed
.Pp
Edit mode page 1 (the Read-Write Error Recover page) for da3, and save the
@ -544,7 +594,7 @@ Rescan SCSI bus 0 for devices that have been added, removed or changed.
Rescan SCSI bus 0, target 1, lun 0 to see if it has been added, removed, or
changed.
.Pp
.Dl camcontrol tags -n da -u 5 -N 24
.Dl camcontrol tags da5 -N 24
.Pp
Set the number of concurrent transactions for da5 to 24.
.Pp

View File

@ -25,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: camcontrol.c,v 1.9 1999/01/14 05:56:30 gibbs Exp $
* $Id: camcontrol.c,v 1.10 1999/05/06 20:15:38 ken Exp $
*/
#include <sys/ioctl.h>
@ -145,6 +145,7 @@ typedef enum {
} camcontrol_optret;
cam_argmask arglist;
int bus, target, lun;
camcontrol_optret getoption(char *arg, cam_argmask *argnum, char **subopt);
@ -159,6 +160,8 @@ static int scsidoinquiry(struct cam_device *device, int argc, char **argv,
static int scsiinquiry(struct cam_device *device, int retry_count, int timeout);
static int scsiserial(struct cam_device *device, int retry_count, int timeout);
static int scsixferrate(struct cam_device *device);
static int parse_btl(char *tstr, int *bus, int *target, int *lun,
cam_argmask *arglist);
static int dorescan_or_reset(int argc, char **argv, int rescan);
static int rescan_or_reset_bus(int bus, int rescan);
static int scanlun_or_reset_dev(int bus, int target, int lun, int scan);
@ -908,12 +911,52 @@ scsixferrate(struct cam_device *device)
return(retval);
}
/*
* Parse out a bus, or a bus, target and lun in the following
* format:
* bus
* bus:target
* bus:target:lun
*
* Returns the number of parsed components, or 0.
*/
static int
parse_btl(char *tstr, int *bus, int *target, int *lun, cam_argmask *arglist)
{
char *tmpstr;
int convs = 0;
while (isspace(*tstr) && (*tstr != '\0'))
tstr++;
tmpstr = (char *)strtok(tstr, ":");
if ((tmpstr != NULL) && (*tmpstr != '\0')) {
*bus = strtol(tmpstr, NULL, 0);
*arglist |= CAM_ARG_BUS;
convs++;
tmpstr = (char *)strtok(NULL, ":");
if ((tmpstr != NULL) && (*tmpstr != '\0')) {
*target = strtol(tmpstr, NULL, 0);
*arglist |= CAM_ARG_TARGET;
convs++;
tmpstr = (char *)strtok(NULL, ":");
if ((tmpstr != NULL) && (*tmpstr != '\0')) {
*lun = strtol(tmpstr, NULL, 0);
*arglist |= CAM_ARG_LUN;
convs++;
}
}
}
return convs;
}
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";
int error = 0;
int rv, error = 0;
int bus = -1, target = -1, lun = -1;
char *tstr, *tmpstr = NULL;
@ -921,53 +964,19 @@ dorescan_or_reset(int argc, char **argv, int rescan)
warnx(must, rescan? "rescan" : "reset");
return(1);
}
/*
* Parse out a bus, or a bus, target and lun in the following
* format:
* bus
* bus:target:lun
* It is an error to specify a bus and target, but not a lun.
*/
tstr = argv[optind];
while (isspace(*tstr) && (*tstr != '\0'))
tstr++;
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;
warnx(must, rescan? "rescan" : "reset");
}
}
} else {
error = 1;
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)
&& (arglist & CAM_ARG_TARGET)
&& (arglist & CAM_ARG_LUN))
error = scanlun_or_reset_dev(bus, target, lun, rescan);
else
error = rescan_or_reset_bus(bus, rescan);
if (error == 0) {
if ((arglist & CAM_ARG_BUS)
&& (arglist & CAM_ARG_TARGET)
&& (arglist & CAM_ARG_LUN))
error = scanlun_or_reset_dev(bus, target, lun, rescan);
else if (arglist & CAM_ARG_BUS)
error = rescan_or_reset_bus(bus, rescan);
else {
error = 1;
warnx(must, rescan? "rescan" : "reset");
}
}
return(error);
}
@ -2575,28 +2584,34 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
}
void
usage(void)
usage(int verbose)
{
fprintf(stderr,
"usage: camcontrol <command> [ generic args ] [ command args ]\n"
"usage: camcontrol <command> [device id][generic args][command args]\n"
" camcontrol devlist [-v]\n"
" camcontrol periphlist [-n dev_name] [-u unit]\n"
" camcontrol tur [generic args]\n"
" camcontrol inquiry [generic args] [-D] [-S] [-R]\n"
" camcontrol start [generic args]\n"
" camcontrol stop [generic args]\n"
" camcontrol eject [generic args]\n"
" camcontrol periphlist [dev_id][-n dev_name] [-u unit]\n"
" camcontrol tur [dev_id][generic args]\n"
" camcontrol inquiry [dev_id][generic args] [-D] [-S] [-R]\n"
" camcontrol start [dev_id][generic args]\n"
" camcontrol stop [dev_id][generic args]\n"
" camcontrol eject [dev_id][generic args]\n"
" camcontrol rescan <bus[:target:lun]>\n"
" camcontrol reset <bus[:target:lun]>\n"
" camcontrol defects [generic args] <-f format> [-P][-G]\n"
" camcontrol modepage [generic args] <-m page> [-P pagectl][-e][-d]\n"
" camcontrol cmd [generic args] <-c cmd [args]> \n"
" camcontrol defects [dev_id][generic args] <-f format> [-P][-G]\n"
" camcontrol modepage [dev_id][generic args] <-m page> [-P pagectl]\n"
" [-e][-d]\n"
" camcontrol cmd [dev_id][generic args] <-c cmd [args]>\n"
" [-i len fmt|-o len fmt [args]]\n"
" camcontrol debug [-I][-T][-S][-c] <all|bus[:target[:lun]]|off>\n"
" camcontrol tags [generic args] [-N tags] [-q] [-v]\n"
" camcontrol negotiate [generic args] [-a][-c][-D <enable|disable>]\n"
" [-O offset][-q][-R syncrate][-v]\n"
" [-T <enable|disable>][-U][-W bus_width]\n"
" camcontrol tags [dev_id][generic args] [-N tags] [-q] [-v]\n"
" camcontrol negotiate [dev_id][generic args] [-a][-c]\n"
" [-D <enable|disable>][-O offset][-q]\n"
" [-R syncrate][-v][-T <enable|disable>]\n"
" [-U][-W bus_width]\n"
" camcontrol help\n");
if (!verbose)
return;
fprintf(stderr,
"Specify one of the following options:\n"
"devlist list all CAM devices\n"
"periphlist list all CAM peripheral drivers attached to a device\n"
@ -2613,6 +2628,11 @@ usage(void)
"debug turn debugging on/off for a bus, target, or lun, or all devices\n"
"tags report or set the number of transaction slots for a device\n"
"negotiate report or set device negotiation parameters\n"
"help this message\n"
"Device Identifiers:\n"
"bus:target specify the bus and target, lun defaults to 0\n"
"bus:target:lun specify the bus, target and lun\n"
"deviceUNIT specify the device name, like \"da4\" or \"cd2\"\n"
"Generic arguments:\n"
"-v be verbose, print out sense information\n"
"-t timeout command timeout in seconds, overrides default timeout\n"
@ -2673,12 +2693,13 @@ main(int argc, char **argv)
char *mainopt = "C:En:t:u:v";
char *subopt = NULL;
char combinedopt[256];
int error = 0;
int error = 0, optstart = 2;
int devopen = 1;
arglist = CAM_ARG_NONE;
if (argc < 2) {
usage();
usage(0);
exit(1);
}
@ -2689,11 +2710,11 @@ main(int argc, char **argv)
if (optreturn == CC_OR_AMBIGUOUS) {
warnx("ambiguous option %s", argv[1]);
usage();
usage(0);
exit(1);
} else if (optreturn == CC_OR_NOT_FOUND) {
warnx("option %s not found", argv[1]);
usage();
usage(0);
exit(1);
}
@ -2750,10 +2771,52 @@ main(int argc, char **argv)
sprintf(combinedopt, "%s", mainopt);
/*
* Start getopt processing at argv[2], since we've already accepted
* argv[1] as the command name.
* For these options we do not parse optional device arguments and
* we do not open a passthrough device.
*/
optind = 2;
if (((arglist & CAM_ARG_OPT_MASK) == CAM_ARG_RESCAN)
|| ((arglist & CAM_ARG_OPT_MASK) == CAM_ARG_RESET)
|| ((arglist & CAM_ARG_OPT_MASK) == CAM_ARG_DEVTREE)
|| ((arglist & CAM_ARG_OPT_MASK) == CAM_ARG_USAGE)
|| ((arglist & CAM_ARG_OPT_MASK) == CAM_ARG_DEBUG))
devopen = 0;
if ((devopen == 1)
&& (argc > 2 && argv[2][0] != '-')) {
char name[30];
int rv;
/*
* First catch people who try to do things like:
* camcontrol tur /dev/rsd0.ctl
* camcontrol doesn't take device nodes as arguments.
*/
if (argv[2][0] == '/') {
warnx("%s is not a valid device identifier", argv[2]);
errx(1, "please read the camcontrol(8) man page");
} else if (isdigit(argv[2][0])) {
/* device specified as bus:target[:lun] */
rv = parse_btl(argv[2], &bus, &target, &lun, &arglist);
if (rv < 2)
errx(1, "numeric device specification must "
"be either bus:target, or "
"bus:target:lun");
optstart++;
} else {
if (cam_get_device(argv[2], name, sizeof name, &unit)
== -1)
errx(1, "%s", cam_errbuf);
device = strdup(name);
arglist |= CAM_ARG_DEVICE | CAM_ARG_UNIT;
optstart++;
}
}
/*
* Start getopt processing at argv[2/3], since we've already
* accepted argv[1..2] as the command name, and as a possible
* device name.
*/
optind = optstart;
/*
* Now we run through the argument list looking for generic
@ -2811,14 +2874,11 @@ main(int argc, char **argv)
* commands, we don't use a passthrough device at all, just the
* transport layer device.
*/
if (((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_RESCAN)
&& ((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_RESET)
&& ((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_DEVTREE)
&& ((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_USAGE)
&& ((arglist & CAM_ARG_OPT_MASK) != CAM_ARG_DEBUG)) {
if ((cam_dev = cam_open_spec_device(device,unit,O_RDWR,
NULL))== NULL)
if (devopen == 1) {
if ((cam_dev = ((arglist & (CAM_ARG_BUS | CAM_ARG_TARGET))?
cam_open_btl(bus, target, lun, O_RDWR, NULL) :
cam_open_spec_device(device,unit,O_RDWR,NULL)))
== NULL)
errx(1,"%s", cam_errbuf);
}
@ -2826,7 +2886,7 @@ main(int argc, char **argv)
* Reset optind to 2, and reset getopt, so these routines can parse
* the arguments again.
*/
optind = 2;
optind = optstart;
optreset = 1;
switch(arglist & CAM_ARG_OPT_MASK) {
@ -2876,8 +2936,11 @@ main(int argc, char **argv)
error = ratecontrol(cam_dev, retry_count, timeout,
argc, argv, combinedopt);
break;
case CAM_ARG_USAGE:
usage(1);
break;
default:
usage();
usage(0);
error = 1;
break;
}

View File

@ -25,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
* $Id: camcontrol.h,v 1.1 1998/09/15 06:43:02 gibbs Exp $
*/
#ifndef _CAMCONTROL_H
@ -50,5 +50,5 @@ void mode_edit(struct cam_device *device, int page, int page_control, int dbd,
char *cget(void *hook, char *name);
int iget(void *hook, char *name);
void arg_put(void *hook, int letter, void *arg, int count, char *name);
void usage(void);
void usage(int verbose);
#endif /* _CAMCONTROL_H */

View File

@ -45,7 +45,7 @@
*/
#ifndef lint
static const char rcsid[] =
"$Id$";
"$Id: modeedit.c,v 1.1 1998/09/15 06:43:02 gibbs Exp $";
#endif /* not lint */
#include <ctype.h>
@ -76,7 +76,7 @@ iget(void *hook, char *name)
if (h->got >= h->argc)
{
fprintf(stderr, "Expecting an integer argument.\n");
usage();
usage(0);
exit(1);
}
arg = strtol(h->argv[h->got], 0, 0);
@ -99,7 +99,7 @@ cget(void *hook, char *name)
if (h->got >= h->argc)
{
fprintf(stderr, "Expecting a character pointer argument.\n");
usage();
usage(0);
exit(1);
}
arg = h->argv[h->got];

View File

@ -45,7 +45,7 @@
*/
#ifndef lint
static const char rcsid[] =
"$Id$";
"$Id: modeedit.c,v 1.1 1998/09/15 06:43:02 gibbs Exp $";
#endif /* not lint */
#include <ctype.h>
@ -76,7 +76,7 @@ iget(void *hook, char *name)
if (h->got >= h->argc)
{
fprintf(stderr, "Expecting an integer argument.\n");
usage();
usage(0);
exit(1);
}
arg = strtol(h->argv[h->got], 0, 0);
@ -99,7 +99,7 @@ cget(void *hook, char *name)
if (h->got >= h->argc)
{
fprintf(stderr, "Expecting a character pointer argument.\n");
usage();
usage(0);
exit(1);
}
arg = h->argv[h->got];