ASPI for Win32 Specification

Read this specification to find out about
    *   How to program ASPI for Win32
    *   The syntax of ASPI for Win32 commands
    *   How to handle polling and posting of ASPI for Win32 SCSI requests
    *   How to migrate to ASPI for Win32

-------------------------------------------------------------------------------

Introduction

The Advanced SCSI Programming Interface (ASPI) has become an industry standard
SCSI software interface in the DOS, Windows, OS/2, and Netware environments.
ASPI allows developers to write device drivers and applications which are
independent of the specific host adapter platform used to connect SCSI
peripherals. With ASPI, there is a single driver managing the host bus
adapter, eliminating conflicts when multiple applications try to access the
SCSI bus at the same time.

With the arrival of Windows NT and Windows 95, ASPI must be extended to allow
applications to take full advantage of these new, 32-bit operating systems.
This specification describes the Advanced SCSI Programming Interface (ASPI)
for the Win32 environment.

Note: This specification defines the protocol between ASPI client
      applications and the ASPI Manager wnaspi32.dll. The specification does
      not describe the protocol between wnaspi32.dll and the target Win32
      environment, since this implementation may vary between operating
      systems.

-------------------------------------------------------------------------------

Using ASPI for Win32 - An Overview

The ASPI manager for Win32 is implemented as a Dynamic Link Library (DLL)
called wnaspi32.dll. ASPI function calls can be used to retrieve information
about installed SCSI host adapters and devices, and to execute SCSI I/O
requests. The ASPI for Win32 layer is fully re-entrant, supporting
multitasking and multithreaded operations. To use ASPI for Win32, the
following two functions must be imported from wnaspi32.dll into the client's
Win32 application.

    Function              Description
    --------------------  -----------------------------------------------------
    GetASPI32SupportInfo  This function returns the number of host adapters
                          installed and other miscellaneous information. You
                          should call this function to make sure that ASPI
                          is properly initialized before calling the
                          SendASPICommand function.
    SendASPI32Command     This function allows you to send an ASPI for Win16
                          command.
    --------------------  -----------------------------------------------------

Note: The structure definitions for ASPI for Win32 have changed from the
      structure definitions for ASPI for DOS and ASPI for Win16.  Please
      make sure that code meant for both platforms is conditionally compiled
      with the new structure defintitions.

-------------------------------------------------------------------------------

GetASPI32SupportInfo Function

Prototype: DWORD GetASPI32SupportInfo( VOID );

The GetASPI32SupportInfo function returns the number of host adapters
installed and ensures that the ASPI manager is initialized properly. This
function must be called once at initialization time, before SendASPI32Command
is accessed. The number of host adapters returned represents the logical bus
count, not the true physical adapter count. For host adapters with a single
bus, the host adapter count and logical bus count are identical.

The DWORD return value specifies the result of the ASPI request. The DWORD is
encoded as follows:

    Table 1: Return Values from GetASPI32SupportInfo Function

    Length  Bits   Description
    ------  -----  ------------------------------------------------------------
    WORD    31-16  Reserved = 0
    BYTE    15-8   Status
                   SS_COMP        = 00h = ASPI request completed without error
                   SS_FAILED_INIT = E4h = ASPI manager unable to initialize or
                                          ASPI services not available
    BYTE    7-0    Number of host adapters
    ------  -----  ------------------------------------------------------------

Example

This example returns the current status of ASPI for Win32.

    DWORD ASPIStatus;
    BYTE NumAdapters;
    HWND hwnd;
            .
            .
    ASPIStatus = GetASPI32SupportInfo();
    switch( HIBYTE(LOWORD(ASPIStatus)) )
    {
        case SS_COMP:
            /*
             * ASPI for Win32 is properly initialized
             */
            NumAdapters = LOBYTE(LOWORD(ASPIStatus));
            break;
        default:
            MessageBox( hwnd,
                        "ASPI for Win32 is not initialized!!",
                        NULL,
                        MB_ICONSTOP );
            return FALSE;
    }
            .
            .

-------------------------------------------------------------------------------

SendASPI32Command Function

Prototype: DWORD SendASPI32Command( LPSRB lpSRB );

The SendASPI32Command function handles all SCSI I/O requests. A command code
is used to specify the type of I/O requested. SendASPI32Command is called with
a pointer to a SCSI Request Block (SRB) structure. While SRB definition can
vary depending on the ASPI command code, all SRBs include a standard SRB
header:

    typedef struct
    {
        BYTE        SRB_Cmd;            // ASPI command code
        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, MUST = 0
    } SRB_Header;

The following SCSI I/O command codes are defined for use in the SRB_Cmd
field within the SendASPI32Command (each of these commands is described in
the following sections):

    Command           Value  Descriptiion
    ----------------  -----  --------------------------------------------------
    SC_HA_INQUIRY      00h   Get information about installed host adapters,
                             including the number of installed adapters.
    SC_GET_DEV_TYPE    01h   Get information about installed SCSI devices.
    SC_EXEC_SCSI_CMD   02h   Execute SCSI I/O.
    SC_ABORT_SRB       03h   Abort an outstanding I/O request.
    SC_RESET_DEV       04h   Reset an individual SCSI target.
    SC_GET_DISK_INFO   06h   Get information on disk type SCSI devices (not
                             available under Windows NT).
    ----------------  -----  --------------------------------------------------

Note: In the following sections, fields marked with 'R' are returned by the
      ASPI manager. Fields marked with 'W' are set by the ASPI client before
      they are sent to the ASPI manager. Fields marked as '-' are reserved and
      must be zeroed before the SRB is sent to the ASPI manager.

-------------------------------------------------------------------------------

Host Adapter Inquiry Command

Prototype: DWORD SendASPI32Command( LPSRB lpSRB );

The SendASPI32Command function with command code SC_HA_INQUIRY is used to get
information on the installed host adapter hardware, including the number of
host adapters installed. As previously stated, the number of host adapters
returned represents the logical bus count instead of the true physical adapter
count. For host adapters that support single bus only, the host adapter count
and logical bus count are identical. For host adapters that support multiple
buses, the host adapter count represents the total logical bus count.

