SCSI-2
Home Up SCSI-1 SCSI-2 SCSI-3 SCSI-5 SCSI-6 SCSI-4 SCSI-7 SCSI-8 SCSI-9 SCSI-10 SCSI-13 SCSI-12 SCSI-11

 

 

2. Data Structures

 

2.0 Introduction

 

Before it is possible to explain how the actual SCSI subsystem works, it is essential that you first understand some of the key data structures which are used all throughout the subsystem. The purpose of this section of the document is to explain what those structures are, and then explain in detail what the structure elements are used for.

The other sections of the Linux SCSI documentation will be linked to this section, as appropriate.

In addition to explaining the purpose of each element of the structure, it is also important to mention exactly who should be allowed to use it.

When originally designed, the data structures were intended to be quasi-object-oriented. Given that the Linux kernel is compiled with the C compiler instead of C++, we have to fake it to some degree - one unfortunate side effect of this is that there is no way to declare private members of the class, and in addition it isn't possible to declare private member functions which are not globally accessible.

Complicating this is the fact that some structure elements are created on behalf of different sections of the SCSI subsystem. For example, some elements may be used entirely by the low-level drivers and not touched anywhere else. Other elements might be used by the mid-level, and shouldn't be touched elsewhere. At some point, it might be a good idea to try and split some of these structures to group out the elements by who is allowed to use them - in the mean time, this documentation will have to suffice.

Alternatively, some of the structure elements in the structures created on behalf of low-level drivers should be abstracted into something like a hostdata pointer which one of the structures already has.

Another factor is that some fields in the structures are used by obsolete parts of the SCSI subsystem, and could in principle be removed once those obsolete portions of the subsystem have been removed.

2.1 Host

The Scsi_Host structure is used to describe each instance of a host adapter on the system. In other words, if you have two Adaptec 1542 cards in your machine, there will be two instances of Scsi_Host, one for each.

The Scsi_Host structure is unique amongst all of the other structures in the sense that it is a structure name, not a typedefed data type. There is no good technical reason for this - I just never got around to it.

2.1.1 Structure definition

 

struct Scsi_Host
{
struct Scsi_Host * next;
Scsi_Device * host_queue;
Scsi_Cmnd * pending_commands;
struct task_struct * ehandler;
struct semaphore * eh_wait;
struct semaphore * eh_notify;
struct semaphore * eh_action;
unsigned int eh_active:1;
struct wait_queue * host_wait;
Scsi_Host_Template * hostt;
atomic_t host_active;
volatile unsigned short host_busy;
volatile unsigned short host_failed;
unsigned short extra_bytes;
unsigned short host_no;
unsigned long last_reset;
unsigned int max_id;
unsigned int max_lun;
unsigned int max_channel;
struct Scsi_Host * block;
unsigned wish_block:1;
unsigned char * base;
unsigned long io_port;
unsigned char n_io_port;
unsigned char dma_channel;
unsigned int irq;
unsigned int unique_id;
int this_id;
int can_queue;
short cmd_per_lun;
short unsigned int sg_tablesize;
unsigned in_recovery:1;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned loaded_as_module:1;
unsigned host_blocked:1;
void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
unsigned long hostdata[0];
};

2.1.2 Element descriptions

 

2.1.2.1 Scsi_Host::next

 

All instances of Scsi_Host on the system are arranged in a linked list - the next pointer is used to traverse the list.

2.1.2.2 Scsi_Host::host_queue

The host_queue field is a linked list of all of the Scsi_Device objects (i.e. physical devices) associated with this instance of Scsi_Host. This field probably should not be used by low-level drivers - this field can be useful in debug dump situations, however.

2.1.2.3 Scsi_Host::pending_commands

The pending_commands field is a linked list of Scsi_Cmnd objects which were rejected by the low-level driver (host or device busy). Commands generally won't remain in this list very long. This field should not be used by low-level drivers.

2.1.2.4 Scsi_Host::ehandler

The ehandler field is a pointer to the kernel thread acting as the error handler for this host. This field should only be used by the SCSI mid-layer, and will be NULL in the event that the associated low-level driver still uses the old error handling code.

2.1.2.5 Scsi_Host::eh_wait

The eh_wait field is used internally by the error handler thread, and is a semaphore that is used to indicate that there is work (i.e. some command has failed).

2.1.2.6 Scsi_Host::eh_notify

The eh_notify field is used internally by the error handler thread, and is a semaphore that is used at the time of thread startup or shutdown for proper synchronization.

2.1.2.7 Scsi_Host::eh_action

The eh_action field is used internally by the error handler thread, and is a semaphore that is used during error recovery. The typical use is so that the error handler thread can wait until an interrupt indicates that some requested action (command abort, for example) is completed.

2.1.2.8 Scsi_Host::eh_active

The eh_active field is a flag that indicates the error handler thread is running. Should not be used by low-level drivers.

2.1.2.9 Scsi_Host::host_wait

The host_wait field is used when we need to block access to a device or host for some reason. There are typically two reasons why we would want to do this - error recovery is in progress is one such reason. This is also used by the broken SCSI_BLOCK "feature". This field should never be used by low-level drivers.

2.1.2.10 Scsi_Host::hostt

The hostt field is a pointer to the instance of Scsi_Host_Template for this Scsi_Host. This field may be read by low-level drivers.

2.1.2.11 Scsi_Host::host_active

This is used by the broken SCSI_BLOCK feature to indicate the host in the block list that is currently active. This field should not be used by low-level drivers.

2.1.2.12 Scsi_Host::host_busy

This field indicates the number of Scsi_Cmnd structures that have been passed into the SCSI middle layer for processing. When a command gets passed back up to the upper layer, the count is decremented. This field should not be used by low-level drivers.

2.1.2.13 Scsi_Host::host_failed

This field is the number of busy commands which have failed. By failed we mean that they require the error handler thread to take some corrective action. This field should not be used by low-level drivers.

