dslib: dsopen, dsclose - communicate with SCSI devices
accessed using the linux-xscsi subsystem.
SYNOPSIS
#include <dslib.h>
struct dsreq *dsopen(opath, oflags)
dsclose(dsp)
ds_showcmd(dsp)
testunitready00(dsp)
requestsense03(dsp, data, datalen, vu)
read08(dsp, data, datalen, lba, vu)
write0a(dsp, data, datalen, lba, vu)
inquiry12(dsp, data, datalen, vu)
modeselect15(dsp, data, datalen, save, vu)
modeselect55(dsp, data, datalen, save, vu)
reserveunit16(dsp, data, datalen, tpr, tpdid, extent, resid, vu)
releaseunit17(dsp, tpr, tpdid, extent, resid, vu)
modesense1a(dsp, data, datalen, pagectrl, pagecode, vu)
modesense5a(dsp, data, datalen, pagectrl, pagecode, vu)
modesenseNB_5a(dsp, data, datalen, pagectrl, pagecode, vu)
senddiagnostic1d(dsp, data, datalen, self, dofl, uofl, vu)
readcapacity25(dsp, data, datalen, lba, pmi, vu)
readextended28(dsp, data, datalen, lba, vu)
writeextended2a(dsp, data, datalen, lba, vu)
getfd(dsp)
doscsireq(fd, dsp)
void fillg0cmd(dsp, cmdbuf, b0, ..., b5)
void fillg1cmd(dsp, cmdbuf, b0, ..., b9)
void fillg2cmd(dsp, cmdbuf, b0, ..., b9)
void fillg5cmd(dsp, cmdbuf, b0, ..., b11)
void filldsreq(dsp, data, datalen, flags)
void vtostr(value, table)
extern int dsdebug;
extern int ds_default_timeout;
extern long dsreqflags;
DSDBG(statement; ...)
struct dsreq *dsp;
struct vtab *table;
char *opath, *cmdbuf, *data;
char b0, ..., b9, dofl, extent, pagecode, pagectrl, pmi, resid,
save, self, tpdid, tpr, uofl, vu;
int fd, oflags;
long datalen, lba, value;
These routines form the basis for a simplified interface
to ds(8) devices. They are included in a program by com
piling with the -lds option. An application would typi
cally use dsopen, dsclose, and a set of command-specific
routines such as testunitready00. The source to this
library can be obtained by installing the xscsi
tools-*.src.rpm with the source code for the library in
the files dstab.c and dslib.c There are also several sam
ple programs using the dslib library provided in the rpm.
The number of truly general SCSI commands is quite lim
ited, so provision is made for supporting vendor-specific
commands. This is normally done by using one of the
existing routines as a template, and creating a new rou
tine of your own. This might be useful if support for a
SCSI command group other than Group 0, 1, 2, or 5 is
needed. It is expected that most non-trivial uses of the
library will involve creating or modifying existing rou
tines. Any SCSI command length from 1 to 12 bytes is sup
ported by the underlying kernel drivers, providing the
ds_cmdlen field is set correctly.
A set of helper routines (fillg0cmd and so on) are used as
the basis for creating your own routines. The utility
function ds_showcmd(dsp) can be used to show information
about the most recently executed command, in cases where
the use of dsdebug is too verbose. testunitready00, for
instance, is implemented as:
testunitready00(dsp)
struct dsreq *dsp;
{
fillg0cmd(dsp, CMDBUF(dsp), G0_TEST, 0, 0, 0, 0, 0);
filldsreq(dsp, 0, 0, DSRQ_READ|DSRQ_SENSE);
return(doscsireq(getfd(dsp), dsp));
}
Note that many of these routines depend upon the exact
setup of the dsreq structure used by dsopen. It is there
fore not recommended that users attempt to use indepen
dently derived dsreq structures with them.
dsopen passes opath and oflags to the open system call.
If the open succeeds, dsopen allocates and fills a dsreq
structure, along with some associated context information.
dsclose deallocates the specified dsreq structure, then
calls close to close the device.
fillg0cmd, fillg1cmd, fillg2cmd, and fillg5cmd are used to
fill Group 0, 1, 2, and 5 command buffers, respectively.
filldsreq fills a dsreq structure with commonly needed
data. The value of dsreqflags is ORed into the ds_flags
DSRQ_SENSE) set for some or all commands, as it allows you
to avoid duplicating the library routines when you need a
special flag set. It also sets the default timeout (for
functions that do not explicitly set a timeout). The
timeout is set from the global variable ds_default_time
out, and that variable is initialized to 10 seconds. It
may be changed for applications that want longer default
timeouts. Individual functions may still need to set
longer (or shorter) timeouts, after calling filldsreq.
doscsireq issues the SCSI ioctl, performs a variety of
error-handling functions, and returns the SCSI status
byte. Also of interest on return is the ds_ret field,
which is 0 on successful returns, and on failures indi
cates what type of error occurred (the DSRT_* values in
<xscsids.h>.
ds_vtostr Takes a value, and a table to look it up in. If
the value is found in the given table, a string describing
the value is returned, else the empty string. Five tables
are provided:
dsrqnametab for the DSRQ_* flags
dsrtnametab for the DSRT_* flags
cmdstatustab for the SCSI status byte return in ds_sta
tus
msgnametab for the SCSI message bytes
cmdnametab for the SCSI commands, such as Testuni
tready (value is the command byte; G0_TEST
in this case)
The dsdebug variable, and the DSDBG() macro can be used to
enable debug printfs, and to add your own. If the dsdebug
variable is non-zero, debugging information is printed by
the library routines. The DSDBG macro is used for this
purpose. A more or less arbitrary sequence of statements
can be used within the parentheses of the DSDBG macro, but
some form of print statement is most frequently used.
Overlay structures define the layouts of the three (Group
0, 1, 6) Common Command Set command buffers. Bytes are
named both by position (g0_b0) and by typical function in
the command buffer (g1_op_code).
Mnemonic names are also defined for all CCS command codes
(G0_TEST), message bytes (MSG_ABORT), and status bytes
(STA_BUSY). There are also a number of macros suitable
for accessing dsreq structures, SCSI byte and bit fields,
etc.
A set of structures contains values, name strings, and
descriptions for commonly used codes and values. The
structures document DSRQ_* and DSRT_* codes, CCS command
codes, and CCS status and message bytes. They are
EXAMPLE PROGRAM
The following code fragment illustrates simple use of the
library, and of some /dev/xscsi/pci*/target*/lun*/ds sup
port macros.
while (--argc > 0) {
fn = *++argv;
printf("%-17s ", fn);
if ((dsp = dsopen(fn, O_RDONLY)) == NULL) {
fflush(stdout);
perror("cannot open");
continue;
}
if(inquiry12(dsp, inqbuf, sizeof inqbuf, 0) != 0)
printf("%-10s inquiry failure0, "---");
else {
pdt = DATABUF(dsp)[0] & 0x7F;
if (DATASENT(dsp) >= 1)
printf("%-10s", pdt_types[(pdt<NPDT) ? pdt : NPDT-1]);
if (DATASENT(dsp) >= 16) printf(" %-12.8s", &DATABUF(dsp)[8]);
if (DATASENT(dsp) >= 32) printf(" %.16s", &DATABUF(dsp)[16]);
if (DATASENT(dsp) >= 36) printf(" %.4s", &DATABUF(dsp)[32]);
/* do test unit ready only if inquiry successful, since many
devices, such as tapes, return inquiry info, even if
not ready (i.e., no tape in a tape drive). */
if(testunitready00(dsp) != 0) {
printf(" %s0,
(RET(dsp)==DSRT_NOSEL) ? "cannot select" : "not ready");
}
else
printf(" ready0);
}
dsclose(dsp);
}
Each device is opened, and the necessary data structures
created. An inquiry is done to see if the device exists;
if so, it's type is printed. A test unit ready is done to
see if the device is ready for I/O. Finally, the device
is closed, releasing the data structures.
DIAGNOSTICS
dsopen returns a NULL pointer on failure. doscsireq
returns -1 on absolute failure, and the status byte other
wise. A status byte of 0xff indicates an invalid status
byte because the scsi command didn't complete. The
RET(dsp) macro returns a result code, which can be con
sulted for any error or 'unusual' status from the driver;
a value of 0 indicates a normal return.
A common failure occurs when the byte count passed to the
dslib routines doesn't match the byte count implied by the
values in the SCSI command descriptor (as filled by
fillg0cmd and so on). This is particularly common with
read08,write0a,readextended28, and writeextended2a. This
is because these commands occur in a number of device spe
cific forms. If you get console error messages similar to
SCSI Bus=# ID=# LUN=#: Too much data (probable SCSI bus
cabling problem) then you are probably seeing this kind of
mismatch. See the comments in the dslib.c source file for
more information.
In the SGI Linux XSCSI infrastructure, devices can be open
via both the ds and other high level drivers at the same
time, Only one program can have any ds device open at a
time, however.
FILES
/dev/xscsi/pci*/target*/lun*/ds
SEE ALSO
ds(8), xscsicontrol(8), xscsidisktest(8).
Man(1) output converted with
man2html