lpSRB is a pointer to the following structure:

    Table 2: Host Adapter Inquiry Command

    typedef struct
    {
        BYTE        SRB_Cmd;            // ASPI command code = SC_HA_INQUIRY
        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, MUST = 0
        BYTE        HA_Count;           // Number of host adapters present
        BYTE        HA_SCSI_ID;         // SCSI ID of host adapter
        BYTE        HA_ManagerId[16];   // String describing the manager
        BYTE        HA_Identifier[16];  // String describing the host adapter
        BYTE        HA_Unique[16];      // Host Adapter Unique parameters
        WORD        HA_Rsvd1;
    } SRB_HAInquiry, *PSRB_HAInquiry;

    Offset   # Bytes  Description                                          R/W
    -------- -------- ---------------------------------------------------- ---
    00h (00) 01h (01) Command Code = SC_HA_INQUIRY (00h)                    W
    01h (01) 01h (01) Command Status. This byte always returns with a       R
                      non-zero status. A SCSI Request Completed Without
                      Error (01h) status indicates that the remaining
                      fields are valid.  See the table below for other
                      return codes for this command.
    02h (02) 01h (01) Host Adapter Number. This field specifies which       W
                      installed host adapter the request is intended for.
                      Host adapter numbers are assigned by the SCSI
                      manager layer, beginning with 0. An Invalid Host
                      Adapter Number (81h) status indicates that the
                      specified host adapter is not installed.
    03h (03) 01h (01) Reserved = 0                                          -
    04h (04) 04h (04) Reserved = 0                                          -
    08h (08) 01h (01) Number of Host Adapters. The ASPI manager sets this   R
                      field with the number of host adapters installed
                      under ASPI. For example, a return value of 2
                      indicates that host adapters #0 and #1 are valid.
                      To determine the total number of host adapters in
                      the system the SRB_HaId field (offset 02h) should
                      be set to 0, or GetASPISupportInfo can be used.
                      The number of host adapters returned represents the
                      logical bus count instead of the true physical
                      adaptec count.  For host adapters that support
                      single bus only, the host adapter count and logical
                      bus count are identical.
    09h (09) 01h (01) Host Adapter SCSI ID. The ASPI manager sets this      R
                      field with the SCSI ID of the given host adapter.
    0Ah (10) 10h (16) SCSI Manager ID. This field contains a 16-byte        R
                      ASCII string describing the SCSI manager.  For
                      ASPI for Win32 the string "ASPI for WIN32" shall
                      be returned.
    1Ah (26) 10h (16) Host Adapter Identifier. This field contains a        R
                      16-byte ASCII string describing the SCSI host
                      adapter.
    2Ah (42) 10h (16) Host Adapter Unique Parameters.  The buffer is        R
                      encoded as follows:
                      Byte 15-8 Reserved
                      Byte  7-4 Maximum transfer length.
                      Byte    3 Maximum SCSI targets.  Indicates the
                                maximum number of targets (SCSI IDs)
                                the adapter supports.  If this value
                                is not set, it is assumed that there
                                are 8 targets (SCSI IDs 0-7).
                      Byte    2 Adapter unique flags:
                                Bit 7-2 Reserved
                                Bit   1 1=Residual byte count supported
                                        0=Residual count not supported
                                Bit   0 Reserved
                      Byte  1-0 Buffer Alignment mask.  The host adapter
                                requires data buffer alignment specified
                                by the 16-bit value.  A value of 0x0000
                                means no boundary requirements (e.g.
                                byte alignment), 0x0001 word alignment,
                                0x0002 double-word, 0x0007 8-byte
                                alignment, etc.  The 16-bit value allows
                                buffer alignments of up to 65536-byte
                                boundaries.  Byte 1 is the most
                                significant byte of the field.
    3Ah (58) 02h (02) Reserved = 0                                          -
    -------- -------- ---------------------------------------------------- ---

The return value specifies the outcome of the function. One of the following
values is returned by ASPI for Win32:

    Table 3: Return Values from Host Adapter Inquiry Command

    Status            Value  Description
    ----------------  -----  --------------------------------------------------
    SS_COMP            01h   SCSI Request Completed Without Error
    SS_INVALID_HA      81h   Invalid Host Adapter Number
    ----------------  -----  --------------------------------------------------

Residual Byte Length

Residual byte length is the number of bytes not transferred to, or received
from, the target SCSI device. For example, if the ASPI buffer length for a
SCSI Inquiry command is set for 100 bytes, but the target only returns 36
bytes; the residual length is 64 bytes. If the ASPI buffer length for a SCSI
Write command is set for 514 bytes but the target only takes 512 bytes, the
residual length is 2 bytes. ASPI modules can determine if the loaded ASPI
manager supports residual byte length by issuing an Extended Host Adapter
Inquiry command, as described in the previous section.

Example

This example of the Host Adapter Inquiry command gets host adapter hardware
information from adapter #0.

    SRB_HAInquiry MySRB;
    WORD ASPI_Status;
                .
                .
    MySRB.SRB_Cmd      = SC_HA_INQUIRY;
    MySRB.SRB_HaId     = 0;
    MySRB.SRB_Flags    = 0;
    MySRB.SRB_Hdr_Rsvd = 0;
    ASPI_Status = SendASPI32Command ( (LPSRB) &MySRB );
                .
                .

-------------------------------------------------------------------------------

Get Device Type Command

Prototype: DWORD SendASPI32Command( LPSRB lpSRB );

The SendASPI32Command function with command code SC_GET_DEV_TYPE enables you
to identify the devices available on the SCSI bus. A Win32 tape backup
package, for example, can scan each target/LUN on each installed host adapter
looking for a device type corresponding to sequential access devices. This
eliminates the need for each Win32 application to duplicate the effort of
scanning the SCSI bus for devices.

lpSRB is a pointer to the following structure:

    Table 4: Get Device Type Command

    typedef struct
    {
        BYTE        SRB_Cmd;            // ASPI command code = SC_GET_DEV_TYPE
        BYTE        SRB_Status;         // ASPI command status byte
        BYTE        SRB_HaId;           // ASPI host adapter number
        BYTE        SRB_Flags;          // Reserved
        DWORD       SRB_Hdr_Rsvd;       // Reserved
        BYTE        SRB_Target;         // Target's SCSI ID
        BYTE        SRB_Lun;            // Target's LUN number
        BYTE        SRB_DeviceType;     // Target's peripheral device type
        BYTE        SRB_Rsvd1;          // Reserved for alignment
    } SRB_GDEVBlock, *PSRB_GDEVBlock;

    Offset   # Bytes  Description                                          R/W
    -------- -------- ---------------------------------------------------- ---
    00h (00) 01h (01) Command Code = SC_GET_DEV_TYPE (01h)                  W
    01h (01) 01h (01) Command Status. This byte always returns with a       R
                      non-zero status. A SCSI Request Completed Without
                      Error (01h) status indicates that the specified
                      device is installed and the Peripheral Device Type
                      field is valid. A SCSI Device Not Installed Error
                      (82h) indicates that the Peripheral Device Type
                      field is not valid.
    02h (02) 01h (01) Host Adapter Number. This field specifies which       W
                      installed host adapter the request is intended for.
                      Host adapter numbers are assigned by the SCSI
                      manager layer, beginning with 0. An Invalid Host
                      Adapter Number (81h) status indicates that the
                      specified host adapter is not installed.
    03h (03) 01h (01) Reserved = 0                                          -
    04h (04) 04h (04) Reserved = 0                                          -
    08h (08) 01h (01) Target ID. This field indicates the SCSI ID of the    W
                      target device.
    09h (09) 01h (01) LUN. This field indicates the Logical Unit Number     W
                      (LUN) of the device.
    0Ah (10) 01h (01) Peripheral Device Type of Target/LUN. The ASPI        R
                      manager fills this field with the peripheral device
                      type, as previously reported by the SCSI Inquiry
                      command. Refer to any SCSI specification to learn
                      more about the SCSI Inquiry command.
    0Bh (11) 01h (01) Reserved = 0                                          -
    -------- -------- ---------------------------------------------------- ---