2.1.2.14 Scsi_Host::extra_bytes

This field indicates the number of bytes allocated in the hostdata field. This is used internally by the SCSI mid-layer only when allocating and deallocating Scsi_Host structures. The value is set from the second argument passed to scsi_register().

2.1.2.15 Scsi_Host::host_no

This is the host number for this host.

2.1.2.16 Scsi_Host::last_reset

This is the time of the last reset for this host. This field is only used by the old error handling code, and will go away eventually.

2.1.2.17 Scsi_Host::max_id

This is the maximum SCSI ID for devices attached to this bus. This will typically be either 8 or 16, where the default value is 8. This is mainly used when we scan the bus so that we can bound the search.

2.1.2.18 Scsi_Host::max_lun

This is the maximum SCSI LUN for devices attached to this bus. This will typically be 8, but hosts can adjust this as required. This is mainly used when we scan the bus so that we can bound the search.

2.1.2.19 Scsi_Host::max_channel

This is the maximum channel for devices attached to this bus. Hosts that only support one channel will leave this field set to the default value of 0. This is mainly used when we scan the bus so that we can bound the search.

2.1.2.20 Scsi_Host::block

 

This field is used by the broken SCSI_BLOCK feature - typically this will be a circularly linked of hosts that desire the "blocked" feature.

The element points to a circularly linked list of Scsi_Host objects.

2.1.2.21 Scsi_Host::wish_block

This field is set by low-level drivers that perform ISA DMA. By setting this field to TRUE, the host is requesting that it be added to the block linked list. Part of the broken SCSI_BLOCK feature.

2.1.2.22 Scsi_Host::base

This field is set by low-level drivers, and is the base address for memory mapped I/O. This field is here as a convenience to low-level drivers that require this - it isn't used by the middle or upper layers.

2.1.2.23 Scsi_Host::io_port

This field is set by low-level drivers, and is the base io_port used by this host. This field is here as a convenience to low-level drivers that require this - it isn't used by the middle or upper layers, with one exception. At the time of module unload, and if the driver hasn't specified a release entrypoint, the middle layer will attempt to call release_region() if the io_port field is non-zero.

2.1.2.24 Scsi_Host::n_io_port

This field is set by low-level drivers, and is the number of I/O ports used by this host. This field is here as a convenience to low-level drivers that require this - it isn't used by the middle or upper layers, with the one exception noted above.

2.1.2.25 Scsi_Host::dma_channel

This field is set by low-level drivers, and is the dma channel number used by this host. This field is here as a convenience to low-level drivers that require this - it isn't used by the middle or upper layers, with one exception. At the time of module unload, and if the driver hasn't specified a release entrypoint, the middle layer will attempt to call free_dma() if the dma_channel field is non-zero.

2.1.2.26 Scsi_Host::irq

This field is set by low-level drivers, and is the IRQ number used by this host. This field is here as a convenience to low-level drivers that require this - it isn't used by the middle or upper layers, with one exception. At the time of module unload, and if the driver hasn't specified a release entrypoint, the middle layer will attempt to call free_irq() if the irq field is non-zero.

2.1.2.27 Scsi_Host::unique_id

The theory is that low-level drivers were supposed to set this field to be a unique ID of some sort - this could be used as required by user level programs that need to somehow identify the host. An example might case where users want to generate SVr4 style device names. Unfortunately very few drivers ever bother to set this to anything meaningful, and the user community has instead adopted the host_no field as the identifier for this instance of the host.

2.1.2.28 Scsi_Host::this_id

This is the SCSI ID of the host adapter itself. This value is initialized from the host template, but low-level drivers are free to modify it as required. This field is only used during the bus scan so that we don't try and send commands out on the bus for the host adapter itself.

2.1.2.29 Scsi_Host::can_queue

This is the maximum number of commands that this host can have active on the bus at any given time. This is initialized from the host template, and can be modified as required by the low-level driver.

2.1.2.30 Scsi_Host::cmd_per_lun

This is the maximum number of outstanding commands per lun that are allowed at one time. This field is initialized from the host template, and can be modified as required by the low-level driver. Hosts that don't support tagged queueing will always set this to 1.

2.1.2.31 Scsi_Host::sg_tablesize

For hosts that support scatter-gather I/O (nearly all do), this is the maximum size of the scatter-gather table that the host can deal with. Hosts that don't support scatter-gather will typically set this to 0. This field is initialized from the host template, but can be modified as required by the low-level driver.

2.1.2.32 Scsi_Host::in_recovery

In the event that the host uses the new error recovery code, this flag will be set when there errors that require the error handler thread take action of some sort.

2.1.2.33 Scsi_Host::unchecked_isa_dma

This flag is set if the host uses ISA DMA. Typically this is used to decide whether bounce buffers should be allocated for the I/O request. This field is initialized from the host template, and can be modified as required by the low-level driver.

2.1.2.34 Scsi_Host::use_clustering

This flag indicates that we should attempt to cluster blocks in an I/O request into larger blocks. Typically this is a win in the event that the host has a limited scatter-gather table size. This is initialized from the host template, but can be modified as required by the low-level driver.

2.1.2.35 Scsi_Host::loaded_as_module

This flag is set if the host is present as result of being loaded as a module. The flag is clear if the low-level driver was compiled into the kernel.

2.1.2.36 Scsi_Host::host_blocked

This flag is set if the host adapter rejected a command (host busy, device busy). The basic purpose is to make sure we don't try and send other commands to the host until the rejected commands have completed. See the pending_commands field for more information.

2.1.2.37 Scsi_Host::select_queue_depths

This is a function pointer into the low-level driver which is used to adjust the data structures for the low-level driver as required to prepare for tagged queueing. FIXME - this needs to be moved to the host template.

2.1.2.38 Scsi_Host::hostdata

This field is used so that hosts can define host-specific data. The extra_bytes field says how large this is. Typically low-level drivers will cast this to some internal structure and use it as appropriate.

