Appendix E. Compile options and System calls including ioctls

Table of Contents

Mid level
Mid level compile options
Mid level ioctls
sd driver
sd compile options
sd ioctls and user interface
sr driver
sr compile options
sr ioctls and user interface
st driver
st compile options
st ioctls and user interface
sg driver
sg compile options
sg ioctls and user interface

The compile options in this appendix are those which a system administrator might conceivably want to change. Naturally the defaults are chosen so the vast majority of users will not need to modify anything. In some cases setting kernel build time options, kernel boot time parameters or module load parameters has the same effect as changing a driver compile time option.

System calls act as the interface between application programs and the kernel and its drivers. In the case of the layered driver architecture that the SCSI subsystem uses, the upper layer drivers handle most of the system calls.

The SCSI subsystem has a "bubble down" ioctl structure. First the upper level driver associated with the open file descriptor attempts to decode the ioctl. If it doesn't recognize it then the ioctl is passed down to the mid level. If the mid level doesn't recognize it then the ioctl is passed down to the lower level driver associated with the file descriptor. If the lower level driver doesn't recognize it then a EINVAL error is generated.

Some ioctls are dispatched to related subsystems.

Mid level

The following header files in the kernel source are relevant to the mid level:

        /usr/src/linux/include/scsi/scsi.h
        /usr/src/linux/include/scsi/scsi_ioctl.h

These files are meant for applications to use (other than parts in a __KERNEL__ conditional compilation block). They may also be found in /usr/include/scsi directory but it is best not to trust these versions as they are maintained with the glibc library and may lag the kernel version being used. Usually in Linux systems /usr/include/linux can be relied upon to be a symbolic link to the kernel source's include area (typically /usr/src/linux/include/linux). This symbolic link can be used to include the correct scsi_ioctl.h using the following trick: #include <linux/../scsi/scsi_ioctl.h>