The return value specifies the outcome of the function. One of the following
values is returned by ASPI for Win32:

    Table 5: Return Values from Get Device Type Command

    Status            Value  Description
    ----------------  -----  --------------------------------------------------
    SS_COMP            01h   SCSI Request Completed Without Error
    SS_INVALID_HA      81h   Invalid Host Adapter Number
    SS_NO_DEVICE       82h   SCSI Device Not Installed
    ----------------  -----  --------------------------------------------------

Example

This example gets the peripheral device type from host adapter #0, target ID
#4, and LUN #0.

    SRB_GDEVBlock MySRB;
    DWORD ASPIStatus;
            .
            .
    MySRB.SRB_Cmd      = SC_GET_DEV_TYPE;
    MySRB.SRB_HaId     = 0;
    MySRB.SRB_Flags    = 0;
    MySRB.SRB_Hdr_Rsvd = 0;
    MySRB.SRB_Target   = 4;
    MySRB.SRB_Lun      = 0;
    ASPIStatus = SendASPI32Command( (LPSRB)&MySRB );
            .
    /****************************************************************/
    /* If MySRB.SRB_Status == SS_COMP, MySRB.SRB_DeviceType
    /* will contain the peripheral device type.
    /****************************************************************/
            .
            .

-------------------------------------------------------------------------------

Execute SCSI I/O Command

Prototype: DWORD SendASPI32Command( LPSRB lpSRB );

The SendASPI32Command function with command code SC_EXEC_SCSI_CMD is used to
execute a SCSI I/O command. Once an ASPI client has initialized, virtually all
I/O is performed with this command.

lpSRB is a pointer to the following structure (note that there are no longer
variable sized CDBs in Win32-this means that CDBs do not have to place the
sense data in a variable location as in Win16):

    Table 6: Execute SCSI I/O Command

    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        *SRB_BufPointer;    // Data Buffer Point
        BYTE        SRB_SenseLen;       // Sense Allocation Length
        BYTE        SRB_CDBLen;         // CDB Length
        BYTE        SRB_HaStat;         // Host Adapter Status
        BYTE        SRB_TargStat;       // Target Status
        void        (*SRB_PostProc)();  // Post routine
        void        *SRB_Rsvd2;         // Reserved
        BYTE        SRB_Rsvd3[16];      // Reserved for expansion
        BYTE        CDBByte[16];        // SCSI CDB
        BYTE        SenseArea[SENSE_LEN+2]; // Request Sense buffer
    } SRB_ExecSCSICmd, *PSRB_ExecSCSICmd;

    Offset   # Bytes  Description                                          R/W
    -------- -------- ---------------------------------------------------- ---
    00h (00) 01h (01) Command Code = SC_EXEC_SCSI_CMD (02h)                 W
    01h (01) 01h (01) Command Status (see below).                           R
    02h (02) 01h (01) Host Adapter Number. This field specifies which       W
                      installed host adapter the request is intended for.
                      Host adapter numbers are assigned by the SCSI
                      manager layer, beginning with 0.
    03h (03) 01h (01) SCSI Request Flags (see below).                       W
    04h (04) 04h (04) Reserved = 0                                          -
    08h (08) 01h (01) Target ID. This field specifies the target ID of      W
                      the peripheral device involved in the I/O
                      operation.
    09h (09) 01h (01) LUN. This field specifies the LUN of the peripheral   W
                      device involved in the I/O operation.
    0Ah (10) 02h (02) Reserved = 0                                          -
    0Ch (12) 04h (04) Data Allocation Length. This field indicates the     R/W
                      number of bytes to be transferred. If the SCSI
                      command to be executed does not transfer data
                      (i.e., Rewind, Start Unit, etc.) the Data
                      Allocation Length MUST be set to zero. If residual
                      byte length is supported and selected, this field
                      is returned with the residual number of bytes.
    10h (16) 04h (04) Data Buffer Pointer.
    14h (20) 01h (01) Sense Allocation Length (N). This field indicates     W
                      the number of bytes allocated at the end of the SRB
                      for sense data. A request sense is automatically
                      generated if a check condition is presented at the
                      end of a SCSI command.
    15h (21) 01h (01) SCSI CDB Length (M). This field establishes the       W
                      length, in bytes, of the SCSI Command Descriptor
                      Block (CDB).
    16h (22) 01h (01) Host Adapter Status.                                  R
                      00h - Host adapter did not detect any error
                      09h - The time allocated for the transaction ran out
                      0Bh - SRB expired (timed out) while waiting to be
                            processed
                      0Dh - While processing SRB, the adapter received
                            a MESSAGE REJECT.
                      0Eh - A bus reset was detected
                      0Fh - A parity error was detected
                      10h - An auto request sense failed
                      11h - Selection time-out
                      12h - Data overrun/underrun
                      13h - Unexpected Bus Free
                      14h - Target Bus phase sequence failure
    17h (23) 01h (01) Target Status.                                        R
                      00h - No target status
                      02h - Check status (sense data is in sense
                            allocation area)
                      08h - Specified target/LUN is busy
                      18h - Reservation conflict
    18h (24) 04h (04) Post Routine Address - If posting is enabled
                      (SRB_POSTING flag), this field contains a pointer
                      to a function.  ASPI for Win32 calls this function
                      upon completion of an ASPI request.  If event
                      notification (SRB_EVENT_NOTIFY flag) is enabled,
                      this field contains a handle to an event.  ASPI
                      for Win32 signals this event upon completion of
                      an ASPI request.
    1Ch (28) 14h (20) Reserved = 0                                          -
    30h (48) 10h (16) SCSI Command Descriptor Block (CDB). This field       W
                      contains the CDB as defined by the target's SCSI
                      command set. The actual length of the SCSI CDB is
                      specified in the SCSI Command Length field, but
                      this buffer is ALWAYS 16 bytes in Win32.
    40h (64) N        Sense Allocation Area. This field is filled with      R
                      sense data on a check condition. The maximum length
                      of this field is specified in the Sense Allocation
                      Length field. The target can return fewer than the
                      number of sense bytes requested.
    -------- -------- ---------------------------------------------------- ---