2.2 Host template

 

The Scsi_Host_Template can be viewed like the base class from which Scsi_Host is derived. Given that the kernel is compiled with a C compiler, it also exists as a simple structure, and the hostt field of Scsi_Host points to the appropriate template.

The Scsi_Host_Template structure differs in one other way from the Scsi_Host structure in that there will always be at most one instance of the host template for a given driver. In other words, using the previous example, if you had two Adaptec 1542 cards in your machine, there would be two instances of the Scsi_Host structure, but there would be only one instance of the Scsi_Host_Template structure.

2.2.1 Structure definition

 

typedef struct SHT
{
struct SHT * next;
struct module * module;
struct proc_dir_entry * proc_dir;
int (*proc_info)(char *, char **, off_t, int, int, int);
const char *name;
int (* detect)(struct SHT *);
int (*release)(struct Scsi_Host *);
const char *(* info)(struct Scsi_Host *);
int (*ioctl)(Scsi_Device *dev, int cmd, void *arg);
int (* command)(Scsi_Cmnd *);
int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int (*eh_strategy_handler)(struct Scsi_Host *);
int (*eh_abort_handler)(Scsi_Cmnd *);
int (*eh_device_reset_handler)(Scsi_Cmnd *);
int (*eh_bus_reset_handler)(Scsi_Cmnd *);
int (*eh_host_reset_handler)(Scsi_Cmnd *);
int (* abort)(Scsi_Cmnd *);
int (* reset)(Scsi_Cmnd *, unsigned int);
int (* slave_attach)(int, int);
int (* bios_param)(Disk *, kdev_t, int []);
int can_queue;
int this_id;
short unsigned int sg_tablesize;
short cmd_per_lun;
unsigned char present;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned use_new_eh_code:1;
unsigned emulated:1;
} Scsi_Host_Template;

2.2.2 Element descriptions

 

2.2.2.1 Scsi_Host_Template::next

This element is used for chaining the Scsi_Host_Template structures together into a linked list.

2.2.2.2 Scsi_Host_Template::module

This element is used when the associated low-level driver is loaded as a module - this will point to the variable "__this_module" in this case. Otherwise it is a NULL pointer. The main reason we need this is so that the __MOD_INC_USE_COUNT and __MOD_DEC_USE_COUNT macros can be used to help prevent the module being unloaded while file descriptors are open for a SCSI device.

2.2.2.3 Scsi_Host_Template::proc_dir

This entry is used to describe the directory entry underneath /proc/scsi that will be used for this host adapter. By holding a pointer to the structure here, it is possible for the SCSI core to sweep through all of the loaded drivers and build the actual /proc/scsi directory.

2.2.2.4 Scsi_Host_Template::proc_info

This entry is an entrypoint into the low-level driver which is used to generate the file contents for files underneath /proc/scsi/driver/hostno, where driver is the driver name (established through the proc_dir entry above), and hostno is the host number. Drivers are not required to supply anything here, however if the default NULL pvalue is used, there isn't any useful information available from the host entry in /proc/scsi.

2.2.2.5 Scsi_Host_Template::name

This is the name of the driver. This is for informational purposes only and is displayed at boot time. The name can also be obtained by querying a device with the IOCTL_PROBE_HOST ioctl. Also note that if the info field is non-NULL, that the display name will instead be generated using that function.

In retrospect, it is silly to have two fields that provide the same information. The info method is more general, and thus at some point in the future this interface should go away.

2.2.2.6 Scsi_Host_Template::detect

This is the entrypoint that is called either at boot time or at the time of module load to probe for the presence of a board which the driver itself can drive.

2.2.2.7 Scsi_Host_Template::release

This is the entrypoint which is called at the time of module unload. The purpose is to allow the driver to release whatever resources it may have allocated.

It is possible, but not recommended to omit this entrypoint - the Scsi_Host structure contains information about any DMA channels, IO ports or IRQs are used by the host in question, and if the release entrypoint is not specified, any resources specified in Scsi_Host will be released.

It is possible that at some point in the future, it will be mandatory for drivers to supply this entrypoint for them to be used in a modular fashion.

2.2.2.8 Scsi_Host_Template::info

This field is an entrypoint into the driver which represents an alternate method of determining the name of the scsi driver. The name field above also provides this capability. In the event that both are specified, the info method takes precedence.

2.2.2.9 Scsi_Host_Template::ioctl

This entrypoint is used for direct ioctl calls in the event that the ioctl code does not apply to the device.

2.2.2.10 Scsi_Host_Template::command

This entrypoint is used for sending commands to the low-level driver. This flavor of the interface is depreciated, and should rarely be used. The only case where this is the appropriate interface to use would be in the case of a driver for a card that has no interrupt capability, and where the driver must instead poll the card at regular intervals. There is only one such driver that I know of - a peculiar parallel port scsi adapter. If it weren't for this one oddball case, this entrypoint would probably be removed entirely. In all other cases, drivers should instead use the queuecommand interface instead.

2.2.2.11 Scsi_Host_Template::queuecommand

This is the normal entrypoint by which a low-level driver receives a command that should be queued to the specified device. The command is not guaranteed to be complete when the function returns - in fact, it would tend to be a rarity for the command to be complete when this interface returns.

2.2.2.12 Scsi_Host_Template::eh_strategy_handler

This is the entrypoint that is used by the error handler thread to actually perform error recovery. If this is NULL, a default function is used instead - the default should be sufficient for most situations, but the capability is present for drivers to override it if they wish. This entrypoint only needs to be specified in the event that the new error handling is in use.

2.2.2.13 Scsi_Host_Template::eh_abort_handler

This is the entrypoint that is called by the default error handler function during error recovery. This entry point should attempt to abort the command, if possible. This entrypoint only has meaning if the new error handling is in use.

2.2.2.14 Scsi_Host_Template::eh_device_reset_handler

