⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 writingscsi driver.htm

📁 What is this ``device driver stuff anyway? Here s a very short introduction to the concept.
💻 HTM
📖 第 1 页 / 共 4 页
字号:
</p><p>Documentation is essential.  At minimum, you will need a
technical manual for your host adapter.  Since Linux is freely
distributable, and since you (ideally) want to distribute your
source code freely, avoid non-disclosure agreements (NDA).
Most NDA's will prohibit you from releasing your source
code--you might be allowed to release an object file containing
your driver, but this is simply not acceptable in the Linux
community at this time.

</p><p>A manual that explains the SCSI standard will be helpful.
Usually the technical manual for your disk drive will be
sufficient, but a copy of the SCSI standard will often be
helpful. (The October 17, 1991, draft of the SCSI-2 standard
document is available via anonymous ftp from
<tt>sunsite.unc.edu</tt> in
<tt>/pub/Linux/development/scsi-2.tar.Z</tt>, and is available
for purchase from Global Engineering Documents (2805 McGaw,
Irvine, CA 92714), (800)-854-7179 or (714)-261-1455.  Please
refer to document X3.131-199X.  In early 1993, the manual cost
US$60--70.)

</p><p>Before you start, make hard copies of <tt>hosts.h</tt>,
<tt>scsi.h</tt>, and one of the existing drivers in the Linux
kernel.  These will prove to be useful references while you
write your driver.

</p><h4>The Linux SCSI Interface</h4>

<p>The high-level SCSI interface in the Linux kernel manages
all of the interaction between the kernel and the low-level
SCSI device driver. Because of this layered design, a low-level
SCSI driver need only provide a few basic services to the
high-level code.  The author of a low-level driver does not
need to understand the intricacies of the kernel I/O system
and, hence, can write a low-level driver in a relatively short
amount of time.

</p><p>Two main structures (<tt>Scsi_Host</tt> and
<tt>Scsi_Cmnd</tt>) are used to communicate between the
high-level code and the low-level code.  The next two sections
provide detailed information about these structures and the
requirements of the low-level driver.

</p><h4>The <tt>Scsi_Host</tt> Structure</h4>

The <tt>Scsi_Host</tt> structure serves to describe the low-level driver to
the high-level code.  Usually, this description is placed in the device
driver's header file in a C preprocessor definition:
<pre>    #define FDOMAIN_16X0  { "Future Domain TMC-16x0",          \
                             fdomain_16x0_detect,              \
                             fdomain_16x0_info,                \
                             fdomain_16x0_command,             \
                             fdomain_16x0_queue,               \
                             fdomain_16x0_abort,               \
                             fdomain_16x0_reset,               \
                             NULL,                             \
                             fdomain_16x0_biosparam,           \
                             1, 6, 64, 1 ,0, 0}
    #endif
</pre>

<p>The <tt>Scsi_Host</tt> structure is presented next. Each of
the fields will be explained in detail later in this section.

</p><pre>    typedef struct     
    {
      char               *name;
      int                (* detect)(int); 
      const char         *(* info)(void);
      int                (* queuecommand)(Scsi_Cmnd *,
                          void (*done)(Scsi_Cmnd *));
      int                (* command)(Scsi_Cmnd *);
      int                (* abort)(Scsi_Cmnd *, int);
      int                (* reset)(void);
      int                (* slave_attach)(int, int);
      int                (* bios_param)(int, int, int []);
      int                can_queue;
      int                this_id;
      short unsigned int sg_tablesize;
      short              cmd_per_lun;
      unsigned           present:1;     
      unsigned           unchecked_isa_dma:1;
    } Scsi_Host;
</pre>


<h4>Variables in the <tt>Scsi_Host</tt> structure</h4>

<p>In general, the variables in the <tt>Scsi_Host</tt>
structure are not used until after the <tt>detect()</tt>
function (see section <a href="#sec:detect"><tt>detect()</tt></a>)
is called. Therefore, any variables which cannot be assigned
before host adapter detection should be assigned during
detection.  This situation might occur, for example, if a
single driver provided support for several host adapters with
very similar characteristics.  Some of the parameters in the
<tt>Scsi_Host</tt> structure might then depend on the specific
host adapter detected.

</p><h5><tt>name</tt></h5>

<p><tt>name</tt> holds a pointer to a short description of the
SCSI host adapter.

