From 0d30b20ac9701cd73e170b6912eef5747fc1113d Mon Sep 17 00:00:00 2001 From: Peter Dufault Date: Fri, 28 Apr 1995 19:24:39 +0000 Subject: [PATCH] Add "-m" command to read mode pages. Also add -z for freezing, though the kernel changes aren't committed yet. --- sbin/scsi/scsi.8 | 46 +++++- sbin/scsi/scsi.c | 361 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 333 insertions(+), 74 deletions(-) diff --git a/sbin/scsi/scsi.8 b/sbin/scsi/scsi.8 index acd9a7d3a104..b843835790f9 100644 --- a/sbin/scsi/scsi.8 +++ b/sbin/scsi/scsi.8 @@ -39,7 +39,7 @@ .\" 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 .Dt SCSI 1 @@ -51,6 +51,8 @@ .Bd -literal -offset Usage: 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 -r [-b bus] [-t targ] [-l lun] # To reprobe a device 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. .Pp 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 option can be used against the "super scsi" device .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 .Ed .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 .Xr scsi 4 , .Xr scsi 3 diff --git a/sbin/scsi/scsi.c b/sbin/scsi/scsi.c index 07807a18e4e3..9686be9f3bb9 100644 --- a/sbin/scsi/scsi.c +++ b/sbin/scsi/scsi.c @@ -39,34 +39,45 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * 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 #include #include +#include #include #include #include #include +#include int fd; int debuglevel; -int dflag,cmd; +int debugflag; +int commandflag; int reprobe; int probe_all; int verbose = 0; int bus = -1; /* all busses */ int targ = -1; /* all targs */ 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( "Usage:\n" "\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 -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" @@ -93,9 +104,9 @@ void procargs(int *argc_p, char ***argv_p) ch; fflag = 0; - cmd = 0; - dflag = 0; - while ((ch = getopt(argc, argv, "vpcrf:d:b:t:l:")) != EOF) { + commandflag = 0; + debugflag = 0; + while ((ch = getopt(argc, argv, "ceprvf:d:b:t:l:z:m:P:")) != EOF) { switch (ch) { case 'p': probe_all = 1; @@ -104,11 +115,14 @@ void procargs(int *argc_p, char ***argv_p) reprobe = 1; break; case 'c': - cmd = 1; + commandflag = 1; break; case 'v': verbose = 1; break; + case 'e': + editflag = 1; + break; case 'f': if ((fd = scsi_open(optarg, O_RDWR)) < 0) { (void) fprintf(stderr, @@ -119,17 +133,27 @@ void procargs(int *argc_p, char ***argv_p) fflag = 1; break; case 'd': - debuglevel = atoi(optarg); - dflag = 1; + debuglevel = strtol(optarg, 0, 0); + debugflag = 1; break; case 'b': - bus = atoi(optarg); + bus = strtol(optarg, 0, 0); break; case 't': - targ = atoi(optarg); + targ = strtol(optarg, 0, 0); break; 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; case '?': default: @@ -163,7 +187,7 @@ int iget(void *hook, char *name) fprintf(stderr, "Expecting an integer argument.\n"); usage(); } - arg = atol(h->argv[h->got]); + arg = strtol(h->argv[h->got], 0, 0); h->got++; 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) { if (verbose && name && *name) - printf("%s: ", name); + printf("%s: ", name); switch(letter) { @@ -251,8 +275,8 @@ void do_cmd(int fd, char *fmt, int argc, char **argv) struct get_hook h; scsireq_t *scsireq = scsireq_new(); enum data_phase data_phase; - int output = 0; - char *data_out = 0; + int count; + char *data_fmt; h.argc = argc; h.argv = argv; @@ -269,40 +293,34 @@ void do_cmd(int fd, char *fmt, int argc, char **argv) */ if (h.got >= h.argc) + { data_phase = none; + count = scsireq->datalen = 0; + } else { char *flag = cget(&h, 0); if (strcmp(flag, "-o") == 0) + { data_phase = out; + scsireq->flags = SCCMD_WRITE; + } else if (strcmp(flag, "-i") == 0) + { data_phase = in; + scsireq->flags = SCCMD_READ; + } else { fprintf(stderr, "Need either \"-i\" or \"-o\" for data phase; not \"%s\".\n", flag); 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) { - char *data_fmt; data_fmt = cget(&h, 0); scsireq->databuf = malloc(count); @@ -317,54 +335,250 @@ void do_cmd(int fd, char *fmt, int argc, char **argv) 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); - 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); } + } + else + { + scsireq_decode_visit(scsireq, data_fmt, arg_put, 0); + putchar('\n'); + } + } +} - if (SCSIREQ_ERROR(scsireq)) - scsi_debug(stderr, 0, scsireq); +static void freeze_ioctl(int fd, int op, void *data) +{ + 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) - { - if (strcmp(data_fmt, "-") == 0) /* stdout */ - { - if (write(1, scsireq->databuf, count) != count) - { - perror("write"); - exit(errno); - } - } - else - { - scsireq_decode_visit(scsireq, data_fmt, arg_put, 0); - putchar('\n'); +/* do_freeze: Freeze the bus for a given number of seconds. + */ +static void do_freeze(int seconds) +{ + if (seconds == -1) { + printf("Hit return to thaw: "); + fflush(stdout); + sync(); + + freeze_ioctl(fd, SCIOCFREEZE, 0); + + (void)getchar(); + + 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 * there. This only does BUS 0 LUN 0. */ -do_probe_all() +void do_probe_all(void) { 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; 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(); - } - - if(reprobe) { + } else if(reprobe) { scaddr.scbus = bus; scaddr.target = targ; scaddr.lun = lun; if (ioctl(fd,SCIOCREPROBE,&scaddr) == -1) perror("ioctl"); - } - - if(dflag) { + } else if(debugflag) { if (ioctl(fd,SCIOCDEBUG,&debuglevel) == -1) { perror("ioctl [SCIODEBUG]"); exit(1); } - } - - if (cmd) { + } else if (commandflag) { + int i; char *fmt; - if (argc <= 1) - { + if (argc < 1) { fprintf(stderr, "Need the command format string.\n"); usage(); } + fmt = argv[0]; argc -= 1; argv += 1; do_cmd(fd, fmt, argc, argv); + } else if (modeflag) { + mode_edit(fd, modepage, editflag, argc, argv); } }