This is the entrypoint that is called by the default error handler function during error recovery. This entry point should attempt to perform a device reset, if possible. This entrypoint only has meaning if the new error handling is in use.

2.2.2.15 Scsi_Host_Template::eh_bus_reset_handler

This is the entrypoint that is called by the default error handler function during error recovery. This entry point should attempt to perform a bus reset, if possible. This entrypoint only has meaning if the new error handling is in use.

2.2.2.16 Scsi_Host_Template::eh_host_reset_handler

This is the entrypoint that is called by the default error handler function during error recovery. This entry point should attempt to reset the host adapter, if possible. This entrypoint only has meaning if the new error handling is in use.

2.2.2.17 Scsi_Host_Template::abort

This is the entrypoint that is used by the old error recovery code in order to attempt a SCSI abort. The old error recovery code is obsolete and will be removed from the kernel once no drivers use it, and once this happens, this field will be removed from the structure.

2.2.2.18 Scsi_Host_Template::reset

This is the entrypoint that is used by the old error recovery code in order to attempt a SCSI reset. The old error recovery code is obsolete and will be removed from the kernel once no drivers use it, and once this happens, this field will be removed from the structure.

2.2.2.19 Scsi_Host_Template::slave_attach

This entrypoint is not used, and the field may be removed at some point in the future.

2.2.2.20 Scsi_Host_Template::bios_param

This entrypoint can be used to obtain the C/H/S for a disk drive. Typically this information is of interest to bootloaders (such as lilo), and perhaps also by programs which would wish to modify the partition table. The C/H/S information that is returned by this function *MUST* return identical information to what the BIOS on the board would return - this is the only way that a bootloader will be able to load the correct files.

2.2.2.21 Scsi_Host_Template::can_queue

This field specifies the maximum number of active SCSI commands which the driver is capable of handling at the same time. This represents a default value which can be overridden in the Scsi_Host structure.

2.2.2.22 Scsi_Host_Template::this_id

This field specifies the SCSI ID of the host adapter itself. This represents a default value which can be overridden in the Scsi_Host structure.

2.2.2.23 Scsi_Host_Template::sg_tablesize

This field specifies the maximum size of a scatter-gather list. Some host adapters have hardware limits to the size of the table - in this case the limit must be specified here.

In the event that there is no upper bound in the driver for the size of the scatter-gather table, then a value of SG_ALL can be specified.

Host adapters that don't support scatter-gather must specify 0. Please note that I/O performance for drivers that do not support scatter-gather is absolutely horrible.

2.2.2.24 Scsi_Host_Template::cmd_per_lun

This field specifies the maximum number of outstanding commands that can be specified per logical unit. Before the days of tagged queueing it didn't make a whole lot of sense to set this above 1. For host adapters that specify a select_queue_depths() function, the value specified here might not be used at all.

The place where this setting comes into play is where the Scsi_Cmnd structures are allocated. The cmd_per_lum field is used to ensure that a sufficient number of structures are allocated so that it is possible to queue this many commands.

2.2.2.25 Scsi_Host_Template::present

This field indicates how many of this type of card were found to be present on the machine.

2.2.2.26 Scsi_Host_Template::unchecked_isa_dma

Boolean value set to TRUE in the event that the card uses DMA over the ISA bus to perform I/O. When true, there are cases where we need to allocate bounce buffers prior to scheduling an I/O request.

2.2.2.27 Scsi_Host_Template::use_clustering

Boolean value set to TRUE in the event that it is a win to try and merge requests for adjacent blocks of memory into larger requests. This is usually a big win for host adapters with a limited maximum scatter-gather table size.

2.2.2.28 Scsi_Host_Template::use_new_eh_code

Boolean value set to TRUE if this host adapter is prepared to use the new error handling code.

2.2.2.29 Scsi_Host_Template::emulated

Boolean value set to TRUE for emulated SCSI host adapters. ATAPI is the only driver which should set this field.

2.3 Device

The Scsi_Device structure is used to describe a single SCSI device. There will be a single instance of the structure allocated for each physical device that is detected.

Any device (such as a CD changer) that responds to multiple LUNs will be treated a separate instances of independent devices.

These structures are allocated at the time the bus is scanned.

2.3.1 Structure definition

 

typedef struct scsi_device
{
struct scsi_device * next;
struct scsi_device * prev;
struct wait_queue * device_wait;
struct Scsi_Host * host;
volatile unsigned short device_busy;
void (* scsi_request_fn)(void);
Scsi_Cmnd * device_queue;
unsigned char id, lun, channel;
unsigned int manufacturer;
int attached;
int access_count;
void *hostdata;
char type;
char scsi_level;
char vendor[8], model[16], rev[4];
unsigned char current_tag;
unsigned char sync_min_period;
unsigned char sync_max_offset;
unsigned char queue_depth;
unsigned online:1;
unsigned writeable:1;
unsigned removable:1;
unsigned random:1;
unsigned has_cmdblocks:1;
unsigned changed:1;
unsigned busy:1;
unsigned lockable:1;
unsigned borken:1;
unsigned tagged_supported:1;
unsigned tagged_queue:1;
unsigned disconnect:1;
unsigned soft_reset:1;
unsigned sync:1;
unsigned wide:1;
unsigned single_lun:1;
unsigned was_reset:1;
unsigned expecting_cc_ua:1;
unsigned device_blocked:1;
} Scsi_Device;

2.3.2 Element descriptions

2.3.2.1 Scsi_Device::next

Pointer used to maintain forward links in the doubly linked list of all devices attached to a given host adapter.

2.3.2.2 Scsi_Device::prev

Pointer used to maintain reverse links in the doubly linked list of all devices attached to a given host adapter.

2.3.2.3 Scsi_Device::device_wait

This field is used in the event that we need to wait for a free Scsi_Cmnd structure for this device. This should be changed to a semaphore.

2.3.2.4 Scsi_Device::host

Pointer to the instance of Scsi_Host to which this device is attached.