The SRB_Flags are defined below.  These flags may be OR'd together to form
the final value for SRB_Flags in the SRB.  Note that SRB_POSTING and
SRB_EVENT_NOTIFY are mutually exclusive, as are SRB_DIR_IN and SRB_DIR_OUT.  In
addition, the directioin bits (SRB_DIR_IN and SRB_DIR_OUT) MUST be set
correctly on commands which transfer data.  Using SRB_DIR_SCSI is no longer
an option as in ASPI for DOS and ASPI for Win16.

    SRB_Flags                 Value Description
    ------------------------- ----- -------------------------------------------
    SRB_POSTING                01h  Enable ASPI command completion posting. See
                                    section on posting below.
    SRB_ENABLE_RESIDUAL_COUNT  04h  Enables reporting of residual byte count.
                                    This flag is only significant if the host
                                    adapter reports support for residual byte
                                    count in the SC_HA_INQUIRY command.  When
                                    data underrun occurs, the SRB_BufLen field
                                    is updated to reflect the remaining bytes
                                    to transfer.
    SRB_DIR_IN                 08h  Data transfer from SCSI target to host.
    SRB_DIR_OUT                10h  Data transfer from host to SCSI target.
    SRB_EVENT_NOTIFY           40h  Enable ASPI command event notification. See
                                    section on event notification below.
    ------------------------- ----- -------------------------------------------

The return value specifies the outcome of the function. ASPI for Win32 returns
one of the following values is SRB_Status (the result of the function call
itself is either SS_PENDING or SS_NO_DEVICE):

    Table 7: Return Values from Execute SCSI I/O Command

    Status            Value  Description
    ----------------  -----  --------------------------------------------------
    SS_PENDING         00h   SCSI request is in progress.
    SS_COMP            01h   SCSI/ASPI request has completed without error.
    SS_ABORTED         02h   SCSI command has been aborted.
    SS_ABORT_FAIL      03h   SCSI command abort failed.
    SS_ERR             04h   SCSI command has completed with an error.
    SS_INVALID_HA      81h   Invalid Host Adapter Number
    SS_INVALID_SRB     E0h   One or more parameters in the SCSI Request Block
                             (SRB) are set incorrectly.
    SS_BUFFER_ALIGN    E1h   The ASPI manager cannot handle the alignment on
                             this buffer.  You must force the buffer into the
                             alignment specified by the alignment mask returned
                             as part of the SC_HA_INQUIRY command.
    SS_ASPI_IS_BUSY    E5h   The ASPI manager cannot handle the request at this
                             time. This error generally occurs if the ASPI
                             manager is already using up all of his resources
                             to execute other requests. Try resending the
                             command later.
    SS_BUFFER_TO_BIG   E6h   The ASPI manager cannot handle the given transfer
                             size. Refer to Miscellaneous for more information.
    ----------------  -----  --------------------------------------------------

Example

This example sends a SCSI Inquiry command to host adapter #0, target #0, LUN
#0.

    SRB_ExecSCSICmd MySRB;
    DWORD ASPIStatus;
    char InquiryBuffer[32];
        .
        .
        .
    MySRB.SRB_Header     = SC_EXEC_SCSI_CMD;
    MySRB.SRB_HaId       = 0;
    MySRB.SRB_Flags      = SRB_DIR_IN | SRB_POSTING;
    MySRB.SRB_Hdr_Rsvd   = 0;
    MySRB.SRB_Target     = 0;
    MySRB.SRB_Lun        = 0;
    MySRB.SRB_BufLen     = 32;
    MySRB.SRB_SenseLen   = SENSE_LEN;
    MySRB.SRB_BufPointer = InquiryBuffer;
    MySRB.SRB_CDBLen     = 6;
    MySRB.RB_PostProc    = PostProcedure;
    MySRB.CDBByte[0]     = SCSI_INQUIRY;
    MySRB.CDBByte[1]     = 0;
    MySRB.CDBByte[2]     = 0;
    MySRB.CDBByte[3]     = 0;
    MySRB.CDBByte[4]     = 32;
    MySRB.CDBByte[5]     = 0;
        .
    /***************************************************/
    /* Make sure all other reserved fields are zeroed
    /* before passing the SRB to ASPI for Win32
    /***************************************************/
        .
    ASPIStatus = SendASPI32Command( (LPSRB)&MySRB );
        .
        .

-------------------------------------------------------------------------------

Abort SCSI I/O Command

Prototype: DWORD SendASPI32Command( LPSRB lpSRB );

The SendASPI32Command function with command code SC_ABORT_SRB is used to
request that a pending SRB be aborted. It should be issued on any I/O request
that has not completed if the application wishes to time-out on that request.
Success of the abort command is never assured.

lpSRB is a pointer to the following structure:

    Table 8: Abort SCSI I/O Command

    typedef struct
    {
        BYTE        SRB_Cmd;            // ASPI command code = SC_ABORT_SRB
        BYTE        SRB_Status;         // ASPI command status byte
        BYTE        SRB_HaId;           // ASPI host adapter number
        BYTE        SRB_Flags;          // Reserved
        DWORD       SRB_Hdr_Rsvd;       // Reserved
        void        *SRB_ToAbort;       // Pointer to SRB to abort
    } SRB_Abort, *PSRB_Abort;

    Offset   # Bytes  Description                                          R/W
    -------- -------- ---------------------------------------------------- ---
    00h (00) 01h (01) Command Code = SC_ARORT_SRB (03h)                     W
    01h (01) 01h (01) Command Status. This byte always returns with a       R
                      non-zero status. A SCSI Request Completed Without
                      Error (01h) status indicates that the remaining
                      fields are valid, and the abort will be attempted.
    02h (02) 01h (01) Host Adapter Number. This field specifies which       W
                      installed host adapter the request is intended for.
                      Host adapter numbers are assigned by the SCSI
                      manager layer, beginning with 0. An Invalid Host
                      Adapter Number (81h) status indicates that the
                      specified host adapter is not installed.
    03h (03) 01h (01) Reserved = 0                                          -
    04h (04) 04h (04) Reserved = 0                                          -
    08h (08) 04h (04) Pointer to SRB previously sent to SendASPI32Command
                      which is to now be aborted.
    -------- -------- ---------------------------------------------------- ---

