Add "-m" command to read mode pages. Also add -z for freezing,

though the kernel changes aren't committed yet.
This commit is contained in:
Peter Dufault 1995-04-28 19:24:39 +00:00
parent c46c1a53eb
commit 0d30b20ac9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=8145
2 changed files with 333 additions and 74 deletions

View File

@ -39,7 +39,7 @@
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.\" .\"
.\" $Id: scsi.8,v 1.1.1.1 1995/01/24 12:07:27 dufault Exp $ .\" $Id: scsi.8,v 1.2 1995/04/17 14:51:54 dufault Exp $
.\" .\"
.Dd October 11, 1993 .Dd October 11, 1993
.Dt SCSI 1 .Dt SCSI 1
@ -51,6 +51,8 @@
.Bd -literal -offset .Bd -literal -offset
Usage: Usage:
scsi -f device -d debug_level # To set debug level scsi -f device -d debug_level # To set debug level
scsi -f device [-v] -z seconds # To freeze bus
scsi -f device -m page [-P pc] # To read mode pages
scsi -f device -p [-b bus] [-l lun] # To probe all devices scsi -f device -p [-b bus] [-l lun] # To probe all devices
scsi -f device -r [-b bus] [-t targ] [-l lun] # To reprobe a device scsi -f device -r [-b bus] [-t targ] [-l lun] # To reprobe a device
scsi -f device [-v] -c cmd_fmt [arg0 ... argn] \\ # To send a command... scsi -f device [-v] -c cmd_fmt [arg0 ... argn] \\ # To send a command...
@ -78,6 +80,37 @@ option. See
to figure out what to set the kernel debug level to. to figure out what to set the kernel debug level to.
.Pp .Pp
The The
.Fr -z
option freezes all activity on all SCSI busses for a given number of
seconds. If
.Fr -v
is also specified then a BEL character is sent to the standard
output at the start and finish of the bus freeze.
This requires that the kernel be built with the SCSI_FREEZE kernel option.
This kernel code is not committed yet.
.Pp
The
.Fr -m
option is used to read a device mode page. The file
.Fr /usr/share/misc/scsi_modes
is read to look at for how to interpret the mode data. The environment
variable SCSI_MODES can specify a different file to use.
The
.Fr -P
option can be used to specify a page control field. The page control
fields are
.Bd -literal -offset
0 Current Values
1 Changeable Values
2 Default Values
3 Saved Values
.Ed
.Pp
Eventually this will also support a
.Fr -e
option to permit editing the fields.
.Pp
The
.Fr -p .Fr -p
option can be used against the "super scsi" device option can be used against the "super scsi" device
.Fr /dev/scsi/super .Fr /dev/scsi/super
@ -160,6 +193,17 @@ root# scsi -f /dev/rsd2c -c "12 0 0 0 64 0" -i 64 "s8 z8 z16 z4"
FUJITSU M2654S-512 010P FUJITSU M2654S-512 010P
.Ed .Ed
.Pp .Pp
.Sh ENVIRONMENT
The SU_DEBUG_OUTPUT variable can be set to a file to send debugging
output to that file.
.Pp
The SU_DEBUG_LEVEL variable can be set to a non-zero integer to increase
the level of debugging. Currently this is a on or off thing; it should
perhaps use the ioctl to set the debug level in the kernel and then set
it back to zero at program exit.
.Pp
The SU_DEBUG_TRUNCATE variable can be set to an integer to limit the
amount of data phase output sent to the debugging file.
.Sh SEE ALSO .Sh SEE ALSO
.Xr scsi 4 , .Xr scsi 4 ,
.Xr scsi 3 .Xr scsi 3

View File