2.3.2.5 Scsi_Device::device_busy

Usage counter representing the number of commands that have been received by the middle layer and for which the upper layer is waiting for a response.

2.3.2.6 Scsi_Device::scsi_request_fn

This entrypoint is a hack, pure and simple. The basic problem is that an ioctl may have blocked normal disk I/O, and once the ioctl is done, we need to jumpstart the normal disk queue to ensure that the request is queued immediately. This will undoubtably go away in the Linux 2.3 timeframe.

2.3.2.7 Scsi_Device::device_queue

This field points to the head of a linked list of Scsi_Cmnd objects that can be used for this device. All command structures (either in-use or idle) are always in the list.

2.3.2.8 Scsi_Device::id

The SCSI ID for this device.

2.3.2.9 Scsi_Device::lun

The SCSI logical unit number for this device.

2.3.2.10 Scsi_Device::channel

The SCSI channel number for this device. This will always be 0 for devices attached to host adapters that only have a single channel.

2.3.2.11 Scsi_Device::manufacturer

This field is unused.

2.3.2.12 Scsi_Device::attached

The number of upper level drivers that have attached to this device. Normally at most 2 (generics, plus one other).

2.3.2.13 Scsi_Device::access_count

Number of open file descriptors for this device. This is mainly used so that we know when to lock and unlock the door for removable media.

2.3.2.14 Scsi_Device::hostdata

This is a void * that can be used by the low-level driver to store additional state related to the device. I cannot tell at the moment whether any low-level drivers actually use this field or not.

2.3.2.15 Scsi_Device::type

The type of the device (i.e. TYPE_DISK, TYPE_SCANNER, etc). See table 7-17 in the SCSI standards for the values that this can take.

2.3.2.16 Scsi_Device::scsi_level

Set based upon INQUIRY data to be SCSI_1, SCSI_1_CCS, SCSI_2, or SCSI_UNKNOWN.

2.3.2.17 Scsi_Device::vendor

The manufacturer ID, as returned from the INQUIRY command.

2.3.2.18 Scsi_Device::model

The model number, as returned from the INQUIRY command.

2.3.2.19 Scsi_Device::rev

The firmware revision level, as returned from the INQUIRY command.

2.3.2.20 Scsi_Device::current_tag

Not 100% sure on this one. I believe the purpose of this is to track how many tagged commands have been issued without a ORDERED_QUEUE_TAG (basically to flush the queue of any pending commands).

2.3.2.21 Scsi_Device::sync_min_period

Not 100% sure on this one. I believe that this is used to keep track of synchronous I/O characteristics of this device.

2.3.2.22 Scsi_Device::sync_max_offset

Not 100% sure on this one. I believe that this is used to keep track of synchronous I/O characteristics of this device.

2.3.2.23 Scsi_Device::queue_depth

The maximum tagged queue depth for this device. The default value is the maximum number of commands per lun for the host itself, and can be overridden by the select_queue_depths() function associated with the host.

2.3.2.24 Scsi_Device::online

Boolean value indicating the device is online. Devices can be taken offline during error recovery in the event that the device is completely toasted.

2.3.2.25 Scsi_Device::writeable

Boolean value that indicates whether the device is writable. Initialized from the INQUIRY data.

2.3.2.26 Scsi_Device::removable

Boolean value that indicates whether the device is removable. Initialized from the INQUIRY data.

2.3.2.27 Scsi_Device::random

Boolean value that indicates whether the device is random-access. Initialized from the INQUIRY data.

2.3.2.28 Scsi_Device::has_cmdblocks

Boolean flag that indicates whether we have allocated Scsi_Cmnd structures for this device.

2.3.2.29 Scsi_Device::changed

Boolean flag that indicates that a media change has taken place. This may cause buffers to be flushed, to remove bogus cached data.

2.3.2.30 Scsi_Device::busy

Boolean value to indicate that the device is busy with something or another (usually rereading partition table). This really needs to be changed to a spinlock instead.

2.3.2.31 Scsi_Device::lockable

Boolean that indicates that it is possible to lock the door of a device that has removable media.

2.3.2.32 Scsi_Device::borken

Boolean flag that indicates we shouldn't attempt synchronous transfers.

2.3.2.33 Scsi_Device::tagged_supported

Boolean that indicates that tagged queuing is supported for this device.

2.3.2.34 Scsi_Device::tagged_queue

Boolean that indicates that tagged queuing is enabled for this device. Can be turned on and off with ioctls.

2.3.2.35 Scsi_Device::disconnect

This device is capable of disconnect. Any device that doesn't answer this one yes should be treated carefully.

2.3.2.36 Scsi_Device::soft_reset

Boolean value which indicates that this device uses the soft reset option.

2.3.2.37 Scsi_Device::sync

Cannot tell for sure. This might be used to indicate that we can do sync transfers, or that we have already checked to see if the device supports sync transfers. Only a small handful of drivers use this.

2.3.2.38 Scsi_Device::wide

Cannot tell for sure. This might be used to indicate that we can do wide transfers, or that we have already checked to see if the device supports wide transfers. Only a small handful of drivers use this.

2.3.2.39 Scsi_Device::single_lun

Another hack. If this boolean value is set, we only allow a single outstanding command to this SCSI Id, and block commands to other luns until the one that is outstanding is complete. Mainly of use for things like changers, where you would thrash the thing by trying to access devices on different luns at the same time.

2.3.2.40 Scsi_Device::was_reset

Indicates that the device was reset. For removable devices, it means we need to relock the door, as it will no longer be locked.

2.3.2.41 Scsi_Device::expecting_cc_ua

Indicates that we are expecting a CHECK_CONDITION/UNIT_ATTENTION as result of a reset.

2.3.2.42 Scsi_Device::device_blocked

Boolean flag that is part of the SCSI_BLOCK hack. As far as I can tell, this is never set to TRUE, and as a result it can be removed.

