I thought I would post a little tuturoial to try and educate those working in the IDE area of the XBOX. Here goes...
Adding support for hard drives larger than 137 GB is actually very easy. The following guide should help those people developing in this area.
NOTE: All of the examples below can be changed to use 32-bit variables (instead of 64-bit). Even if only 32-bits of the 48-bit LBA is supported in XBOX software, this will still allow 2.2 Tera-byte hard drives!
There are two places in the IDE driver that need to be update to add support for 48-bit LBA addressing:
1. Initialization
2. Issuing Commands
Initialization:
During initialization the drive is issued an Identify Drive command to determine the capabilities of the drive. 48-bit LBA support is specified by bit 10 in word 83. If this bit is set, than the "real" size of the drive is given by the four words starting at word 100.
Sample code follows:
****************************************************************************
uint16_t drive_info[265];
uint64_t maxLba;
... Issue identify drive command and store in drive_info array
/* Check for drive support of 48-bit LBA */
if( drive_info[83] & 1ul<<10 ) {
/* 48-bit LBA supported */
maxLba = *((uint64_t*)&(drive_info[100]));
} else {
/* Only 28-bit LBA supported */
maxLba = *((uint32_t*)&(drive_info[60]));
}
****************************************************************************
2. There are some new commands supported by drives that support the 48-bit LBA feature. These commands are the same as the non-EXT flavors of the commands, except these commands support "double-pumping" some of the IDE registers in order to support 48-bit LBAs. The new commands include:
- FLUSH CACHE EXT (0xEA)
- READ DMA EXT (0x25)
- READ DMA QUEUED EXT (0x26)
- READ MULTIPLE EXT (0x29)
- READ NATIVE MAX ADDRESS EXT (0x27)
- READ SECTOR(S) EXT (0x24)
- READ VERIFY SECTOR(S) (0x42)
- SET MAX ADDRESS EXT (0x37)
- WRITE DMA EXT (0x35)
- WRITE DMA QUEUED EXT (0x36)
- WRITE MULTIPLE EXT (0x39)
- WRITE SECTOR(S) EXT (0x34)
Keep in mind that all of these commands work almost exactly the same as the non-EXT flavors, with the exception of having to double pump the regististers in order to communicate the 48-bit LBA. I will focus my example on the READ EXT command.
Here is some sample code that shows how to issue a read command (using standard read command). This code is from the Cromwell ide driver (with hacked support of 48-bit LBA).
****************************************************************************
int BootIdeReadSector(int nDriveIndex, void * pbBuffer, unsigned int block, int byte_offset, int n_bytes)
{
...
if( block >= 0x10000000 ) { /* 48-bit LBA access required for this block (a.k.a. LBA) */
/* This routine uses a max LBA of 32 bits (due to unsigned int data type used for block parameter) */
tsicp.m_bCountSectorExt = 0; /* Don't support read sizes greater than 512 sectors */
tsicp.m_wCylinderExt = 0; /* 47:32 */
tsicp.m_bSectorExt = (block >> 24) & 0xff; /* 31:24 */
tsicp.m_wCylinder = (block >>
& 0xffff; /* 23:8 */
tsicp.m_bSector = block & 0xff; /* 7:0 */
tsicp.m_bDrivehead = IDE_DH_DRIVE(nDriveIndex) | IDE_DH_LBA;
ideReadCommand = IDE_CMD_READ_SECTOR_EXT;
} else {
tsicp.m_bSector = block & 0xff; /* lower byte of block (lba) */
tsicp.m_wCylinder = (block >>
& 0xffff; /* middle 2 bytes of block (lba) */
tsicp.m_bDrivehead = IDE_DH_DEFAULT | /* set bits that must be on */
((block >> 24) & 0x0f) | /* lower nibble of byte 3 of block */
IDE_DH_DRIVE(nDriveIndex) |
IDE_DH_LBA;
ideReadCommand = IDE_CMD_READ_SECTOR;
}
BootIdeIssueAtaCommand(uIoBase, ideReadCommand, &tsicp);
....
}
int BootIdeIssueAtaCommand( unsigned uIoBase, ide_command_t command, tsIdeCommandParams * params )
{
int n;
IoInputByte(IDE_REG_STATUS(uIoBase));
n=BootIdeWaitNotBusy(uIoBase);
/* 48-bit LBA */
/* this won't hurt for non 48-bit LBA commands since we re-write these registers below */
IoOutputByte(IDE_REG_SECTOR_COUNT(uIoBase), params->m_bCountSectorExt);
IoOutputByte(IDE_REG_SECTOR_NUMBER(uIoBase), params->m_bSectorExt);
IoOutputByte(IDE_REG_CYLINDER_LSB(uIoBase), params->m_wCylinderExt & 0xFF);
IoOutputByte(IDE_REG_CYLINDER_MSB(uIoBase), (params->m_wCylinderExt >>
);
IoOutputByte(IDE_REG_SECTOR_COUNT(uIoBase), params->m_bCountSector);
IoOutputByte(IDE_REG_SECTOR_NUMBER(uIoBase), params->m_bSector);
IoOutputByte(IDE_REG_CYLINDER_LSB(uIoBase), params->m_wCylinder & 0xFF);
IoOutputByte(IDE_REG_CYLINDER_MSB(uIoBase), (params->m_wCylinder >>
);
IoOutputByte(IDE_REG_DRIVEHEAD(uIoBase), params->m_bDrivehead);
IoOutputByte(IDE_REG_COMMAND(uIoBase), command);
Delay();
n=BootIdeWaitNotBusy(uIoBase);
return 0;
}
****************************************************************************
The actual ATA specification that gives the details for the 48-bit LBA feature can be found here:
http://www.t13.org/docs2002/d1410r3b.pdf