ASPI For Windows Specification About This Chapter Read this chapter to find out: - An overview of the steps involved in programming ASPI for Windows - ASPI for Windows commands - Polling and posting of ASPI for Windows SCSI requests - Important information for ASPI for Windows developers - The scanscsi.exe application which scans the SCSI bus and displays the device name of each target - A summary of the error codes and messages returned by ASPI routines Using ASPI For Windows – An Overview ASPI for Windows is implemented as a Dynamic Link Library (DLL). The name of this file is called winaspi.dll. ASPI function calls are used to return information about the ASPI manager, host adapter, and SCSI devices, but are mainly used to execute SCSI I/O requests. The ASPI for Windows layer is fully multitasking and can accept function calls before previous calls have completed. There are two functions which need to be imported, from winaspi.dll, into your Windows application. Function Description GetASPISupportInfo 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. SendASPICommand This function allows you to send an ASPI for Windows command. All of your SRBs and data buffers must be in locked memory before being passed to ASPI. This is discussed in greater detail later in this chapter. ASPI Managers For Windows It is not the intent of this specification to define the protocol between winaspi.dll and any DOS ASPI managers which may be loaded. There are many reasons for this including: - Some hardware companies may decide to write an ASPI for Windows -manager without concurrent ASPI for DOS support. - Some may decide to have winaspi.dll communicate with a Windows 386 - Enhanced Mode Virtual Device Driver (VxD). - Some may decide to only support Windows 3.1 which may, or may not, have improved hardware support. It is also not the intent of this specification to define which modes of Windows need to be supported. We anticipate that most hardware companies will support ASPI for -Windows in Standard and 386 Enhanced Modes, and forego Real Mode support. GetASPISupportInfo WORD GetASPISupportInfo(VOID) The GetASPISupportInfo function returns the number of host adapters installed and other miscellaneous information. It is recommended that this function be called first before issuing an ASPI command to ensure ASPI has been properly initialized. This function call does not perform any initialization itself, but rather confirms everything is ready for processing. This function has no parameters. Returns The return value specifies the outcome of the function. The LOBYTE returns the -number of host adapters installed if the HIBYTE value equals SS_COMP. The HIBYTE returns whether ASPI for Windows is ready to accept ASPI commands. -Refer to the example code. The HIBYTE is defined as follows: Value Meaning SS_COMP SCSI/ASPI request has completed without error. SS_OLD_MANAGER There are one or more ASPI for DOS managers loaded which do not -support ASPI for Windows. SS_ILLEGAL_MODE This ASPI manager does not support this mode of Windows. You will -typically see this error code when running Windows in Real Mode. SS_NO_ASPI There are no ASPI managers loaded. This is typically caused by a DOS ASPI manager not being resident in memory. SS_FAILED_INIT For some reason, other than SS_OLD_MANAGER, SS_ILLEGAL_MODE or SS_NO_ASPI, ASPI for Windows could not properly initialize itself. This may be caused by a lack of system resources. Example The following example returns the current status of ASPI for Windows: WORD ASPIStatus; BYTE NumAdapters; HWND hwnd; . . ASPIStatus = GetASPISupportInfo(); switch ( HIBYTE(ASPIStatus) ) { case SS_COMP: //ASPI for Windows is properly initialized NumAdapters = LOBYTE(ASPIStatus); break; case SS_NO_ASPI: MessageBox( hwnd, "No ASPI managers were found!!", NULL, MB_ICONSTOP ); return 0; case SS_ILLEGAL_MODE: MessageBox( hwnd, "ASPI for Windows does not support this mode!!", NULL, MB_ICONSTOP ); return 0; case SS_OLD_MANAGER: MessageBox( hwnd, "An ASPI manager which does not support Windows is resident!!", NULL, MB_ICONSTOP ); return 0; default: MessageBox( hwnd, " ASPI for Windows is not initialized!!", NULL, MB_ICONSTOP ); return 0; } . . SendASPICommand – SC_HA_INQUIRY WORD SendASPICommand(lpSRB) LPSRB lpSRB; The SendASPICommand function with command code SC_HA_INQUIRY is used to get information on the installed host adapter hardware, including number of host adapters installed. Parameter Description lpSRB Points to the following SCSI request block: 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 } SRB_HAInquiry; Member Description R/W* SRB_Cmd This field must contain SC_HA_INQUIRY. W SRB_Status On return, this field will be the same as the return status defined below. R SRB_HaId This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the SCSI manager layer beginning with zero. W SRB_Flags The SRB Flags field is currently reserved for this function and must be zeroed before passed to the ASPI manager. W SRB_Hdr_Rsvd This DWORD field is currently reserved for this function and must be zeroed before passed to the ASPI manager. — HA_Count The ASPI manager will set this 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 should be set to zero, or GetASPISupportInfo can be used. R HA_SCSI_ID The ASPI manager will set this field with the SCSI ID of the given host adapter. R HA_ManagerId[..] The ASPI manager will fill this 16-character buffer with an ASCII string describing the ASPI manager. R HA_Identifier[..] The ASPI manager will fill this 16-character buffer with an ASPI string describing the SCSI host adapter. R HA_Unique[..] The ASPI manager will fill this 16-byte buffer with host adapter unique parameters. The definition is left to implementation notes specific to a particular host adapter. R *The R/W column indicates whether the field is sent to ASPI (W), returned from ASPI (R), or reserved (—). Returns The return value specifies the outcome of the function. One of the following values will be returned by ASPI for Windows: Value Meaning SS_COMP SCSI/ASPI request has completed without error. SS_INVALID_HA Invalid host adapter number. SS_INVALID_SRB The SCSI Request Block (SRB) has one, or more, parameters set incorrectly. Example The following example retrieves 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 = SendASPICommand ( (LPSRB) &MySRB ); . . SendASPICommand – SC_GET_DEV_TYPE WORD SendASPICommand(lpSRB) LPSRB lpSRB; The SendASPICommand function with command code SC_GET_DEV_TYPE is -intended for use by Windows applications for identifying the targets which they need to support. For example, a Windows tape backup package can scan each Target/LUN on each installed host adapter looking for the device type corresponding to sequential access devices. This eliminates the need for each Windows application to duplicate the effort of scanning the SCSI bus for devices. Note: Rather than use this command, some Windows applications may favor scanning the SCSI bus themselves in case a SCSI device was not present during ASPI initialization, but was rather powered-up after ASPI initialization Parameter Description lpSRB Points to the following SCSI request block: 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; // ASPI request flags DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 BYTE SRB_Target; // Target's SCSI ID BYTE SRB_Lun; // Target's LUN number BYTE SRB_DeviceType; // Target's peripheral device type } SRB_GDEVBlock; Member Description R/W* SRB_Cmd This field must contain SC_GET_DEV_TYPE. W SRB_Status On return, this field will be the same as the return status defined below. R SRB_HaId This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the SCSI manager layer beginning with zero. W SRB_Flags The SRB Flags field is currently reserved for this function and must be zeroed before passed to the ASPI manager. W SRB_Hdr_Rsvd This DWORD field is currently reserved for this function and must be zeroed before passed to the ASPI manager. — SRB_Target Target ID of device. W SRB_Lun Logical Unit Number (LUN) of device. W SRB_DeviceType The ASPI manager will fill this field with the peripheral device type. Refer to any SCSI specification to learn more about the SCSI Inquiry command. R *The R/W column indicates whether the field is sent to ASPI (W), returned from ASPI (R), or reserved (—). Returns The return value specifies the outcome of the function. One of the following values will be returned by ASPI for Windows: Value Meaning SS_COMP SCSI/ASPI request has completed without error. SS_INVALID_HA Invalid host adapter number. SS_NO_DEVICE SCSI device not installed. SS_INVALID_SRB The SCSI Request Block (SRB) has one, or more, parameters set incorrectly. Example The following example retrieves the peripheral device type from host adapter #0, -target ID #4, and LUN #0. SRB_GDEVBlock MySRB; WORD ASPI_Status; . . 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; ASPI_Status = SendASPICommand ( (LPSRB) &MySRB ); . /***************************************************/ /* If ASPI_Status == SS_COMP, MySRB.SRB_DeviceType */ /* will contain the peripheral device type. */ /***************************************************/ . . SendASPICommand – SC_EXEC_SCSI_CMD WORD SendASPICommand(lpSRB) LPSRB lpSRB; The SendASPICommand function with command code SC_EXEC_SCSI_CMD is used to execute a SCSI command. For example, send a SCSI Test Unit Ready -command to a tape drive, etc. Parameter Description lpSRB Points to one of the following SCSI request blocks: typedef struct { // Structure for 6-byte CDBs 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, MUST = 0 BYTE SRB_Target; // Target's SCSI ID BYTE SRB_Lun; // Target's LUN number DWORD SRB_BufLen; // Data Allocation LengthPG BYTE SRB_SenseLen; // Sense Allocation Length BYTE far *SRB_BufPointer; // Data Buffer Pointer DWORD SRB_Rsvd1; // Reserved, MUST = 0 BYTE SRB_CDBLen; // CDB Length = 6 BYTE SRB_HaStat; // Host Adapter Status BYTE SRB_TargStat; // Target Status FARPROC SRB_PostProc; // Post routine BYTE SRB_Rsvd2[34]; // Reserved, MUST = 0 BYTE CDBByte[6]; // SCSI CDB BYTE SenseArea6[SENSE_LEN]; // Request Sense buffer } SRB_ExecSCSICmd6; typedef struct { // Structure for 10-byte CDBs 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, MUST = 0 BYTE SRB_Target; // Target's SCSI ID BYTE SRB_Lun; // Target's LUN number DWORD SRB_BufLen; // Data Allocation Length BYTE SRB_SenseLen; // Sense Allocation Length BYTE far *SRB_BufPointer; // Data Buffer Pointer DWORD SRB_Rsvd1; // Reserved, MUST = 0 BYTE SRB_CDBLen; // CDB Length = 10 BYTE SRB_HaStat; // Host Adapter Status BYTE SRB_TargStat; // Target Status FARPROC SRB_PostProc; // Post routine BYTE SRB_Rsvd2[34]; // Reserved, MUST = 0 BYTE CDBByte[10]; // SCSI CDB BYTE SenseArea10[SENSE_LEN]; // Request Sense buffer } SRB_ExecSCSICmd10; Note: You can easily create a new structure for non-standard CDB lengths. Member Description R/W* SRB_Cmd This field must contain SC_EXEC_SCSI_CMD. W SRB_Status On return, this field will be the same as the return status defined below. R SRB_HaId This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the SCSI manager layer beginning with zero. W SRB_Flags The SRB Flags field is defined as follows: W Value Meaning SRB_DIR_SCSI Direction determined by SCSI -command. Length not checked. SRB_DIR_IN Transfer from SCSI target to host. Length checked. SRB_DIR_OUT Transfer from host to SCSI target. Length checked. SRB_POSTING If this value is OR'ed in with one of the previous three values, posting will be enabled. Refer to the section on ASPI Posting. SRB_Hdr_Rsvd This DWORD field is currently reserved for this function and must be zeroed before passed to the ASPI manager. — SRB_Target Target ID of device. W SRB_Lun Logical Unit Number (LUN) of device. W SRB_BufLen This field indicates the number of bytes to be transferred. If the SCSI command to be executed does not transfer data (i.e., Test Unit Ready, Rewind, etc.), this field must be set to zero. W SRB_SenseLen This field indicates 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. W SRB_BufPointer This field is a pointer to the data buffer. W SRB_CDBLen This field establishes the length, in bytes, of the SCSI Command Descriptor Block (CDB). This value will typically be 6 or 10. W SRB_HaStat Upon completion of the SCSI command, the ASPI manager will set this field with the host adapter status as follows: R Value Meaning HASTAT_OK Host adapter did not detect an error HASTAT_SEL_TO Selection timeout HASTAT_DO_DU Data overrun/underrun HASTAT_BUS_FREE Unexpected bus free HASTAT_PHASE_ERR Target bus phase sequence failure SRB_TargStat Upon completion of the SCSI command, the ASPI manager will set this field with the target status as follows: R Value Meaning STATUS_GOOD No target status STATUS_CHKCOND Check status (Sense data is in SenseArea) STATUS_BUSY Specified Target/LUN is busy STATUS_RESCONF Reservation conflict SRB_PostProc If posting is enabled, ASPI for Windows will post completion of an ASPI request to this function pointer. Refer to the section on ASPI Posting. W CDBByte[..] This field contains the CDB as defined by the target's SCSI command set. The length of the SCSI CDB is specified in the SRB_CDBLen field. W SenseArea[..] The SenseArea is filled with the sense data on a check condition. The maximum length of this field is specified in the SRB_SenseLen field. Note that the target can return fewer than the number of sense bytes requested. R *The R/W column indicates whether the field is sent to ASPI (W), returned from ASPI (R), or reserved (—). Returns The return value specifies the outcome of the function. One of the following values will be returned by ASPI for Windows: Value Meaning SS_PENDING SCSI request is in progress. SS_COMP SCSI/ASPI request has completed without error. SS_ABORTED SCSI command has been aborted. SS_ERR SCSI command has completed with an error. SS_INVALID_SRB The SCSI Request Block (SRB) has one or more parameters set incorrectly. SS_ASPI_IS_BUSY The ASPI manager cannot handle the request at this time. This error will generally occur if the ASPI manager is already using up all of his resources to execute other requests. You should try resending the command later. SS_BUFFER_TO_BIG The ASPI manager cannot handle the given transfer size. Please refer to Miscellaneous for more information. Example The following example sends a SCSI Inquiry command to host adapter #0, target #0, and LUN #0: SRB_ExecSCSICmd6 MySRB; char InquiryBuffer[32]; FARPROC lpfnPostProcedure; . . lpfnPostProcedure = MakeProcInstance (PostProcedure, hInstance); . . MySRB.SRB_Cmd = SC_EXEC_SCSI_CMD; MySRB.SRB_HaId = 0; MySRB.SRB_Flags = SRB_DIR_SCSI | 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.SRB_PostProc = lpfnPostProcedure; 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 Windows */ /**************************************************/ . SendASPICommand ( (LPSRB) &MySRB ); . . SendASPICommand – SC_ABORT_SRB WORD SendASPICommand(lpSRB) LPSRB lpSRB; The SendASPICommand function with command code SC_ABORT_SRB is used to request that an SRB be aborted. It should be issued on any I/O request that has not completed if the application wishes to timeout on that request. Success of the Abort command is never assured. Parameter Description lpSRB Points to the following SCSI request block: 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; // ASPI request flags DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 LPSRB SRB_ToAbort; // Pointer to SRB to abort } SRB_Abort; Member Description R/W* SRB_Cmd This field must contain SC_ABORT_SRB. W SRB_Status On return R SRB_HaId This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the SCSI manager layer beginning with zero. W SRB_Flags The SRB flags field is currently reserved for this function and must be zeroed before passed to the ASPI manager. W SRB_Hdr_Rsvd This DWORD field is currently reserved for this function and must be zeroed before passed to the ASPI manager. — SRB_ToAbort This fields contains a pointer to the SRB which is to be aborted. The actual failure or success of the abort operation is indicated by the -status eventually returned in this SRB. W *The R/W column indicates whether the field is sent to ASPI (W), returned from ASPI (R), or reserved (—). Returns The return value specifies the outcome of the function. One of the following values will be returned by ASPI for Windows: Value Meaning SS_COMP SCSI/ASPI request has completed without error. SS_INVALID_HA Invalid host adapter number. SS_INVALID_SRB The SCSI Request Block (SRB) has one or more parameters set incorrectly. Example The following example shows how to abort a stuck SCSI I/O: SRB_ExecSCSICmd6 StuckSRB; SRB_Abort AbortSRB; WORD ASPI_Status; . . AbortSRB.SRB_Cmd = SC_ABORT_SRB; AbortSRB.SRB_HaId = 0; AbortSRB.SRB_Flags = 0; AbortSRB.SRB_Hdr_Rsvd = 0; AbortSRB.SRB_ToAbort = (LPSRB) &StuckSRB; ASPI_Status = SendASPICommand ( (LPSRB) &AbortSRB ); . . while (StuckSRB.SRB_Status==SS_PENDING); . . /**************************************************/ /* This sample code has no error handling, time- */ /* out code, nor does it free up the processor. */ /* Your application should be more robust. */ /**************************************************/ SendASPICommand – SC_RESET_DEV WORD SendASPICommand(lpSRB) LPSRB lpSRB; The SendASPICommand function with command code SC_RESET_DEV is used to send a SCSI bus device reset to the specified target. Parameter Description lpSRB Points to the following SCSI request block: 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; // ASPI request flags DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 BYTE SRB_Target; // Target's SCSI ID BYTE SRB_Lun; // Target's LUN number BYTE SRB_ResetRsvd1[14]; // Reserved, MUST = 0 BYTE SRB_HaStat; // Host Adapter Status BYTE SRB_TargStat; // Target Status FARPROC SRB_PostProc; // Post routine BYTE SRB_ResetRsvd2[34]; // Reserved, MUST = 0 } SRB_BusDeviceReset Member Description R/W* SRB_Cmd This field must contain SC_RESET_DEV. W SRB_Status On return, this field will be the same as the return status defined below. R SRB_HaId This field specifies which installed host adapter the request is intended for. Host adapter numbers are always assigned by the SCSI manager layer beginning with zero. W SRB_Flags The SRB Flags field is currently reserved for this function and must be zeroed before passed to the ASPI manager. W SRB_Hdr_Rsvd This DWORD field is currently reserved for this function and must be zeroed before passed to the ASPI manager. — SRB_Target Target ID of device. W SRB_Lun Logical Unit Number (LUN) of device. This field is ignored by ASPI for Windows since SCSI bus device resets are done on a per target basis only. W SRB_HaStat Upon completion of the SCSI command, the ASPI manager will set this field with the host adapter status as follows: R Value Meaning HASTAT_OK Host adapter did not detect an error HASTAT_SEL_TO Selection timeout HASTAT_DO_DU Data overrun/underrun HASTAT_BUS_FREE Unexpected bus free HASTAT_PHASE_ERR Target bus phase sequence failure SRB_TargStat Upon completion of the SCSI command, the ASPI manager will set this field with the target status as follows: R Value Meaning STATUS_GOOD No target status STATUS_CHKCOND Check status (sense data is in SenseArea) STATUS_BUSY Specified Target/LUN is busy STATUS_RESCONF Reservation conflict SRB_PostProc If posting is enabled, ASPI for Windows will post completion of an ASPI request to this function pointer. Refer to the section on ASPI Posting. W *The R/W column indicates whether the field is sent to ASPI (W), returned from ASPI (R), or reserved (—). Returns The return value specifies the outcome of the function. One of the following values will be returned by ASPI for Windows. Refer to each ASPI command code definition for information on which ASPI commands return which errors. Value Meaning SS_COMP SCSI/ASPI request has completed without error. SS_INVALID_HA Invalid host adapter number. SS_INVALID_SRB The SCSI Request Block (SRB) has one or more parameters set incorrectly. SS_ASPI_IS_BUSY The ASPI manager cannot handle the request at this time. This error will generally occur if the ASPI manager is already using up all of his resources to execute other requests. You should try resending the command later. Example The following example issues a SCSI bus device reset to host adapter #0, target #5: SRB_BusDeviceReset MySRB; WORD ASPI_Status; . . MySRB.SRB_Cmd = SC_RESET_DEV; MySRB.SRB_HaId = 0; MySRB.SRB_Flags = 0; MySRB.SRB_Hdr_Rsvd = 0; MySRB.SRB_Target = 5; MySRB.SRB_Lun = 0; ASPI_Status = SendASPICommand ( (LPSRB) &MySRB ); . /**************************************************/ /* Make sure all other reserved fields are zeroed */ /* before passing the SRB to ASPI for Windows */ /**************************************************/ . while (MySRB.SRB_Status==SS_PENDING); . . /**************************************************/ /* This sample code has no error handling, time- */ /* out code, nor does it free up the processor. */ /* Your application should be more robust. */ /**************************************************/ ASPI Polling Once you send an ASPI for Windows SCSI request, you have two ways of being -notified that the SCSI request has completed. The first and simplest method is called polling. After the command is sent, and ASPI for Windows returns control back to your program, you can poll the status byte waiting for the command to complete. For -example, the following code segment sends a SCSI Inquiry command to target #2. SRB_ExecSCSICmd6 MySRB; 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; . . SendASPICommand ( (LPSRB) &MySRB ); // Send Inquiry command while ( MySRB.SRB_Status == SS_PENDING ); // Wait till it's finished /**************************************************/ /* At this point, the SCSI command has completed */ /* with or without an error. */ /**************************************************/ if ( MySRB.SRB_Status == SS_COMP ) ; // Command completed without error else ; // Command completed with error Since Windows is currently a non-preemptive multitasking operating system, you should use polling with caution. The example above is not very good about freeing up the processor, nor does it have any timeout handler. Later in this specification, you will find sample code which does free up the processor while using polling. ASPI Posting Most applications will use posting, rather than polling, to be notified that a SCSI -request has completed. When posting is enabled, ASPI for Windows will post completion by calling your callback function. For example, the following code segment will send a SCSI Inquiry command to target #2 during the WM_CREATE message. long FAR PASCAL WndProc (HWND, WORD, WORD, LONG); void FAR PASCAL ASPIPostProc ( LPSRB ); HWND PostHWND; HANDLE hInstance; . . . //********************************************************************** // ASPIPostProc - ASPI for Windows will post completion of a SCSI // request to this function. Note that this is most // likely during interrupt time so you can only use // a few Windows functions like 'PostMessage.' This // example post procedure is very simple. It will // wake up your application by posting a WM_ASPIPOST // message to your window handle. //********************************************************************** void FAR PASCAL ASPIPostProc ( LPSRB DoneSRB ) { PostMessage ( PostHWND, WM_ASPIPOST, (WORD) ((SRB_ExecSCSICmd6 far *)DoneSRB)->SRB_Status, (DWORD) DoneSRB ); return; } //*********************************************************************** // WndProc - Window message handler //*********************************************************************** long FAR PASCAL WndProc ( HWND hwnd, WORD message, WORD wParam, LONG lParam) { static SRB_ExecSCSICmd6 MySRB; static char InquiryBuffer[32]; switch (message) { case WM_CREATE: /**************************************************/ /* Code is entered with 'MySRB' zeroed. */ /**************************************************/ lpfnASPIPostProc = MakeProcInstance (ASPIPostProc, hInstance); PostHWND = hwnd; MySRB.SRB_Cmd = SC_EXEC_SCSI_CMD; MySRB.SRB_Flags = SRB_DIR_SCSI|SRB_POSTING; MySRB.SRB_Target = 2; MySRB.SRB_BufLen = 32; MySRB.SRB_SenseLen = SENSE_LEN; MySRB.SRB_BufPointer = InquiryBuffer; MySRB.SRB_CDBLen = 6; ExecSRB.SRB_PostProc = lpfnASPIPostProc; MySRB.CDBByte[0] = SCSI_INQUIRY; MySRB.CDBByte[4] = 32; . . if ( SendASPICommand ( (LPSRB) &MySRB ) != SS_PENDING ) { ; // Check return status for cause of failure! ; // Posting will NOT occur due to failure } else { ; // ASPI for Windows will post completion to ; // 'lpfnASPIPostProc' when command has completed. } return 0; case WM_ASPIPOST: // Return status is in 'wParam' // SRB Pointer is in 'lParam' // We might want to send another ASPI request here. // Look at 'ASPIPostProc' for more information. return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc ( hwnd, message, wParam, lParam ); } . . . When the post routine gets called, our sample post handler will fill the wParam field and will contain the status of ASPI command (SRB_Status) while the lParam field will contain a far pointer to the SRB which has completed. Refer to the sample -application, in this chapter, for a working example. Miscellaneous This section brings together important information which may not have been touched on earlier. - Your ASPI for Windows program should never exit with pending SCSI I/Os. Doing so could lead to system instability. Send an ASPI Abort command if you need to. - Your SRBs and data buffers must be in page-locked memory. Most SCSI host adapters are bus masters. This means that the data buffer must not move while the transfer is taking place. We recommend that you allocate your -buffers using GlobalAlloc and then locking it first with GlobalLock and then with GlobalPageLock. This technique has been used to overcome some of the quirks that -Windows 3.x seems to have with locking down buffers. - It is a minimal requirement that all ASPI for Windows managers support transfers of 64 KBytes or less. It is not possible for all SCSI host adapters to transfer data larger than this size. If the ASPI manager is unable to support your requested transfer size, you will be returned the -SS_BUFFER_TO_BIG error from the SendASPICommand routine. No posting will occur. If this occurs, you should break the transfer down into 64K transfers or less. For maximum -compatibility, it is recommend that you do not request transfer sizes larger than 64 KBytes if you do not need to. - Do not forget to support the SS_ASPI_IS_BUSY return status when sending a SCSI command. Under extreme loads, some ASPI for Windows managers may not have enough resources to service each request. - If you send an ASPI request with posting enabled, and the return value is not equal to SS_PENDING (in other words, the request is not in progress), then ASPI for Windows will not post completion to your specified window handle. (Refer to the specific return value for more information as to why the request is not in progress.) - ASPI for Windows is fully multitasking. You can send a request to ASPI while another request is executing. Make sure you use a separate SRB for each ASPI request. It is also recommended that you only send one SRB at a time per target. - If using posting, your post routine will most likely be called during interrupt time. Since most Windows routines are non-reentrant, you should call -Windows routines with cautions. One function you can call is PostMessage which can be called during interrupt time. - Make sure that you zero out all reserved fields before passing the SRB to ASPI for Windows. SCANSCSI.EXE scanscsi.exe is a very simple ASPI for Windows application which scans the SCSI bus and displays the device name of each target it finds on the SCSI bus. When the program first comes up, the user will be prompted as to whether he would like to use ASPI posting or polling to detect completion of a SCSI request. While the program is -running, it may look like the following: Under the Scan menu, scanscsi.exe allows the user to configure which targets should be scanned and which should not: This sample code also shows you how to free up the processor while SCSI operations are running in the background. This is very important since Windows is currently a non-preemptive multitasking operating system. scanscsi.exe does minimal error -checking and has no timeout code. Your application should be more robust. SCANSCSI.MAK ######################################################################## # # # SCANSCSI.MAK makefile # # # ######################################################################## scanscsi.exe: scanscsi.obj scanscsi.def scanscsi.res link /co scanscsi, /align:16, NUL, /nod slibcew libw, scanscsi rc -30 scanscsi.res scanscsi.obj: scanscsi.c winaspi.h cl -Zi -c -Gsw -Ow -W2 -Zp scanscsi.c SCANSCSI.C //********************************************************************** // // Copyright 1992 Adaptec, Inc., All Rights Reserved. // // This software contains the valuable trade secrets of Adaptec. // The software is protected under copyright laws as an // unpublished work of Adaptec. Notice is for informational // purposes only and does not imply publication. The user of this // software may make copies of the software for use with parts // manufactured by Adaptec or under license from Adaptec and for // no other use. // //********************************************************************** //********************************************************************** // // Program Name: SCANSCSI.EXE // // Version: 1.00 // Source Code: SCANSCSI.MAK SCANSCSI.C SCANSCSI.DEF // SCANSCSI.RES SCSIDEFS.H WINASPI.H // // Description: This ASPI for Windows test utility will run on // Windows 3.0 or later. The program opens a window // and loops forever while displaying all of the // devices found on the SCSI bus. The user can // always exit the program by pressing ALT or // selecting "Exit" from the application's menu. // The user can enable and disable, on a per // target basis, which targets should get scanned // for a SCSI device. In order to edit the // resource file SCANSCSI.RES, you will need a // Windows resource editor. For compile/link // purposes, you will not need the resource editor. // You should have a basic understanding of writing // Windows applications before looking at this // source code. // // Note that this sample code does minimal error // checking and no timeout handling. Your // application should be more robust. This code // also demonstrates the polling or posting // techniques of determining when a SCSI command // has completed. REFER TO THE ASPI FOR WINDOWS // SPECIFICATION FOR INFORMATION ON PROPERLY // LOCKING DOWN BUFFERS. // // History: // // 06/15/92 - MDB - v1.00 - Submitted. // //*********************************************************************** #include windows.h #include "winaspi.h" #include "scsidefs.h" long FAR PASCAL WndProc (HWND, WORD, WORD, LONG); void ScanNextTarget (HWND); void DisplaySCSIID (HWND, SRB_ExecSCSICmd6 far *); void FAR PASCAL ASPIPostProc ( LPSRB ); char szAppName[] = "SCANSCSI"; int UsePosting; RECT rect; short cxChar,cyChar; WORD NumAdapters; FARPROC lpfnASPIPostProc; HWND PostHWND; //*********************************************************************** // WinMain //*********************************************************************** int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS wndclass; WORD ASPIStatus,j,flags; char string_buf[20]; if (!hPrevInstance) { wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon (hInstance,szAppName); wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = GetStockObject (WHITE_BRUSH); wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; RegisterClass (&wndclass); } hwnd = CreateWindow (szAppName, // Registered class "ASPI For Windows - SCANSCSI", // Window text WS_OVERLAPPEDWINDOW, // Window style CW_USEDEFAULT, // Horizontal window position CW_USEDEFAULT, // Vertical window position CW_USEDEFAULT, // Window width CW_USEDEFAULT, // Window height NULL, // Parent window handle NULL, // Menu Handle hInstance, // Application instance NULL); // Creation data ShowWindow (hwnd, nCmdShow); UpdateWindow (hwnd); // We're going to check to make sure that ASPI for Windows has been // properly initialized. If it hasn't, it is recommended that you // provide more user feedback/help than what is shown in this sample // code. ASPIStatus = GetASPISupportInfo(); switch ( HIBYTE(ASPIStatus) ) { case SS_COMP: //ASPI for Windows is properly initialized NumAdapters = LOBYTE(ASPIStatus); break; case SS_NO_ASPI: MessageBox( hwnd, "No ASPI managers were found!!", szAppName, MB_ICONSTOP ); return 0; case SS_ILLEGAL_MODE: MessageBox( hwnd, "ASPI for Windows does not support this mode!!", szAppName, MB_ICONSTOP ); return 0; case SS_OLD_MANAGER: MessageBox( hwnd, "An ASPI manager which does not support Windows is resident!!", szAppName, MB_ICONSTOP ); return 0; default: MessageBox( hwnd, "ASPI for Windows is not initialized!!", szAppName, MB_ICONSTOP ); return 0; } // This code demonstrates the posting abilities of ASPI for Windows as // well as the polling technique. Ask the user which method he would // like to use to indicate completion of a SCSI request. UsePosting = MessageBox ( hwnd, "Use ASPI for Windows Posting?", szAppName, MB_YESNO | MB_ICONQUESTION ); LockData(0); lpfnASPIPostProc = MakeProcInstance (ASPIPostProc, hInstance); PostHWND = hwnd; if ( UsePosting == IDYES ) { ScanNextTarget (hwnd); while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } } else { while (TRUE) { if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage (&msg); DispatchMessage (&msg); } else // While the processor is free, check ScanNextTarget (hwnd); // the SCSI bus status } } ScanNextTarget (0); // Finish any pending ASPI requests return msg.wParam; } //*********************************************************************** // AboutDlgProc //*********************************************************************** BOOL FAR PASCAL AboutDlgProc (HWND hDlg, WORD message, WORD wParam, LONG lParam) { switch (message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch (wParam) { case IDOK: case IDCANCEL: EndDialog (hDlg,0); return TRUE; } break; } return FALSE; } //*********************************************************************** // WndProc //*********************************************************************** long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam) { HMENU hMenu; WORD status; static HANDLE hInstance; static FARPROC lpfnAboutDlgProc; SRB_ExecSCSICmd6 far *SRBPtr; HDC hdc; TEXTMETRIC tm; PAINTSTRUCT ps; 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; hInstance = ((LPCREATESTRUCT) lParam)-hInstance; lpfnAboutDlgProc = MakeProcInstance (AboutDlgProc, hInstance); return 0; case WM_PAINT: InvalidateRect (hwnd, NULL, TRUE); hdc = BeginPaint (hwnd, &ps); EndPaint (hwnd,&ps); return 0; case WM_SIZE: rect.right = LOWORD (lParam); rect.bottom = HIWORD (lParam); UpdateWindow (hwnd); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; case WM_COMMAND: hMenu = GetMenu (hwnd); switch (wParam) { case 18: SendMessage (hwnd, WM_CLOSE, 0, 0L); return 0; case 100: DialogBox (hInstance, "ABOUTBOX", hwnd, lpfnAboutDlgProc); 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 // 20 = host adapter #0 // 21 = host adapter #1 (etc.) if ( (wParam = 10 && wParam <=17) (wParam = 20 && wParam <=100) ) { /* Toggle the SCSI target scan status (enabled/disabled)*/ status = GetMenuState (hMenu, wParam, MF_BYCOMMAND) & MF_CHECKED; CheckMenuItem (hMenu, wParam, MF_BYCOMMAND | (status ? MF_UNCHECKED:MF_CHECKED) ); } return 0; } case WM_ASPIPOST: SRBPtr = (SRB_ExecSCSICmd6 far *) lParam; DisplaySCSIID ( hwnd, SRBPtr ); ScanNextTarget ( hwnd ); return 0; } return DefWindowProc(hwnd,message,wParam,lParam); } //********************************************************************** // Function: ScanNextTarget // // Description: If polling is enabled, this function is called // whenever Windows is idle. If a SCSI Inquiry command is // still in progress, this routine will return control back // to the caller to free up the CPU. If posting is enabled, // this function is called when the SCSI Inquiry command has // completed. // // hwnd - This parameter contains the window handle where the device // names should be listed. If hwnd equals zero, this indicates // that we're exiting this program and this routine should return // only after all outstanding ASPI requests have completed. // // Returns: Nothing //********************************************************************** void ScanNextTarget (HWND hwnd) { HMENU hMenu; static WORD target_id=7,adapter_id=0, SRBIsPending=FALSE; static SRB_ExecSCSICmd6 ExecSRB; static char InquiryBuffer[100]; WORD status,j; if (hwnd==0) // If user is exiting the program, wait until all { // pending ASPI requests are finished. if (SRBIsPending==TRUE) while (ExecSRB.SRB_Status==SS_PENDING); return; } // If we're still waiting for the previous SCSI Inquiry to finish, // simply return back to the caller to free up the CPU. if ( UsePosting==IDNO && SRBIsPending==TRUE && ExecSRB.SRB_Status==0 ) return; if ( SRBIsPending==FALSE || UsePosting == IDYES ) { hMenu = GetMenu (hwnd); target_id = (target_id+1)%8; //Move to next SCSI ID if ( target_id==0 ) { adapter_id++; if (adapter_id = NumAdapters) adapter_id=0; } for (j=0;j;j++) { status = GetMenuState (hMenu, target_id+10, MF_BYCOMMAND) & MF_CHECKED; if (status==0) //If this target is disabled, { target_id = (target_id+1)%8; // move to next SCSI ID. if ( target_id==0 ) { adapter_id++; if (adapter_id = NumAdapters) adapter_id=0; } } else break; } if (j==8) // Return if user disabled scanning of ALL return; // SCSI targets. ExecSRB.SRB_Cmd = SC_EXEC_SCSI_CMD; ExecSRB.SRB_HaId = adapter_id; ExecSRB.SRB_Flags = SRB_DIR_IN; ExecSRB.SRB_Target = target_id; ExecSRB.SRB_BufPointer = InquiryBuffer; ExecSRB.SRB_BufLen = 32; ExecSRB.SRB_SenseLen = SENSE_LEN; ExecSRB.SRB_CDBLen = 6; ExecSRB.CDBByte[0] = SCSI_INQUIRY; ExecSRB.CDBByte[4] = 32; if ( UsePosting == IDYES ) { ExecSRB.SRB_Flags |= SRB_POSTING; ExecSRB.SRB_PostProc = lpfnASPIPostProc; } SendASPICommand ( (LPSRB) &ExecSRB ); SRBIsPending=TRUE; // ASPI command in process return; } if ( UsePosting == IDNO ) { SRBIsPending=FALSE; // Inquiry command has completed DisplaySCSIID ( hwnd, &ExecSRB ); } return; } //********************************************************************** // Function: DisplaySCSIID // // Description: This function will scroll the window down and display // the device name of the target we just sent a SCSI Inquiry // command. // // hwnd - This parameter contains the window handle where the // device name should be displayed. // // ExecSRB - This parameter points to the ASPI SCSI Request Block (SRB) // which has completed. // // Returns: Nothing //********************************************************************** void DisplaySCSIID ( HWND hwnd, SRB_ExecSCSICmd6 far *ExecSRB ) { HDC hdc; char string_buf[80]; int string_len; hdc = GetDC (hwnd); ScrollDC (hdc, 0, -cyChar, &rect, &rect, NULL, NULL); SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)); if (ExecSRB-SRB_Status==SS_COMP) { wsprintf ( string_buf, "Host Adapter #%d - SCSI ID #%d: ", (int) ExecSRB-SRB_HaId, (int) ExecSRB-SRB_Target ); lstrcat ( string_buf, &ExecSRB-SRB_BufPointer[8] ); string_len = lstrlen ( string_buf ); } else { string_len = wsprintf ( string_buf, "Host Adapter #%d - SCSI ID #%d: %-32s", (int) ExecSRB-SRB_HaId, (int) ExecSRB-SRB_Target, (LPSTR) "NO Device" ); } TextOut (hdc, cxChar, rect.bottom-cyChar, string_buf, string_len); ReleaseDC (hwnd,hdc); ValidateRect (hwnd, NULL); return; } //********************************************************************** // 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 //********************************************************************** void FAR PASCAL ASPIPostProc ( LPSRB DoneSRB ) { PostMessage ( PostHWND, WM_ASPIPOST, (WORD) ((SRB_ExecSCSICmd6 far *)DoneSRB)-SRB_Status, (DWORD) DoneSRB ); return; } SCANSCSI.DEF NAME SCANSCSI DESCRIPTION 'ASPI For Windows - SCANSCSI' EXETYPE WINDOWS STUB 'WINSTUB.EXE' CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVEABLE NONDISCARDABLE MULTIPLE HEAPSIZE 1024 STACKSIZE 8192 EXPORTS WndProc AboutDlgProc ASPIPostProc IMPORTS WINASPI.GetASPISupportInfo WINASPI.SendASPICommand WINASPI.H //********************************************************************** // // Name: WINASPI.H // // Description: ASPI for Windows definitions ('C' Language) // //********************************************************************** typedef BYTE far *LPSRB; WORD FAR PASCAL SendASPICommand (LPSRB); WORD FAR PASCAL GetASPISupportInfo (VOID); #define SENSE_LEN 14 // Default sense buffer length #define SRB_DIR_SCSI 0x00 // Direction determined by SCSI command #define SRB_DIR_IN 0x08 // Transfer from SCSI target to host #define SRB_DIR_OUT 0x10 // Transfer from host to SCSI targetw #define SRB_POSTING 0x01 // Enable ASPI posting #define WM_ASPIPOST 0x4D42 // ASPI Post message //********************************************************************** // %%% ASPI Command Definitions %%% //********************************************************************** #define SC_HA_INQUIRY 0x00 // Host adapter inquiry #define SC_GET_DEV_TYPE 0x01 // Get device type #define SC_EXEC_SCSI_CMD 0x02 // Execute SCSI command #define SC_ABORT_SRB 0x03 // Abort an SRB #define SC_RESET_DEV 0x04 // SCSI bus device reset //********************************************************************** // %%% SRB Status %%% //********************************************************************** #define SS_PENDING 0x00 // SRB being processed #define SS_COMP 0x01 // SRB completed without error #define SS_ABORTED 0x02 // SRB aborted #define SS_ABORT_FAIL 0x03 // Unable to abort SRB #define SS_ERR 0x04 // SRB completed with error #define SS_INVALID_CMD 0x80 // Invalid ASPI command #define SS_INVALID_HA 0x81 // Invalid host adapter number #define SS_NO_DEVICE 0x82 // SCSI device not installed #define SS_INVALID_SRB 0xE0 // Invalid parameter set in SRB #define SS_OLD_MANAGER 0xE1 // ASPI manager doesn't support Window #define SS_ILLEGAL_MODE 0xE2 // Unsupported Windows mode #define SS_NO_ASPI 0xE3 // No ASPI managers resident #define SS_FAILED_INIT 0xE4 // ASPI for windows failed init #define SS_ASPI_IS_BUSY 0xE5 // No resources available to execute cmd #define SS_BUFFER_TO_BIG 0xE6 // Buffer size to big to handle! //********************************************************************** // %%% Host Adapter Status %%% //********************************************************************** #define HASTAT_OK 0x00 // Host adapter did not detect an error #define HASTAT_SEL_TO 0x11 // Selection Timeout #define HASTAT_DO_DU 0x12 // Data overrun data underrun #define HASTAT_BUS_FREE 0x13 // Unexpected bus free #define HASTAT_PHASE_ERR 0x14 // Target bus phase sequence failure //********************************************************************** // %%% SRB - HOST ADAPTER INQUIRY - SC_HA_INQUIRY %%% //********************************************************************** 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 } SRB_HAInquiry; //********************************************************************** // %%% SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE %%% //********************************************************************** 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; // ASPI request flags DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 BYTE SRB_Target; // Target's SCSI ID BYTE SRB_Lun; // Target's LUN number BYTE SRB_DeviceType; // Target's peripheral device type } SRB_GDEVBlock; //********************************************************************** // %%% SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD %%% //********************************************************************** typedef struct { // Structure for 6-byte CDBs 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, MUST = 0 BYTE SRB_Target; // Target's SCSI ID BYTE SRB_Lun; // Target's LUN number DWORD SRB_BufLen; // Data Allocation Length BYTE SRB_SenseLen; // Sense Allocation Length BYTE far *SRB_BufPointer; // Data Buffer Pointer DWORD SRB_Rsvd1; // Reserved, MUST = 0 BYTE SRB_CDBLen; // CDB Length = 6 BYTE SRB_HaStat; // Host Adapter Status BYTE SRB_TargStat; // Target Status FARPROC SRB_PostProc; // Post routine BYTE SRB_Rsvd2[34]; // Reserved, MUST = 0 BYTE CDBByte[6]; // SCSI CDB BYTE SenseArea6[SENSE_LEN]; // Request Sense buffer } SRB_ExecSCSICmd6; typedef struct { // Structure for 10-byte CDBs 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, MUST = 0 BYTE SRB_Target; // Target's SCSI ID BYTE SRB_Lun; // Target's LUN number DWORD SRB_BufLen; // Data Allocation Length BYTE SRB_SenseLen; // Sense Allocation Length BYTE far *SRB_BufPointer; // Data Buffer Pointer DWORD SRB_Rsvd1; // Reserved, MUST = 0 BYTE SRB_CDBLen; // CDB Length = 10 BYTE SRB_HaStat; // Host Adapter Status BYTE SRB_TargStat; // Target Status FARPROC SRB_PostProc; // Post routine BYTE SRB_Rsvd2[34]; // Reserved, MUST = 0 BYTE CDBByte[10]; // SCSI CDB BYTE SenseArea10[SENSE_LEN]; // Request Sense buffer } SRB_ExecSCSICmd10; typedef struct { // Structure for 12-byte CDBs 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, MUST = 0 BYTE SRB_Target; // Target's SCSI ID BYTE SRB_Lun; // Target's LUN number DWOR SRB_BufLen; // Data Allocation Length BYTE SRB_SenseLen; // Sense Allocation Length BYTE far *SRB_BufPointer; // Data Buffer Pointer DWORD SRB_Rsvd1; // Reserved, MUST = 0 BYTE SRB_CDBLen; // CDB Length = 12 BYTE SRB_HaStat; // Host Adapter Status BYTE SRB_TargStat; // Target Status FARPROC SRB_PostProc; // Post routine BYTE SRB_Rsvd2[34]; // Reserved, MUST = 0 BYTE CDBByte[12]; // SCSI CDB BYTE SenseArea12[SENSE_LEN]; // Request Sense buffer } SRB_ExecSCSICmd12; //********************************************************************** // %%% SRB - ABORT AN SRB - SC_ABORT_SRB %%% //********************************************************************** 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; // ASPI request flags DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 LPSRB SRB_ToAbort; // Pointer to SRB to abort } SRB_Abort; //********************************************************************** // %%% SRB - BUS DEVICE RESET - SC_RESET_DEV %%% //********************************************************************** 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; // ASPI request flags DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0 BYTE SRB_Target; // Target's SCSI ID BYTE SRB_Lun; // Target's LUN number BYTE SRB_ResetRsvd1[14]; // Reserved, MUST = 0 BYTE SRB_HaStat; // Host Adapter Status BYTE SRB_TargStat; // Target Status FARPROC SRB_PostProc; // Post routine BYTE SRB_ResetRsvd2[34]; // Reserved, MUST = 0 } SRB_BusDeviceReset; SCSIDEFS.H //********************************************************************** // // Name: SCSIDEFS.H // // Description: SCSI definitions ('C' Language) // //********************************************************************** //********************************************************************** // %%% TARGET STATUS VALUES %%% //********************************************************************** #define STATUS_GOOD 0x00 // Status Good #define STATUS_CHKCOND 0x02 // Check Condition #define STATUS_CONDMET 0x04 // Condition Met #define STATUS_BUSY 0x08 // Busy #define STATUS_INTERM 0x10 // Intermediate #define STATUS_INTCDMET 0x14 // Intermediate-condition met #define STATUS_RESCONF 0x18 // Reservation conflict #define STATUS_COMTERM 0x22 // Command Terminated #define STATUS_QFULL 0x28 // Queue full //********************************************************************** // %%% SCSI MISCELLANEOUS EQUATES %%% //********************************************************************** #define MAXLUN 7 // Maximum Logical Unit Id #define MAXTARG 7 // Maximum Target Id #define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs #define MAX_NUM_HA 8 // Maximum Number of SCSI HA's //\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ // // %%% SCSI COMMAND OPCODES %%% // ///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ //********************************************************************** // %%% Commands for all Device Types %%% //********************************************************************** #define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional) #define SCSI_COMPARE 0x39 // Compare (O) #define SCSI_COPY 0x18 // Copy (O) #define SCSI_COP_VERIFY 0x3A // Copy and Verify (O) #define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY) #define SCSI_LOG_SELECT 0x4C // Log Select (O) #define SCSI_LOG_SENSE 0x4D // Log Sense (O) #define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific) #define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific) #define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific) #define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific) #define SCSI_READ_BUFF 0x3C // Read Buffer (O) #define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY) #define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O) #define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O) #define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY) #define SCSI_WRITE_BUFF 0x3B // Write Buffer (O) //********************************************************************** // %%% Commands Unique to Direct Access Devices %%% //********************************************************************** #define SCSI_FORMAT 0x04 // Format Unit (MANDATORY) #define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O) #define SCSI_PREFETCH 0x34 // Prefetch (O) #define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O) #define SCSI_READ6 0x08 // Read 6-byte (MANDATORY) #define SCSI_READ10 0x28 // Read 10-byte (MANDATORY) #define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY) #define SCSI_RD_DEFECT 0x37 // Read Defect Data (O) #define SCSI_READ_LONG 0x3E // Read Long (O) #define SCSI_REASS_BLK 0x07 // Reassign Blocks (O) #define SCSI_RELEASE 0x17 // Release Unit (MANDATORY) #define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY) #define SCSI_REZERO 0x01 // Rezero Unit (O) #define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O) #define SCSI_SRCH_DAT_H 0x30 // Search Data High (O) #define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O) #define SCSI_SEEK6 0x0B // Seek 6-Byte (O) #define SCSI_SEEK10 0x2B // Seek 10-Byte (O) #define SCSI_SET_LIMIT 0x33 // Set Limits (O) #define SCSI_START_STP 0x1B // Start/Stop Unit (O) #define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O) #define SCSI_VERIFY 0x2F // Verify (O) #define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY) #define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY) #define SCSI_WRT_VERIFY 0x2E // Write and Verify (O) #define SCSI_WRITE_LONG 0x3F // Write Long (O) #define SCSI_WRITE_SAME 0x41 // Write Same (O) //********************************************************************** // %%% Commands Unique to Sequential Access Devices %%% //********************************************************************** #define SCSI_ERASE 0x19 // Erase (MANDATORY) #define SCSI_LOAD_UN 0x1B // Load/Unload (O) #define SCSI_LOCATE 0x2B // Locate (O) #define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY) #define SCSI_READ_POS 0x34 // Read Position (O) #define SCSI_READ_REV 0x0F // Read Reverse (O) #define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O) #define SCSI_REWIND 0x01 // Rewind (MANDATORY) #define SCSI_SPACE 0x11 // Space (MANDATORY) #define SCSI_VERIFY_T 0x13 // Verify (Tape) (O) #define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY) #define SCSI_PARTITION 0x0D // DAT/QFA Partition Select #define SCSI_READWRITE 0x06 // Set Read/Write Parameters //********************************************************************** // %%% Commands Unique to Printer Devices %%% //********************************************************************** #define SCSI_PRINT 0x0A // Print (MANDATORY) #define SCSI_SLEW_PNT 0x0B // Slew and Print (O) #define SCSI_STOP_PNT 0x1B // Stop Print (O) #define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O) //********************************************************************** // %%% Commands Unique to Processor Devices %%% //********************************************************************** #define SCSI_RECEIVE 0x08 // Receive (O) #define SCSI_SEND 0x0A // Send (O) //********************************************************************** // %%% Commands Unique to Write-Once Devices %%% //********************************************************************** #define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O) #define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O) #define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O) #define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O) #define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O) #define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O) #define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O) #define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O) #define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O) #define SCSI_VERIFY10 0x2F // Verify 10-Byte (O) #define SCSI_VERIFY12 0xAF // Verify 12-Byte (O) #define SCSI_WRITE12 0xAA // Write 12-Byte (O) #define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O) #define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O) //********************************************************************** // %%% Commands Unique to CD-ROM Devices %%% //********************************************************************** #define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O) #define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O) #define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O) #define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O) #define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O) #define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O) #define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY) #define SCSI_READHEADER 0x44 // Read Header (O) #define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O) #define SCSI_READ_TOC 0x43 // Read TOC (O) //********************************************************************** // %%% Commands Unique to Scanner Devices %%% //********************************************************************** #define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O) #define SCSI_GETWINDOW 0x25 // Get Window (O) #define SCSI_OBJECTPOS 0x31 // Object Position (O) #define SCSI_SCAN 0x1B // Scan (O) #define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY) //********************************************************************** // %%% Commands Unique to Optical Memory Devices %%% //********************************************************************** #define SCSI_UpdateBlk 0x3D // Update Block (O) //********************************************************************** // %%% Commands Unique to Medium Changer Devices %%% //********************************************************************** #define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O) #define SCSI_INITELSTAT 0x07 // Initialize Element Status (O) #define SCSI_POSTOELEM 0x2B // Position to Element (O) #define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O) #define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O) //********************************************************************** // %%% Commands Unique to Communication Devices %%% //********************************************************************** #define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY) #define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O) #define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O) #define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY) #define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O) #define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O) //\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ // // %%% END OF SCSI COMMAND OPCODES %%% // ///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ //********************************************************************** // %%% Request Sense Data Format %%% //********************************************************************** typedef struct { BYTE ErrorCode; // Error Code (70H or 71H) BYTE SegmentNum; // Number of current segment descriptor BYTE SenseKey; // Sense Key(See bit definitions too) BYTE InfoByte0; // Information MSB BYTE InfoByte1; // Information MID BYTE InfoByte2; // Information MID BYTE InfoByte3; // Information LSB BYTE AddSenLen; // Additional Sense Length BYTE ComSpecInf0; // Command Specific Information MSB BYTE ComSpecInf1; // Command Specific Information MID BYTE ComSpecInf2; // Command Specific Information MID BYTE ComSpecInf3; // Command Specific Information LSB BYTE AddSenseCode; // Additional Sense Code BYTE AddSenQual; // Additional Sense Code Qualifier // BYTE FieldRepUCode; // Field Replaceable Unit Code // BYTE SenKeySpec15; // Sense Key Specific 15th byte // BYTE SenKeySpec16; // Sense Key Specific 16th byte // BYTE SenKeySpec17; // Sense Key Specific 17th byte // BYTE AddSenseBytes; // Additional Sense Bytes } SENSE_DATA_FMT; //********************************************************************** // %%% REQUEST SENSE ERROR CODE %%% //********************************************************************** #define SERROR_CURRENT 0x70 // Current Errors #define SERROR_DEFERED 0x71 // Deferred Errors //********************************************************************** // %%% REQUEST SENSE BIT DEFINITIONS %%% //********************************************************************** #define SENSE_VALID 0x80 // Byte 0 Bit 7 #define SENSE_FILEMRK 0x80 // Byte 2 Bit 7 #define SENSE_EOM 0x40 // Byte 2 Bit 6 #define SENSE_ILI 0x20 // Byte 2 Bit 5 //********************************************************************** // %%% REQUEST SENSE SENSE KEY DEFINITIONS %%% //********************************************************************** #define KEY_NOSENSE 0x00 // No Sense #define KEY_RECERROR 0x01 // Recovered Error #define KEY_NOTREADY 0x02 // Not Ready #define KEY_MEDIUMERR 0x03 // Medium Error #define KEY_HARDERROR 0x04 // Hardware Error #define KEY_ILLGLREQ 0x05 // Illegal Request #define KEY_UNITATT 0x06 // Unit Attention #define KEY_DATAPROT 0x07 // Data Protect #define KEY_BLANKCHK 0x08 // Blank Check #define KEY_VENDSPEC 0x09 // Vendor Specific #define KEY_COPYABORT 0x0A // Copy Abort #define KEY_ABORT 0x0B // Abort #define KEY_EQUAL 0x0C // Equal (Search) #define KEY_VOLOVRFLW 0x0D // Volume Overflow #define KEY_MISCOMP 0x0E // Miscompare (Search) #define KEY_RESERVED 0x0F // Reserved //********************************************************************** // %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%% //********************************************************************** #define DTYPE_DASD 0x00 // Disk Device #define DTYPE_SEQD 0x01 // Tape Device #define DTYPE_PRNT 0x02 // Printer #define DTYPE_PROC 0x03 // Processor #define DTYPE_WORM 0x04 // Write-once read-multiple #define DTYPE_CROM 0x05 // CD-ROM device #define DTYPE_SCAN 0x06 // Scanner device #define DTYPE_OPTI 0x07 // Optical memory device #define DTYPE_JUKE 0x08 // Medium Changer device #define DTYPE_COMM 0x09 // Communications device #define DTYPE_RESL 0x0A // Reserved (low) #define DTYPE_RESH 0x1E // Reserved (high) #define DTYPE_UNKNOWN 0x1F // Unknown or no device type //********************************************************************** // %%% ANSI APPROVED VERSION DEFINITIONS %%% //********************************************************************** #define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand #define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1) #define ANSI_SCSI2 0x2 // Device complies to SCSI-2 #define ANSI_RESLO 0x3 // Reserved (low) #define ANSI_RESHI 0x7 // Reserved (high) Error Codes and Messages All ASPI for Windows calls can fail. This specification has already defined which -error codes can be returned by each ASPI routine. The following table summarizes all of the error codes returned by ASPI routines. Error Code Value Meaning 0x0000 SS_PENDING SCSI request is in progress. 0x0001 SS_COMP SCSI/ASPI request has completed without error. 0x0002 SS_ABORTED SCSI command has been aborted. 0x0004 SS_ERR SCSI command has completed with an error. 0x0080 SS_INVALID_CMD Invalid ASPI command code. 0x0081 SS_INVALID_HA Invalid host adapter number. 0x0082 SS_NO_DEVICE SCSI device not installed. 0x00E0 SS_INVALID_SRB The SCSI Request Block (SRB) has one or more parameters set incorrectly. 0x00E1 SS_OLD_MANAGER There are one or more ASPI for DOS managers loaded which do not support Windows. 0x00E2 SS_ILLEGAL_MODE This ASPI manager does not support this mode of -Windows. You will typically see this error code when running Windows in Real Mode. 0x00E3 SS_NO_ASPI There are no ASPI managers loaded. This is typically caused by a DOS ASPI manager not being resident in memory. 0x00E4 SS_FAILED_INIT For some reason, other than SS_OLD_MANAGER, SS_ILLEGAL_MODE or SS_NO_ASPI, ASPI for -Windows could not properly initialize itself. This may be caused by a lack of system resources. 0x00E5 SS_ASPI_IS_BUSY The ASPI manager cannot handle the request at this time. This error will generally occur if the ASPI - manager is already using up all of his resources to - execute other requests. You should try resending the command later. 0x00E6 SS_BUFFER_TO_BIG The ASPI manager cannot handle this larger than 64 KByte transfer. You'll need to break up the SCSI I/O into smaller 64K transfers. Refer to Miscellaneous for more information.