SD(4)

NAME
sd*, rsd*, rct* - SCSI Device Driver

DESCRIPTION
This is a driver for SCSI peripheral devices connected to the host computer through a SCSI Expansion Card. The files /dev/sd* and /dev/r{sd,ct}* are block and character devices respectively to peripherals attached to the SCSI Bus: sd is the name conventionally used for Direct Access class devices, (typically winchester discs), and ct refers to Sequential Access devices (e.g. cartridge tapes).

Explicit support is provided for Direct and Sequential Access devices which conform to the ANSI standard, although facilities exist to handle other SCSI peripherals.

SCSI Expansion Cards may be fitted in any expansion slot. Each Expansion Card may be used to address up to seven SCSI Peripherals. The SCSI Device Driver reserves for itself the ID of 7; attached peripherals may take IDs between 0 and 6.

Individual target devices are addressed through the major and minor device numbers according to the following rules:

SCSI devices are addressed via a contiguous block of 28 major device numbers. Using the first target as a base
    logical expansion slot number = (major(dev) - base) / 7
    target = (major(dev) - base) % 7
For block devices the base number is 12, while character devices have a base of 21. See the RISC iX System Administrator's Guide for more information about setting up SCSI devices.

The minor device number of a file is arranged as a bitmap. This bitmap encodes the Logical Unit Number, an Escape flag and an Exclusive Access flag.
    LUN = (minor(dev) >> 5) & 7
    Escape = minor(dev) & 0x08
    Exclusive = minor(dev) & 0x10
Meanings for bits 0 - 2 are assigned by individual SCSI Device Class Handlers. If the Escape bit is set, then these bits must all be clear for an open on the device to succeed.

A generic ioctl(2) call is provided. The file must be opened for at least WRITE.
#define SCSI_CDB       12
#define SCSI_SENSE     20
struct scsiop {
  char  cdb[SCSI_CDB];		/* control block for the operation */
  int   xfer;			/* transfer count in bytes         */
  char *addr;			/* transfer address                */
  int   timeout;		/* timeout value in centiseconds   */
  int   flags;			/* Read/Write etc.                 */
  char  sense[SCSI_SENSE];	/* Extended Sense Information      */
  char  status;			/* completion status               */
};
#define SCSIDO      _IOWR(s, 0, struct scsiop)      /* generic scsi operation */
/* SCSI Status Codes */
#define SCSI_GOOD_STATUS           0x00
#define SCSI_CHECK_CONDITION       0x02
#define SCSI_TIMEOUT               0x04
#define SCSI_BUSY                  0x08
#define SCSI_RESERVATION_CONFLICT  0x10
#define SCSI_EXPIRED               0x20
#define SCSI_PARITY_ERROR          0x40
/* flags for SCSIDO */
#define SC_READ             (1<<0)
#define SC_WRITE            (1<<1)
#define SC_SENSE_VALID      (1<<2)   /* returned to indicate the        */
                                     /* condition of the sense bytes    */
#define SC_NO_SENSE         (1<<3)   /* set to indicate that the driver */
                                     /* should not perform a REQUEST    */
                                     /* SENSE should the command fail   */
#define SC_ALLOW_DISCONNECT (1<<11)  /* set to indicate that the driver */
                                     /* should always allow target */
                                     /* disconnection */
/* Special timeout value to indicate "do not timeout" */
#define NO_TIMEOUT     (-1)
/* Escape flag for generic device, held in minor device */
#define SCSI_ESCAPE  (1<<3)
/* Exclusive Access flag for generic device, held in minor device */
#define SCSI_EXCL    (1<<4)

If the transfer count is zero, then the transfer address should still reference a valid data buffer. In this situation, NULL is not classed as an acceptable address.

There is a difference between the status codes SC_TIMEOUT, and SC_EXPIRED: SC_TIMEOUT is returned on a selection timeout, i.e. when no device responded to the selection phase; SC_EXPIRED is returned when a device did respond to the selection phase, but failed to complete the command within the timeout period specified.

Usually, when only a single device is open, the driver will inhibit device disconnection in an attempt to avoid unnecessary bus overhead. This optimisation is undesirable for “long-lived” commands e.g. mag. tape rewinds, as no new device may be opened until the command has finished and the bus is idle. The SC_ALLOW_DISCONNECT flag forces the driver to allow disconnection, even when only one device is open.

If the Escape flag is set in the minor device number, then the SCSIDO ioctl() is the only operation that may be performed on that device, apart from open() and close().