2.4 Device template

The Scsi_Device_Template is used to describe a single type of SCSI device. In the current implementation there will be an absolute maximum of 4 instances of this structure on any given system. One for disk, one for CDROM, one for tapes, and one for the generics pass-through. If other driver types are added (e.g. scanner), a new device template would be created.

There is no direct mapping between a Scsi_Device_Template and a Scsi_Device. The reason for this is that a single physical device can be attached to more than one device template (usually the generics pass-through, plus one more).

Many of the elements of this structure are required abstractions to make modules possible. The fundamental issue is that adding or removing a low-level driver will add/remove new devices to the kernel which in turn must be driven by the upper level drivers. We needed an abstraction of the upper level drivers to make it possible for module load/unload of low-level drivers to do the proper attach/detach.

2.4.1 Structure definition

struct Scsi_Device_Template
{
struct Scsi_Device_Template * next;
const char * name;
const char * tag;
struct module * module;
unsigned char scsi_type;
unsigned char major;
unsigned char nr_dev;
unsigned char dev_noticed;
unsigned char dev_max;
unsigned blk:1;
int (*detect)(Scsi_Device *);
int (*init)(void);
void (*finish)(void);
int (*attach)(Scsi_Device *);
void (*detach)(Scsi_Device *);
};

2.4.2 Element descriptions

 

2.4.2.1 Scsi_Device_Template::next

Used for linking together all Scsi_Device_Template instances into a linked list.

2.4.2.2 Scsi_Device_Template::name

ASCII Description of the type of device. For example, "disk", "tape".

2.4.2.3 Scsi_Device_Template::tag

Canonical ASCII name of the device. For example, "sd", or "st".

2.4.2.4 Scsi_Device_Template::module

This element is used when the associated upper-level driver is loaded as a module - this will point to the variable "__this_module" in this case. Otherwise it is a NULL pointer. The main reason we need this is so that the __MOD_INC_USE_COUNT and __MOD_DEC_USE_COUNT macros can be used to help prevent the module being unloaded while file descriptors are open for a SCSI device.

2.4.2.5 Scsi_Device_Template::scsi_type

The SCSI type for devices that this driver will handle. For example, TYPE_DISK, TYPE_TAPE. Note - as far as I can tell this isn't used for anything. It would probably be wise to remove this field at some later date.

2.4.2.6 Scsi_Device_Template::major

The major number which this driver will be responsible for.

2.4.2.7 Scsi_Device_Template::nr_dev

The number of physical devices that are attached to the driver.

2.4.2.8 Scsi_Device_Template::dev_noticed

During the bus scan phase, all detected devices are passed to the detect interface, which decides whether the driver is capable of handling the device in question. The dev_noticed field is a counter that tracks the total number of devices which the driver is in fact capable of driving. This does not physically attach the device to the driver - it merely bumps the counter.

2.4.2.9 Scsi_Device_Template::dev_max

This field indicates the absolute maximum number of devices that this driver is capable of driving. As a practical matter, this indicates the allocation size of some of the internal data structures.

2.4.2.10 Scsi_Device_Template::blk

Boolean flag which indicates whether this driver is for a block device or for a character device.

2.4.2.11 Scsi_Device_Template::detect

This interface is used at the time of bus scan. A Scsi_Device structure is passed in, and this function should decide whether the driver is capable of driving the device or not. Generally, this consists of checking the device type. If the driver is capable of driving the device, then the dev_noticed counter should be incremented, and the function should return 1. Otherwise the function should return 0.

This function will only be called at either boot time, or when SCSI modules are being loaded.

2.4.2.12 Scsi_Device_Template::init

This function is called once the bus scan is complete, and we have knowledge of the total number of devices that the driver will need to drive in the dev_noticed field. Typically this function will allocate the internal structures, and register the block or character device major number, if required. Note that if none of the physical devices can be drived by the driver, this interface can simply return 0 and not do anything else. Otherwise it should return 1.

Most of the internal data structures are tables that are indexed into by the minor number to obtain the size of the device, blocksize, a pointer to the Scsi_Device structure, and other device specific bits of information.

This function will only be called at either boot time, or when SCSI modules are being loaded.

2.4.2.13 Scsi_Device_Template::finish

This interface is called once all of the devices are fully attached. This has the job of initializing the internal data structures that were allocated by the init entrypoint. It also has the job of checking media capacity, spinning up disks, preparing datastructures related to partition tables, etc.

2.4.2.14 Scsi_Device_Template::attach

After the bus scan, and after the init entry point is called, a second scan over all devices is made. The general purpose is to insert a pointer to the Scsi_Device structure into the internal data structures used by the upper level driver.

2.4.2.15 Scsi_Device_Template::detach

This interface is used in the event that a low-level driver module is being unloaded, and we need to disconnect the physical devices from the upper level drivers.

2.5 Command

 

The Scsi_Cmnd structure is probably the most commonly used structure throughout the SCSI subsystem. The structure is used to represent a single command which in some stage of being queued or processed by some driver or perhaps even the physical device. All of the context associated with the actual running command is stored in this structure such that when the command actually finishes, all we need is the pointer to this structure to initiate post-processing. The closest analogy is sort of like a thread, I guess, but the analogy doesn't really work all that well.

There are a number of fields in the structure that are present purely as a convenience for low-level drivers. This should be recoded at some point, and use an abstract hostdata element at the end to contain the host-specific data.

These structures are all allocated at the time of bus scan (or shortly thereafter). For each device, we look at the queue depth for the device (or the maximum number of commands per lun) and allocate up to this number.

At runtime allocation and deallocation of these structures doesn't involve any communication with the memory manager. We simply look through the list and find a command block that is not in use and return it. When we free a block, we merely set the flag saying the command block is not in use.

2.5.1 Structure definition