@ -39,34 +39,45 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: scsi.c,v 1.2 1995/01/26 23:40:40 dufault Exp $ * $Id: scsi.c,v 1.3 1995/04/17 14:35:07 dufault Exp $
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <errno.h> #include <errno.h>
#include <sys/scsiio.h> #include <sys/scsiio.h>
#include <sys/file.h> #include <sys/file.h>
#include <scsi.h> #include <scsi.h>
#include <ctype.h>
int fd; int fd;
int debuglevel; int debuglevel;
int dflag,cmd; int debugflag;
int commandflag;
int reprobe; int reprobe;
int probe_all; int probe_all;
int verbose = 0; int verbose = 0;
int bus = -1; /* all busses */ int bus = -1; /* all busses */
int targ = -1; /* all targs */ int targ = -1; /* all targs */
int lun = 0; /* just lun 0 */ int lun = 0; /* just lun 0 */
int freeze = 0; /* Freeze this many seconds */
usage() int modeflag;
int editflag;
int modepage = 0; /* Read this mode page */
int pagectl = 0; /* Mode sense page control */
void usage(void)
{ {
printf( printf(
"Usage:\n" "Usage:\n"
"\n" "\n"
" scsi -f device -d debug_level # To set debug level\n" " scsi -f device -d debug_level # To set debug level\n"
" scsi -f device [-v] -z seconds # To freeze bus\n"
" scsi -f device -m page [-P pc] # To read mode pages\n"
" scsi -f device -p [-b bus] [-l lun] # To probe all devices\n" " scsi -f device -p [-b bus] [-l lun] # To probe all devices\n"
" scsi -f device -r [-b bus] [-t targ] [-l lun] # To reprobe a device\n" " scsi -f device -r [-b bus] [-t targ] [-l lun] # To reprobe a device\n"
" scsi -f device [-v] -c cmd_fmt [arg0 ... argn] \\ # To send a command...\n" " scsi -f device [-v] -c cmd_fmt [arg0 ... argn] \\ # To send a command...\n"
@ -93,9 +104,9 @@ void procargs(int *argc_p, char ***argv_p)
ch; ch;
fflag = 0; fflag = 0;
cmd = 0; commandflag = 0;
dflag = 0; debugflag = 0;
while ((ch = getopt(argc, argv, "vpcrf:d:b:t:l:")) != EOF) { while ((ch = getopt(argc, argv, "ceprvf:d:b:t:l:z:m:P:")) != EOF) {
switch (ch) { switch (ch) {
case 'p': case 'p':
probe_all = 1; probe_all = 1;
@ -104,11 +115,14 @@ void procargs(int *argc_p, char ***argv_p)
reprobe = 1; reprobe = 1;
break; break;
case 'c': case 'c':
cmd = 1; commandflag = 1;
break; break;
case 'v': case 'v':
verbose = 1; verbose = 1;
break; break;
case 'e':
editflag = 1;
break;
case 'f': case 'f':
if ((fd = scsi_open(optarg, O_RDWR)) < 0) { if ((fd = scsi_open(optarg, O_RDWR)) < 0) {
(void) fprintf(stderr, (void) fprintf(stderr,
@ -119,17 +133,27 @@ void procargs(int *argc_p, char ***argv_p)
fflag = 1; fflag = 1;
break; break;
case 'd': case 'd':
debuglevel = atoi(optarg); debuglevel = strtol(optarg, 0, 0);
dflag = 1; debugflag = 1;
break; break;
case 'b': case 'b':
bus = atoi(optarg); bus = strtol(optarg, 0, 0);
break; break;
case 't': case 't':
targ = atoi(optarg); targ = strtol(optarg, 0, 0);
break; break;
case 'l': case 'l':
lun = atoi(optarg); lun = strtol(optarg, 0, 0);
break;
case 'z':
freeze = strtol(optarg, 0, 0);
break;
case 'P':
pagectl = strtol(optarg, 0, 0);
break;
case 'm':
modeflag = 1;
modepage = strtol(optarg, 0, 0);
break; break;
case '?': case '?':
default: default:
@ -163,7 +187,7 @@ int iget(void *hook, char *name)
fprintf(stderr, "Expecting an integer argument.\n"); fprintf(stderr, "Expecting an integer argument.\n");
usage(); usage();
} }
arg = atol(h->argv[h->got]); arg = strtol(h->argv[h->got], 0, 0);
h->got++; h->got++;
if (verbose && name) if (verbose && name)
@ -198,7 +222,7 @@ char *cget(void *hook, char *name)
void arg_put(void *hook, int letter, void *arg, int count, char *name) void arg_put(void *hook, int letter, void *arg, int count, char *name)
{ {
if (verbose && name && *name) if (verbose && name && *name)
printf("%s: ", name); printf("%s: ", name);
switch(letter) switch(letter)
{ {
@ -251,8 +275,8 @@ void do_cmd(int fd, char *fmt, int argc, char **argv)
struct get_hook h; struct get_hook h;
scsireq_t *scsireq = scsireq_new(); scsireq_t *scsireq = scsireq_new();
enum data_phase data_phase; enum data_phase data_phase;
int output = 0; int count;
char *data_out = 0; char *data_fmt;
h.argc = argc; h.argc = argc;
h.argv = argv; h.argv = argv;
@ -269,40 +293,34 @@ void do_cmd(int fd, char *fmt, int argc, char **argv)
*/ */
if (h.got >= h.argc) if (h.got >= h.argc)
{
data_phase = none; data_phase = none;
count = scsireq->datalen = 0;
}
else else
{ {
char *flag = cget(&h, 0); char *flag = cget(&h, 0);
if (strcmp(flag, "-o") == 0) if (strcmp(flag, "-o") == 0)
{
data_phase = out; data_phase = out;
scsireq->flags = SCCMD_WRITE;
}
else if (strcmp(flag, "-i") == 0) else if (strcmp(flag, "-i") == 0)
{
data_phase = in; data_phase = in;
scsireq->flags = SCCMD_READ;
}
else else
{ {
fprintf(stderr, fprintf(stderr,
"Need either \"-i\" or \"-o\" for data phase; not \"%s\".\n", flag); "Need either \"-i\" or \"-o\" for data phase; not \"%s\".\n", flag);
usage(); usage();
} }
}
if (data_phase == none)
scsireq->datalen = 0;
else
{
int count;
if (data_phase == out)
scsireq->flags = SCCMD_WRITE;
else
scsireq->flags = SCCMD_READ;
count = iget(&h, 0);
scsireq->datalen = count;
count = scsireq->datalen = iget(&h, 0);
if (count) if (count)
{ {
char *data_fmt;
data_fmt = cget(&h, 0); data_fmt = cget(&h, 0);
scsireq->databuf = malloc(count); scsireq->databuf = malloc(count);
@ -317,54 +335,250 @@ void do_cmd(int fd, char *fmt, int argc, char **argv)
exit(errno); exit(errno);
} }
} }
else /* XXX: Not written yet */ else
{ {
#if 0
int scsireq_encode_visit(scsireq_t *scsireq, char
*fmt,
int (*arg_get)(void *hook, char *field_name),
void *gethook)
#endif
bzero(scsireq->databuf, count); bzero(scsireq->databuf, count);
scsireq_encode_visit(scsireq, data_fmt, iget, (void *)&h); scsireq_encode_visit(scsireq, data_fmt, iget, (void *)&h);
} }
} }
}
}
if (scsireq_enter(fd, scsireq) == -1) if (scsireq_enter(fd, scsireq) == -1)
{
scsi_debug(stderr, -1, scsireq);
exit(errno);
}
if (SCSIREQ_ERROR(scsireq))
scsi_debug(stderr, 0, scsireq);
if (count && data_phase == in)
{
if (strcmp(data_fmt, "-") == 0) /* stdout */
{
if (write(1, scsireq->databuf, count) != count)
{ {
scsi_debug(stderr, -1, scsireq); perror("write");
exit(errno); exit(errno);
} }
}
else
{
scsireq_decode_visit(scsireq, data_fmt, arg_put, 0);
putchar('\n');
}
}
}
if (SCSIREQ_ERROR(scsireq)) static void freeze_ioctl(int fd, int op, void *data)
scsi_debug(stderr, 0, scsireq); {
if (ioctl(fd, SCIOCFREEZE, 0) == -1) {
if (errno == ENODEV) {
fprintf(stderr,
"Your kernel must be configured with option SCSI_FREEZE.\n");
}
else
perror("SCIOCFREEZE");
exit(errno);
}
}
if (data_phase == in) /* do_freeze: Freeze the bus for a given number of seconds.
{ */
if (strcmp(data_fmt, "-") == 0) /* stdout */ static void do_freeze(int seconds)
{ {
if (write(1, scsireq->databuf, count) != count) if (seconds == -1) {
{ printf("Hit return to thaw: ");
perror("write"); fflush(stdout);
exit(errno); sync();
}
} freeze_ioctl(fd, SCIOCFREEZE, 0);
else
{ (void)getchar();
scsireq_decode_visit(scsireq, data_fmt, arg_put, 0);
putchar('\n'); freeze_ioctl(fd, SCIOCTHAW, 0);
}
else {
sync();
freeze_ioctl(fd, SCIOCFREEZETHAW, &seconds);
if (verbose) {
putchar('\007');
fflush(stdout);
}
freeze_ioctl(fd, SCIOCWAITTHAW, 0);
if (verbose) {
putchar('\007');
fflush(stdout);
}
}
}
void mode_sense(int fd, u_char *data, int len, int pc, int page)
{
scsireq_t *scsireq;
bzero(data, len);
scsireq = scsireq_new();
if (scsireq_enter(fd, scsireq_build(scsireq,
len, data, SCCMD_READ,
"1A 0 v:2 {Page Control} v:6 {Page Code} 0 v:i1 {Allocation Length} 0",
pc, page, len)) == -1) /* Mode sense */
{
scsi_debug(stderr, -1, scsireq);
exit(errno);
}
if (SCSIREQ_ERROR(scsireq))
{
scsi_debug(stderr, 0, scsireq);
exit(-1);
}
free(scsireq);
}
#define START_ENTRY '{'
#define END_ENTRY '}'
static void
skipwhite(FILE *f)
{
int c;
skip_again:
while (isspace(c = getc(f)))
;
if (c == '#') {
while ((c = getc(f)) != '\n' && c != EOF)
;
goto skip_again;
}
ungetc(c, f);
}
/* mode_lookup: Lookup a format description for a given page.
*/
char *mode_db = "/usr/share/misc/scsi_modes";
static char *mode_lookup(int page)
{
char *new_db;
FILE *modes;
int match, next, found, c;
static char fmt[1024]; /* XXX This should be with strealloc */
int page_desc;
new_db = getenv("SCSI_MODES");
if (new_db)
mode_db = new_db;
modes = fopen(mode_db, "r");
if (modes == 0)
return 0;
next = 0;
found = 0;
while (!found) {
skipwhite(modes);
if (fscanf(modes, "%i", &page_desc) != 1)
break;
if (page_desc == page)
found = 1;
skipwhite(modes);
if (getc(modes) != START_ENTRY) {
fprintf(stderr, "Expected %c.\n", START_ENTRY);
exit(-1);
}
match = 1;
while (match != 0) {
c = getc(modes);
if (c == EOF) {
fprintf(stderr, "Expected %c.\n", END_ENTRY);
}
if (c == START_ENTRY) {
match++;
}
if (c == END_ENTRY) {
match--;
if (match == 0)
break;
}
if (found && c != '\n') {
if (next >= sizeof(fmt)) {
fprintf(stderr, "Stupid program: Buffer overflow.\n");
exit(ENOMEM);
} }
fmt[next++] = (u_char)c;
} }
} }
} }
fmt[next] = 0;
return (found) ? fmt : 0;
}
static void mode_edit(int fd, int page, int edit, int argc, char *argv[])
{
int i;
u_char data[255];
int mode_data_length;
int block_descriptor_length;
u_char *mode_data;
u_char *mode_parameters;
int page_length;
char *fmt = mode_lookup(page);
if (!fmt && verbose) {
fprintf(stderr,
"No mode data base entry in \"%s\" for page %d; binary %s only.\n",
mode_db, page, (edit ? "edit" : "display"));
}
if (edit)
fprintf(stderr, "Sorry; can't edit yet.\n");
mode_sense(fd, data, sizeof(data), pagectl, page);
/* Skip over the block descriptors.
*/
mode_data_length = data[0];
block_descriptor_length = data[3];
mode_data = data + 4 + block_descriptor_length;
page_length = mode_data[1];
mode_parameters = mode_data + 2;
if (!fmt) {
for (i = 0; i < mode_data_length; i++) {
printf("%02x%c",mode_parameters[i],
(((i + 1) % 8) == 0) ? '\n' : ' ');
}
putc('\n', stdout);
} else {
verbose = 1;
scsireq_buff_decode_visit(mode_parameters,
mode_data_length, fmt, arg_put, 0);
}
} }
/* do_probe_all: Loop over all SCSI IDs and see if something is /* do_probe_all: Loop over all SCSI IDs and see if something is
* there. This only does BUS 0 LUN 0. * there. This only does BUS 0 LUN 0.
*/ */
do_probe_all() void do_probe_all(void)
{ {
scsireq_t *scsireq; scsireq_t *scsireq;
@ -418,47 +632,48 @@ do_probe_all()
} }
} }
main(int argc, char **argv) void main(int argc, char **argv)
{ {
struct scsi_addr scaddr; struct scsi_addr scaddr;
procargs(&argc,&argv); procargs(&argc,&argv);
if (probe_all) { /* XXX This has grown to the point that it should be cleaned up.
*/
if (freeze) {
do_freeze(freeze);
} else if (probe_all) {
do_probe_all(); do_probe_all();
} } else if(reprobe) {
if(reprobe) {
scaddr.scbus = bus; scaddr.scbus = bus;
scaddr.target = targ; scaddr.target = targ;
scaddr.lun = lun; scaddr.lun = lun;
if (ioctl(fd,SCIOCREPROBE,&scaddr) == -1) if (ioctl(fd,SCIOCREPROBE,&scaddr) == -1)
perror("ioctl"); perror("ioctl");
} } else if(debugflag) {
if(dflag) {
if (ioctl(fd,SCIOCDEBUG,&debuglevel) == -1) if (ioctl(fd,SCIOCDEBUG,&debuglevel) == -1)
{ {
perror("ioctl [SCIODEBUG]"); perror("ioctl [SCIODEBUG]");
exit(1); exit(1);
} }
} } else if (commandflag) {
int i;
if (cmd) {
char *fmt; char *fmt;
if (argc <= 1) if (argc < 1) {
{
fprintf(stderr, "Need the command format string.\n"); fprintf(stderr, "Need the command format string.\n");
usage(); usage();
} }
fmt = argv[0]; fmt = argv[0];
argc -= 1; argc -= 1;
argv += 1; argv += 1;
do_cmd(fd, fmt, argc, argv); do_cmd(fd, fmt, argc, argv);
} else if (modeflag) {
mode_edit(fd, modepage, editflag, argc, argv);
} }
} }