diff options
author | dufault <dufault@FreeBSD.org> | 1995-04-28 19:24:39 +0000 |
---|---|---|
committer | dufault <dufault@FreeBSD.org> | 1995-04-28 19:24:39 +0000 |
commit | 0066e95aad8a417bae7dc26a8126eef616eba5d6 (patch) | |
tree | ae73cc1c517063754a27e16ba44af25e50c5f332 /sbin/scsi/scsi.c | |
parent | d1214fe1e858f03c29ab0eee597e36e45f26ea21 (diff) | |
download | FreeBSD-src-0066e95aad8a417bae7dc26a8126eef616eba5d6.zip FreeBSD-src-0066e95aad8a417bae7dc26a8126eef616eba5d6.tar.gz |
Add "-m" command to read mode pages. Also add -z for freezing,
though the kernel changes aren't committed yet.
Diffstat (limited to 'sbin/scsi/scsi.c')
-rw-r--r-- | sbin/scsi/scsi.c | 361 |
1 files changed, 288 insertions, 73 deletions
diff --git a/sbin/scsi/scsi.c b/sbin/scsi/scsi.c index 07807a1..9686be9 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 <stdio.h> #include <string.h> #include <stdlib.h> +#include <unistd.h> #include <errno.h> #include <sys/scsiio.h> #include <sys/file.h> #include <scsi.h> +#include <ctype.h> 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) + { + scsi_debug(stderr, -1, scsireq); + exit(errno); + } + + if (SCSIREQ_ERROR(scsireq)) + scsi_debug(stderr, 0, scsireq); - if (scsireq_enter(fd, scsireq) == -1) + 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); } } |