/*
 * distilled information from various header files from Microsoft's
 * DDK for Windows NT 4.0
 */
#ifndef NTSCSI_H_INCLUDED
#define NTSCSI_H_INCLUDED

#ifdef _XBOX
#include <xtl.h>
#endif

// 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.

#define	SRB_POSTING					0x01	// Enable ASPI command completion posting. See section on posting below.
#define	SRB_ENABLE_RESIDUAL_COUNT	0x04	// 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.
#define	SRB_DIR_IN					0x08	// Data transfer from SCSI target to host.
#define SRB_DIR_OUT					0x10	// Data transfer from host to SCSI target.
#define	SRB_EVENT_NOTIFY			0x40	// Enable ASPI command event notification. See section on event notification below.


// Inquiry DeviceTypeCodes 
#define DTC_DISK			0x00	// Direct-access device
#define DTC_TAPE			0x01	// Sequential-access device 
#define DTC_PRINTER			0x02	// Printer device 
#define DTC_PROCESSOR		0x03	// Processor device 
#define DTC_WORM			0x04	// Write-once device 
#define DTC_CDROM			0x05	// CD-ROM device 
#define DTC_SCANNER			0x06	// Scanner device 
#define DTC_OPTICAL			0x07	// Optical memory device 
#define DTC_JUKEBOX			0x08	// Medium changer device 
#define DTC_COMM			0x09	// Communications device 
#define DTC_PREPRESS1		0x0A	// Pre-press device 1 
#define DTC_PREPRESS2		0x0B	// Pre-press device 2 
#define DTC_UNKNOWN			0x1F	// Unknown or no device type 


/***************************************************************************
 ** 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   */
                                         /* windows                        */
#define SS_BUFFER_ALIGN           0xE1   /* Buffer not aligned (replaces   */
                                         /* SS_OLD_MANAGER in Win32)       */
#define SS_ILLEGAL_MODE           0xE2   /* Unsupported Windows mode       */
#define SS_NO_ASPI                0xE3   /* No ASPI managers               */
#define SS_FAILED_INIT            0xE4   /* ASPI for windows failed init   */
#define SS_ASPI_IS_BUSY           0xE5   /* No resources available to      */
                                         /* execute command                */
#define SS_BUFFER_TO_BIG          0xE6   /* Buffer size too big to handle  */
#define SS_BUFFER_TOO_BIG         0xE6   /* Correct spelling of 'too'      */
#define SS_MISMATCHED_COMPONENTS  0xE7   /* The DLLs/EXEs of ASPI don't    */
                                         /* version check                  */
#define SS_NO_ADAPTERS            0xE8   /* No host adapters to manager    */
#define SS_INSUFFICIENT_RESOURCES 0xE9   /* Couldn't allocate resources    */
                                         /* needed to init                 */
#define SS_ASPI_IS_SHUTDOWN       0xEA   /* Call came to ASPI after        */
                                         /* PROCESS_DETACH                 */
#define SS_BAD_INSTALL            0xEB   /* The DLL or other components    */
                                         /* are installed wrong            */


// SRB defines
#define	SC_HA_INQUIRY		0x00	// Get information about installed host adapters,including the number of installed adapters.
#define	SC_GET_DEV_TYPE		0x01	// Get information about installed SCSI devices.
#define	SC_EXEC_SCSI_CMD	0x02	// Execute SCSI I/O.
#define	SC_ABORT_SRB		0x03	// Abort an outstanding I/O request.
#define	SC_RESET_DEV		0x04	// Reset an individual SCSI target.
#define	SC_GET_DISK_INFO	0x06	// Get information on disk type SCSI devices (not available under Windows NT).
#define SC_GETSET_TIMEOUTS	0x08

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, *LPSRB;

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, *LPSRB_GDEVBLOCK;

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, *LPSRB_HAINQUIRY;

#define SENSE_LEN 14				// Maximum sense length

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, *LPSRB_EXECSCSICMD;