This include file: /usr/src/linux/drivers/scsi/scsi.h is the key internal header file for the SCSI subsystem. As such it will not be discussed here other than to point out it has the same file name (but it's in a different directory) as the include file mentioned at the beginning of this section. This sometimes causes confusion.

The mid level drivers/scsi/scsi_scan.c file maintains an array of known SCSI devices with idiosyncrasies . [This was known as the "black list" but that was considered to judgmental.] The array is called "device_list". The various value are:

  • BLIST_NOLUN only probe lun 0

  • BLIST_FORCELUN force all 8 luns to be probed

  • BLIST_BORKEN passes through broken flag to lower level driver

  • BLIST_KEY sends magical MODE SENSE (pc=0x2e) to unlock device

  • BLIST_SINGLELUN only allow IO on one lun at a time

  • BLIST_NOTQ disable tagged queuing

  • BLIST_SPARSELUN keep going after lun not found

  • BLIST_MAX5LUN only probe up to lun 5

  • BLIST_ISDISK override INQUIRY's type with disk (direct access) type

  • BLIST_ISROM override INQUIRY's type with ROM

Mid level compile options

None.

Mid level ioctls

See the following files:

/usr/src/linux/include/scsi/scsi.h

Note that the SCSI status constants defined in include/scsi/scsi.h are shifted 1 bit right from the values in the SCSI standards:


scsi.h constant      value     SCSI 2 standard value
----------------------------------------------------
CHECK_CONDITION       0x1           0x2
CHECK_GOOD            0x2           0x4
BUSY                  0x4           0x8
....

Summary of ioctl()s follow:

SCSI_IOCTL_SEND_COMMAND
  This interface is deprecated - users should use
  the scsi generic (sg) interface instead, as this
  is a more flexible approach to performing
  generic SCSI commands on a device.

  The structure that we are passed should look like:

  struct sdata {
   unsigned int inlen;     [i] Length of data written to device
   unsigned int outlen;    [i] Length of data read from device
   unsigned char cmd[x];   [i] SCSI command (6 <= x <= 16)
                           [o] Data read from device starts here
                           [o] On error, sense buffer starts here
   unsigned char wdata[y]; [i] Data written to device starts here
  };
  Notes:
    -  The SCSI command length is determined by examining
       the 1st byte of the given command. There is no way
       to override this.
    -  Data transfers are limited to PAGE_SIZE (4K on
       i386, 8K on alpha).
    -  The length (x + y) must be at least OMAX_SB_LEN
       bytes long to accommodate the sense buffer when
       an error occurs. The sense buffer is truncated to
       OMAX_SB_LEN (16) bytes so that old code will not
       be surprised.
    -  If a Unix error occurs (e.g. ENOMEM) then the user
       will receive a negative return and the Unix error
       code in 'errno'. If the SCSI command succeeds then
       0 is returned. Positive numbers returned are the
       compacted SCSI error codes (4 bytes in one int)
       where the lowest byte is the SCSI status. See the
       drivers/scsi/scsi.h file for more information on this.

SCSI_IOCTL_GET_IDLUN
  This ioctl takes a pointer to a "struct scsi_idlun" object
  as its third argument. The "struct scsi_idlun" definition
  is found in <scsi/scsi.h>. It gets populated with scsi
  host, channel, device id and lun data for the given device.
  Unfortunately that header file "hides" that structure
  behind a "#ifdef __KERNEL__" block. To use this, that
  structure needs to be replicated in the user's program.
  Something like:
  typedef struct my_scsi_idlun {
      int four_in_one;    /* 4 separate bytes of info
                             compacted into 1 int */
      int host_unique_id; /* distinguishes adapter cards from
                             same supplier */
  } My_scsi_idlun;
      "four_in_one" is made up as follows:
      (scsi_device_id | (lun << 8) | (channel << 16) |
      (host << 24))
  These 4 components are assumed (or masked) to be 1 byte each.

SCSI_IOCTL_GET_BUS_NUMBER
  In lk 2.2 and earlier this ioctl was needed to get the
  host number. During lk 2.3 development the
  SCSI_IOCTL_GET_IDLUN ioctl was changed to include this
  information. Hence this ioctl is only needed for
  backward compatibility.
SCSI_IOCTL_TAGGED_ENABLE
  Probably a remnant of the past when the mid level
  addressed such issues. Now this functionality is
  controlled by the lower level drivers. Best ignored.
SCSI_IOCTL_TAGGED_DISABLE
  See comment for SCSI_IOCTL_TAGGED_ENABLE.
SCSI_IOCTL_PROBE_HOST
  This ioctl expects its 3rd argument to be a pointer to
  a union that looks like this:
  union probe_host {
    unsigned int length;  /* [i] max length of
                                 output ASCII string */
    char str[length];     /* [o] N.B. may need '\0' 
    				 appended */
  };
  The host associated with the device's fd either has a
  host dependent information string or failing that its
  name, output into the given structure. Note that the
  output starts at the beginning of given structure
  (overwriting the input length). N.B. A trailing '\0'
  may need to be put on the output string if it has been
  truncated by the input length. A return value of 1
  indicates the host is present, 0 indicates that the
  host isn't present (how can that happen?) and a
  negative value indicates an error.

SCSI_IOCTL_DOORLOCK
SCSI_IOCTL_DOORUNLOCK
SCSI_IOCTL_TEST_UNIT_READY
  Returns 0 if the unit (device) is ready, a positive
  number if it is not or a negative number when there
  is an OS error.

SCSI_IOCTL_START_UNIT
SCSI_IOCTL_STOP_UNIT
SCSI_EMULATED_HOST          {same as SG_EMULATED_HOST <new>}

SCSI_IOCTL_GET_PCI
  Yields the PCI slot name (pci_dev::slot_name) associated with the lower
  level (adapter) driver that controls the current device. Up to 8 characters
  are output to the locations pointed to by 'arg'. If the current device
  is not controlled by a PCI device then errno is set to ENXIO.
  [This ioctl() was introduced in lk 2.4.4]