The return value specifies the outcome of the function. One of the following
values is returned by ASPI for Win32:

    Table 9: Return Values from Abort SCSI I/O Command

    Status            Value  Description
    ----------------  -----  --------------------------------------------------
    SS_COMP            01h   SCSI/ASPI request has completed without error.
    SS_INVALID_HA      81h   Invalid Host Adapter Number
    SS_INVALID_SRB     E0h   One or more parameters in the SCSI Request Block
                             (SRB) are set incorrectly.
    ----------------  -----  --------------------------------------------------

Example

This example shows how to abort a "stuck" SCSI I/O.

    SRB_ExecSCSICmd StuckSRB;
    SRB_Abort AbortSRB;
    DWORD ASPIStatus;
        .
        .
    AbortSRB.SRB_Cmd      = SC_ABORT_SRB;
    AbortSRB.SRB_HaId     = 0;
    AbortSRB.SRB_Flags    = 0;
    AbortSRB.SRB_Hdr_Rsvd = 0;
    AbortSRB.SRB_ToAbort  = (LPSRB)&StuckSRB;
    ASPIStatus = SendASPI32Command ( (LPSRB)&AbortSRB );
        .
        .

-------------------------------------------------------------------------------

Reset SCSI Device Command

Prototype: DWORD SendASPI32Command( LPSRB lpSRB );

The SendASPI32Command function with command code SC_RESET_DEV is used to
send a SCSI Bus Device reset to the specified target.  At the present time
this function is not fully operational under Windows NT.  In particular,
requests for posting using this command are not processed.

lpSRB is a pointer to the following structure:

    Table 10: Reset SCSI Device Command

    typedef struct
    {
        BYTE        SRB_Cmd;            // ASPI command code = SC_RESET_DEV
        BYTE        SRB_Status;         // ASPI command status byte
        BYTE        SRB_HaId;           // ASPI host adapter number
        BYTE        SRB_Flags;          // Reserved
        DWORD       SRB_Hdr_Rsvd;       // Reserved
        BYTE        SRB_Target;         // Target's SCSI ID
        BYTE        SRB_Lun;            // Target's LUN number
        BYTE        SRB_Rsvd1[12];      // Reserved for Alignment
        BYTE        SRB_HaStat;         // Host Adapter Status
        BYTE        SRB_TargStat;       // Target Status
        void        *SRB_PostProc;      // Post routine
        void        *SRB_Rsvd2;         // Reserved
        BYTE        SRB_Rsvd3[32];      // Reserved
    } SRB_BusDeviceReset, *PSRB_BusDeviceReset;

    Offset   # Bytes  Description                                          R/W
    -------- -------- ---------------------------------------------------- ---
    00h (00) 01h (01) Command Code = SC_EXEC_SCSI_CMD (02h)                 W
    01h (01) 01h (01) Command Status (see below).                           R
    02h (02) 01h (01) Host Adapter Number. This field specifies which       W
                      installed host adapter the request is intended for.
                      Host adapter numbers are assigned by the SCSI
                      manager layer, beginning with 0.
    03h (03) 01h (01) SCSI Request Flags = 0 or SRB_POSTING.                W
    04h (04) 04h (04) Reserved = 0                                          -
    08h (08) 01h (01) Target ID. This field specifies the target ID of      W
                      the peripheral device to be reset.
    09h (09) 01h (01) LUN. This field specifies the LUN of the peripheral   W
                      device to be reset.  It is ignored by ASPI for Win32
                      since SCSI bus resets are done on a per-target basis
                      only.
    0Ah (10) 0Ch (12) Reserved = 0                                          -
    16h (22) 01h (01) Host Adapter Status.                                  R
                      00h - Host adapter did not detect any error
                      09h - The time allocated for the transaction ran out
                      0Bh - SRB expired (timed out) while waiting to be
                            processed
                      0Dh - While processing SRB, the adapter received
                            a MESSAGE REJECT.
                      0Eh - A bus reset was detected
                      0Fh - A parity error was detected
                      10h - An auto request sense failed
                      11h - Selection time-out
                      12h - Data overrun/underrun
                      13h - Unexpected Bus Free
                      14h - Target Bus phase sequence failure
    17h (23) 01h (01) Target Status.                                        R
                      00h - No target status
                      02h - Check status (sense data is in sense
                            allocation area)
                      08h - Specified target/LUN is busy
                      18h - Reservation conflict
    18h (24) 04h (04) Post Routine Address - If posting is enabled
                      (SRB_POSTING flag), this field contains a pointer
                      to a function.  ASPI for Win32 calls this function
                      upon completion of an ASPI request.
    1Ch (28) 24h (36) Reserved = 0                                          -
    -------- -------- ---------------------------------------------------- ---

The return value specifies the outcome of the function. ASPI for Win32 returns
one of the following values:

    Table 11: Return Values from Reset SCSI Device Command

    Status            Value  Description
    ----------------  -----  --------------------------------------------------
    SS_PENDING         00h   SCSI request is in progress.
    SS_COMP            01h   SCSI/ASPI request has completed without error.
    SS_ABORTED         02h   SCSI command has been aborted.
    SS_ABORT_FAIL      03h   SCSI command abort failed.
    SS_ERR             04h   SCSI command has completed with an error.
    SS_INVALID_SRB     E0h   One or more parameters in the SCSI Request Block
                             (SRB) are set incorrectly.
    ----------------  -----  --------------------------------------------------

Example

This example issues a SCSI bus device reset to host adapter #0, target #5.

    SRB_BusDeviceReset MySRB;
    DWORD ASPIStatus;
        .
        .
    MySRB.SRB_Header   = SC_RESET_DEV;
    MySRB.SRB_HaId     = 0;
    MySRB.SRB_Flags    = 0;
    MySRB.SRB_Hdr_Rsvd = 0;
    MySRB.SRB_Target   = 5;
    MySRB.SRB_Lun      = 0;
    ASPIStatus = SendASPI32Command ( (LPSRB) &MySRB );
        .
        .

-------------------------------------------------------------------------------

Get SCSI Disk Information Command

Prototype: DWORD SendASPI32Command( LPSRB lpSRB );

