Table of Contents
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.
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
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]