Offshore Banking & Asset Protection

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
  • About ASPI
  • SendASPI32Command, the ASPI programming workhorse
  • Focus on Exec SCSI2 command, the most useful ASPI command
  • Language specifics
  • ======= About ASPI =======

    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:

    Subliminal messages: Flirting & love
    Now available: Free Report Online Profits

    ========== SendASPI32Command, ==========
    ========== the ASPI programming workhorse ==========

    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:

    1. the first byte is the ASPI command code, see the table above for each ASPI command
    2. the second byte (named SRB_Status) is the ASPI command status, to be checked after any call to SendASPI32Command
    3. 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
    4. 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.

    ========== Focus on Exec SCSI2 command, ==========
    ========== the most useful ASPI command ==========

    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
    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_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

    ========== Language specifics ==========

    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:


    A DAY FOR HEARTS : Congenital
 Heart Defects Awareness Day
- Click here for details