typedef struct scsi_cmnd
{
struct Scsi_Host * host;
unsigned short state;
unsigned short owner;
Scsi_Device * device;
struct scsi_cmnd * next;
struct scsi_cmnd * reset_chain;
int eh_state;
void (*done)(struct scsi_cmnd *);
unsigned long serial_number;
unsigned long serial_number_at_timeout;
int retries;
int allowed;
int timeout_per_command;
int timeout_total;
int timeout;
unsigned volatile char internal_timeout;
struct scsi_cmnd * bh_next;
unsigned char target;
unsigned char lun;
unsigned char channel;
unsigned char cmd_len;
unsigned char old_cmd_len;
unsigned char cmnd[12];
unsigned request_bufflen;
struct timer_list eh_timeout;
void * request_buffer;
unsigned char data_cmnd[12];
unsigned short old_use_sg;
unsigned short use_sg;
unsigned short sglist_len;
unsigned short abort_reason;
unsigned bufflen;
void * buffer;
unsigned underflow;
unsigned transfersize;
struct request request;
unsigned char sense_buffer[16];
unsigned flags;
unsigned host_wait:1;
unsigned device_wait:1;
int this_count;
void (*scsi_done)(struct scsi_cmnd *);
Scsi_Pointer SCp;
unsigned char * host_scribble;
int result;
unsigned char tag;
unsigned long pid;
} Scsi_Cmnd;

2.5.2 Element descriptions

2.5.2.1 Scsi_Cmnd::host

Pointer to the Scsi_Host associated with the device.

2.5.2.2 Scsi_Cmnd::state

Indicates the current status of this command block. It can take one of these values:
SCSI_STATE_TIMEOUT
SCSI_STATE_FINISHED
SCSI_STATE_FAILED
SCSI_STATE_QUEUED
SCSI_STATE_UNUSED
SCSI_STATE_DISCONNECTING
SCSI_STATE_INITIALIZING
SCSI_STATE_BHQUEUE
SCSI_STATE_MLQUEUE

2.5.2.3 Scsi_Cmnd::owner

Indicates what part of the SCSI subsystem currently owns the command block. It can take one of the following values:
SCSI_OWNER_HIGHLEVEL
SCSI_OWNER_MIDLEVEL
SCSI_OWNER_LOWLEVEL
SCSI_OWNER_ERROR_HANDLER
SCSI_OWNER_BH_HANDLER
SCSI_OWNER_NOBODY

2.5.2.4 Scsi_Cmnd::device

Pointer to the Scsi_Device object associated with this command block.

2.5.2.5 Scsi_Cmnd::next

Used to link together Scsi_Cmnd structures together into a linked list.

2.5.2.6 Scsi_Cmnd::reset_chain

This field is used only by the BusLogic driver. Ask Leonard what it is used for. This should be abstracted into a hostdata field.

2.5.2.7 Scsi_Cmnd::eh_state

This field is used by the error handler to record the internal state. It can currently take one of three values:
SUCCESS
FAILED
SCSI_STATE_TIMEOUT
SCSI_STATE_QUEUED

This field should not be used by low-level drivers, although I notice that some low-level drivers are attempting to use this. If a low-level driver needs to know why a command has failed, the state field should probably be used instead. It depends a bit upon what information the driver really needs.

2.5.2.8 Scsi_Cmnd::done

The done field is a pointer to the upper-level completion function for the command. Low-level drivers should not attempt to use this field.

2.5.2.9 Scsi_Cmnd::serial_number

A sequence number for the command. Each new command that comes through will have a unique sequence number. Note - the pid field serves an identical function, and one of the two (probably the pid) should be eliminated and merged with the serial number.

2.5.2.10 Scsi_Cmnd::serial_number_at_timeout

When a command times out, the serial number is saved in this field. This can be of use if the command might have later completed before error recovery had started, however in the new error handling code this should not be a problem.

2.5.2.11 Scsi_Cmnd::retries

The number of times we have retried the command. Only used during error recovery.

2.5.2.12 Scsi_Cmnd::allowed

The maximum number of retries allowed during error recovery.

2.5.2.13 Scsi_Cmnd::timeout_per_command

The amount of time (in jiffies) that we will wait before we decide that a command has timed out.

2.5.2.14 Scsi_Cmnd::timeout_total

This field is unused and should be removed from the structure.

2.5.2.15 Scsi_Cmnd::timeout

This field is unused and should be removed from the structure.

2.5.2.16 Scsi_Cmnd::internal_timeout

This field is used by the old error handling code to keep track of the current state of the command. Once the old error handling code is gone, this field can be removed.

2.5.2.17 Scsi_Cmnd::bh_next

This field is used for the linked list of commands that are in the queue for the bottom half handler.

2.5.2.18 Scsi_Cmnd::target

The SCSI ID of the device. This is somewhat redundant, in that we can also get the same information from device->id.

2.5.2.19 Scsi_Cmnd::lun

The SCSI logical unit number of the device. This is somewhat redundant, in that we can also get the same information from device->lun.

2.5.2.20 Scsi_Cmnd::channel

The channel number for the device. This is somewhat redundant, in that we can also get the same information from device->channel.

2.5.2.21 Scsi_Cmnd::cmd_len

The length (number of bytes) of the SCSI command. Typically either 6, 10, or 12.

2.5.2.22 Scsi_Cmnd::old_cmd_len

Saved copy of the command length. Used during error recovery, as we sometimes need to issue other commands (REQUEST_SENSE, or TEST_UNIT_READY) before we finally retry the command itself.

2.5.2.23 Scsi_Cmnd::cmnd

The SCSI command that needs to be sent to the device. This is normally initialized by the upper layer, however error recovery sometimes modifies the field. As far as low-level drivers are concerned, this is the command that the driver needs to try and run.

2.5.2.24 Scsi_Cmnd::request_bufflen

This is the saved buffer length associated with the request. This is a copy of the bufflen field, and is needed because we may need to restore the original settings during error recovery.

2.5.2.25 Scsi_Cmnd::eh_timeout

