|
ASPI programming in Win32
Don't forget to check FROGASPI:
a *free* ASPI driver implemented by my friend Bertrand Danos. If you experience
troubles using ASPI with WinXP the solution is the following: replace WNASPI32.DLL with the DLL that comes with
FrogASPI. This DLL is not a copy of ASPI, it is a replacement. It works its own way (using SPT) but has the
same syntax of the old ASPI manager from Adaptec. Bertrand is working hard to make FrogASPI as much compatible as
he can with any existing software. He told me that release 1.0 will soon be released. (In the meantime you can use
release 0.xx).
|
General information for the programmer
Recommended SCSI hw & books from Amazon
Adaptec made it easy to deal with SCSI2 devices by
means of its ASPI drivers (ASPI stands for Advanced SCSI Programming
Interface).
ASPI provides an easy mean to:
- manage SCSI2 devices
- send them SCSI2 commands
According to my experience ASPI can also be used to manage SCSI3
devices and send them SCSI3 commands.
Long ago ASPI support was provided under DOS by an ASPI4DOS.SYS device
defined into the CONFIG.SYS file.
In Windows 3.1x support was provided by WINASPI.DLL.
Today in Win32 the support for ASPI programming is provided by
WNASPI32.DLL (not to be confused with WINASPI.DLL), APIX.VXD and
ASPIENUM.VXD under Windows
95, 98 and ME, and by WNASPI32.DLL and ASPI32.SYS under
Windows NT, 2000, XP. This support is the one we will be talking about.
To install ASPI support follow the link to ASPI32.EXE provided below.
Having the latest WNASPI32.DLL in the C:\WINDOWS\SYSTEM directory is the
minimal *prerequisite* for ASPI programming. In fact this DLL will at least let you call
GetASPI32SupportInfo (see below) and know whether ASPI support is properly
installed. If not, you will be returned a SS_NO_ASPI status code, meaning that some
file is missing (APIX.VXD and ASPIENUM.VXD under Win95-98-ME, and ASPI32.SYS under
WinNT-2000-XP), or you will be returned a SS_MISMATCHED_COMPONENTS meaning a version
conflict between these files.
Adaptec's used to help programmers providing them with the following:
- ASPI32.EXE: the utility to upgrade ASPI for Windows95 and WindowsNT
(
download page)
- ASPICHK.EXE: the ASPI installation verification utility, used to check
whether ASPI support is properly installed, and also used to know the current
installed version
(
download page)
- ASPI SDK: ASPI Software Development Kit, complete with its "ASPI for
Win32 Technical Reference, January 2nd, 1997"
Nowadays you can't download the ASPI SDK from Adaptec's site anymore, and
the ASPI SDK tech reference has just been replaced with a big text file
linked here.
No fear, anycase, and keep on reading: if
you are willing to send SCSI2 commands to SCSI2 devices by means of
ASPI support this tutorial is tailored for you.
The heart of ASPI programming is WNASPI32.DLL. Before using the DLL you
should load it with a LoadLibrary API call. Before exiting
the program you should unload the DLL with a FreeLibrary API call.
ASPI support provided by WNASPI32.DLL consists of five function calls
and eight ASPI commands for the programmer to use.
Among the five functions only two of them are important to learn
and use: GetASPI32SupportInfo and SendASPI32Command:
- GetASPI32SupportInfo takes no parameters, and is used to check
whether hardware and software are properly installed on the PC. It returns
a doubleword which must be split into three pieces. Bits 31-16 are unused and
set to zero. Bits 15-8 represent the status code. Bits 7-0
return the host adapters count (i.e. the number of installed host adapter
cards: if one card is fitted into the PC bus the count is 2 because the
IDE/EIDE controller is always "seen" by the ASPI support): this value should
be stored for subsequent inquiries. If the status code is
SS_COMP it means that ASPI support is OK. Other values (listed in the
SRB status section of WNASPI32.H)
will indicate the cause of the absence of the support, for example:
SS_NO_ADAPTERS indicates that the hardware is missing, or
SS_NO_ASPI indicates that the ASPI manager has not been found
- SendASPI32Command is the ASPI function used to execute the eight
ASPI commands provided by the ASPI support, and is covered in detail in the
following section:
SendASPI32Command is the general purpose function used to execute eight ASPI
commands.
Please keep ASPI commands *distinguished* from SCSI2 commands.
ASPI commands can be synchronous or asynchronous.
Synchronous ASPI commands, and their respective purposes are the following:
- Inquiry: retrieves information from the installed host adapters
- Get device type: retrieves the device type at a specific SCSI address
- Abort SRB: cancels a previous ASPI command
- Get disk info: retrieves BIOS information for SCSI2 disks (Win95 only)
- Rescan SCSI2 bus: requests a rescan fo the SCSI2 bus
- Get/set timeouts: gets/sets SRB timeouts for specific target devices
Asynchronous ASPI commands, and their respective purpose are the following:
- Exec SCSI2 command: sends a SCSI2 command to a SCSI2 target device
- Reset device: sends a Bus Device Reset message to a SCSI2 target device
Properly using the above ASPI commands is up to the programmer. The most
used ASPI commands are Inquiry, Get device type and Exec SCSI2 command.
Different examples are given into the language specific sections to be linked at the end
of this page.
Each ASPI command is assigned an ASPI command code as shown
in the following table:
ASPI command |
ASPI command code |
ASPI command type |
Inquiry |
SC_HA_INQUIRY |
synchronous |
Get device type |
SC_GET_DEV_TYPE |
synchronous |
Abort SRB |
SC_ABORT_SRB |
synchronous |
Get disk info |
SC_GET_DISK_INFO |
synchronous |
Rescan SCSI2 bus |
SC_RESCAN_SCSI_BUS |
synchronous |
Get/set timeouts |
SC_GETSET_TIMEOUTS |
synchronous |
Exec SCSI2 command |
SC_EXEC_SCSI_CMD |
asynchronous |
Reset device |
SC_RESET_DEV |
asynchronous |
|
.
|
SendASPI32Command takes one parameter, a long pointer to the SCSI2
Request Block (SRB for short).
The SRB is a structure that must be prepared before calling the function.
There are as many SRBs as the ASPI commands, according to this table:
|
ASPI command |
ASPI command code |
SRB to use with |
Inquiry |
SC_HA_INQUIRY |
SRB_HAInquiry |
Get device type |
SC_GET_DEV_TYPE |
SRB_GDEVBlock |
Abort SRB |
SC_ABORT_SRB |
SRB_Abort |
Get disk info |
SC_GET_DISK_INFO |
SRB_GetDiskInfo |
Rescan SCSI2 bus |
SC_RESCAN_SCSI_BUS |
SRB_RescanPort |
Get/set timeouts |
SC_GETSET_TIMEOUTS |
SRB_GetSetTimeouts |
Exec SCSI2 command |
SC_EXEC_SCSI_CMD |
SRB_ExecSCSICmd |
Reset device |
SC_RESET_DEV |
SRB_BusDeviceReset |
|
The first 8 bytes of any SRB are always the same, the remaining
bytes are command specific. Although ASPI command codes and SRB structures
are defined into WNASPI32.H and you can have
a look there, let's revise here the first 4 bytes:
- the first byte is the ASPI command code, see the table above for
each ASPI command
- the second byte (named SRB_Status) is the ASPI command status,
to be checked after any call to SendASPI32Command
- the third byte is the ASPI host adapter number, to be set according
to the numeration that the ASPI manager assigns to each installed adapter;
a wrong number makes the application program appear to do nothing
- the fourth byte is the ASPI request flags, must be set to zero
unless the ASPI command code is SC_EXEC_SCSI_CMD or SC_GETSET_TIMEOUTS
SendASPI32Command invoked for a synchronous ASPI command returns only
after the command has been completed. The ASPI_Status byte (ASPI
command status, see WNASPI32.H) must be checked
to know the result of the command.
SendASPI32Command invoked for an asynchronous ASPI command, on the contrary,
immediately returns the control to the calling program, and the
ASPI_Status is set to SS_PENDING. As soon as the ASPI command
is actually completed the ASPI_Status byte in the SRB structure will
contain the actual ASPI command status. (In the meantime the ASPI command is
not completed, the application program can release other ASPI commands).
How to make the program aware that the asynchronous ASPI command is
completed ? A very trivial method would be continuously testing the
ASPI_Status byte: as soon as it is changes from SS_PENDING to anything else
it means the ASPI command is completed, and the very byte represents the
actual return code from the SendASPI32Command call.
Another method would be posting the ASPI command and setting a callback
function to be called from the ASPI manager as soon the command is completed.
The third method, much more elegant, and the preferred one, is used in the
sample code provided later on in the language specific sections. It is the event
notification method, and it works like this: an event is created and
assigned to the SRB_PostProc member of the asyncronous ASPI command SRB
structure. The event is reset, then SendASPI32Command is called, and the
application program waits for a single object. When the ASPI command has
been completed the event is signalled, and the application program
can check the ASPI_Status byte to determine the final result of the ASPI
command. Simple and effective. Perfectly suitable when working with
threads, because WaitForSingleObject requires very little CPU time.
Please note that the second parameter of WaitForSingleObiect is the
timeout that limits the amount of time that the application must wait
for the event to be signalled. In well behaving application programs you can
usually set it to INFINITE, because command sequences generally start
with a TEST UNIT READY command, and the application must send no further
commands when the target responds that it is not ready. But when experimenting
it can be useful to set the timeout at some dozens of seconds, according
to the kind of operations you are experimenting with. Give the target time
enough to complete the experimental command sequence. If the sequence is
wrong, and the target will be busy forever, you will only wait for some
dozens of seconds, without the need to restart the frozen PC. Then reset
the SCSI bus by executing this code
and you are ready to test the next command sequence.
Exec SCSI2 command, as explained above, is the asynchronous ASPI
command used to send SCSI2 commands to SCSI2 devices.
For the following discussion it is good to remember that SCSI2 commands
can be broken into three cathegories:
- commands that are not followed by any data transfer
- commands that are followed by a data transfer from the target to the
host (INPUT commands, like READ, MODE SENSE, etc.)
- commands that are followed by a data transfer from the host to the
target (OUTPUT commands, like WRITE, MODE SELECT, etc.)
The SRB corresponding to Exec SCSI2 command ASPI command is worth
some discussion. This is the structure:
typedef struct
{
BYTE SRB_Cmd; // ASPI command code = SC_EXEC_SCSI_CMD
BYTE SRB_Status; // ASPI command status byte
BYTE SRB_HaId; // ASPI host adapter number
BYTE SRB_Flags; // ASPI request flags
DWORD SRB_Hdr_Rsvd; // Reserved
BYTE SRB_Target; // Target's SCSI ID
BYTE SRB_Lun; // Target's LUN number
WORD SRB_Rsvd1; // Reserved for Alignment
DWORD SRB_BufLen; // Data Allocation Length
BYTE FAR *SRB_BufPointer; // Data Buffer Pointer
BYTE SRB_SenseLen; // Sense Allocation Length
BYTE SRB_CDBLen; // CDB Length
BYTE SRB_HaStat; // Host Adapter Status
BYTE SRB_TargStat; // Target Status
VOID FAR *SRB_PostProc; // Post routine
BYTE SRB_Rsvd2[20]; // Reserved, MUST = 0
BYTE CDBByte[16]; // SCSI CDB
BYTE SenseArea[SENSE_LEN+2]; // Request Sense buffer
}
SRB_ExecSCSICmd, *PSRB_ExecSCSICmd, FAR *LPSRB_ExecSCSICmd;
The best way to use this SRB, just like any other SRB, is to fill it
with all zeroes, and then only fill the members that need to be
filled. Let's revise each member, pointing out any eventually relevant
information:
- SRB_Cmd - ASPI command code: set it to SC_EXEC_SCSI_CMD
- SRB_Status - ASPI command status byte: set it to zero. Upon
return it will be set to the proper ASPI status by the ASPI manager;
possible status are the following:
- SS_PENDING (0x00): the ASPI command is in progress
- SS_COMP (0x01): successful completion of the ASPI command
- SS_ABORTED (0x02): ASPI command aborted due to external events
- SS_ERR (0x04): an error occurred during the ASPI command
execution due to the host adapter, the target, or the SCSI bus itself;
examine the SRB_TargStat and the SRB_HaStat to get more information
- SS_INVALID_CMD (0x80): invalid SRB_Cmd (ASPI command code)
- SS_INVALID_HA (0x81): invalid host adapter number
- SS_NO_DEVICE (0x82): no device at SCSI-ID/LUN supplied in
SRB_Target and SRB_Lun
- SS_INVALID_SRB (0xE0): malformed SCSI Request Block; check
all the members of the structure
- SS_BUFFER_ALIGN (0xE1): don't know
- SS_ILLEGAL_MODE (0xE2): invalid temptative to use ASPI for
Win32 in a 16-bit environment such as Win32s or Win16
- SS_NO_ASPI (0xE3): ASPI support not properly installed
- SS_FAILED_INIT (0xE4): ASPI general internal failure
- SS_ASPI_IS_BUSY (0xE5): insufficient resources to complete
SendASPI32Command
- SS_BUFFER_TOO_BIG (0xE6): don't know
- SS_MISMATCHED_COMPONENTS (0xE7): ASPI support not propery
installed
- SS_NO_ADAPTERS (0xE8): ASPI support does not recognize any
host adapter plugged into the PC bus
- SS_INSUFFICIENT_RESOURCES (0xE9): low system resource for
ASPI to be initialized
- SRB_HaId - ASPI host adapter number: set it to the number of
the host adapter card the target is attached to; the number is assigned by the ASPI manager to each
SCSI2 host adapted card fitted into the PC bus; usually if there is
only one SCSI2 host adapter card it will be given the number 0; remember
that the IDE/EIDE controller is also given a number by the ASPI manager,
even if it is not a SCSI2 entity; to fugate any doubt you can run one
of the "scanning the SCSI2 bus" projects explained in these pages and get
the HaId for any controller installed on the motherboard
- SRB_Flags - ASPI request flags: you can OR one or more of the
following flags:
- SRB_DIR_SCSI (0x00): can't tell you the meaning; anycase its
use is always implicit because OR-ing something with zero doesn't change
the result...
- SRB_POSTING (0x01): enable ASPI posting, to be used when the
event notification method has been chosen to determine the completion of
asynchronous ASPI commands; I never used it because I prefer SRB_EVENT_NOTIFY
- SRB_ENABLE_RESIDUAL_COUNT (0x04): enable residual byte count
reporting, if supported, to be used with those commands that report the
residual byte count; whenever a data underrun occurs the SRB_BufLen
structure member will reflect the remaining bytes to transfer
- SRB_DIR_IN (0x08): to be used with those commands that are
followed by a data transfer from the target to the host (INPUT
commands)
- SRB_DIR_OUT (0x10): to be used with those commands that are
followed by a data transfer from the host to the target (OUTPUT
commands)
- SRB_EVENT_NOTIFY (0x40): enable ASPI event notification, to be
always used when the event notification method has been chosen to determine
the completion of asynchronous ASPI commands
- SRB_Hdr_Rsvd - Reserved: set it to zero
- SRB_Target - Target's SCSI ID: obvious meaning
- SRB_Lun - Target's LUN number: obvious meaning
- SRB_Rsvd1 - Reserved for Alignment: set it to zero
- SRB_BufLen - Data Allocation Length: set it to zero unless the
SCSI2 command is to be followed by a data transfer from the target to
the host (INPUT commands) or from the host to the target (OUTPUT
commands); in this case set it to the number of bytes of data that
is expected to be transferred; use it in conjunction with the following
Data Buffer Pointer
- FAR *SRB_BufPointer - Data Buffer Pointer: set it to zero unless
the SCSI2 command is to be followed by a data transfer from the target to
the host (INPUT commands) or from the host to the target (OUTPUT
commands); in this case set it to the pointer to the preallocated
buffer that will be used to receive or send the data; use it in conjunction
with the preceeding Data Allocation Length
- SRB_SenseLen - Sense Allocation Length: set it to SENSE_LEN (as
defined in WNASPI32.H or WNASPI32.INC depending on the programming
language you are using, C++ or ASM)
- SRB_CDBLen - CDB Length: set it to the length of the SCSI2
Command Descriptor Block; SCSI2 commands are usually 6, 10 or 12 bytes
long
- SRB_HaStat - Host Adapter Status: set it to zero, upon
return it will be set with the proper ASPI status by the ASPI manager
with one of the following:
- HASTAT_OK (0x00): host adapter status OK (no error)
- HASTAT_TIMEOUT (0x09): bus transaction timeout
- HASTAT_COMMAND_TIMEOUT (0x0B): SRB expired while waiting to
be processed
- HASTAT_MESSAGE_REJECT (0x0D): MESSAGE REJECTED received
while processing the SRB
- HASTAT_BUS_RESET (0x0E): unexpected bus reset occurred
- HASTAT_PARITY_ERROR (0x0F): parity error occurred
- HASTAT_REQUEST_SENSE_FAILED (0x10): REQUESTE SENSE failed
- HASTAT_SEL_TO (0x11): selection of the target timed out
(target not ready ?)
- HASTAT_DO_DU (0x12): data underrun or data overrun
- HASTAT_BUS_FREE (0x13): unexpected bus free
- HASTAT_PHASE_ERR (0x14): bus phase sequence failure
- SRB_TargStat - Target Status: set it to zero, upon
return it will be set with the proper ASPI status by the ASPI manager
with one of the following:
- STATUS_GOOD (0x00): target status OK (no error)
- STATUS_CHKCOND (0x02): target check condition occurred; the
sense data is automatically retrieved for you by the ASPI manager; check
it in the SenseArea of the SRB
- STATUS_BUSY (0x08): specified target/LUN is busy
- STATUS_RESCONF (0x18): target reservation conflict
- FAR *SRB_PostProc - Post routine: set it to the callback
procedure to be called when the ASPI command is completed if the command
competion method chosen is posting (SRB_POSTING in SRB_Flags); otherwise
set it to the handle of the event used to signal the command completion
is the event notify method has been chosen, the preferred method
(SRB_EVENT_NOTIFY in SRB_Flags)
- SRB_Rsvd2[20] - Reserved: set it to all zeroes
- CDBByte[16] - SCSI CDB: this is the place to put the SCSI2
Command Descriptor Block; use as many bytes as required, according to
the number in SRB_CDBLen; this member describes the SCSI2 command that
will be sent to the SCSI2 device; refer to the SCSI2 command reference
of the target device
- SenseArea[SENSE_LEN+2] - Request Sense buffer: set it to all
zeroes; in case of target check condition you will find this area
automatically filled with the sense data
Now you should turn to one of the following articles, according to the
programming language you are used to work with:
Hints for application developers:
Working with SCSI ? This is the book to buy: | |
|
|