</p><h5><tt>can_queue</tt></h5>
<a name="sec:can.queue"></a>

<p><tt>can_queue</tt> holds the number of outstanding commands
the host adapter can process.  Unless RESELECTION is supported
by the driver and the driver is interrupt-driven, (some of the
early Linux drivers were not interrupt driven and,
consequently, had very poor performance) this variable should
be set to 1.

</p><h5><tt>this_id</tt></h5>

<p>Most host adapters have a specific SCSI ID assigned to them.
This SCSI ID, usually 6 or 7, is used for RESELECTION.  The
<tt>this_id</tt> variable holds the host adapter's SCSI ID.  If
the host adapter does not have an assigned SCSI ID, this
variable should be set to -1 (in this case, RESELECTION cannot
be supported).

</p><h5><tt>sg_tablesize</tt></h5>

<p>The high-level code supports ``scatter-gather,'' a method of
increasing SCSI throughput by combining many small SCSI
requests into a few large SCSI requests.  Since most SCSI disk
drives are formatted with 1:1 interleave, (``1:1 interleave''
means that all of the sectors in a single track appear
consecutively on the disk surface) the time required to perform
the SCSI ARBITRATION and SELECTION phases is longer than the
rotational latency time between sectors. (This may be an
over-simplification.  On older devices, the actual command
processing can be significant.  Further, there is a great deal
of layered overhead in the kernel: the high-level SCSI code,
the buffering code, and the file-system code all contribute to
poor SCSI performance.) Therefore, only one SCSI request can be
processed per disk revolution, resulting in a throughput of
about 50 kilobytes per second.  When scatter-gather is
supported, however, average throughput is usually over 500
kilobytes per second.

</p><p>The <tt>sg_tablesize</tt> variable holds the maximum
allowable number of requests in the scatter-gather list.  If
the driver does not support scatter-gather, this variable
should be set to <tt>SG_NONE</tt>.  If the driver can support
an unlimited number of grouped requests, this variable should
be set to <tt>SG_ALL</tt>.  Some drivers will use the host
adapter to manage the scatter-gather list and may need to limit
<tt>sg_tablesize</tt> to the number that the host adapter
hardware supports.  For example, some Adaptec host adapters
require a limit of 16.

</p><h5><tt>cmd_per_lun</tt></h5>

<p>The SCSI standard supports the notion of ``linked
commands.'' Linked commands allow several commands to be queued
consecutively to a single SCSI device.  The
<tt>cmd_per_lun</tt> variable specifies the number of linked
commands allowed.  This variable should be set to 1 if command
linking is not supported.  At this time, however, the
high-level SCSI code will not take advantage of this feature.

</p><p>Linked commands are fundamentally different from multiple
outstanding commands (as described by the <tt>can_queue</tt>
variable).  Linked commands always go to the same SCSI target
and do not necessarily involve a RESELECTION phase.  Further,
linked commands eliminate the ARBITRATION, SELECTION, and
MESSAGE OUT phases on all commands after the first one in the
set.  In contrast, multiple outstanding commands may be sent to
an arbitrary SCSI target, and <i>require</i> the ARBITRATION,
SELECTION, MESSAGE OUT, and RESELECTION phases.

</p><h5><tt>present</tt></h5>

<p>The <tt>present</tt> bit is set (by the high-level code) if
the host adapter is detected.

</p><h5><tt>unchecked_isa_dma</tt></h5>
<a name="sec:dma"></a>

<p>Some host adapters use Direct Memory Access (DMA) to read
and write blocks of data directly from or to the computer's
main memory.  Linux is a virtual memory operating system that
can use more than 16 MB of physical memory.  Unfortunately, on
machines using the ISA bus (the so-called ``Industry Standard
Architecture'' bus was introduced with the IBM PC/XT and IBM
PC/AT computers), DMA is limited to the low 16 MB of physical
memory.

</p><p>If the <tt>unchecked_isa_dma</tt> bit is set, the high-level
code will provide data buffers which are guaranteed to be in
the low 16 MB of the physical address space.  Drivers written
for host adapters that do not use DMA should set this bit to
zero.  Drivers specific to EISA bus (the ``Extended Industry
Standard Architecture'' bus is a non-proprietary 32-bit bus for
386 and i486 machines) machines should also set this bit to
zero, since EISA bus machines allow unrestricted DMA access.

