📄 writingscsi driver.htm
字号:
synchronous communications between the host adapter and the
target drive. This negotiation requires an exchange of a pair
of SYNCHRONOUS DATA TRANSFER REQUEST messages between the
initiator and the target. This exchange should occur under the
following conditions [LXT91]:
</p><blockquote>
A SCSI device that supports synchronous data transfer recognizes it has
not communicated with the other SCSI device since receiving the last
``hard'' RESET.
<p>A SCSI device that supports synchronous data transfer recognizes it has
not communicated with the other SCSI device since receiving a BUS
DEVICE RESET message.
</p></blockquote>
<h5><tt>bios_param()</tt></h5>
<p>Linux supports the MS-DOS (MS-DOS is a registered trademark
of Microsoft Corporation) hard disk partitioning system. Each
disk contains a ``partition table'' which defines how the disk
is divided into logical sections. Interpretation of this
partition table requires information about the size of the disk
in terms of cylinders, heads, and sectors per cylinder. SCSI
disks, however, hide their physical geometry and are accessed
logically as a contiguous list of sectors. Therefore, in order
to be compatible with MS-DOS, the SCSI host adapter will
``lie'' about its geometry. The physical geometry of the SCSI
disk, while available, is seldom used as the ``logical
geometry.'' (The reasons for this involve archaic and arbitrary
limitations imposed by MS-DOS.)
</p><p>Linux needs to determine the ``logical geometry'' so that it
can correctly modify and interpret the partition table.
Unfortunately, there is no standard method for converting
between physical and logical geometry. Hence, the
<tt>bios_param()</tt> function was introduced in an attempt to
provide access to the host adapter geometry information.
</p><p>The <tt>size</tt> parameter is the size of the disk in
sectors. Some host adapters use a deterministic formula based
on this number to calculate the logical geometry of the drive.
Other host adapters store geometry information in tables which
the driver can access. To facilitate this access, the
<tt>dev</tt> parameter contains the drive's device number. Two
macros are defined in <tt>linux/fs.h</tt> which will help to
interpret this value: <tt>MAJOR(dev)</tt> is the device's major
number, and <tt>MINOR(dev)</tt> is the device's minor number.
These are the same major and minor device numbers used by the
standard Linux <b>mknod</b> command to create the device in the
/dev directory. The <tt>info</tt> parameter points to an array
of three integers that the <tt>bios_param()</tt> function will
fill in before returning:
</p><dl>
<dt><tt>info[0]</tt>
</dt><dd>Number of heads
</dd><dt><tt>info[1]</tt>
</dt><dd>Number of sectors per cylinder
</dd><dt><tt>info[2]</tt>
</dt><dd>Number of cylinders
</dd></dl>
<p>The information in <tt>info</tt> is <i>not</i> the physical
geometry of the drive, but only a <i>logical</i> geometry that
is identical to the <i>logical</i> geometry used by MS-DOS to
access the drive. The distinction between physical and logical
geometry cannot be overstressed.
</p><h4>The <tt>Scsi_Cmnd</tt> Structure</h4>
<a name="sec:scsi.cmnd"></a>
<p>The <tt>Scsi_Cmnd</tt> structure, (Linux 0.99.7 kernel,
linux/kernel/blk_drv/scsi/scsi.h) as shown below, is used by
the high-level code to specify a SCSI command for execution by
the low-level code. Many variables in the <tt>Scsi_Cmnd</tt>
structure can be ignored by the low-level device driver--other
variables, however, are extremely important.
</p><pre> typedef struct scsi_cmnd
{
int host;
unsigned char target,
lun,
index;
struct scsi_cmnd *next,
*prev;
unsigned char cmnd[10];
unsigned request_bufflen;
void *request_buffer;
unsigned char data_cmnd[10];
unsigned short use_sg;
unsigned short sglist_len;
unsigned bufflen;
void *buffer;
struct request request;
unsigned char sense_buffer[16];
int retries;
int allowed;
int timeout_per_command,
timeout_total,
timeout;
unsigned char internal_timeout;
unsigned flags;
void (*scsi_done)(struct scsi_cmnd *);
void (*done)(struct scsi_cmnd *);
Scsi_Pointer SCp;
unsigned char *host_scribble;
int result;
} Scsi_Cmnd;
</pre>
<h4>Reserved Areas</h4>
<h5>Informative Variables</h5>
<p><tt>host</tt> is an index into the <tt>scsi_hosts</tt>
array.
</p><p><tt>target</tt> stores the SCSI ID of the target of the SCSI
command. This information is important if multiple outstanding
commands or multiple commands per target are supported.
</p><p><tt>cmnd</tt> is an array of bytes which hold the actual
SCSI command. These bytes should be sent to the SCSI target
during the COMMAND phase. <tt>cmnd[0]</tt> is the SCSI command
code. The <tt>COMMAND_SIZE</tt> macro, defined in
<tt>scsi.h</tt>, can be used to determine the length of the
current SCSI command.
</p><p><tt>result</tt> is used to store the result code from the
SCSI request. Please see section
<a href="#sec:done"><tt>done()</tt></a> for more information about
this variable. This variable <i>must</i> be correctly set
before the low-level routines return.
</p><h5>The Scatter-Gather List</h5>
<p><tt>use_sg</tt> contains a count of the number of pieces in
the scatter-gather chain. If <tt>use_sg</tt> is zero, then
<tt>request_buffer</tt> points to the data buffer for the SCSI
command, and <tt>request_bufflen</tt> is the length of this
buffer in bytes. Otherwise, <tt>request_buffer</tt> points to
an array of <tt>scatterlist</tt> structures, and
<tt>use_sg</tt> will indicate how many such structures are in
the array. The use of <tt>request_buffer</tt> is non-intuitive
and confusing.
</p><p>Each element of the <tt>scatterlist</tt> array contains an
<tt>address</tt> and a <tt>length</tt> component. If the
<tt>unchecked_isa_dma</tt> flag in the <tt>Scsi_Host</tt>
structure is set to 1 (see section
<a href="#sec:dma"><tt>unchecked_isa_dma</tt></a> for more
information on DMA transfers), the address is guaranteed to be
within the first 16 MB of physical memory. Large amounts of
data will be processed by a single SCSI command. The length of
these data will be equal to the sum of the lengths of all the
buffers pointed to by the <tt>scatterlist</tt> array.
</p><h4>Scratch Areas</h4>
<p>Depending on the capabilities and requirements of the host
adapter, the scatter-gather list can be handled in a variety of
ways. To support multiple methods, several scratch areas are
provided for the exclusive use of the low-level driver.
</p><h5>The <tt>scsi_done()</tt> Pointer</h5>
<p>This pointer should be set to the <tt>done()</tt> function
pointer in the <tt>queuecommand()</tt> function (see section
<a href="#sec:queuecommand"><tt>queuecommand()</tt></a> for more
information). There are no other uses for this pointer.
</p><h5>The <tt>host_scribble</tt> Pointer</h5>
<p>The high-level code supplies a pair of memory allocation
functions, <tt>scsi_malloc()</tt> and <tt>scsi_free()</tt>,
which are guaranteed to return memory in the first 16 MB of
physical memory. This memory is, therefore, suitable for use
with DMA. The amount of memory allocated per request
<i>must</i> be a multiple of 512 bytes, and <i>must</i> be less
than or equal to 4096 bytes. The total amount of memory
available via <tt>scsi_malloc()</tt> is a complex function of
the <tt>Scsi_Host</tt> structure variables
<tt>sg_tablesize</tt>, <tt>cmd_per_lun</tt>, and
<tt>unchecked_isa_dma</tt>.
</p><p>The <tt>host_scribble</tt> pointer is available to point to
a region of memory allocated with <tt>scsi_malloc()</tt>. The
low-level SCSI driver is responsible for managing this pointer
and its associated memory, and should free the area when it is
no longer needed.
</p><h5>The <tt>Scsi_Pointer</tt> Structure</h5>
The <tt>SCp</tt> variable, a structure of type <tt>Scsi_Pointer</tt>, is
described here:
<pre> typedef struct scsi_pointer
{
char *ptr; /* data pointer */
int this_residual; /* left in this buffer */
struct scatterlist *buffer; /* which buffer */
int buffers_residual; /* how many buffers left */
volatile int Status;
volatile int Message;
volatile int have_data_in;
volatile int sent_command;
volatile int phase;
} Scsi_Pointer;
</pre>
The variables in this structure can be used in <i>any</i> way
necessary in the low-level driver. Typically, <tt>buffer</tt>
points to the current entry in the <tt>scatterlist</tt>,
<tt>buffers_residual</tt> counts the number of entries
remaining in the <tt>scatterlist</tt>, <tt>ptr</tt> is used as
a pointer into the buffer, and <tt>this_residual</tt> counts
the characters remaining in the transfer. Some host adapters
require support of this detail of interaction--others can
completely ignore this structure.
<p>The second set of variables provide convenient locations to
store SCSI status information and various pointers and flags.
</p><h3>Acknowledgements</h3>
<p>Thanks to Drew Eckhardt, Michael K. Johnson, Karin Boes,
Devesh Bhatnagar, and Doug Hoffman for reading early versions
of this paper and for providing many helpful comments. Special
thanks to my official COMP-291 (Professional Writing in
Computer Science) ``readers,'' Professors Peter Calingaert and
Raj Kumar Singh.
</p><h3>Bibliography</h3>
<dl>
<dt>[ANS]
</dt><dd><i>Draft Proposed American National Standard for Information Systems:
Small Computer System Interface-2 (SCSI-2).</i> (X3T9.2/86-109,
revision 10h, October 17, 1991).
</dd><dt>[Int90]
</dt><dd>Intel. <i>i486 Processor Programmer's Reference Manual.</i>
Intel/McGraw-Hiull, 1990.
</dd><dt>[LXT91]
</dt><dd><i>LXT SCSI Products: Specification and OEM Technical Manual,</i> 1991.
</dd><dt>[Nor85]
</dt><dd>Peter Norton. <i>The Peter Norton Programmer's Guide to the IBM PC.</i>
Bellevue, Washington: Microsoft Press, 1985.
</dd></dl>
<p>
</p><p></p><hr size="3">
<p><b><a name="Messages">Messages</a></b>
<nobr>
<font size="-1">
</font>
</nobr>
</p><p>
<nobr>
<dl compact="compact">
<dt> 1. <img src="writingscsi%20driver_files/feedback.gif" alt="Feedback:" align="middle" height="15" width="15">
<a href="http://tldp.org/LDP/khg/HyperNews/get/devices/scsi/1.html">
Writing a SCSI Device Driver</a> <i> by rohit patil</i> </dt>
</dl>
</nobr>
</p><p>
</p><p>
<br>
<br></p></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -