SA(4S) — DEVICES AND NETWORK INTERFACES
NAME
sa − user level SCSI access driver
SYNOPSIS
#include <dev/saio.h>
DESCRIPTION
The sa device driver provides a mechanism for the user to access the SCSI bus without having to go to the trouble of writing a kernel device driver. The driver is intended for use in quickly interfacing non-standard (application specific) SCSI devices to a Solbourne machine. The remainder of this section discusses the use of this interface.
The driver supports only three operations: open, close, and ioctl. Each minor device number represents an exclusive use channel of communication to the SCSI bus. An open of a channel is not specific to any SCSI target/lun and will always succeed if the channel is not already inuse (given appropriate permissions on the special file). The channel will remain open until it is closed (or the process which opened it exits).
An open channel supports two ioctls: one to bind the channel to the specified SCSI device, and one to issue a SCSI command to the device. The definitions of these ioctl operations are in <dev/saio.h>:
/∗
∗ Copyright 1988 Solbourne Computer, Inc.
∗ All rights reserved.
∗/
#ifndef _SAIO_
#define _SAIO_
#include <sys/ioccom.h>
#include <dev/scsi.h>
/∗
∗ Structures and definitions for scsi user io control commands
∗/
/∗
∗ Structures used as data by ioctl calls.
∗/
/∗
∗ Used to bind an unit to a scsi target
∗/
#define SA_IO_BIND _IOW(u, 0, struct sa_bind) /∗ Bind to device ∗/
struct sa_bind {
u_char sa_bind_target; /∗ scsi target id to bind ∗/
u_char sa_bind_lun; /∗ lun of target to bind ∗/
int sa_bind_flags;
#define SA_BIND_FLAGS_SILENT 0x01 /∗ no error messages ∗/
#define SA_BIND_FLAGS_DISCON 0x02 /∗ allow disconnect ∗/
#define SA_BIND_FLAGS_SYNCH 0x04 /∗ allow synchronous ∗/
#define SA_BIND_FLAGS_PARITY 0x08 /∗ allow parity ∗/
#define SA_BIND_FLAGS_NON_MUX 0x10 /∗ non-multiplexed device ∗/
#define SA_BIND_FLAGS_MSG_CC 0x20 /∗ only supports cmd complete ∗/
int sa_bind_blksize;
};
/∗
∗ Used for commands
∗/
#define SA_IO_CMD _IOWR(u, 1, struct sa_cmd) /∗ issue cmd ∗/
struct sa_cmd {
union scsi_cdb ∗sa_cmd_cdb; /∗ scsi command block ∗/
caddr_t sa_cmd_bufaddr; /∗ user’s buffer address ∗/
u_int sa_cmd_buflen; /∗ size of user’s buffer ∗/
short sa_cmd_ctlb_flags; /∗ command flags for ∗/
/∗ non-standard commands. ∗/
/∗ see scsi.h ctlb_flags...∗/
short sa_cmd_timeout; /∗ time for completion ∗/
int sa_cmd_error_class; /∗ see scsi_var.h ∗/
int sa_cmd_error_code; /∗ host adaptor specific ∗/
union scsi_scb ∗sa_cmd_scb; /∗ execution status ∗/
};
#endif !_SAIO_
};
EXAMPLE
The following example will print out the current devices plugged into the SCSI bus.
#include <sys/types.h>
#include <dev/saio.h>
struct sa_bind sa_bind;
struct sa_cmd sa_cmd;
struct scsi_inq scsi_inq;
union scsi_cdb scsi_cdb;
union scsi_scb scsi_scb;
main()
{
int fd, target;
if ((fd = open("/dev/sa0", 2)) < 0) {
perror("failed open");
exit(1);
}
for (target = 0 ; target < 7 ; target++) {
sa_bind.sa_bind_target = target;
sa_bind.sa_bind_lun = 0;
sa_bind.sa_bind_flags =
SA_BIND_FLAGS_DISCON | SA_BIND_FLAGS_PARITY;
if (ioctl(fd, SA_IO_BIND, &sa_bind) < 0) {
perror("failed bind");
exit(1);
}
SET_CDB_0(scsi_cdb, SC_INQUIRY, 0, 0, sizeof(struct scsi_inq));
sa_cmd.sa_cmd_cdb = &scsi_cdb;
sa_cmd.sa_cmd_bufaddr = (caddr_t) &scsi_inq;
sa_cmd.sa_cmd_buflen = sizeof(struct scsi_inq);
sa_cmd.sa_cmd_timeout = 60;
sa_cmd.sa_cmd_scb = &scsi_scb;
if (ioctl(fd, SA_IO_CMD, &sa_cmd) < 0) {
perror("failed cmd");
exit(1);
}
printf("target %d lun 0: ", target);
if (sa_cmd.sa_cmd_error_class || sa_cmd.sa_cmd_error_code)
printf("ERROR_CLASS %d, ERROR_CODE %d0,
sa_cmd.sa_cmd_error_class,
sa_cmd.sa_cmd_error_code);
else
printf("%s0, scsi_inq.inq_vendor);
}
exit(0);
}
SEE ALSO
Solbourne Computer, Inc. — 13 December 1989