Skip to content

IDEDisk Driver

opencode-agent[bot] edited this page May 10, 2026 · 2 revisions

IDEDisk Driver

JNode's primary IDE/ATA disk driver providing block-level access to PATA devices via LBA addressing with both PIO and DMA transfer modes.

Overview

The IDEDiskDriver is a critical JNode driver that manages Parallel ATA (PATA) disk devices. It extends the Driver class and implements the IDEDeviceAPI, providing the bridge between JNode's block device layer and hardware IDE controllers. The driver supports both 28-bit and 48-bit LBA addressing, enabling access to disks larger than 128GB.

Key Components

File Purpose
fs/src/driver/org/jnode/driver/block/ide/disk/IDEDiskDriver.java Main driver class
fs/src/driver/org/jnode/driver/block/ide/disk/IDEDiskPartitionDevice.java Partition device representation
fs/src/driver/org/jnode/driver/block/ide/disk/IDEDiskPartitionDriver.java Partition driver
fs/src/driver/org/jnode/driver/bus/ide/IDEBus.java Command queue processing bus
fs/src/driver/org/jnode/driver/bus/ide/IDEConstants.java ATA register definitions, commands, timeouts
fs/src/driver/org/jnode/driver/bus/ide/command/IDERWSectorsCommand.java Read/write sector commands
fs/src/driver/org/jnode/driver/bus/ide/IDEDriveDescriptor.java Drive identification data

How It Works

Device Startup

When startDevice() is called, the driver:

  1. Creates an IDEDiskBus (internal Bus subclass) wrapping the IDEDevice
  2. Reads the MBR boot sector via LBA sector 0
  3. Creates an IBMPartitionTable from the boot sector
  4. Registers partition devices for each valid partition entry
  5. Handles extended partitions by iterating through chained partition tables
protected void startDevice() throws DriverException {
    final IDEDevice dev = (IDEDevice) getDevice();
    diskBus = new IDEDiskBus(dev);
    dev.registerAPI(IDEDeviceAPI.class,
        new IDEDeviceBlockAlignmentSupport<IBMPartitionTableEntry>(this, SECTOR_SIZE));

    final IDEDriveDescriptor descr = dev.getDescriptor();
    is48bit = descr.supports48bitAddressing();
    maxSector = descr.getSectorsAddressable();

    // Read boot sector, create partition table, register partitions
    final byte[] bs = new byte[SECTOR_SIZE];
    read(0, ByteBuffer.wrap(bs));
    this.pt = factory.createIBMPartitionTable(bs, dev);
    // ... register partitions
}

Data Transfer

The transfer() method handles block reads/writes with the following flow:

  1. Validates offset/length alignment to 512-byte sector boundaries
  2. Splits large transfers into chunks respecting the maximum sector count:
    • 256 sectors for 28-bit addressing
    • 65536 sectors for 48-bit addressing
  3. Creates IDEReadSectorsCommand or IDEWriteSectorsCommand for each chunk
  4. Executes commands via bus.executeAndWait() with a 10-second timeout
  5. Handles errors by throwing IOException
protected void transfer(long devOffset, ByteBuffer buf, boolean isWrite) throws IOException {
    final long lbaStart = devOffset / SECTOR_SIZE;
    final int sectors = length / SECTOR_SIZE;
    final int maxSectorCount = is48bit ? MAX_SECTOR_COUNT_48 : MAX_SECTOR_COUNT_28;

    while (length > 0) {
        final int partSectorCount = Math.min(length / SECTOR_SIZE, maxSectorCount);
        final IDERWSectorsCommand cmd = isWrite ?
            new IDEWriteSectorsCommand(primary, master, is48bit, partLbaStart, partSectorCount, buf) :
            new IDEReadSectorsCommand(primary, master, is48bit, partLbaStart, partSectorCount, buf);
        bus.executeAndWait(cmd, IDE_DATA_XFER_TIMEOUT);
        // ...
    }
}

Command Queue Architecture

IDEBus manages a QueueProcessorThread that sequentially processes IDE commands:

  • Commands are added via execute(command)
  • Synchronous wait via executeAndWait(command, timeout)
  • IRQ handler (handleInterrupt) signals command completion
  • Software reset via softwareReset() if commands timeout

ATA Register Interface

IDEConstants defines all ATA register offsets and command codes:

Register Offset Purpose
Data 0x1F0/0x170 16-bit data I/O
Error/Feature 1 Read errors, write features
Sector Count 2 Number of sectors (LBA low)
LBA Low 3 LBA bits 0-7
LBA Mid 4 LBA bits 8-15
LBA High 5 LBA bits 16-23
Drive/Head 6 Drive selection, LBA bit 24-27
Status/Command 7 Read status, write commands

LBA Addressing Modes

28-bit LBA: Uses Drive/Head register for LBA bits 24-27

io.setSelectReg(SEL_LBA | getSelect() | ((int)(lbaStart >> 24) & 0xF));

48-bit LBA: Writes registers twice (high then low)

io.setSectorCountReg((sectorCount >> 8) & 0xFF); // high byte
io.setLbaLowReg((int)((lbaStart >> 24) & 0xFF));
// ... more high bytes ...
io.setSectorCountReg((sectorCount >> 0) & 0xFF); // low byte
io.setLbaLowReg((int)((lbaStart >> 0) & 0xFF));
// ... more low bytes ...

Gotchas

  1. Double boot sector read: The driver reads sector 0 twice as a workaround for an unknown first-read failure (IDEDiskDriver.java:106-112). The exact cause is unclear but may relate to controller initialization.

  2. Partition unregistration on stop: stopDevice() manually iterates the device manager to find and unregister partition children, rather than using a hierarchical shutdown mechanism.

  3. DMA mode disabled: DMA support is commented out in the codebase (//dma = descr.supportsDMA()). The driver currently uses PIO mode exclusively, despite having DMA command definitions in IDEConstants (e.g., CMD_READDMA, CMD_WRITEDMA).

  4. Command timeout handling: Timeouts result in InterruptedIOException, but the controller may remain in a busy state, potentially affecting subsequent commands.

  5. No error recovery: On command errors, the driver throws an IOException with minimal diagnostic information (just the error code).

Related Pages

Clone this wiki locally