Submitted by: Julian Elischer and Peter Dufault

Obtained from: 1.1.5

"scsi (8)" from 1.1.5, with added support for any command from
the command line.
This commit is contained in:
Peter Dufault 1995-01-24 12:07:27 +00:00
parent d1b8cd258b
commit 2208cace06
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/scsi/; revision=5843
3 changed files with 640 additions and 0 deletions

7
sbin/scsi/Makefile Normal file
View File

@ -0,0 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/5/93
PROG= scsi
MAN8= scsi.8
LDADD= -lscsi
.include <bsd.prog.mk>

192
sbin/scsi/scsi.8 Normal file
View File

@ -0,0 +1,192 @@
.\"
.\" Written By Julian ELischer
.\" Copyright julian Elischer 1993.
.\" Permission is granted to use or redistribute this file in any way as long
.\" as this notice remains. Julian Elischer does not guarantee that this file
.\" is totally correct for any given task and users of this file must
.\" accept responsibility for any damage that occurs from the application of this
.\" file.
.\"
.\" (julian@tfs.com julian@dialix.oz.au)
.\" User SCSI hooks added by Peter Dufault:
.\"
.\" Copyright (c) 1994 HD Associates
.\" (contact: dufault@hda.com)
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. The name of HD Associates
.\" may not be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\"
.\" $Id: scsi.1,v 1.1 1993/11/18 05:05:27 rgrimes Exp $
.\"
.Dd October 11, 1993
.Dt SCSI 1
.Os BSD 4
.Sh NAME
.Nm scsi
.Nd program to assist with scsi devices.
.Sh SYNOPSIS
.Bd -literal -offset
Usage:
scsi -f device -d debug_level # To set debug level
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...
-o count out_fmt [arg0 ... argn] # EITHER (for data out)
-i count in_fmt # OR (for data in)
.Pp
"out_fmt" can be "-" to read output data from stdin;
"in_fmt" can be "-" to write input data to stdout;
.Pp
If debugging is not compiled in the kernel, "-d" will have no effect
.Ed
.Sh DESCRIPTION
The
.Nm scsi
program is used to send commands to a scsi device. It is also
a sample usage of the user level SCSI commands.
.Pp
The
.Fr -d
option sets the SCSI kernel debug level. The kernel must have been compiled
with the
.Em SCSIDEBUG
option. See
.Fr /sys/scsi/scsi_debug.h
to figure out what to set the kernel debug level to.
.Pp
The
.Fr -p
option can be used against the "super scsi" device
.Fr /dev/scsi/super
to probe all devices with a given SCSI lun on a given SCSI bus.
The bus can be selected with the -b option and the default is 0.
The lun can be selected with the -l option and the default is 0.
See
.Xr scsi 4
for a description of the "super scsi" device.
.Pp
The
.Fr -r
option can be used in FreeBSD 1.1 to reprobe a specific SCSI device at a given
Bus, Target and Lun.
This is not needed in FreeBSD 2.1, since opening a fixed SCSI device
has the side effect of reprobing it, and probing with the bus with the
-p option should bring on line any newly found devices.
See
.Xr scsi 4
for a description of fixed scsi devices.
.Pp
The
.Fr -c
option permits you to send user level SCSI commands specified on
the command line to a
device. The command is sent using the SCIOCCOMMAND ioctl, so the
device you are accessing must permit this ioctl. See
.Xr scsi 4
for full details of which minor devices permit the ioctl, and
.Xr scsi 3
for the full details on how to build up the commands and data phases
using the format arguments.
.Pp
.Fr -v
turns on more verbose information.
.Pp
.Fr "-c cmd_fmt"
specifies the command as described in
.Xr scsi 3 "."
The additional arguments provide values for any variables
specified in the command format.
.Pp
.Fr "-o count out_fmt arg0 ... argn"
indicates that this is a data out command (i.e., data will be sent from
the system to the device) with
.Fr count
bytes of data. The data out is built up using the facilities described in
.Xr scsi 3
using the provided arguments to fill in any integer variables.
.Fr out_fmt
can be specified as a hyphen ("-") to indicate that the
.Fr count
bytes of data should be read from the standard input.
.Pp
.Fr "-o count out_fmt arg0 ... argn"
.Fr "-i count in_fmt"
indicates that this is a data in command (i.e., data will be read from
the device into the system) with
.Fr count
bytes of data read in. The information is extracted according to
.Fr in_fmt
using the facilities described in
.Xr scsi 3
and displayed on the standard output.
.Fr in_fmt
can be specified as a hyphen ("-") to indicate that the
.Fr count
bytes of data input should be written to the standard output.
.Sh EXAMPLES
To verify that the device type for the disk /dev/rsd0d is 0
(direct access device):
.Bd -literal -offset
root# scsi -f /dev/rsd0d -c "12 0 0 0 64 0" -i 64 "*b3 b5"
0
.Ed
.Pp
To do an inquiry to /dev/rsd2d:
.Bd -literal -offset
root# scsi -f /dev/rsd2d -c "12 0 0 0 64 0" -i 64 "s8 z8 z16 z4"
FUJITSU M2654S-512 010P
.Ed
.Pp
.Sh SEE ALSO
.Xr scsi 4 ,
.Xr scsi 3
.Sh BUGS
.Pp
.Fr out_fmt
support for
.Fr "-o count out_fmt arg0 ... argn"
isn't written yet. You have to specify out_fmt as "-" and read the
data in from standard input. If you want that capability
ask dufault@hda.com.
.Pp
This command wasn't ready for inclusion in 2.0R and so is missing in
that release.
.Pp
Some devices respond to an inquiry for all LUNS. This will cause them
to come on line to 8 times during reprobe to different logical units.
.Pp
The "-i" option to do an inquiry went away in 2.1. The new facilities
provided by "-c" supercede that.
.Pp
Check your permissions carefully.
"scsi -f /dev/rsd0d -c "4 0 0 0 0 0" permits anyone who can open
/dev/rsd0d to format the disk drive. This must be changed to
at least require write access to the drive.
.Sh HISTORY
The
.Nm scsi
command appeared in 386BSD 0.1.2.4/FreeBSD to support the new reprobe
and user SCSI commands.