</p><h4>Functions in the <tt>Scsi_Host</tt> Structure</h4>

<h5><tt>detect()</tt></h5>
<a name="sec:detect"></a>

<p>The <tt>detect()</tt> function's only argument is the ``host
number,'' an index into the <tt>scsi_hosts</tt> variable (an
array of type <tt>struct Scsi_Host</tt>).  The
<tt>detect()</tt> function should return a non-zero value if
the host adapter is detected, and should return zero otherwise.

</p><p>Host adapter detection must be done carefully.  Usually the
process begins by looking in the ROM area for the ``BIOS
signature'' of the host adapter. On PC/AT-compatible computers,
the use of the address space between <tt>0xc0000</tt> and
<tt>0xfffff</tt> is fairly well defined.  For example, the
video BIOS on most machines starts at <tt>0xc0000</tt> and the
hard disk BIOS, if present, starts at <tt>0xc8000</tt>.  When a
PC/AT-compatible computer boots, every 2-kilobyte block from
<tt>0xc0000</tt> to <tt>0xf8000</tt> is examined for the 2-byte
signature (<tt>0x55aa</tt>) which indicates that a valid BIOS
extension is present [Nor85].

</p><p>The BIOS signature usually consists of a series of bytes that uniquely
identifies the BIOS.  For example, one Future Domain BIOS signature is
the string
</p><pre>    FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89
</pre>
found exactly five bytes from the start of the BIOS block.

<p>After the BIOS signature is found, it is safe to test for
the presence of a functioning host adapter in more specific
ways.  Since the BIOS signatures are hard-coded in the kernel,
the release of a new BIOS can cause the driver to mysteriously
fail.  Further, people who use the SCSI adapter exclusively for
Linux may want to disable the BIOS to speed boot time. For
these reasons, if the adapter can be detected safely without
examining the BIOS, then that alternative method should be
used.

</p><p>Usually, each host adapter has a series of I/O port
addresses which are used for communications.  Sometimes these
addresses will be hard coded into the driver, forcing all Linux
users who have this host adapter to use a specific set of I/O
port addresses.  Other drivers are more flexible, and find the
current I/O port address by scanning all possible port
addresses. Usually each host adapter will allow 3 or 4 sets of
addresses, which are selectable via hardware jumpers on the
host adapter card.

</p><p>After the I/O port addresses are found, the host adapter can
be interrogated to confirm that it is, indeed, the expected
host adapter. These tests are host adapter specific, but
commonly include methods to determine the BIOS base address
(which can then be compared to the BIOS address found during
the BIOS signature search) or to verify a unique identification
number associated with the board.  For MCA bus (the
``Micro-Channel Architecture'' bus is IBM's proprietary 32 bit
bus for 386 and i486 machines) machines, each type of board is
given a unique identification number which no other
manufacturer can use--several Future Domain host adapters, for
example, also use this number as a unique identifier on ISA bus
machines.  Other methods of verifying the host adapter
existence and function will be available to the programmer.


</p><h4>Requesting the IRQ</h4>

<p>After detection, the <tt>detect()</tt> routine must request
any needed interrupt or DMA channels from the kernel.  There
are 16 interrupt channels, labeled IRQ 0 through IRQ 15.  The
kernel provides two methods for setting up an IRQ handler:
<tt>irqaction()</tt> and <tt>request_irq()</tt>.

</p><p>The <tt>request_irq()</tt> function takes two parameters,
the IRQ number and a pointer to the handler routine.  It then
sets up a default <tt>sigaction</tt> structure and calls
<tt>irqaction()</tt>.  The code (Linux 0.99.7 kernel source
code, <tt>linux/kernel/irq.c</tt>) for the
<tt>request_irq()</tt> function is shown below.  I will limit
my discussion to the more general <tt>irqaction()</tt>
function.
</p><pre>    int request_irq( unsigned int irq, void (*handler)( int ) )
    {
      struct sigaction sa;
    
      sa.sa_handler  = handler;
      sa.sa_flags    = 0;
      sa.sa_mask     = 0;
      sa.sa_restorer = NULL;
      return irqaction( irq, &amp;sa );
    }
</pre>

<p>The declaration (Linux 0.99.5 kernel source code,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -