Files
2024-02-19 00:23:35 -05:00

1341 lines
58 KiB
TeX

% scsi.tex -- Writing a SCSI Device Driver for Linux
% Created: Sat Feb 20 12:56:25 1993 by faith@cs.unc.edu
% Revised: Mon Jun 7 21:30:37 1993 by faith@cs.unc.edu
% Written at the University of North Carolina, 1993, for COMP-291.
% The information contained herein comes with ABSOLUTELY NO WARRANTY.
%
% Copyright 1993 Rickard E. Faith (faith@cs.unc.edu). All rights reserved.
% Permission is granted to make and distribute verbatim copies of this
% paper provided the copyright notice and this permission notice are
% preserved on all copies.
%
%
% $Log: scsi.tex,v $
% Revision 1.12 1993/06/07 21:35:46 root
% First Public Release
%
% Revision 1.11 1993/06/06 22:23:59 root
% Filename change to scsi.tex
%
% Revision 1.10 1993/06/06 22:20:10 root
% Pre-release Draft
%
% Revision 1.9 1993/04/03 22:50:55 root
% Draft #2
%
% Revision 1.8 1993/03/20 19:39:47 root
% Saturday's Draft
%
% Revision 1.7 1993/03/13 15:46:30 root
% Draft #1
%
% Revision 1.6 1993/03/12 20:49:43 root
% Friday's Draft.
%
% Revision 1.5 1993/03/10 21:19:10 root
% Wednesday's Final Draft
%
% Revision 1.4 1993/03/10 20:37:41 root
% Wednesday's Draft
%
% Revision 1.3 1993/03/08 22:40:30 root
% Monday's Draft
%
% Revision 1.2 1993/03/08 13:36:40 root
% Draft 0.1
%
% Revision 1.1 1993/03/08 10:49:46 root
% Initial revision
%
%
\def\FileCreated{Sat Feb 20 12:56:25 1993}
\def\FileRevised{Mon Jun 7 21:30:37 1993}
\newcommand{\Linux}{{\sc Linux}}
\documentstyle[12pt,draft]{article}%\setstretch{1.0}
\makeatletter
\def\@date{\FileRevised} % get rid of changedate style
\def\singlespace{} % get rid of doublespace style
\def\endsinglespace{}
% This is to get a copyright notice at the bottom of page one without a
% footnote mark.
\def\mynote#1{\begingroup\noindent
\def\protect{\noexpand\protect\noexpand}\xdef\@thanks{\@thanks
\protect\footnotetext[\the\c@footnote]{#1}}\endgroup}
% This is for the desc environment, modified from the description
% environment.
\def\desclabel#1{\hspace\labelsep\mbox{\bf #1}\hfil}
\def\desc#1{\list{}{\settowidth{\labelwidth}{\desclabel{#1}}
\leftmargin\labelwidth\let\makelabel\desclabel}}
\let\enddesc\endlist
% This is stuff for the Linux document style.
% Comment it out if you have linuxdoc.sty
\topmargin -0.5in
%\textheight 8.75in
\textheight 8.5in
\advance\headsep 2ex
\advance\textheight -2ex % decrease by amount headsep was increased
\marginparwidth 0in
%\textwidth 6.25in
\textwidth 6in
\if@twoside
%\oddsidemargin 0.25in
\oddsidemargin 0.5in
\evensidemargin 0in
\def\ps@headings{\let\@mkboth\markboth
\def\@oddfoot{}\def\@evenfoot{}% No feet.
\def\@evenhead{\protect\rule[-4pt]{\textwidth}{.5pt}\kern-\textwidth
\rm \thepage\hfil \sl \leftmark} % Left heading.
\def\@oddhead{\protect\rule[-4pt]{\textwidth}{.5pt}\kern-\textwidth
{\sl \rightmark}\hfil \rm\thepage} % Right heading.
\def\chaptermark##1{\markboth {\uppercase{\ifnum \c@secnumdepth >\m@ne
\@chapapp\ \thechapter. \ \fi ##1}}{}}%
\def\sectionmark##1{\markright {\uppercase{\ifnum \c@secnumdepth >\z@
\thesection. \ \fi ##1}}}}
\else
%\oddsidemargin 0.25in
\oddsidemargin 0.5in
\evensidemargin\oddsidemargin
\def\ps@headings{\let\@mkboth\markboth
\def\@oddfoot{}\def\@evenfoot{}% No feet.
\def\@oddhead{\protect\rule[-4pt]{\textwidth}{.5pt}\kern-\textwidth
{\sl \rightmark}\hfil \rm\thepage} % Right heading.
\def\@evenhead\@oddhead
\def\chaptermark##1{\markboth {\uppercase{\ifnum \c@secnumdepth >\m@ne
\@chapapp\ \thechapter. \ \fi ##1}}{}}%
\def\sectionmark##1{\markright {\uppercase{\ifnum \c@secnumdepth >\z@
\thesection. \ \fi ##1}}}}
\fi
\ps@headings
\makeatother
\title{Writing a SCSI Device Driver for \Linux{}}
\author{Rickard E. Faith\mynote{Copyright \copyright{} 1993 Rickard E.
Faith (faith@cs.unc.edu). All rights reserved. Permission is granted
to make and distribute verbatim copies of this paper provided the
copyright notice and this permission notice are preserved on all
copies.}}
\begin{document}\bibliographystyle{alpha}\pagenumbering{roman}
\begin{singlespace}
\maketitle\thispagestyle{empty}
\tableofcontents
% \pagebreak
% \listoffigures
% \pagebreak
% \listoftables
\end{singlespace}
\pagebreak\pagenumbering{arabic}
\section{Introduction}
In this paper, I have presented an overview of the information necessary to
write a low-level SCSI device driver for \Linux{}. The author of such a
driver is expected to have a thorough knowledge of C programming, but does
not need to have previous experience writing kernel or device driver code.
References to other resources have been provided---access to these
resources will make writing and debugging a low-level driver much easier.
\subsection{\Linux{}: The Operating System}
\Linux{} is a freely available {\sc unix}\footnote{{\sc unix} is a
registered trademark of AT\&T Bell Laboratories.}-like operating system
for 386 and i486 systems.\footnote{386 and i486 are trademarks of Intel
Corporation.} The kernel, written from scratch by Linus
Torvalds,\footnote{Internet mail address: torvalds@kruuna.Helsinki.FI}
contains {\em no\/} proprietary source code and is available for use
without licensing fees. Linus distributes the kernel freely under the terms
of the GNU General Public License.\footnote{For those interested, a copy of
the GNU General Public License is available via anonymous ftp from {\tt
prep.ai.mit.edu}. Copies can also be obtained by writing to the Free
Software Foundation, Inc., 675 Massachusetts Ave., Cambridge, MA 02139,
USA.}
Since its introduction in November 1991, \Linux{} has matured rapidly. The
kernel contains support for SCSI disks and tapes, sound cards, mice,
TCP/IP, and several file systems. The C library contains POSIX, System~V,
and BSD compatible routines. \Linux{} installations are capable of running
large software packages such as \TeX{} and the X Window System.
\subsection{Why You Want to Write a SCSI Driver}
Currently, the \Linux{} kernel contains drivers for the following SCSI host
adapters: Adaptec 1542, Adaptec 1740, Future Domain TMC-1660/TMC-1680,
Seagate ST-01/ST-02, UltraStor 14F, and Western Digital WD-7000. You may
want to write your own driver for an unsupported host adapter. You may
also want to re-write or update one of the existing drivers.
\section{What is SCSI?}
The foreword to the SCSI-2 standard draft \cite{scsi2.standard} gives a
succinct definition of the Small Computer System Interface and briefly
explains how SCSI-2 is related to SCSI-1 and CCS:
\begin{singlespace}
\begin{quotation}
The SCSI protocol is designed to provide an efficient peer-to-peer I/O
bus with up to 8 devices, including one or more hosts. Data may be
transferred asynchronously at rates that only depend on device
implementation and cable length. Synchronous data transfers are
supported at rates up to 10 mega-transfers per second. With the 32~bit
wide data transfer option, data rates of up to 40 megabytes per second
are possible.
SCSI-2 includes command sets for magnetic and optical disks, tapes,
printers, processors, CD-ROMs, scanners, medium changers, and
communications devices.
In 1985, when the first SCSI standard was being finalized as an
American National Standard, several manufacturers approached the X3T9.2
Task Group. They wanted to increase the mandatory requirements of SCSI
and to define further features for direct-access devices. Rather than
delay the SCSI standard, X3T9.2 formed an ad hoc group to develop a
working paper that was eventually called the Common Command Set
(CCS)\@. Many disk products were designed using this working paper in
conjunction with the SCSI standard.
In parallel with the development of the CCS working paper, X3T9.2 began
work on an enhanced SCSI standard which was named SCSI-2. SCSI-2
included the results of the CCS working paper and extended them to all
device types. It also added caching commands, performance enhancement
features, and other functions that X3T9.2 deemed worthwhile. While
SCSI-2 has gone well beyond the original SCSI standard (now referred to
as SCSI-1), it retains a high degree of compatibility with SCSI-1
devices.
\end{quotation}
\end{singlespace}
\subsection{SCSI Phases}
\label{sec:status}
\label{sec:message}
The ``SCSI bus'' transfers data and state information between
interconnected SCSI devices. A single transaction between an ``initiator''
and a ``target'' can involve up to 8 distinct ``phases.'' These phases are
almost entirely determined by the target (e.g., the hard disk drive). The
current phase can be determined from an examination of five SCSI bus
signals, as shown in Table~\ref{tab:phase} \cite[p.~57]{lxt.manual}.
\begin{table}[hbtp]
\leavevmode
\begin{center}
\begin{tabular}{|c|c|c|c|c|l|} \hline
-SEL & -BSY & -MSG & -C/D & -I/O & PHASE \\\hline\hline
HI & HI & ? & ? & ? & BUS FREE \\\hline
HI & LO & ? & ? & ? & ARBITRATION \\\hline
I & I\&T & ? & ? & ? & SELECTION \\\hline
T & I\&T & ? & ? & ? & RESELECTION \\\hline
HI & LO & HI & HI & HI & DATA OUT \\\hline
HI & LO & HI & HI & LO & DATA IN \\\hline
HI & LO & HI & LO & HI & COMMAND \\\hline
HI & LO & HI & LO & LO & STATUS \\\hline
HI & LO & LO & LO & HI & MESSAGE OUT \\\hline
HI & LO & LO & LO & LO & MESSAGE IN \\\hline
\multicolumn{6}{l}{{\footnotesize I = Initiator Asserts, T = Target
Asserts, ? = HI or LO}}
\end{tabular}
\caption{SCSI Bus Phase Determination}
\label{tab:phase}
\end{center}
\end{table}
Some controllers (notably the inexpensive Seagate controller) require
direct manipulation of the SCSI bus---other controllers automatically
handle these low-level details. Each of the eight phases will be described
in detail.
\begin{description}
\item[BUS FREE Phase] The BUS FREE phase indicates that the SCSI bus is
idle and is not currently being used.
\item[ARBITRATION Phase] The ARBITRATION phase is entered when a SCSI
device attempts to gain control of the SCSI bus. Arbitration can start
only if the bus was previously in the BUS FREE phase. During
arbitration, the arbitrating device asserts its SCSI ID on the DATA
BUS\@. For example, if the arbitrating device's SCSI ID is 2, then the
device will assert {\tt 0x04}\@. If multiple devices attempt
simultaneous arbitration, the device with the highest SCSI ID will win.
Although ARBITRATION is optional in the SCSI-1 standard, it is a required
phase in the SCSI-2 standard.
\item[SELECTION Phase] After ARBITRATION, the arbitrating device (now
called the initiator) asserts the SCSI ID of the target on the DATA
BUS\@. The target, if present, will acknowledge the selection by raising
the -BSY line. This line remains active as long as the target is
connected to the initiator.
\item[RESELECTION Phase] The SCSI protocol allows a device to disconnect
from the bus while processing a request. When the device is ready, it
reconnects to the host adapter. The RESELECTION phase is identical to
the SELECTION phase, with the exception that it is used by the
disconnected target to reconnect to the original initiator. Drivers
which do not currently support RESELECTION do not allow the SCSI target
to disconnect. RESELECTION should be supported by all drivers, however,
so that multiple SCSI devices can simultaneously process commands. This
allows dramatically increased throughput due to interleaved I/O requests.
\item[COMMAND Phase] During this phase, 6, 10, or 12 bytes of command
information are transferred from the initiator to the target.
\item[DATA OUT and DATA IN Phases] During these phases, data are
transferred between the initiator and the target. For example, the DATA
OUT phase transfers data from the host adapter to the disk drive. The
DATA IN phase transfers data from the disk drive to the host adapter. If
the SCSI command does not require data transfer, then neither phase is
entered.
\item[STATUS Phase] This phase is entered after completion of all commands,
and allows the target to send a status byte to the initiator. There are
nine valid status bytes, as shown in Table~\ref{tab:status}
\cite[p.~77]{scsi2.standard}. Note that since bits\footnote{Bit 0 is the
least significant bit.} 1--5 are used for the status code (the other
bits are reserved), the status byte should be masked with \verb|0x3e|
before being examined.
\begin{table}[hbtp]
\leavevmode
\begin{center}
\begin{tabular}{|l|l|} \hline
Value${}^{\dag}$ & Status \\\hline\hline
0x00 & GOOD \\\hline
0x02 & CHECK CONDITION \\\hline
0x04 & CONDITION MET \\\hline
0x08 & BUSY \\\hline
0x10 & INTERMEDIATE \\\hline
0x14 & INTERMEDIATE-CONDITION MET \\\hline
0x18 & RESERVATION CONFLICT \\\hline
0x22 & COMMAND TERMINATED \\\hline
0x28 & QUEUE FULL \\\hline
\multicolumn{2}{l}{{\footnotesize ${}^{\dag}$ After masking with 0x3e}}
\end{tabular}
\caption{SCSI Status Codes}
\label{tab:status}
\end{center}
\end{table}
The meanings of the three most important status codes are outlined below:
\begin{desc}{CHECK CONDITION}
\item[GOOD] The operation completed successfully.
\item[CHECK CONDITION] An error occurred. The REQUEST SENSE command
should be used to find out more information about the error (see
section~\ref{sec:scsi.commands}).
\item[BUSY] The device was unable to accept a command. This may occur
during a self-test or shortly after power-up.
\end{desc}
\item[MESSAGE OUT and MESSAGE IN Phases] Additional information is
transferred between the target and the initiator. This information may
regard the status of an outstanding command, or may be a request for a
change of protocol. Multiple MESSAGE IN and MESSAGE OUT phases may occur
during a single SCSI transaction. If RESELECTION is supported, the
driver must be able to correctly process the SAVE DATA POINTERS, RESTORE
POINTERS, and DISCONNECT messages. Although required by the SCSI-2
standard, some devices do not automatically send a SAVE DATA POINTERS
message prior to a DISCONNECT message.
\end{description}
\subsection{SCSI Commands}
\label{sec:scsi.commands}
Each SCSI command is 6, 10, or 12 bytes long. The following commands must
be well understood by a SCSI driver developer.
\begin{description}
\item[REQUEST SENSE] Whenever a command returns a CHECK CONDITION status,
the high-level \Linux{} SCSI code automatically obtains more information
about the error by executing the REQUEST SENSE\@. This command returns a
sense key and a sense code (called the ``additional sense code,'' or ASC,
in the SCSI-2 standard \cite{scsi2.standard}). Some SCSI devices may
also report an ``additional sense code qualifier'' (ASCQ)\@. The 16
possible sense keys are described in Table~\ref{tab:sense.keys}. For
information on the ASC and ASCQ, please refer to the SCSI standard
\cite{scsi2.standard} or to a SCSI device technical manual.
\begin{table}[hbtp]
\leavevmode
\begin{center}
\begin{tabular}{|l|l|}\hline
Sense Key & Description \\\hline\hline
{\tt 0x00} & NO SENSE \\\hline
{\tt 0x01} & RECOVERED ERROR \\\hline
{\tt 0x02} & NOT READY \\\hline
{\tt 0x03} & MEDIUM ERROR \\\hline
{\tt 0x04} & HARDWARE ERROR \\\hline
{\tt 0x05} & ILLEGAL REQUEST \\\hline
{\tt 0x06} & UNIT ATTENTION \\\hline
{\tt 0x07} & DATA PROTECT \\\hline
{\tt 0x08} & BLANK CHECK \\\hline
{\tt 0x09} & (Vendor specific error) \\\hline
{\tt 0x0a} & COPY ABORTED \\\hline
{\tt 0x0b} & ABORTED COMMAND \\\hline
{\tt 0x0c} & EQUAL \\\hline
{\tt 0x0d} & VOLUME OVERFLOW \\\hline
{\tt 0x0e} & MISCOMPARE \\\hline
{\tt 0x0f} & RESERVED \\\hline
\end{tabular}
\caption{Sense Key Descriptions}
\label{tab:sense.keys}
\end{center}
\end{table}
\item[TEST UNIT READY] This command is used to test the target's status.
If the target can accept a medium-access command (e.g., a READ or a
WRITE), the command returns with a GOOD status. Otherwise, the command
returns with a CHECK CONDITION status and a sense key of NOT READY\@.
This response usually indicates that the target is completing power-on
self-tests.
\item[INQUIRY] This command returns the target's make, model, and device
type. The high-level \Linux{} code uses this command to differentiate
among magnetic disks, optical disks, and tape drives (the high-level code
currently does not support printers, processors, or juke boxes).
\item[READ and WRITE] These commands are used to transfer data from and to
the target. You should be sure your driver can support simpler commands,
such as TEST UNIT READY and INQUIRY, before attempting to use the READ and
WRITE commands.
\end{description}
\section{Getting Started}
\subsection{Dangers of Kernel Hacking}
Writing code for the \Linux{} kernel (or for any kernel) is somewhat
different from writing normal C code. The most striking differences are
that static variables are not initialized to zero and that the common
functions found in the standard C library are not available.
\subsubsection{Uninitialized Static Variables are Evil}
The ANSI C standard \cite[p.~40]{k.and.r} and the current C++ description
\cite[pp.~19 and~150]{the.arm} both guarantee that static variables are, by
default, initialized to zero. While the merits of relying on this default
initialization are debatable, static variables in the kernel are {\em
not\/} automatically initialized to zero.\footnote{Some boot/loader
programs (e.g., LILO) can zero memory before loading the kernel. This
will make memory appear {\em as if\/} static variables were, indeed,
initialized to zero. However, when the same kernel is placed on a floppy
disk, and the system is booted from that floppy, the uninitialized static
variables will contain random data. Because of this behavior, a kernel
which works fine when booted from the hard disk sometimes fails
mysteriously when booted from the floppy.} To avoid many debugging
nightmares, all otherwise uninitialized static variables should be {\em
explicitly\/} initialized to zero.
\subsubsection{{\tt libc} Unavailable}
The kernel maintains a small set of commonly used library functions, which
permit file manipulation (e.g., \verb|open()|, \verb|close()|), string
manipulation (e.g., \verb|strcmp()|), and character type testing (e.g.,
\verb|isdigit()|). Most other standard C library functions, however, are
{\em not\/} available.
\subsubsection{Commonly Used Kernel Functions}
The kernel contains several special library functions. The most commonly
used function is \verb|printk()|. This function acts exactly like
\verb|printf()|, except its output will be sent to the console or to the
system log facility.
Another commonly used kernel function is \verb|panic()|. This function
takes a single parameter, which is a message to be printed on the console
explaining why the system has just crashed. This function should be used
if the driver enters an unrecoverable error state in which the only option
is to shut down the system.
The author of a low-level device driver will need to have an understanding
of how interruptions are handled by the kernel. At minimum, the kernel
functions that disable (\verb|cli()|) and enable (\verb|sti()|)
interruptions should be understood. The scheduling functions (e.g.,
\verb|schedule()|, \verb|sleepon()|, and \verb|wakeup()|) may also be
needed by some drivers. A detailed explanation of these functions is
outside the scope of this paper.
\subsection{Before You Begin: Gathering Tools}
Before you begin to write a SCSI driver for \Linux{}, you will need to
obtain several resources.
The most important is a bootable \Linux{} system---preferably one which
boots from an IDE, RLL, or MFM hard disk. During the development of your
new SCSI driver, you will rebuild the kernel and reboot your system many
times. Programming errors may result in the destruction of data on your
SCSI drive {\em and\/} on your non-SCSI drive. {\em Back up your system
before you begin\/}.
The installed \Linux{} system can be quite minimal: the GCC compiler
distribution (including libraries and the binary utilities), an editor, and
the kernel source are all you need. Additional tools like \verb|od|,
\verb|hexdump|, and \verb|less| will be quite helpful. All of these tools
will fit on an inexpensive 20-30~MB hard disk.\footnote{A used 20~MB MFM
hard disk and controller should cost less than US\$100.}.
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.
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.\footnote{The October 17, 1991, draft
of the SCSI-2 standard document is available via anonymous ftp from
\verb|sunsite.unc.edu| in \verb|/pub/Linux/development/scsi-2.tar.Z|, 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.}
Before you start, make hard copies of \verb|hosts.h|, \verb|scsi.h|, and
one of the existing drivers in the \Linux{} kernel. These will prove to be
useful references while you write your driver.
\section{The \Linux{} SCSI Interface}
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.
Two main structures (\verb|Scsi_Host| and \verb|Scsi_Cmnd|) 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.
\section{The {\tt Scsi\_Host} Structure}
The \verb|Scsi_Host| 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, as shown in
Figure~\ref{fig:header}.
\begin{figure}[hbtp]
\leavevmode
\begin{center}
\begin{verbatim}
#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
\end{verbatim}
\caption{Device Driver Header File}
\label{fig:header}
\end{center}
\end{figure}
The \verb|Scsi_Host| structure is presented in Figure~\ref{fig:scsi.host}.
Each of the fields will be explained in detail later in this section.
\begin{figure}[hbtp]
\leavevmode
\begin{center}
\begin{verbatim}
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;
\end{verbatim}
\caption{The {\tt Scsi\_Host} Structure}
\label{fig:scsi.host}
\end{center}
\end{figure}
\subsection{Variables in the {\tt Scsi\_Host} Structure}
In general, the variables in the \verb|Scsi_Host| structure are not used
until after the \verb|detect()| function (see section \ref{sec:detect}) 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 \verb|Scsi_Host| structure might then depend on the specific host
adapter detected.
\subsubsection{{\tt name}}
\verb|name| holds a pointer to a short description of the SCSI host adapter.
\subsubsection{{\tt can\_queue}}
\label{sec:can.queue}
\verb|can_queue| holds the number of outstanding commands the host adapter
can process. Unless RESELECTION is supported by the driver and the driver
is interrupt-driven,\footnote{Some of the early \Linux{} drivers were not
interrupt driven and, consequently, had very poor performance.} this
variable should be set to 1.
\subsubsection{{\tt this\_id}}
Most host adapters have a specific SCSI ID assigned to them. This SCSI ID,
usually 6 or 7, is used for RESELECTION\@. The \verb|this_id| 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).
\subsubsection{{\tt sg\_tablesize}}
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,\footnote{``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.\footnote{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.
The \verb|sg_tablesize| 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 \verb|SG_NONE|\@. If the
driver can support an unlimited number of grouped requests, this variable
should be set to \verb|SG_ALL|\@. Some drivers will use the host adapter
to manage the scatter-gather list and may need to limit \verb|sg_tablesize|
to the number that the host adapter hardware supports. For example, some
Adaptec host adapters require a limit of 16.
\subsubsection{{\tt cmd\_per\_lun}}
The SCSI standard supports the notion of ``linked commands.'' Linked
commands allow several commands to be queued consecutively to a single SCSI
device. The \verb|cmd_per_lun| 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.
Linked commands are fundamentally different from multiple outstanding
commands (as described by the \verb|can_queue| 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 {\em require\/} the ARBITRATION, SELECTION,
MESSAGE OUT, and RESELECTION phases.
\subsubsection{{\tt present}}
The \verb|present| bit is set (by the high-level code) if the host adapter
is detected.
\subsubsection{{\tt unchecked\_isa\_dma}}
\label{sec:dma}
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\footnote{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.
If the \verb|unchecked_isa_dma| 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\footnote{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.
\subsection{Functions in the {\tt Scsi\_Host} Structure}
\subsubsection{{\tt detect()}}
\label{sec:detect}
The \verb|detect()| function's only argument is the ``host number,'' an
index into the \verb|scsi_hosts| variable (an array of type \verb|struct
Scsi_Host|). The \verb|detect()| function should return a non-zero value
if the host adapter is detected, and should return zero otherwise.
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} and {\tt 0xfffff} is fairly well defined. For example, the
video BIOS on most machines starts at {\tt 0xc0000} and the hard disk BIOS,
if present, starts at {\tt 0xc8000}. When a PC/AT-compatible computer
boots, every 2-kilobyte block from {\tt 0xc0000} to {\tt 0xf8000} is
examined for the 2-byte signature ({\tt 0x55aa}) which indicates that a
valid BIOS extension is present \cite{norton.guide}.
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
\begin{singlespace}
\begin{center}
\begin{verbatim}
FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89
\end{verbatim}
\end{center}
\end{singlespace}
\noindent found exactly five bytes from the start of the BIOS block.
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.
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.
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\footnote{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.
\paragraph{Requesting the IRQ}
After detection, the \verb|detect()| 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: \verb|irqaction()| and \verb|request_irq()|.
The \verb|request_irq()| function takes two parameters, the IRQ number and
a pointer to the handler routine. It then sets up a default
\verb|sigaction| structure and calls \verb|irqaction()|. The
code\footnote{\Linux{} 0.99.7 kernel source code,
\verb|linux/kernel/irq.c|} for the \verb|request_irq()| function is shown
in Figure~\ref{fig:request.irq}. I will limit my discussion to the more
general \verb|irqaction()| function.
\begin{figure}[hbtp]
\leavevmode
\begin{center}
\begin{verbatim}
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, &sa );
}
\end{verbatim}
\caption{The {\tt request\_irq()} Function}
\label{fig:request.irq}
\end{center}
\end{figure}
The declaration\footnote{\Linux{} 0.99.5 kernel source code,
\verb|linux/kernel/irq.c|} for the \verb|irqaction()| function is
\begin{singlespace}
\begin{center}
\begin{verbatim}
int irqaction( unsigned int irq, struct sigaction *new )
\end{verbatim}
\end{center}
\end{singlespace}
\noindent where the first parameter, \verb|irq|, is the number of the IRQ
that is being requested, and the second parameter, \verb|new|, is a
structure with the definition\footnote{\Linux{} 0.99.5 kernel source code,
\verb|linux/include/linux/signal.h|} shown in Figure~\ref{fig:sigaction}.
\begin{figure}[hbtp]
\leavevmode
\begin{center}
\begin{verbatim}
struct sigaction
{
__sighandler_t sa_handler;
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
\end{verbatim}
\caption{The {\tt sigaction} Structure}
\label{fig:sigaction}
\end{center}
\end{figure}
In this structure, \verb|sa_handler| should point to your interrupt handler
routine, which should have a definition similar to the following:
\begin{singlespace}
\begin{center}
\begin{verbatim}
void fdomain_16x0_intr( int irq )
\end{verbatim}
\end{center}
\end{singlespace}
\noindent where \verb|irq| will be the number of the IRQ which caused the
interrupt handler routine to be invoked.
The \verb|sa_mask| variable is used as an internal flag by the
\verb|irqaction()| routine. Traditionally, this variable is set to zero
prior to calling \verb|irqaction()|.
The \verb|sa_flags| variable can be set to zero or to
\verb|SA_INTERRUPT|\@. If zero is selected, the interrupt handler will run
with other interrupts enabled, and will return via the signal-handling
return functions. This option is recommended for relatively slow IRQ's,
such as those associated with the keyboard and timer interrupts. If
\verb|SA_INTERRUPT| is selected, the handler will be called with interrupts
disabled and return will avoid the signal-handling return functions.
\verb|SA_INTERRUPT| selects ``fast'' IRQ handler invocation routines, and
is recommended for interrupt driven hard disk routines. The interrupt
handler should turn interrupts on as soon as possible, however, so that
other interrupts can be processed.
The \verb|sa_restorer| variable is not currently used, and is traditionally
set to \verb|NULL|\@.
The \verb|request_irq()| and \verb|irqaction()| functions will return zero
if the IRQ was successfully assigned to the specified interrupt handler
routine. Non-zero result codes may be interpreted as follows:
\begin{desc}{{\tt -EINVAL}}
\item[{\tt -EINVAL}] Either the IRQ requested was larger than 15, or a
\verb|NULL| pointer was passed instead of a valid pointer to the
interrupt handler routine.
\item[{\tt -EBUSY}] The IRQ requested has already been allocated to another
interrupt handler. This situation should never occur, and is reasonable
cause for a call to \verb|panic()|.
\end{desc}
The kernel uses an Intel ``interrupt gate'' to set up IRQ handler routines
requested via the \verb|irqaction()| function. The Intel i486 manual
\cite[p.~9-11]{i486.manual} explains the interrupt gate as follows:
\begin{singlespace}
\begin{quotation}
Interrupts using\ldots interrupt gates\ldots cause the TF flag [trap
flag] to be cleared after its current value is saved on the stack as
part of the saved contents of the EFLAGS register. In so doing, the
processor prevents instruction tracing from affecting interrupt
response. A subsequent IRET [interrupt return] instruction restores
the TF flag to the value in the saved contents of the EFLAGS register
on the stack.
\ldots{} An interrupt which uses an interrupt gate clears the IF flag
[in\-ter\-rupt-enable flag], which prevents other interrupts from
interfering with the current interrupt handler. A subsequent IRET
instruction restores the IF flag to the value in the saved contents of
the EFLAGS register on the stack.
\end{quotation}
\end{singlespace}
\paragraph{Requesting the DMA channel}
Some SCSI host adapters use DMA to access large blocks of data in memory.
Since the CPU does not have to deal with the individual DMA requests, data
transfers are faster than CPU-mediated transfers and allow the CPU to do
other useful work during a block transfer (assuming interrupts are
enabled).
The host adapter will use a specific DMA channel. This DMA channel will be
determined by the \verb|detect()| function and requested from the kernel
with the \verb|request_dma()| function. This function takes the DMA
channel number as its only parameter and returns zero if the DMA channel
was successfully allocated. Non-zero results may be interpreted as
follows:
\begin{desc}{{\tt -EINVAL}}
\item[{\tt -EINVAL}] The DMA channel number requested was larger than 7.
\item[{\tt -EBUSY}] The requested DMA channel has already been allocated.
This is a very serious situation, and will probably cause any SCSI
requests to fail. It is worthy of a call to \verb|panic()|.
\end{desc}
\subsubsection{{\tt info()}}
The \verb|info()| function merely returns a pointer to a static area
containing a brief description of the low-level driver. This description,
which is similar to that pointed to by the \verb|name| variable, will be
printed at boot time.
\subsubsection{{\tt queuecommand()}}
\label{sec:queuecommand}
The {\tt queuecommand()} function sets up the host adapter for processing
a SCSI command and then returns. When the command is finished, the
\verb|done()| function is called with the \verb|Scsi_Cmnd| structure
pointer as a parameter. This allows the SCSI command to be executed in an
interrupt-driven fashion. Before returning, the \verb|queuecommand()|
function must do several things:
\begin{enumerate}
\item Save the pointer to the \verb|Scsi_Cmnd| structure.
\item Save the pointer to the \verb|done()| function in the
\verb|scsi_done()| function pointer in the \verb|Scsi_Cmnd| structure.
See section~\ref{sec:done} for more information.
\item Set up the special \verb|Scsi_Cmnd| variables required by the driver.
See section~\ref{sec:scsi.cmnd} for detailed information on the
\verb|Scsi_Cmnd| structure.
\item Start the SCSI command. For an advanced host adapter, this may be as
simple as sending the command to a host adapter ``mailbox.'' For less
advanced host adapters, the ARBITRATION phase is manually started.
\end{enumerate}
The \verb|queuecommand()| function is called {\em only\/} if the
\verb|can_queue| variable (see section~\ref{sec:can.queue}) is non-zero.
Otherwise the \verb|command()| function is used for all SCSI requests. The
\verb|queuecommand()| function should return zero on success (the current
high-level SCSI code presently ignores the return value).
\subsubsection{{\tt done()}}
\label{sec:done}
The \verb|done()| function is called after the SCSI command completes. The
single parameter that this command requires is a pointer to the same
\verb|Scsi_Cmnd| structure that was previously passed to the
\verb|queuecommand()| function. Before the \verb|done()| function is
called, the \verb|result| variable must be set correctly. The
\verb|result| variable is a 32~bit integer, each byte of which has
specific meaning:
\begin{desc}{Byte 3 (MSB)}
\item[Byte 0 (LSB)] This byte contains the SCSI STATUS code for the
command, as described in section~\ref{sec:status}.
\item[Byte 1] This byte contains the SCSI MESSAGE, as described in
section~\ref{sec:message}.
\item[Byte 2] This byte holds the host adapter's return code. The valid
codes for this byte are given in \verb|scsi.h| and are described below:
\begin{desc}{{\tt DID\_NO\_CONNECT}}
\item[{\tt DID\_OK}] No error.
\item[{\tt DID\_NO\_CONNECT}] SCSI SELECTION failed because there was no
device at the address specified.
\item[{\tt DID\_BUS\_BUSY}] SCSI ARBITRATION failed.
\item[{\tt DID\_TIME\_OUT}] A time-out occurred for some unknown reason,
probably during SELECTION or while waiting for RE\-SE\-LEC\-TION\@.
\item[{\tt DID\_BAD\_TARGET}] The SCSI ID of the target was the same as
the SCSI ID of the host adapter.
\item[{\tt DID\_ABORT}] The high-level code called the low-level
\verb|abort()| function (see section~\ref{sec:abort}).
\item[{\tt DID\_PARITY}] A SCSI PARITY error was detected.
\item[{\tt DID\_ERROR}] An error occurred which lacks a more appropriate
error code (for example, an internal host adapter error).
\item[{\tt DID\_RESET}] The high-level code called the low-level
\verb|reset()| function (see section~\ref{sec:reset}).
\item[{\tt DID\_BAD\_INTR}] An unexpected interrupt occurred {\em and\/}
there is no appropriate way to handle this interrupt.
\end{desc}
Note that returning \verb|DID_BUS_BUSY| will force the command to be
retried, whereas returning \verb|DID_NO_CONNECT| will abort the command.
\item[Byte 3 (MSB)] This byte is for a high-level return code, and should
be left as zero by the low-level code.
\end{desc}
Current low-level drivers do not uniformly (or correctly) implement error
reporting, so it may be better to consult {\tt scsi.c} to determine exactly
how errors should be reported, rather than exploring existing drivers.
\subsubsection{{\tt command()}}
The \verb|command()| function processes a SCSI command and returns when the
command is finished. When the original SCSI code was written,
interrupt-driven drivers were not supported. The old drivers are much less
efficient (in terms of response time and latency) than the current
interrupt-driven drivers, but are also much easier to write. For new
drivers, this command can be replaced with a call to the
\verb|queuecommand()| function, as demonstrated in
Figure~\ref{fig:command}.\footnote{\Linux{} 0.99.5 kernel, {\tt
linux/kernel/blk\_drv/scsi/aha1542.c}, written by Tommy Thorn.}
\begin{figure}[hbtp]
\leavevmode
\begin{center}
\begin{verbatim}
static volatile int internal_done_flag = 0;
static volatile int internal_done_errcode = 0;
static void internal_done( Scsi_Cmnd *SCpnt )
{
internal_done_errcode = SCpnt->result;
++internal_done_flag;
}
int aha1542_command( Scsi_Cmnd *SCpnt )
{
aha1542_queuecommand( SCpnt, internal_done );
while (!internal_done_flag);
internal_done_flag = 0;
return internal_done_errcode;
}
\end{verbatim}
\caption{Example {\tt command()} Function}
\label{fig:command}
\end{center}
\end{figure}
The return value is the same as the \verb|result| variable in the
\verb|Scsi_Cmnd| structure. Please see sections~\ref{sec:done} and
\ref{sec:scsi.cmnd} for more details.
\subsubsection{{\tt abort()}}
\label{sec:abort}
The high-level SCSI code handles all timeouts. This frees the low-level
driver from having to do timing, and permits different timeout periods to
be used for different devices (e.g., the timeout for a SCSI tape drive is
nearly infinite, whereas the timeout for a SCSI disk drive is relatively
short).
The {\tt abort()} function is used to request that the currently
outstanding SCSI command, indicated by the \verb|Scsi_Cmnd| pointer, be
aborted. After setting the \verb|result| variable in the \verb|Scsi_Cmnd|
structure, the \verb|abort()| function returns zero. If \verb|code|, the
second parameter to the \verb|abort()| function, is zero, then
\verb|result| should be set to \verb|DID_ABORT|\@. Otherwise,
\verb|result| shoudl be set equal to \verb|code|\@. If \verb|code| is not
zero, it is usually \verb|DID_TIME_OUT| or \verb|DID_RESET|\@.
Currently, none of the low-level drivers is able to correctly abort a SCSI
command. The initiator should request (by asserting the \verb|-ATN| line)
that the target enter a MESSAGE OUT phase. Then, the initiator should send
an ABORT message to the target.
\subsubsection{{\tt reset()}}
\label{sec:reset}
The {\tt reset()} function is used to reset the SCSI bus. After a SCSI bus
reset, any executing command should fail with a \verb|DID_RESET| result
code (see section~\ref{sec:done}).
Currently, none of the low-level drivers handles resets correctly. To
correctly reset a SCSI command, the initiator should request (by asserting
the \verb|-ATN| line) that the target enter a MESSAGE OUT phase. Then, the
initiator should send a BUS DEVICE RESET message to the target. It may
also be necessary to initiate a SCSI RESET by asserting the \verb|-RST|
line, which will cause all target devices to be reset. After a reset, it
may be necessary to renegotiate a synchronous communications protocol with
the targets.
\subsubsection{{\tt slave\_attach()}}
The {\tt slave\_attach()} function is {\em not\/} currently implemented.
This function would be used to negotiate 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 \cite{lxt.manual}:
\begin{singlespace}
\begin{quotation}
A SCSI device that supports synchronous data transfer recognizes it has
not communicated with the other SCSI device since receiving the last
``hard'' RESET\@.
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.
\end{quotation}
\end{singlespace}
\subsubsection{{\tt bios\_param()}}
\Linux{} supports the MS-DOS\footnote{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\@.)
\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()} function was introduced in an attempt to
provide access to the host adapter geometry information.
The \verb|size| 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 \verb|dev| parameter contains the drive's device number. Two
macros are defined in \verb|linux/fs.h| which will help to interpret this
value: \verb|MAJOR(dev)| is the device's major number, and
\verb|MINOR(dev)| is the device's minor number. These are the same major
and minor device numbers used by the standard \Linux{} {\tt mknod} command
to create the device in the {\tt /dev} directory. The \verb|info|
parameter points to an array of three integers that the \verb|bios_param()|
function will fill in before returning:
\begin{singlespace}
\begin{center}
\begin{desc}{{\tt info[2]}}
\item[{\tt info[0]}] Number of heads
\item[{\tt info[1]}] Number of sectors per cylinder
\item[{\tt info[2]}] Number of cylinders
\end{desc}
\end{center}
\end{singlespace}
The information in \verb|info| is {\em not\/} the physical geometry of the
drive, but only a {\em logical\/} geometry that is identical to the {\em
logical\/} geometry used by MS-DOS to access the drive. The distinction
between physical and logical geometry cannot be overstressed.
\section{The {\tt Scsi\_Cmnd} Structure}
\label{sec:scsi.cmnd}
The \verb|Scsi_Cmnd| structure,\footnote{\Linux{} 0.99.7 kernel, {\tt
linux/kernel/blk\_drv/scsi/scsi.h}} as shown in
Figure~\ref{fig:scsi.cmnd}, is used by the high-level code to specify a
SCSI command for execution by the low-level code. Many variables in the
\verb|Scsi_Cmnd| structure can be ignored by the low-level device
driver---other variables, however, are extremely important.
\begin{figure}[hbtp]
\leavevmode
\begin{center}
\begin{verbatim}
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;
\end{verbatim}
\caption{The {\tt Scsi\_Cmnd} Structure}
\label{fig:scsi.cmnd}
\end{center}
\end{figure}
\subsection{Reserved Areas}
\subsubsection{Informative Variables}
\verb|host| is an index into the \verb|scsi_hosts| array.
\verb|target| 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.
\verb|cmnd| is an array of bytes which hold the actual SCSI command. These
bytes should be sent to the SCSI target during the COMMAND phase.
\verb|cmnd[0]| is the SCSI command code. The \verb|COMMAND_SIZE| macro,
defined in \verb|scsi.h|, can be used to determine the length of the
current SCSI command.
\verb|result| is used to store the result code from the SCSI request.
Please see section~\ref{sec:done} for more information about this variable.
This variable {\em must\/} be correctly set before the low-level routines
return.
\subsubsection{The Scatter-Gather List}
\verb|use_sg| contains a count of the number of pieces in the
scatter-gather chain. If \verb|use_sg| is zero, then \verb|request_buffer|
points to the data buffer for the SCSI command, and \verb|request_bufflen|
is the length of this buffer in bytes. Otherwise, \verb|request_buffer|
points to an array of \verb|scatterlist| structures, and \verb|use_sg| will
indicate how many such structures are in the array. The use of
\verb|request_buffer| is non-intuitive and confusing.
Each element of the \verb|scatterlist| array contains an \verb|address| and
a \verb|length| component. If the \verb|unchecked_isa_dma| flag in the
\verb|Scsi_Host| structure is set to 1 (see section~\ref{sec:dma} 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 \verb|scatterlist|
array.
\subsection{Scratch Areas}
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.
\subsubsection{The {\tt scsi\_done()} Pointer}
This pointer should be set to the \verb|done()| function pointer in the
\verb|queuecommand()| function (see section~\ref{sec:queuecommand} for more
information). There are no other uses for this pointer.
\subsubsection{The {\tt host\_scribble} Pointer}
The high-level code supplies a pair of memory allocation functions,
\verb|scsi_malloc()| and \verb|scsi_free()|, 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 {\em
must\/} be a multiple of 512 bytes, and {\em must\/} be less than or
equal to 4096 bytes. The total amount of memory available via
\verb|scsi_malloc()| is a complex function of the \verb|Scsi_Host|
structure variables \verb|sg_tablesize|, \verb|cmd_per_lun|, and
\verb|unchecked_isa_dma|.
The \verb|host_scribble| pointer is available to point to a region of
memory allocated with \verb|scsi_malloc()|. 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.
\subsubsection{The {\tt Scsi\_Pointer} Structure}
The \verb|SCp| variable, a structure of type \verb|Scsi_Pointer|, is
described in Figure~\ref{fig:scsi.pointer}.
\begin{figure}[hbtp]
\leavevmode
\begin{center}
\begin{verbatim}
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;
\end{verbatim}
\caption{The {\tt Scsi\_Pointer} Structure}
\label{fig:scsi.pointer}
\end{center}
\end{figure}
The variables in this structure can be used in {\em any\/} way necessary in
the low-level driver. Typically, \verb|buffer| points to the current entry
in the \verb|scatterlist|, \verb|buffers_residual| counts the number of
entries remaining in the \verb|scatterlist|, \verb|ptr| is used as a
pointer into the buffer, and \verb|this_residual| counts the characters
remaining in the transfer. Some host adapters require support of this
detail of interaction---others can completely ignore this structure.
The second set of variables provide convenient locations to store SCSI
status information and various pointers and flags.
\section{Acknowledgements}
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.
\begin{singlespace}
\bibliography{scsi}
\end{singlespace}
\end{document}