Timer structure used by error recovery. Should not be manipulated by low-level drivers.

2.5.2.26 Scsi_Cmnd::request_buffer

This is the saved buffer pointer associated with the request. This will either point to the actual buffer, or in the event that scatter-gather is in use it will point to the the scatter-gather table. This is a copy of the buffer field, and is needed because we may need to restore the original settings during error recovery.

2.5.2.27 Scsi_Cmnd::data_cmnd

This is a saved copy of the cmnd array, and is needed because we may need to restore the original settings during error recovery.

2.5.2.28 Scsi_Cmnd::old_use_sg

This is a saved copy of use_sg, and is needed because we may need to restore the original settings during error recovery.

2.5.2.29 Scsi_Cmnd::use_sg

This field indicates whether the command should use scatter-gather or not. If 0, it means that the buffer field indicates the actual I/O buffer, if non-zero, the buffer field indicates the address of the scatter-gather table, and the use_sg field will indicate the number of entries in the scatter-gather table.

2.5.2.30 Scsi_Cmnd::sglist_len

Amount of memory allocated for the scatter-gather list. Needed so that we know how much memory to free, when it comes time to release it.

2.5.2.31 Scsi_Cmnd::abort_reason

Used by the old error handling code - indicates the reason that we are tring to abort a command. Either DID_TIME_OUT, or DID_RESET.

2.5.2.32 Scsi_Cmnd::bufflen

Indicates the number of data bytes to be transferred by the I/O request.

2.5.2.33 Scsi_Cmnd::buffer

Indicates the buffer to be used for the data transfer. In the event that scatter-gather is in use, this field indicates the address of the scatter-gather table.

2.5.2.34 Scsi_Cmnd::underflow

Indicates the minimum number of bytes for data transfer - useful for underflow detection. Very few drivers actually use this. It is considered an error if fewer bytes than this are transferred. Set by the upper-level.

2.5.2.35 Scsi_Cmnd::transfersize

Amount of data that we are guaranteed to transfer with each SCSI transfer (between disconnect/reconnects). Usually the sector size. Generally only really dumb drivers need to worry about this.

2.5.2.36 Scsi_Cmnd::request

A copy of the request structure that this command is processing. This is useful during final post-processing when we need to mark buffers uptodate.

2.5.2.37 Scsi_Cmnd::sense_buffer

In the event of errors, this buffer contains the sense data.

2.5.2.38 Scsi_Cmnd::flags

This is only used by the old error handling code, and indicates additional information about the command. Allowable values are:
WAS_RESET
WAS_TIMEDOUT
WAS_SENSE
IS_RESETTING
IS_ABORTING
ASKED_FOR_SENSE

2.5.2.39 Scsi_Cmnd::host_wait

For commands in the Scsi_Host pending command queue, this bit indicates if the command is in the queue because the host or driver did not have sufficient resources to queue the command right away.

2.5.2.40 Scsi_Cmnd::device_wait

For commands in the Scsi_Host pending command queue, this bit indicates if the command is in the queue because the device did not have sufficient resources to queue the command right away. Usually because of a QUEUE_FULL message.

2.5.2.41 Scsi_Cmnd::this_count

In theory this field should be the number of sectors being transferred. In practice it isn't used, and thus this field should be removed to simplify the code. It was supposed to be the number of 512 byte sectors. For larger sector sizes, it is just a multiplier.

For devices with smaller sector sizes (256 bytes), it currently appears as if it will be impossible to request odd numbers of sectors.

2.5.2.42 Scsi_Cmnd::scsi_done

This field holds the completion routine in the SCSI middle layer. In all cases, the function scsi_done() in the middle layer is this function, and thus it seems a little silly to obscure things in this way. This field shouldn't be removed until the rewrite of the upper layer is complete for Linux 2.3.

2.5.2.43 Scsi_Cmnd::SCp

This field is a pointer to a Scsi_Pointer structure - this is used as a scratchpad for hosts that need to walk the scatter-gather list themselves.

2.5.2.44 Scsi_Cmnd::host_scribble

This field is used as a pointer to a scratchpad area that low-level drivers can use as they wish.

2.5.2.45 Scsi_Cmnd::result

Low-level drivers will fill in this field with the status of the command prior to calling the mid-level completion routine. The status consists of the status_byte, the msg_byte, the host_byte, and the driver_byte.
The status byte is the status that is returned from the device itself.
The host_byte is the status that is returned from the host adapter.
The driver_byte is the status returned by the low-level driver.
The msg_byte is simply the message byte that comes back.

2.5.2.46 Scsi_Cmnd::tag

Not 100% sure on this one. I believe the purpose of this is to track how many tagged commands have been issued without a ORDERED_QUEUE_TAG (basically to flush the queue of any pending commands).

2.5.2.47 Scsi_Cmnd::pid

A sort of sequence number for the command. Each new command that comes through will have a unique pid. Note - the serial_number field serves an identical function, and one of the two (probably the pid) should be eliminated and merged with the serial number.

2.6 Pointer

2.6.1 Structure definition

 

typedef struct scsi_pointer
{
char * ptr;
int this_residual;
struct scatterlist *buffer;
int buffers_residual;
volatile int Status;
volatile int Message;
volatile int have_data_in;
volatile int sent_command;
volatile int phase;
} Scsi_Pointer;

2.6.2 Element descriptions

2.6.2.1 Scsi_Pointer::ptr

2.6.2.2 Scsi_Pointer::this_residual

2.6.2.3 Scsi_Pointer::buffer

2.6.2.4 Scsi_Pointer::buffers_residual

2.6.2.5 Scsi_Pointer::Status

2.6.2.6 Scsi_Pointer::Message

2.6.2.7 Scsi_Pointer::have_data_in

2.6.2.8 Scsi_Pointer::sent_command

2.6.2.9 Scsi_Pointer::phase

If you have comments or suggestions, you can email me by clicking here

Last updated: 4/99.