The SendASPI32Command function with command code SC_GET_DISK_INFO is used to
obtain information about a disk type SCSI device. The information returned
includes BIOS Int 13h control and accessibility of the device, the drive's Int
13h physical drive number, and the geometry used by the Int 13h services for
the drive.

Note: This command is not valid for Windows NT, which does not use the Int 13
      interface.

lpSRB is a pointer to the following structure:

    Table 12: Get SCSI Disk Information Command

    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;          // Reserved
        DWORD       SRB_Hdr_Rsvd;       // Reserved
        BYTE        SRB_Target;         // Target's SCSI ID
        BYTE        SRB_Lun;            // Target's LUN number
        BYTE        SRB_DriveFlags;     // Driver flags
        BYTE        SRB_Int13HDriveInfo;// Host Adapter Status
        BYTE        SRB_Heads;          // Preferred number of heads translation
        BYTE        SRB_Sectors;        // Preferred number of sectors translation
        BYTE        SRB_Rsvd1[10];      // Reserved
    } SRB_GetDiskInfo, *PSRB_GetDiskInfo;

    Offset   # Bytes  Description                                          R/W
    -------- -------- ---------------------------------------------------- ---
    00h (00) 01h (01) Command Code = SC_GET_DISK_INFO (06h)                 W
    01h (01) 01h (01) Command Status. ASPI managers that support this       R
                      command code always return with a status of SCSI
                      Request Completed Without Error (01h). ASPI
                      managers that do not support this command code
                      always return with a status of Invalid SCSI Request
                      (80h).
    02h (02) 01h (01) Host Adapter Number. This field specifies which       W
                      installed host adapter the request is intended for.
                      Host adapter numbers are assigned by the SCSI
                      manager layer, beginning with 0. An Invalid Host
                      Adapter Number (81h) status indicates that the
                      specified host adapter is not installed.
    03h (03) 01h (01) SCSI Request Flags. This field is currently           -
                      undefined for this command and should be zero
    04h (04) 04h (04) Reserved = 0                                          -
    08h (08) 01h (01) Target ID. This field indicates the SCSI ID of the    W
                      target device.
    09h (09) 01h (01) LUN. This field indicates the Logical Unit Number     W
                      (LUN) of the device.
    0Ah (10) 01h (01) Drive Flags                                           R
                      Bits 7-2  Reserved
                      Bits 1-0  These bits return information pertaining
                                to the Int 13 drive field:
                                00 The given drive (HA #/Target/LUN) is
                                   not accessible via Int 13h. If you wish
                                   to read/write to this drive, you must
                                   send ASPI read/write requests to the
                                   drive. The Int 13h Drive field is
                                   invalid.
                                01 The given drive (HA #/Target/LUN) is
                                   accessible via Int 13h. The Int 13h
                                   Drive field contains the drive's Int
                                   13h drive number. This drive is under
                                   the control of DOS.
                                10 The given drive (HA #/Target/LUN) is
                                   accessible via Int 13h. The Int 13h
                                   Drive field contains the drive's Int
                                   13h drive number. This drive is not
                                   under control of DOS and can be used,
                                   for example, by a SCSI Disk Driver.
                                11 Invalid.
    0Bh (11) 01h (01) Int 13h Drive. This field returns the Int 13 drive    R
                      number for the given host adapter number, target
                      ID, and LUN. Valid Int 13 drive numbers range for
                      00-FFh.
    0Ch (12) 01h (01) Preferred Head Translation. This field indicates      R
                      the given host adapter's/disk drive's preferred
                      head translation method. A typical value is 64
                      heads.
    0Dh (13) 01h (01) Preferred Sector Translation. This field indicates    R
                      the given host adapter's/disk drive's preferred
                      sector translation method. A typical value is 32
                      sectors per track.
    0Eh (14) 0Ah (10) Reserved = 0                                          -
    -------- -------- ---------------------------------------------------- ---

The return value specifies the outcome of the function. ASPI for Win32 returns
one of the following values:

    Table 4-13. Return Values from Get SCSI Disk Information Command

    Status            Value  Description
    ----------------  -----  --------------------------------------------------
    SS_COMP            01h   SCSI/ASPI request has completed without error.
    SS_INVALID_HA      81h   Invalid Host Adapter Number
    SS_INVALID_SRB     E0h   One or more parameters in the SCSI Request Block
                             (SRB) are set incorrectly.
    ----------------  -----  --------------------------------------------------

Example

This example obtains disk information from device LUN 0, SCSI ID 2, attached to
host adapter #0.

    SRB_GetDiskInfo MySRB;
    DWORD ASPIStatus;
        .
        .
    MySRB.SRB_Cmd      = SC_GET_DISK_INFO;
    MySRB.SRB_HaId     = 0;
    MySRB.SRB_Flags    = 0;
    MySRB.SRB_Hdr_Rsvd = 0;
    MySRB.SRB_Target   = 2;
    MySRB.SRB_Lun      = 0;
    ASPIStatus = SendASPI32Command ( (LPSRB) &MySRB );
        .
        .

-------------------------------------------------------------------------------

Rescan SCSI Port Command

Prototype: DWORD SendASPI32Command( LPSRB lpSRB );

The SendASPI32Command function with command code SC_RESCAN_SCSI_BUS is used to
rescan the SCSI bus for targets which may have been powered on after the
system was started.  This command is only available under ASPI for Win32 under
Windows NT.

lpSRB is a pointer to the following structure:

    Table 11: Rescan SCSI Port Command

    typedef struct
    {
        BYTE    SRB_Cmd;                // ASPI code = SC_RESCAN_SCSI_BUS
        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, MUST = 0
    } SRB_RescanPort, *PSRB_RescanPort;

    Offset   # Bytes  Description                                          R/W
    -------- -------- ---------------------------------------------------- ---
    00h (00) 01h (01) Command Code = SC_RESCAN_SCSI_BUS (07h)               W
    01h (01) 01h (01) Command Status (see below).                           R
    02h (02) 01h (01) Host Adapter Number. This field specifies which       W
                      installed host adapter the request is intended for.
                      Host adapter numbers are assigned by the SCSI
                      manager layer, beginning with 0.
    03h (03) 01h (01) SCSI Request Flags = 0                                W
    04h (04) 04h (04) Reserved = 0                                          -
    -------- -------- ---------------------------------------------------- ---

The return value specifies the outcome of the function. ASPI for Win32 returns
one of the following values:

    Table 12: Return Values from Rescan SCSI Port Command

    Status            Value  Description
    ----------------  -----  --------------------------------------------------
    SS_COMP            01h   SCSI/ASPI request has completed without error.
    SS_INVALID_HA      81h   Invalid Host Adapter Number
    SS_NO_DEVICE       82h   SCSI Device Not Installed
    ----------------  -----  --------------------------------------------------

Example

This example forces a rescan of all devices attached to host adapter #0:

    SRB_RescanPort MySRB;
    DWORD ASPIStatus;
        .
        .
    MySRB.SRB_Cmd      = SC_RESCAN_SCSI_BUS;
    MySRB.SRB_HaId     = 0;
    MySRB.SRB_Flags    = 0;
    MySRB.SRB_Hdr_Rsvd = 0;
    ASPIStatus = SendASPI32Command ( (LPSRB) &MySRB );
        .
        .

-------------------------------------------------------------------------------

Request Completion/Notification

Once an ASPI for Win32 SCSI request has been sent to the ASPI manager, there
are three ways of being notified that the SCSI request has completed. The
first and recommended method uses event notification. The second method uses
callback (also referred to as posting). The third method uses polling.

-------------------------------------------------------------------------------

Using Event Notification

Event notification is an ideal mechanism for notifying ASPI clients of the
completion of an ASPI request.  ASPI clients may block on this event until
completion. Upon completion of a request, the ASPI for Win32 manager will set
the event to the signaled state. The ASPI client is responsible for making
sure that the event is not in a signaled state when an ASPI command request is
submitted to the ASPI for WIN32 manager.  The following sample code
illustrates event notification. The sample code sends a SCSI Inquiry command
to target #2

    SRB_ExecSCSICmd MySRB;
    HANDLE ASPICompletionEvent;
    DWORD ASPIEventStatus;
    DWORD ASPIStatus;
    char InquiryBuffer[32];
    .
    /**************************************************/
    /* Create event for MySRB.  Initial state         */
    /* non-signaled, manual reset.                    */
    /**************************************************/

    if ((ASPICompletionEvent = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL)
          return FALSE;

    /**************************************************/
    /* Code is entered with 'MySRB' zeroed.           */
    /**************************************************/

    MySRB.SRB_Cmd        = SC_EXEC_SCSI_CMD;
    MySRB.SRB_Flags      = SRB_DIR_SCSI|SRB_EVENT_NOTIFY;
    MySRB.SRB_Target     = 2;
    MySRB.SRB_BufLen     = 32;
    MySRB.SRB_SenseLen   = SENSE_LEN;
    MySRB.SRB_BufPointer = InquiryBuffer;
    MySRB.SRB_CDBLen     = 6;
    MySRB.CDBByte[0]     = SCSI_INQUIRY;
    MySRB.CDBByte[4]     = 32;
    MySRB.SRB_PostProc   = ASPICompletionEvent;
    .
    .
    ASPIStatus = SendASPI32Command ( (LPSRB) &MySRB );

    /**************************************************/
    /* Block on event till signaled                   */
    /**************************************************/

    if ( MySRB.SRB_Status == SS_PENDING )
          ASPIEventStatus == WaitForSingleObject(ASPICompletionEvent, TIMEOUT);

    /**************************************************/
    /* Reset event to non-signaled state.             */
    /**************************************************/

    if (ASPIEventStatus == WAIT_OBJECT_0)
         ResetEvent(ASPICompletionEvent);
              .
              .

-------------------------------------------------------------------------------

Using Callback

Callback (or posting) may also be used to receive notification that a SCSI
request has completed. When callback is used, ASPI for Win32 posts
completion by passing control to your callback function. For example, the
following code segment sends a SCSI Inquiry command to target #2 during the
WM_CREATE message.

    LRESULT CALLBACK WndProc (HWND, UINT, UPARAM, LPARAM);
    void APIENTRY ASPIPostProc (PSRB_ExecSCSICmd );

    HWND        PostHWND;
    HANDLE      hInstance;
                        .
                        .
                        .
    // ************************************************************************
    //
    // Function:    ASPIPostProc
    //
    // Description: If POSTING is enabled,  this function is called by ASPI
    //              for Windows when the SCSI request has completed.  This
    //              sample function simply posts a message to our Window
    //              handle to indicate that the SCSI request has completed.
    //
    //  DoneSRB     This parameter points to the ASPI SCSI Request Block (SRB)
    //              which has completed.
    //
    //  Returns     Nothing
    //
    // ************************************************************************

    #ifdef WIN32
        void ASPIPostProc(PSRB_ExecSCSICmd DoneSRB)
        {
            PostMessage(PostHWND,WM_ASPIPOST,0,(LPARAM)DoneSRB);
            return;
        }
    #else
        void _loadds __far __pascal ASPIPostProc(LPSRB DoneSRB)
        {
            PostMessage(PostHWND,WM_ASPIPOST,
                        (WORD)((SRB_ExecSCSICmd6 far *)DoneSRB)->SRB_Status,
                        (DWORD)DoneSRB);
            return;
        }
    #endif

    // ************************************************************************
    //
    // Procedure: WndProc()
    //
    // ************************************************************************

    #ifdef WIN32
        LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,
                                 LPARAM lParam)
    #else
        long __far __pascal _export WndProc(HWND hwnd,UINT message,WPARAM
                                            wParam,LPARAM lParam)
    #endif
    {
        HDC          hdc;
        PAINTSTRUCT  ps;
        TEXTMETRIC   tm;
        HMENU        hMenu;
        static short cxClient, cyClient;
        int          i=0;
        WORD         status;

        #ifdef WIN32
            SRB_ExecSCSICmd *SRBPtr;
        #else
            SRB_ExecSCSICmd6 far *SRBPtr;
        #endif

        switch (message)
        {
            case WM_CREATE:
                hdc = GetDC(hwnd);
                SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
                GetTextMetrics(hdc,&tm);
                cxChar = tm.tmAveCharWidth;
                cyChar = tm.tmHeight;
                ReleaseDC(hwnd,hdc);
                rect.top = 0;
                return 0;

            case WM_PAINT:
                InvalidateRect(hwnd,NULL,TRUE);
                hdc = BeginPaint(hwnd,&ps) ;
                EndPaint (hwnd,&ps) ;
                return 0 ;

            case WM_SIZE:
                cxClient = LOWORD(lParam);
                cyClient = HIWORD(lParam);
                rect.right  = LOWORD(lParam);
                rect.bottom = HIWORD(lParam);
                UpdateWindow(hwnd);
                return 0;

            case WM_COMMAND:
                hMenu = GetMenu(hwnd);
                switch (wParam)
                {
                    case ID_FILE_EXIT:
                        SendMessage(hwnd,WM_CLOSE,0,0L);
                        return 0;

                    default:
                        // 10 = target #0
                        // 11 = target #1
                        // 12 = target #2
                        // 13 = target #3
                        // 14 = target #4
                        // 15 = target #5
                        // 16 = target #6
                        // 17 = target #7

                        // Toggle the SCSI target scan status (ENABLED/DISABELD)
                        if ((wParam >= 10 && wParam <= 17) ||
                            (wParam >= 20 && wParam <= 27))
                        {
                            status = GetMenuState(hMenu,wParam,MF_BYCOMMAND) &
                                                MF_CHECKED;
                            CheckMenuItem(hMenu,wParam,MF_BYCOMMAND | ((status) ?
                                                MF_UNCHECKED:MF_CHECKED));
                        }
                        return 0;
                }

            case WM_ASPIPOST:
                #ifdef WIN32
                    SRBPtr = (PSRB_ExecSCSICmd)lParam;
                #else
                    SRBPtr = (SRB_ExecSCSICmd6 far *)lParam;
                #endif
                DisplaySCSIID(hwnd,SRBPtr);
                ScanNextTarget(hwnd);
                return 0;

            case WM_DESTROY:
                PostQuitMessage(0) ;
                return 0 ;
        }
        return DefWindowProc (hwnd, message, wParam, lParam) ;
    }

When the post routine is called, this sample post handler will fill the wParam
field with the status of ASPI command (SRB_Status) while the lParam field will
contain a pointer to the SRB which has completed.

-------------------------------------------------------------------------------

Polling

Polling is another method of determining SCSI request completion. This method
is not recommended. After the command is sent and ASPI for Win32 returns
control back to the calling application, you can then poll the status byte
waiting for the command to complete. For example, the following code segment
will execute a SCSI Inquiry command to target #2 using polling.

    SRB_ExecSCSICmd6 MySRB;
    DWORD ASPIStatus;
    char InquiryBuffer[32];
        .
        .
    /**************************************************/
    /* Code is entered with 'MySRB' zeroed.
    /**************************************************/
    MySRB.SRB_Cmd        = SC_EXEC_SCSI_CMD;
    MySRB.SRB_Flags      = SRB_DIR_SCSI;
    MySRB.SRB_Target     = 2;
    MySRB.SRB_BufLen     = 32;
    MySRB.SRB_SenseLen   = SENSE_LEN;
    MySRB.SRB_BufPointer = InquiryBuffer;
    MySRB.SRB_CDBLen     = 6;
    MySRB.CDBByte[0]     = SCSI_INQUIRY;
    MySRB.CDBByte[4]     = 32;
        .
        .
    ASPIStatus = SendASPI32Command( (LPSRB)&MySRB );// Send inquiry command
    while( MySRB.SRB_Status == SS_PENDING );        // Wait till it's finished

-------------------------------------------------------------------------------

Migrating to ASPI for Win32

If you have written ASPI or ASPI for Windows applications in the past, here
are some key points to keep in mind when you migrate the applications to ASPI
for Win32:

*   Although structure definitions have changed slightly to optimize alignment
    for 32-bit processors, structure names are consistent with those used in
    previous ASPI developer's kits. If you would like to use one source base
    for both 16-bit and 32-bit applications, make sure that you conditionally
    compile with the appropriate include files for each programming model. New
    32-bit include files are available in the ASPI developer's kit. There are
    many #ifdef statements in the sample code.

*   The CDB area has been fixed in length at 16. Therefore, the sense data
    area no longer shifts location depending on command length. If you are
    developing an application targeted only at Win32, you no longer need to
    account for the "floating" sense buffer.

*   For requests requiring data transfers, the direction bits in the SRB Flags
    field must be set correctly. Direction bits are no longer optional for
    data transfers. For requests not requiring data transfers, the direction
    bits are ignored.

*   If you are using dynamic DLL linking, use LoadLibrary (winaspi32.dll)
    instead of LoadLibrary(winaspi.dll) in order to access ASPI for Win32. If
    you are using static DLL linking, use the wnaspi32.lib.

*   All pointers in Win32 are 32 bits (Flat model). Therefore, FAR references
    are not used.

*   When allocating memory, page locking and global allocations are not
    necessary.

-------------------------------------------------------------------------------

Programming Guidelines

The following are additional guidelines for writing ASPI for Win32 applications.

*   ASPI for Win32 applications/clients should send an ASPI Abort command to
    terminate pending ASPI requests before exit.

*   SRBs and data buffers do not need to be in page-locked memory. The ASPI
    manager takes care of locking buffers and SRBs.

*   If an error SS_BUFFER_TO_BIG is returned by the SendASPI32Command
    routine, you should break the transfer down into 64 KByte transfers or
    less. For maximum compatibility, we recommend that you do not request
    transfer sizes larger than 64 KBytes unless your application requires it.

*   If you send an ASPI request with posting or callback enabled, the
    callback procedure will always be called. The post or callback routine is
    called as a standard C function. The caller (in this case, the ASPI
    manager) cleans up the stack.

*   ASPI for Win32 is fully re-entrant and permits overlapped, asynchronous
    I/O. Clients can send additional ASPI requests while others are pending
    completion. Be sure to use a separate SRB for each ASPI request.

*   Be sure to zero out all reserved fields before passing an SRB to ASPI for
    Win32.

*   Be sure that buffers are aligned according to the buffer alignment mask
    returned by the SC_HA_INQUIRY command. An alignment of at least a double
    word is recommended.

*   All structures must be "packed" onto byte alingments.  To do this using
    Microsoft compilers use the "#pragma pack(1)" command within your source
    code or use the /Zp1 command line option.  Please check your documentation
    for the proper commands or pragmas for other compilers.

*   All of the ASPI functions use 'C' style name decoration.  If using a
    'C++' compiler then make sure to include your function prototypes within
    an "extern "C" {}" block.

*   Some SCSI devices may have security restrictions that make them
    inaccessible for read/write operations. In operating systems where
    security is a feature, accessing a device where the application does not
    have sufficient security privilege results in a SS_SECURITY_VIOLATION
    error.

*   When scanning for devices, the SendASPI32Command may also return the
    status SS_NO_DEVICE in the SRB_Status field. Check for this exception in
    addition to the host adapter status HASTAT_SEL_TO. As previously
    mentioned, the callback procedure is always called, including this
    condition.

*   The SRB flags SRB_POSTING and SRB_EVENT_NOTIFY are mutually exclusive.