441
sbin/scsi/scsi.c Normal file
View File

@ -0,0 +1,441 @@
/*
* Written By Julian ELischer
* Copyright julian Elischer 1993.
* Permission is granted to use or redistribute this file in any way as long
* as this notice remains. Julian Elischer does not guarantee that this file
* is totally correct for any given task and users of this file must
* accept responsibility for any damage that occurs from the application of this
* file.
*
* (julian@tfs.com julian@dialix.oz.au)
*
* User SCSI hooks added by Peter Dufault:
*
* Copyright (c) 1994 HD Associates
* (contact: dufault@hda.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of HD Associates
* may not be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: scsi.c,v 1.1 1993/11/18 05:05:28 rgrimes Exp $
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/scsiio.h>
#include <sys/file.h>
#include <scsi.h>
int fd;
int debuglevel;
int dflag,cmd;
int reprobe;
int probe_all;
int verbose = 0;
int bus = -1; /* all busses */
int targ = -1; /* all targs */
int lun = 0; /* just lun 0 */
usage()
{
printf(
"Usage:\n"
"\n"
" scsi -f device -d debug_level # To set debug level\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"
" -o count out_fmt [arg0 ... argn] # EITHER (for data out)\n"
" -i count in_fmt # OR (for data in)\n"
"\n"
"\"out_fmt\" can be \"-\" to read output data from stdin;\n"
"\"in_fmt\" can be \"-\" to write input data to stdout;\n"
"\n"
"If debugging is not compiled in the kernel, \"-d\" will have no effect\n"
);
exit (1);
}
void procargs(int *argc_p, char ***argv_p)
{
int argc = *argc_p;
char **argv = *argv_p;
extern char *optarg;
extern int optind;
int fflag,
ch;
fflag = 0;
cmd = 0;
dflag = 0;
while ((ch = getopt(argc, argv, "vpcrf:d:b:t:l:")) != EOF) {
switch (ch) {
case 'p':
probe_all = 1;
break;
case 'r':
reprobe = 1;
break;
case 'c':
cmd = 1;
break;
case 'v':
verbose = 1;
break;
case 'f':
if ((fd = scsi_open(optarg, O_RDWR)) < 0) {
(void) fprintf(stderr,
"%s: unable to open device %s: %s\n",
argv[0], optarg, strerror(errno));
exit(errno);
}
fflag = 1;
break;
case 'd':
debuglevel = atoi(optarg);
dflag = 1;
break;
case 'b':
bus = atoi(optarg);
break;
case 't':
targ = atoi(optarg);
break;
case 'l':
lun = atoi(optarg);
break;
case '?':
default:
usage();
}
}
*argc_p = argc - optind;
*argv_p = argv + optind;
if (!fflag) usage();
}
/* get_hook: Structure for evaluating args in a callback.
*/
struct get_hook
{
int argc;
char **argv;
int got;
};
/* iget: Integer argument callback
*/
int iget(void *hook, char *name)
{
struct get_hook *h = (struct get_hook *)hook;
int arg;
if (h->got >= h->argc)
{
fprintf(stderr, "Expecting an integer argument.\n");
usage();
}
arg = atol(h->argv[h->got]);
h->got++;
return arg;
}
/* cget: char * argument callback
*/
char *cget(void *hook, char *name)
{
struct get_hook *h = (struct get_hook *)hook;
char *arg;
if (h->got >= h->argc)
{
fprintf(stderr, "Expecting a character pointer argument.\n");
usage();
}
arg = h->argv[h->got];
h->got++;
return arg;
}
/* arg_put: "put argument" callback
*/
void arg_put(void *hook, int letter, void *arg, int count, char *name)
{
if (verbose)
printf("%s: ", name);
switch(letter)
{
case 'i':
case 'b':
printf("%d ", (int)arg);
break;
case 'c':
case 'z':
{
char *p = malloc(count + 1);
p[count] = 0;
strncpy(p, (char *)arg, count);
if (letter == 'z')
{
int i;
for (i = count - 1; i >= 0; i--)
if (p[i] == ' ')
p[i] = 0;
else
break;
}
printf("%s ", p);
}
break;
default:
printf("Unknown format letter: '%c'\n", letter);
}
if (verbose)
putchar('\n');
}
/* data_phase: SCSI bus data phase: DATA IN, DATA OUT, or no data transfer.
*/
enum data_phase {none = 0, in, out};
/* do_cmd: Send a command to a SCSI device
*/
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;
h.argc = argc;
h.argv = argv;
h.got = 0;
scsireq_reset(scsireq);
scsireq_build_visit(scsireq, 0, 0, 0, fmt, iget, (void *)&h);
/* Three choices here:
* 1. We've used up all the args and have no data phase.
* 2. We have input data ("-i")
* 3. We have output data ("-o")
*/
if (h.got >= h.argc)
data_phase = none;
else
{
char *flag = cget(&h, 0);
if (strcmp(flag, "-o") == 0)
data_phase = out;
else if (strcmp(flag, "-i") == 0)
data_phase = in;
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;
if (count)
{
char *data_fmt;
data_fmt = cget(&h, 0);
scsireq->databuf = malloc(count);
if (data_phase == out)
{
if (strcmp(data_fmt, "-") == 0) /* stdin */
{
if (read(0, scsireq->databuf, count) != count)
{
perror("read");
exit(errno);
}
}
else /* XXX: Not written yet */
{
fprintf(stderr, "Can't set up output data using %s.\n",
data_fmt);
exit(-1);
}
}
if (scsireq_enter(fd, scsireq) == -1)
{
scsi_debug(stderr, -1, scsireq);
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_probe_all: Loop over all SCSI IDs and see if something is
* there. This only does BUS 0 LUN 0.
*/
do_probe_all()
{
scsireq_t *scsireq;
char vendor_id[8 + 1], product_id[16 + 1], revision[4 + 1];
int id;
u_char *inq_buf = malloc(96);
struct scsi_addr addr;
scsireq = scsireq_build(scsireq_new(),
96, inq_buf, SCCMD_READ,
"12 0 0 0 v 0", 96);
addr.scbus = (bus == -1) ? 0 : bus;
addr.lun = lun;
if (addr.scbus || addr.lun)
{
printf("For bus %d lun %d:\n", addr.scbus, addr.lun);
}
for (id = 0; id < 8; id++)
{
addr.target = id;
printf("%d: ", id);
if (ioctl(fd, SCIOCADDR, &addr) == -1) {
if (errno == ENXIO)
{
errno = 0;
printf("nothing.\n");
}
else
printf("SCIOCADDR: %s\n", strerror(errno));
continue;
}
if (scsireq_enter(fd, scsireq) == -1) {
printf("scsireq_enter: %s\n", strerror(errno));
continue;
}
vendor_id[sizeof(vendor_id) - 1] = 0;
product_id[sizeof(product_id) - 1] = 0;
revision[sizeof(revision) - 1] = 0;
scsireq_decode(scsireq, "s8 c8 c16 c4",
vendor_id, product_id, revision);
printf("%s %s %s\n", vendor_id, product_id, revision);
}
}
main(int argc, char **argv)
{
struct scsi_addr scaddr;
procargs(&argc,&argv);
if (probe_all) {
do_probe_all();
}
if(reprobe) {
scaddr.scbus = bus;
scaddr.target = targ;
scaddr.lun = lun;
if (ioctl(fd,SCIOCREPROBE,&scaddr) == -1)
perror("ioctl");
}
if(dflag) {
if (ioctl(fd,SCIOCDEBUG,&debuglevel) == -1)
{
perror("ioctl [SCIODEBUG]");
exit(1);
}
}
if (cmd) {
char *fmt;
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);
}
}