DEVICE CLASS HANDLERS
Two SCSI Device Classes are currently supported. These are the Direct and Sequential Access Classes. Each Device Class Handler provides its own ioctl(2) interfaces and the style of interface which is conventional for that family of peripherals.

DIRECT ACCESS CLASS HANDLER
The Direct Access Class Handler implements a partitioning scheme as found in other device drivers. The partition table is written on the disc medium during initialisation and read from the driver on the initial open. Up to eight partitions are defined, although some may be left invalid.
/* Partition Table Information */
#define MAX_PARTITION             (8)
#define TEXT                     (16)
#define END_OF_DISC      (0xFFFFFFFF)
#define ID_MARK          (0x4A657320)
typedef struct {
  unsigned int     start;	/* offset of partition from block 0 */
  unsigned int     length;	/* length of partition in blocks    */
  unsigned int     flags;	/* flags to indicate state          */
          char     text[TEXT];	/* identifying text for partition   */
} Partition;
typedef struct {
  long      time_stamp;		/* monotonic id for table */
  Partition pt[MAX_PARTITION];	/* array of partitions    */
} Table;
typedef struct {
  unsigned int     id;		/* marker to indicate UNIX Info */
  Table            pt;		/* partition table */
} UNIX_Info;
/* Flags for Partition Table */
#define PT_VALID              (1<<0)
#define PT_READ_ONLY          (1<<1)
/* Names for partitions */
#define P_ROOT                    (0)
#define P_SWAP                    (1)
#define P_BOOT                    (6)
#define P_ALL                     (7)
/*
 * Reading and Writing the Partition Table (RAM copy)
 */
#define WRITEPART     _IOW(d, 0, Table *)
#define READPART      _IOW(d, 1, Table *)
/*
 * Writing the Block size (RAM copy)
 */
#define WRITEBLOCK    _IOW(d, 2, int)
/* Partition Indication bits */
#define PARTITION_BITS (0x07)

The scsidm(8) program, used to create a partition table on a raw disc, supplies default values for P_ALL (the whole disc), and P_BOOT (the portion of the disc reserved for RISC OS). Any attempt to access the RISC OS area through a partition other than P_BOOT will be logged, and any write attempt will be refused with ENXIO.

SEQUENTIAL ACCESS CLASS HANDLER
The Sequential Access Class Handler administers devices such as Streaming Tapes. It supports the standard ioctl interfaces defined in <sys/mtio.h>. Two device types are provided, one a vanilla device, the other offering automatic rewind when the device is closed.
/* Flags set in the minor device number */
#define REWIND_ON_CLOSE   (1<<0)

ERRORS
The following errors may be returned by the driver:

[ENXIO] No expansion card found, illegal attempt to write P_BOOT, or the card is not a SCSI card or the card is malfunctioning. Attempt to open device with combination of Escape bit and device class specific bits (0-2) set in minor number.

[ENODEV] The addressed peripheral is not present or powered on. The specified partition may not be opened. The addressed peripheral is returning a NOT READY condition.

[EIO] An error occurred during the request. The request may be retried although the condition is probably not transient.

[EROFS] Attempt to write to a device which is READ ONLY.

[EBUSY] The target device is currently active. This condition is usually transient.

[EBADF] Attempt to call an ioctl which may perform a write operation without the appropriate permissions.

[EINVAL] Attempt to access a block oriented device in a non block-aligned manner. Transfer count passed to SCSIDO ioctl() too large.

[ENOTBLK] The block size of the target device is incompatible with DEV_BSIZE.

DIAGNOSTICS
Serious hardware errors are logged under the following categories.
LOG_NOTICE
SCSI: Recovered Error for device#%x.%x%x, info bytes [0..3] %x %x %x
SCSI: Recovered Error for device#%x.%x%x, no info returned
LOG_ALERT
SCSI: Unexpected UNIT ATTENTION for device #%x:%x%x
LOG_CRIT
SCSI: Medium Error for device#%x.%x%x, info bytes [0..3] %x %x %x
SCSI: Medium Error for device#%x.%x%x, no info returned
SCSI: Unable to initialise expansion card#%x
LOG_WARNING
SCSI: Device %x:%x%x timed out
LOG_ERROR
SCSI: Cannot read boot block on device #%x:%x%x
SCSI: Cannot read partition table on device #%x:%x%x
SCSI: read BOOT area: block %x partition %d on device #%x:%x%
SCSI: write BOOT area: block %x partition %d on device #%x:%x%
SCSI: device #%x.%x%x offline

FILES
/dev/sd*
/dev/rsd*
/dev/rct*

SEE ALSO
scsidm(8), RISC iX System Administrator's Guide.