summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authordufault <dufault@FreeBSD.org>1995-04-28 19:24:39 +0000
committerdufault <dufault@FreeBSD.org>1995-04-28 19:24:39 +0000
commit0066e95aad8a417bae7dc26a8126eef616eba5d6 (patch)
treeae73cc1c517063754a27e16ba44af25e50c5f332 /sbin
parentd1214fe1e858f03c29ab0eee597e36e45f26ea21 (diff)
downloadFreeBSD-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')
-rw-r--r--sbin/scsi/scsi.846
-rw-r--r--sbin/scsi/scsi.c361
2 files changed, 333 insertions, 74 deletions
diff --git a/sbin/scsi/scsi.8 b/sbin/scsi/scsi.8
index acd9a7d..b843835 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 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);
}
}
OpenPOWER on IntegriCloud