NOTE: The ATADRVR History has been moved to the User Guide (see below).
ATADRVR is Hale Landis' C code that shows the low level programming required to configure and execute commands on ATA and ATAPI devices. Over the years this code has been updated to support all of the ATA and now ATA/ATAPI standards. This C code has been placed into the public domain by Hale Landis. This C code has no copyright or other restrictions on how it is used.
Before using ATADRVR in your project you should read the PIO.HTM, DMA.HTM and SATA.HTM documentation files.
ATADRVR and the EXAMPLE1 and EXAMPLE2 programs are DOS "real mode" programs. This software will not execute in a Windows DOS session (a virtual x86 session). You must use a compiler and linker that are able to create DOS real mode programs. Hale uses Borland C/C++ 4.5. Note that the free (or low cost) Borland C++ 5.x compiler will not compile this code -- you need the full Borland C++ 5.x compiler.
The best way to see how this code can be used is shown in the C program files EXAMPLE1.C and EXAMPLE2.C. ATADRVR provides all of the funcitons and facilities needed to perform the low level I/O port activities on an x86 computer so that ATA and ATAPI commands can be executed.
ATADRVR also includes detailed low level and command history tracing funcitons.
ATADRVR source code is organized into two H files and several C files.
The H files are:
ATAIO.H
The file ATAIO.H defines all of the "public" functions and data for ATADRVR. This file should be included into any program using the ATADRVR functions.
The C files are:
ATAIOINT.C ATAIOISA.C ATAIOPCI.C ATAIOPIO.C ATAIOREG.C ATAIOSUB.C ATAIOTMR.C ATAIOTRC.C EXAMPLE1.C EXAMPLE2.C
The file ATAIOINT.C contains the x86 interrupt setup and handling data and functions. The public symbols in this file begin with the characters "int_".
The file ATAIOISA.C contains the x86 ISA bus DMA functions. The public symbols in this file begin with characters "dma_isa_".
The file ATAIOPCI.C contains the x86 PCI Bus Mastering DMA functions. The public symbols in this file begin with characters "dma_pci_".
The file ATAIOPIO.C contains the lowest level I/O port access functions. The public symbols in this file begin with characters "pio_".
The file ATAIOREG.C contains ATA and ATAPI functions to perform ATA Soft Reset, Non-Data, PIO Data IN, PIO Data Out and ATAPI Packet command protocols. The public symbols in this file begin with characters "reg_".
The file ATAIOSUB.C contains severals "private" functions used by ATADRVR.
The file ATAIOTMR.C contains the timer reading and command timeout functions. The public symbols in this file begin with characters "tmr_".
The file ATAIOTRC.C contains the low level and command history trace functions. The public symbols in this file begin with characters "trc_".
The file EXAMPLE1.C is an example of using ATADRVR to configure an ATA device and execute a few commands.
The file EXAMPLE2.C is an example of using ATADRVR to configure an ATAPI CD-ROM device and execute a few commands.
NOTE:If you use ATADRVR in a program you should use only the public symbols. This will allow you too upgrade to newer versions of ATADRVR (assuming there will be new versions in the future) with minimum effort. The private data and functions are subject to change in future versions of ATADRVR.
Before using the ATADRVR code in your program, please review the EXAMPLE1.C, EXAMPLE1.MAK, EXAMPLE2.C and EXAMPLE2.MAK files. These files will provide a basic overview of how this driver code can be used.
The basics of using ATADRVR, as shown in EXAMPLE1.C or EXAMPLE2.C, are these:
1) #include "ataio.h" in your program.
2) Call pio_set_iobase_addr() or pio_set_memory_addr() to set the base I/O or memory address used by the ATA host adapter.
3) Call reg_config() so that ATADRVR can determine what devices are attached to the ATA host adapter.
4) Call reg_reset() or any of the other "reg" functions to issue ATA or ATAPI commands in PIO data transfer mode.
ATADRVR has been developed using Borland C and can be compiled in any x86 real mode memory mode.
One of the dumber things T13 did was to allow the 48-bit LBA commands to transfer huge amounts of data, up to 65536 sectors (33Mbytes) in a single command. ATADRVR is able to support these huge transfers even if the data buffer is not that big. The I/O buffer must be at least the size of the largest DRQ block that will be transferred by a PIO data transfer command. For READ/WRITE SECTORS that is a single sector buffer. For READ/WRITE MULTIPLE that is a buffer that holds the current multiple block count number of sectors. For PACKET commands the size of a DRQ data block can not exceed the buffer size and (according to all ATA/ATAPI protocol rules) can not exceed the PACKET command's Byte Count Limit (BCL).
This mode of PIO data transfer is enabled when the reg_drq_block_call_back function pointer is not NULL. Note that this facility of ATADRVR can be used with any PIO Data In/Out command and/or any PIO PACKET command.
ATADRVR supports these transfers by calling back to a user supplied function at these times:
* For ATA or PACKET PIO Data In commands, after each DRQ block has been read from the device. The call back function should use this call to access the data buffer.
* For ATA or PACKET PIO Data Out commands, before each DRQ block is written to the device. The call back function should use this call to fill the data buffer.
The call back function receives a pointer to a REG_CMD_INFO structure. It must use the data in this structure to determine what is happening. The call back function has no return value.
The reg_drq_block_call_back function pointer is set to NULL before the ATA or PACKET PIO Data In/Out functions return.
struct REG_CMD_INFO { unsigned char flg; // see TRC_FLAG_xxx in ATAIO.H unsigned char ct; // see TRC_TYPE_xxx in ATAIO.H unsigned char cmd; // command code unsigned char fr1; // feature reg before // ... See ATAIO.H ... unsigned char dc1; // device control before unsigned char ec; // ATADRVR error code unsigned char to; // not zero if time out error unsigned char st2; // status reg after // ... See ATAIO.H ... unsigned char dh2; // device head after long totalBytesXfer; // total bytes transferred unsigned int failbits; // failure bits (protocol violation bits) long drqPackets; // number of PIO DRQ data packets long drqPacketSize; // number of bytes in current DRQ block } ; struct REG_CMD_INFO reg_cmd_info;
This data structure contains all the "before" and "after" information for the last command or reset executed.
When the PIO data transfer call back function is called drqPackets is the DRQ block number (1, 2, 3, ...) and drqPacketSize is the number of bytes in the current DRQ block See reg_drq_block_call_back.
Each of the public functions and symbols of ATADRVR are described below in alphabetical order.
These functions setup interrupt handling for the ATA host adapter. Interrupts are not required in order to execute nost ATA or ATAPI commands but are usually used. Interrupts are required in order to execute DMA data transfer commands. If int_enable_irq() is called, then int_disable_irq() MUST be called before your program exits (otherwise your system may hang). The functions int_enable_irq() and int_disable_irq() may be called multiple times in order to switch between polling and interrupt mode on a command by command basis.
void int_disable_irq( void );
Disable interrupt use.
int int_enable_irq( int shared, int irqNum, unsigned int bmAddr, unsigned int ataAddr );
Enable interrupt use. shared is 0 or not 0. shared is not 0 to use the IRQ in shared mode. irqNum is 1 to 15. bmAddr is the I/O port address for the BMIDE Status regiser. This value is found in BAR 4 (offset 20H) of the ATA controllers PCI configuration space data. bmAddr is that value +2 for the primary side of the controller and +10 for the secondary side of the controller. ataAddr is the I/O port address for the ATA Status register (not the Alternate Status register!).
int int_use_intr_flag;
This value is READONLY -- DO NOT ALTER.
The value is not zero if an IRQ is currently configured.
These functions setup ISA bus DMA (ATA Multiword DMA) and perform ATA and ATAPI commands using DMA. The function dma_isa_config() MUST be called with no error before any of the other functions will attempt to execute a command.
int dma_isa_chs( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count unsigned int cyl, // CHS cylinder high/low int head, // CHS head int sect, // CHS sector unsigned seg, // buffer address unsigned off ); // buffer address
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command using CHS sector addressing.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int dma_isa_lba28( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lba, // LBA unsigned seg, // buffer address unsigned off ); // buffer address
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int dma_isa_lba48( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lbahi, // LBA upper 16-bits long lbalo, // LBA lower 32 bits unsigned seg, // buffer address unsigned off ); // buffer address
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int dma_isa_config( int chan );
Configure ATADRVR to use ISA bus DMA (ATA Multiword DMA) on ISA DMA Channel 5, 6 or 7.
int dma_isa_packet( int dev, // device (0 or 1) unsigned int cpbc, // command packet size unsigned int cpseg, // command packet buffer unsigned int cpoff, // command packet buffer int dir, // 0 for no data or read, 1 for write unsigned int dpbc, // max data packet size unsigned int dpseg, // data packet buffer unsigned int dpoff ); // data packet buffer
Execute an ATAPI Packet (A0H) command in DMA mode. Note that the first byte of the Commmand Packet buffer is the command code of the "SCSI CDB" that is to be executed by the device.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
These functions setup PCI bus DMA (ATA Multiword or Ultra DMA) and perform ATA and ATAPI commands using DMA. The function dma_pci_config() MUST be called with no error before any of the other functions will attempt to execute a command.
int dma_pci_chs( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count unsigned int cyl, // CHS cylinder high/low int head, // CHS head int sect, // CHS sector int dir, // 0=read, 1=write unsigned seg, // buffer address unsigned off ); // buffer address
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command using CHS sector addressing.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int dma_pci_lba28( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lba, // LBA int dir, // 0=read, 1=write unsigned seg, // buffer address unsigned off ); // buffer address
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int dma_pci_lba48( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lbahi, // LBA upper 16-bits long lbalo, // LBA lower 32 bits int dir, // 0=read, 1=write unsigned seg, // buffer address unsigned off ); // buffer address
Execute an ATA Read DMA (C8H) or ATA Write DMA (CAH) command using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int dma_pci_config( unsigned int regAddr );
Configure ATADRVR to use PCI bus DMA (ATA Multiword or Ultra DMA) on a PCI Bus Mastering ATA controller.
int dma_pci_packet( int dev, // device (0 or 1) unsigned int cpbc, // command packet size unsigned int cpseg, // command packet buffer unsigned int cpoff, // command packet buffer int dir, // 0 for no data or read, 1 for write unsigned int dpbc, // max data packet size unsigned int dpseg, // data packet buffer unsigned int dpoff ); // data packet buffer
Execute an ATAPI Packet (A0H) command in DMA mode. Note that the first byte of the Commmand Packet buffer is the command code of the "SCSI CDB" that is to be executed by the device.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
void dma_pci_set_max_xfer( unsigned int seg, unsigned int off, long bufSize );
This function uses the caller's I/O buffer description (seg;off and size) to compute if LARGE PRD lists can be supported. See the variables: dma_pci_prd_type, dma_pci_largeMaxB, dma_pci_largeMaxS, dma_pci_largePrdBufPtr and dma_pci_largeIoBufPtr.
unsigned int dma_pci_bmide_reg_addr; // BMIDE reg base i/o address
This value is READONLY -- DO NOT ALTER.
This value is the base I/O address of the BMIDE I/O registers. The value is set by dma_pci_config().
Note that in order to use PCI DMA the calling program must determine the current base I/O address of the BMIDE registers.
int dma_pci_prd_type;
This variable determines the type of PRD list that will be used. Choices are SIMPLE, COMPLEX and LARGE. SIMPLE are the most common type. COMPLEX lists are the same as SIMPLE but with more PRD entries that break the transfers into smaller memory areas. LARGE PRD lists are built in the caller's I/O buffer and a 64K chunk of the same I/O buffer is used over and over for the data transfer. LARGE PRD lists enable READ/WRITE DMA EXT transfers up to 65356 sectors. Use the function dma_pci_set_max_xfer() to determine if LARGE PRD lists can be supported.
Note that COMPLEX PRD lists may cause data corruption and/or system hang problems on some ATA host controllers.
unsigned long * dma_pci_prd_ptr; // current BMIDE PRD buffer address
This value is READONLY -- DO NOT ALTER.
This value is the segment address of the BMIDE PRD buffer. This value is determined by dma_pci_config().
int dma_pci_num_prd; // current number of PRD entries
This value is READONLY -- DO NOT ALTER.
This value is the number of PRD entries used for the last DMA command.
long dma_pci_largeMaxB; // max LARGE dma transfer size in bytes long dma_pci_largeMaxS; // max LARGE dma transfer size in sectors unsigned long far * dma_pci_largePrdBufPtr; // LARGE PRD buffer ptr unsigned char far * dma_pci_largeIoBufPtr; // LARGE PRD I/O address
These values are READONLY -- DO NOT ALTER.
These values are set by calling the function dma_pci_set_max_xfer(). If dma_pci_set_max_xfer() sets these values to non-zero and non-NULL values then LARGE PRD lists can be supported.
These functions setup the ATA host adapter I/O port address (or in PCMCIA PC Card ATA Memory mode, the host adapter memory address). The function pio_set_iobase_addr() (or pio_set_memory_addr()) MUST be the first function called in order to initialize ATADRVR. However, normal usage of ATADRVR does NOT require calling any of the other pio functions. But if you needed to create you own unique command protocol, these functions can be used directly.
unsigned int pio_base_addr1;
This value is READONLY -- DO NOT ALTER.
This is the base I/O address of the ATA Command Block registers. This value is set by pio_set_iobase_addr().
unsigned int pio_base_addr2;
This value is READONLY -- DO NOT ALTER.
This is the base I/O address of the ATA Control Block registers. This value is set by pio_set_iobase_addr().
void pio_drq_block_in( unsigned int addrDataReg, unsigned int bufSeg, unsigned int bufOff, long wordCnt );
This function calls one of the reg_rep_in*() functions based on the value of reg_xfer_width.
void pio_drq_block_out( unsigned int addrDataReg, unsigned int bufSeg, unsigned int bufOff, long wordCnt )
This function calls one of the reg_rep_out*() functions based on the value of reg_xfer_width.
unsigned char pio_inbyte( unsigned int addr );
Read one ATA command or control block register. addr MUST be one of the following values (as defined in ATAIO.H): CB_DATA, CB_ERR, CB_FR, CB_SC, CB_SN, CB_CL, CB_CH, CB_DH, CB_STAT, CB_CMD, CB_ASTA, CB_DC, CB_DA.
unsigned int pio_inword( unsigned int addr );
Read two ATA command or control block registers. addr MUST be one of the following values (as defined in ATAIO.H): CB_DATA, CB_ERR, CB_FR, CB_SC, CB_SN, CB_CL, CB_CH, CB_DH, CB_STAT, CB_CMD, CB_ASTA, CB_DC, CB_DA.
Note: ATADRVR does not use this function.
unsigned char pio_last_read[10];
This value is READONLY -- DO NOT ALTER.
This array contains the last data read from each of the ATA command or control block registers. Index into this array using the values (as defined in ATAIO.H): CB_DATA, CB_ERR, CB_FR, CB_SC, CB_SN, CB_CL, CB_CH, CB_DH, CB_STAT, CB_CMD, CB_ASTA, CB_DC, CB_DA.
unsigned char pio_last_write[10];
This value is READONLY -- DO NOT ALTER.
This array contains the last data written to each of the ATA command or control block registers. Index into this array using the values (as defined in ATAIO.H): CB_DATA, CB_ERR, CB_FR, CB_SC, CB_SN, CB_CL, CB_CH, CB_DH, CB_STAT, CB_CMD, CB_ASTA, CB_DC, CB_DA.
unsigned int pio_memory_seg;
This value is READONLY -- DO NOT ALTER.
This is the base memory address of the ATA Command and Control Block registers in PCMCIA PC Card ATA Memory mode. This value is set by pio_set_memory_addr().
int pio_memory_dt_opt;
This value is used only in PCMCIA PC Card ATA Memory mode. The value controls how ATADRVR reads/write the ATA Data register. It can be set to the following values (see ATAIO.H):
PIO_MEMORY_DT_OPT0 - use Data reg at offset 0H PIO_MEMORY_DT_OPT8 - use Data reg at offset 8H PIO_MEMORY_DT_OPTB - use Data reg at offsets 400-7ffH PIO_MEMORY_DT_OPTR - randomly select these options
The default is PIO_MEMORY_DT_OPT0.
void pio_outbyte( unsigned int addr, unsigned char data );
Write one ATA command or control block register. addr MUST be one of the following values (as defined in ATAIO.H): CB_DATA, CB_ERR, CB_FR, CB_SC, CB_SN, CB_CL, CB_CH, CB_DH, CB_STAT, CB_CMD, CB_ASTA, CB_DC, CB_DA.
void pio_outword( unsigned int addr, unsigned int data );
Write two ATA command or control block registers. addr MUST be one of the following values (as defined in ATAIO.H): CB_DATA, CB_ERR, CB_FR, CB_SC, CB_SN, CB_CL, CB_CH, CB_DH, CB_STAT, CB_CMD, CB_ASTA, CB_DC, CB_DA.
Note: ATADRVR does not use this function.
unsigned int pio_reg_addrs[10];
This value is READONLY -- DO NOT ALTER.
This array provides the actually I/O addresses for the ATA Command and Control Block registers. This array is not useful in PCMCIA PC Card ATA Memory mode.
void pio_rep_inbyte( unsigned int addrDataReg, // register address unsigned int bufSeg, // buffer address unsigned int bufOff, // buffer address unsigned int byteCnt ); // byte count
NOTE: Normally this function is not called directly but is called by the pio_drq_block_in() function!
Use the REP INS instruction to read the ATA Data Register during PIO data transfer.
void pio_rep_indword( unsigned int addrDataReg, // register address unsigned int bufSeg, // buffer address unsigned int bufOff, // buffer address unsigned int dwordCnt ); // dword count
NOTE: Normally this function is not called directly but is called by the pio_drq_block_in() function!
Use the REP INSD instruction to read the ATA Data Register during PIO data transfer. Note that this function is called by pio_drq_block_in() but only if: 1) pio_xfer_width is 32 and 2) the number of bytes to be read is a multiple of 4.
void pio_rep_inword( unsigned int addrDataReg, // register address unsigned int bufSeg, // buffer address unsigned int bufOff, // buffer address unsigned int wordCnt ); // word count
NOTE: Normally this function is not called directly but is called by the pio_drq_block_in() function!
Use the REP INSW instruction to read the ATA Data Register during PIO data transfer.
void pio_rep_outbyte( unsigned int addrDataReg, // register address unsigned int bufSeg, // buffer address unsigned int bufOff, // buffer address unsigned int bytedCnt ); // byte count
NOTE: Normally this function is not called directly but is called by the pio_drq_block_out() function!
Use the REP OUTS instruction to write the ATA Data Register during PIO data transfer.
void pio_rep_outdword( unsigned int addrDataReg, // register address unsigned int bufSeg, // buffer address unsigned int bufOff, // buffer address unsigned int dwordCnt ); // dword count
NOTE: Normally this function is not called directly but is called by the pio_drq_block_out() function!
Use the REP OUTSD instruction to write the ATA Data Register during PIO data transfer. Note that this function is called by pio_drq_block_out() but only if: 1) pio_xfer_width is 32 and 2) the number of bytes to be written is a multiple of 4.
void pio_rep_outword( unsigned int addrDataReg, // register address unsigned int bufSeg, // buffer address unsigned int bufOff, // buffer address unsigned int wordCnt ); // word count
NOTE: Normally this function is not called directly but is called by the pio_drq_block_out() function!
Use the REP OUTSW instruction to write the ATA Data Register during PIO data transfer.
void pio_set_iobase_addr( unsigned int base1, unsigned int base2 );
Either pio_set_iobase_addr() or pio_set_memory_addr() must be called before any other ATADRVR functions can be used!
Configure the ATA host adapter's I/O port addresses. Normal calls to this function are:
pio_set_iobase_addr( 0x1f0, 0x3f0 ) // primary pio_set_iobase_addr( 0x170, 0x370 ) // secondary
For PCMCIA PC Card ATA Contiguous I/O mode use:
pio_set_iobase_addr( addr, addr+8 )
where the least significant 4 bits of addr are zero. Note that the calling program must find a contiguous set of 16 I/O port addresses that are not in use in order to use this PCMCIA I/O mode. See the documentation file PCC.HTM!
void pio_set_memory_addr( unsigned int seg );
Either pio_set_iobase_addr() or pio_set_memory_addr() must be called before any other ATADRVR functions can be used!
Configure the ATA host adapter's memory address in PCMCIA PC Card ATA Memory mode. Note that the calling program must find a 4K block of memory that is not in use in order to use this PCMCIA mode. See the documentation file PCC.HTM!
int pio_use_dword;
NOTE: pio_use_dword has been replaced by pio_xfer_width !
int pio_xfer_width;
This variable controls the width of PIO data transfers. This variable can have the following values:
8 = 8-bits. PIO transfers will use REP INS and REP OUTS or 8-bit memory write/read in PCMCIA Memory mode.
16 = 16-bits. PIO transfers will use REP INSW and REP OUTSW or 16-bit memory write/read in PCMCIA Memory mode.
32 = 32-bits. PIO transfers will use REP INSD and REP OUTSD.
Any other value is treated the same as 16.
The default value is 16.
See the pio_rep_*() functions above.
Use this ATADRVR feature with great care and read the documentation file PIO.HTM!
These functions provide the basic ATA and ATAPI command protocol functions. The function reg_config() MUST be called after calling pio_set_iobase_addr() (or pio_set_memory_addr()). Failure to call reg_config() will cause ATADRVR to operate incorrectly.
unsigned char reg_atapi_cp_data[16]; int reg_atapi_cp_size;
These values are READONLY -- DO NOT ALTER.
reg_atapi_cp_size is the size of the most recent ATAPI command packet size (normally 12 or 16). reg_atapi_cp_data[16] is the most recent ATAPI command packet (SCSI CDB) data.
int reg_atapi_delay_flag;
Many ATAPI devices are very poorly designed and do not follow the ATA or ATAPI protocols as defined by the ATA/ATAPI-4 standard. Setting this word to a non-zero value causes ATADRVR to insert an approximately 100ms delay into the ATA and/or ATAPI command protocols. This delay seems to allow enough time for these non-conforming devices to operate correctly.
unsigned char reg_atapi_reg_fr; // 0x01 OR'ed in for DMA unsigned char reg_atapi_reg_sc; unsigned char reg_atapi_reg_sn; unsigned char reg_atapi_reg_dh; // only bits 3,2,1,0 are used
These values are placed into the Feature, Sector Count, Sector Number and Device/Head register by the reg_packet(), dma_isa_packet() and dma_pci_packet() functions before the A0H command is started. These values are then set to zero before reg_packet() returns.
long reg_buffer_size;
This must be set to the size in bytes of the data buffer provided by the caller.
int reg_config( void );
This function MUST be called so that ATADRVR can correctly configure itself. reg_config() sets the values into reg_config_info[2].
int reg_config_info[2];
This array is set by calling reg_config(). reg_config_info[0] describes device 0 and reg_config_info[1] describes device 1. The possible values in these words are (see ATAIO.H): REG_CONFIG_TYPE_NONE, REG_CONFIG_TYPE_UNKN, REG_CONFIG_TYPE_ATA, REG_CONFIG_TYPE_ATAPI.
Note that ATADRVR is not able to determine the type of some devices. However, after issuing some commands the calling program may be able to determine the exact type of a device. The calling program may change the values in this array but this must be done very carefully:
a) DO NOT CHANGE the value REG_CONFIG_TYPE_NONE. b) DO NOT CHANGE a value to REG_CONFIG_TYPE_NONE. c) The value REG_CONFIG_TYPE_UNKN can be changed to either REG_CONFIG_TYPE_ATA or REG_CONFIG_TYPE_ATAPI.
void ( * reg_drq_block_call_back ) ( struct REG_CMD_INFO * )
When this value is not NULL the PIO Data In/Out functions place the data for each DRQ block at the beginning of the data buffer. This function is called after each DRQ data block is read from the device or before each DRQ data block is written to the device. The call back function receives a pointer to a REG_CMD_INFO structure. Do not assume this pointer contains the address of the static structure reg_cmd_info. To determine what is happening the call back function should use these variables in the structure: flg, ct, cmd, drqPackets and drqPacketSize. The call back function must not modify the contents of the REG_CMD_INFO structure.
This value is set back to NULL before the PIO Data In/Out functions return.
unsigned long reg_lba_chs; #define REG_NO_LBA_CHS 0xf0000000L
The LBA that is equivalent to the CHS used by a command. This value will be placed into the command history trace. Use the value REG_NO_LBA_CHS for commands that execute in CHS mode but do not access media sectors, for example IDENTIFY or SMART write/read log, etc.
int reg_non_data_chs( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count unsigned int cyl, // CHS cylinder high/low int head, // CHS head int sect ); // CHS sector
Execute an ATA Non-Data command using CHS sector addressing.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_non_data_lba28( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lba ); // LBA
Execute an ATA Non-Data command using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_non_data_lba48( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lbahi, // LBA upper 16-bits long lbalo ); // LBA lower 32 bits
Execute an ATA Non-Data command using LBA sector addressing.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_packet( int dev, // device (0 or 1) unsigned int cpbc, // command packet size unsigned int cpseg, // command packet buffer unsigned int cpoff, // command packet buffer int dir, // 0 for no data or read, 1 for write unsigned int dpbc, // max data packet size unsigned int dpseg, // data packet buffer unsigned int dpoff ); // data packet buffer
Execute an ATAPI Packet (A0H) command in PIO mode. Note that the first byte of the Commmand Packet buffer is the command code of the "SCSI CDB" that is to be executed by the device.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_pio_data_in_chs( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count unsigned int cyl, // CHS cylinder high/low int head, // CHS head int sect, // CHS sector unsigned seg, // buffer address unsigned off, // buffer address int numSect, // number of sectors to transfer int multiCnt ); // current multiple count
Execute an ATA PIO Data In command in CHS sector addressing mode.
numSect is the actual number of sectors to be transferred. This value may be different than the sc value.
If cmd is C4H (Read Multiple) then multiCnt MUST be set to the current sectors per block.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_pio_data_in_lba28( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lba, // LBA unsigned seg, // buffer address unsigned off, // buffer address int numSect, // number of sectors to transfer int multiCnt ); // current multiple count
Execute an ATA PIO Data In command in LBA sector addressing mode.
numSect is the actual number of sectors to be transferred. This value may be different than the sc value.
If cmd is C4H (Read Multiple) then multiCnt MUST be set to the current sectors per block.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_pio_data_in_lba48( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lbahi, // LBA upper 16-bits long lbalo, // LBA lower 32 bits unsigned seg, // buffer address unsigned off, // buffer address int numSect, // number of sectors to transfer int multiCnt ); // current multiple count
Execute an ATA PIO Data In command in LBA sector addressing mode.
numSect is the actual number of sectors to be transferred. This value may be different than the sc value.
If cmd is C4H (Read Multiple) then multiCnt MUST be set to the current sectors per block.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_pio_data_out_chs( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count unsigned int cyl, // CHS cylinder high/low int head, // CHS head int sect, // CHS sector unsigned seg, // buffer address unsigned off, // buffer address int numSect, // number of sectors to transfer int multiCnt ); // current multiple count
Execute an ATA PIO Data Out command in CHS sector addressing mode.
numSect is the actual number of sectors to be transferred. This value may be different than the sc value.
If cmd is C5H (Write Multiple) then multiCnt MUST be set to the current sectors per block.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_pio_data_out_lba28( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lba, // LBA unsigned seg, // buffer address unsigned off, // buffer address int numSect, // number of sectors to transfer int multiCnt ); // current multiple count
Execute an ATA PIO Data Out command in LBA sector addressing mode.
numSect is the actual number of sectors to be transferred. This value may be different than the sc value.
If cmd is C5H (Write Multiple) then multiCnt MUST be set to the current sectors per block.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_pio_data_out_lba48( int dev, // device (0 or 1) int cmd, // command register int fr, // feature register int sc, // sector count long lbahi, // LBA upper 16-bits long lbalo, // LBA lower 32 bits unsigned seg, // buffer address unsigned off, // buffer address int numSect, // number of sectors to transfer int multiCnt ); // current multiple count
Execute an ATA PIO Data Out command in LBA sector addressing mode.
numSect is the actual number of sectors to be transferred. This value may be different than the sc value.
If cmd is C5H (Write Multiple) then multiCnt MUST be set to the current sectors per block.
Returns 0 if no error or 1 if there is an error. See the contents of reg_cmd_info.
int reg_reset( int skipFlag, // skip flag int devRtrn ); // device's data returned
Execute an ATA Soft Reset. Set skipFlag to a non-zero value to bypass the setting of the SRST bit to 0 and then to 1 (used in some diagnostic programs). Set devRtrn to 0 or 1 to determine which device's register contents are returned in reg_cmd_info.
long reg_sector_size;
Size of an ATA media data sector. This can be any even number. The default is 512. This is used in the ATA PIO write/read functions. This should be set to 512 before any non-media PIO data transfer command such as IDENTIFY, SMART, SECURITY, etc. This value is not used by ATAPI PIO write/read functions.
int reg_slow_xfer_flag;
Set this word to a non-zero value to cause ATADRVR to insert a 0 to 55ms delay into ATA and ATAPI commands in PIO mode. This simulates a very slow host system and is know to cause various problems for devices (such as buffer overruns and or underruns, firmware hangs, etc).
For ATA PIO commands, if the value is zero or greater than numSect, no delay is inserted, else the delay is inserted when the number of sector remaining to be transferred is less than this value.
For ATAPI PIO commands, if the value is zero or greater than the number of DRQ blocks transferred by the device, no delay is inserted, else the delay is inserted prior to the DRQ block number specified by this value.
These functions provide the command timeout functions used by ATADRVR. Normally these functions are called only by ATADRVR.
int tmr_chk_timeout( void );
Used by ATADRVR to check if a command or reset has timed out. The function tmr_set_timeout() MUST be called before using this function to time a command or reset.
void tmr_delay_1ms( long count );
Delays for count milliseconds.
tmr_get_delay_counts() must be called before using this function - tmr_get_delay_counts() is called by reg_config().
void tmr_delay_1us( long count );
Delays for count microseconds.
tmr_get_delay_counts() must be called before using this function - tmr_get_delay_counts() is called by reg_config().
void tmr_delay_ata( void );
Delays for ~500 nanoseconds.
tmr_get_delay_counts() must be called before using this function - tmr_get_delay_counts() is called by reg_config().
void tmr_delay_atapi( int dev );
Delays for ~80 milliseconds.
tmr_get_delay_counts() must be called before using this function - tmr_get_delay_counts() is called by reg_config().
void tmr_delay_xfer( void );
Delays a random time from 0 to 55 milliseconds.
tmr_get_delay_counts() must be called before using this function - tmr_get_delay_counts() is called by reg_config().
void tmr_get_delay_counts( void );
tmr_get_delay_counts() must be called before using any of the tmr_delay_*() functions - tmr_get_delay_counts() is called by reg_config().
long tmr_read_bios_timer( void );
Used by ATADRVR to read the current contents of the BIOS timer. Normally this value increments every 55ms and is reset to zero at midnight.
void tmr_set_timeout( void );
Used by ATADRVR to start the timeout timer for a command or reset. The value tmr_time_out is added to the current time and this becomes the time that is checked whenever tmr_chk_timeout() is called.
long tmr_time_out;
This value is the command timeout value in seconds. ATADRVR assumes a device is hung if a command or reset requires more than this number of seconds to complete. The default is 20 (20 seconds). Note that some ATA commands (such as power management may require this value be set larger (perhaps to 40).
The following define the size of the Command History and Low Level Trace buffers.
#define TRC_MAX_CHT 100 // default buffer size
The default size of the Command History Trace buffer. The ATADRVR caller can define this value before including the ATAIO.H file.
#define TRC_MAX_LLT 200 // default buffer size
The default size of the Low Level Trace buffer. The ATADRVR caller can define this value before including the ATAIO.H file.
These functions are the public interface to the command history and low level trace facility of ATADRVR.
unsigned char * trc_get_cmd_name( unsigned char flg, unsigned char cc );
Return a pointer to a character string that is the name of an ATA command. flg MUST be one of the following values (as defined in ATAIO.H): TRC_FLAG_SRST or TRC_FLAG_ATA or TRC_FLAG_ATAPI. cc is the ATA command code (the value is ignored if flg is TRC_FLAG_SRST).
unsigned char * trc_get_er_bit_name( unsigned char er );
Return a pointer to a character string that is the list of error bits that are 1 in the ATA Error register. er is assumed to be a value read from the ATA Error register.
unsigned char * trc_get_err_name( int ec );
Return a pointer to a character string that describes the ATADRVR error code (ec).
unsigned char * trc_get_st_bit_name( unsigned char st );
Return a pointer to a character string that is the list of status bits that are 1 in the ATA Error register. st is assumed to be a value read from the ATA Status or Alternate Status register.
void trc_err_dump1( void ); unsigned char * trc_err_dump2( void );
Use these funcitons to return a set of character strings that describe the results of the last command executed. See EXAMPLE1.C or EXAMPLE2.C for details on how to call these functions.
void trc_cht_dump0( void ); void trc_cht_dump1( void ); unsigned char * trc_cht_dump2( void );
Use these funcitons to return a set of character strings that are the current contents of the command history trace buffer. See EXAMPLE1.C or EXAMPLE2.C for details on how to call these functions. Note that these strings are formated to make it easy to create an ATADEMO script file (convert the comma characters to new-line characters).
void trc_cht_types( int type );
The types of commands that are traced in the command history can be restricted to the types specified in this function call. type MUST be one of these values (as defined in ATAIO.H): TRC_TYPE_ALL, TRC_TYPE_NONE, TRC_TYPE_ADMAI, TRC_TYPE_ADMAO, TRC_TYPE_AND, TRC_TYPE_APDI, TRC_TYPE_APDO, TRC_TYPE_ASR, TRC_TYPE_PDMAI, TRC_TYPE_PDMAO, TRC_TYPE_PND, TRC_TYPE_PPDI, TRC_TYPE_PPDO.
void trc_llt_dump0( void ); void trc_llt_dump1( void ); unsigned char * trc_llt_dump2( void );
Use these funcitons to return a set of character strings that are the current contents of the low level trace buffer. See EXAMPLE1.C or EXAMPLE2.C for details on how to call these functions.
Version numbers not shown were test versions or skipped.
Version 17A
Version 16P
Version 16N
Version 16M
Version 16J
Version 16H
Version 16G
Version 16E and 16F
Version 16D
Version 16C
Version 16B
Version 16A
Version 17A
Version 16K-16P
Version 16J
Version 16H
Version 16B-16G
Version 16A
Technical support can be found at:
http://www.ata-atapi.com/techsupp.html
-end-