typedef struct {
  USHORT Length;
  UCHAR  ScsiStatus;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  CdbLength;
  UCHAR  SenseInfoLength;
  UCHAR  DataIn;
  ULONG  DataTransferLength;
  ULONG  TimeOutValue;
  ULONG  DataBufferOffset;
  ULONG  SenseInfoOffset;
  UCHAR  Cdb[16];
} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;


typedef struct {
  USHORT Length;
  UCHAR  ScsiStatus;
  UCHAR  PathId;
  UCHAR  TargetId;
  UCHAR  Lun;
  UCHAR  CdbLength;
  UCHAR  SenseInfoLength;
  UCHAR  DataIn;
  ULONG  DataTransferLength;
  ULONG  TimeOutValue;
  PVOID  DataBuffer;
  ULONG  SenseInfoOffset;
  UCHAR  Cdb[16];
} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;

#if 0	// Now defined in win32_ioctl.c
typedef struct {
  SCSI_PASS_THROUGH spt;
  ULONG Filler;
  UCHAR ucSenseBuf[32];
  UCHAR ucDataBuf[512];
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
#endif

typedef struct {
  SCSI_PASS_THROUGH_DIRECT spt;
  ULONG Filler;
  UCHAR ucSenseBuf[32];
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;



typedef struct {
  UCHAR NumberOfLogicalUnits;
  UCHAR InitiatorBusId;
  ULONG InquiryDataOffset;
} SCSI_BUS_DATA, *PSCSI_BUS_DATA;


typedef struct {
  UCHAR NumberOfBusses;
  SCSI_BUS_DATA BusData[1];
} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO;


typedef struct {
  UCHAR PathId;
  UCHAR TargetId;
  UCHAR Lun;
  BOOLEAN DeviceClaimed;
  ULONG InquiryDataLength;
  ULONG NextInquiryDataOffset;
  UCHAR InquiryData[1];
} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA;


typedef struct {
  ULONG Length;
  UCHAR PortNumber;
  UCHAR PathId;
  UCHAR TargetId;
  UCHAR Lun;
} SCSI_ADDRESS, *PSCSI_ADDRESS;


/*
 * method codes
 */
#define  METHOD_BUFFERED     0
#define  METHOD_IN_DIRECT    1
#define  METHOD_OUT_DIRECT   2
#define  METHOD_NEITHER      3

/*
 * file access values
 */
#define  FILE_ANY_ACCESS      0
#define  FILE_READ_ACCESS     (0x0001)
#define  FILE_WRITE_ACCESS    (0x0002)


#define IOCTL_SCSI_BASE    0x00000004

/*
 * constants for DataIn member of SCSI_PASS_THROUGH* structures
 */
#define  SCSI_IOCTL_DATA_OUT          0
#define  SCSI_IOCTL_DATA_IN           1
#define  SCSI_IOCTL_DATA_UNSPECIFIED  2

/*
 * Standard IOCTL define
 */
#define CTL_CODE( DevType, Function, Method, Access ) (                 \
    ((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)

#define IOCTL_SCSI_PASS_THROUGH         CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define IOCTL_SCSI_MINIPORT             CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define IOCTL_SCSI_GET_INQUIRY_DATA     CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_GET_CAPABILITIES     CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_PASS_THROUGH_DIRECT  CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define IOCTL_SCSI_GET_ADDRESS          CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS )

int		NtScsiInit( void );
int		NtScsiDeInit( void );

BYTE	NtScsiGetNumAdapters( void );
DWORD	NtScsiGetASPI32SupportInfo( void );
DWORD	NtScsiGetDeviceType( LPSRB_GDEVBLOCK lpsrb );
BYTE	NtScsiGetDeviceIndex( BYTE ha, BYTE tgt, BYTE lun );

DWORD	NtScsiHandleHaInquiry( LPSRB_HAINQUIRY lpsrb );
DWORD	NtScsiSendASPI32Command( LPSRB lpsrb );
DWORD	NtScsiExecSCSICommand( LPSRB_EXECSCSICMD lpsrb, BOOL bBeenHereBefore );

typedef DWORD (*lpGetSupport)	(void);
typedef DWORD (*lpSendCommand)		(LPSRB lpSRB);

#endif
