Fixes to DMA writing (still unverified) and added serialize/unserialize
authorAndrew Schultz <alschult@umich.edu>
Wed, 12 May 2004 20:55:49 +0000 (16:55 -0400)
committerAndrew Schultz <alschult@umich.edu>
Wed, 12 May 2004 20:55:49 +0000 (16:55 -0400)
dev/ide_ctrl.cc:
    Added serialize/unserialize functions and move some inlined functions
    to regular functions
dev/ide_ctrl.hh:
    Change inlined functions to regular functions
dev/ide_disk.cc:
    Changes to dmaWrite and also add serialize/unserialize functions
dev/ide_disk.hh:
    Support for serializing/unserializing

--HG--
extra : convert_revision : 40e016dc7f6637b033fe33409338437c985a05f4

dev/ide_ctrl.cc
dev/ide_ctrl.hh
dev/ide_disk.cc
dev/ide_disk.hh

index f038acecab35e9df61a0119db6ad8a9fe0347668..a21cf12d790e61516e2766ba17c719c6a6d89d2a 100644 (file)
@@ -126,6 +126,72 @@ IdeController::~IdeController()
             delete disks[i];
 }
 
+////
+// Utility functions
+///
+
+void
+IdeController::parseAddr(const Addr &addr, Addr &offset, bool &primary,
+                         RegType_t &type)
+{
+    offset = addr;
+
+    if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
+        offset -= pri_cmd_addr;
+        type = COMMAND_BLOCK;
+        primary = true;
+    } else if (addr >= pri_ctrl_addr &&
+               addr < (pri_ctrl_addr + pri_ctrl_size)) {
+        offset -= pri_ctrl_addr;
+        type = CONTROL_BLOCK;
+        primary = true;
+    } else if (addr >= sec_cmd_addr &&
+               addr < (sec_cmd_addr + sec_cmd_size)) {
+        offset -= sec_cmd_addr;
+        type = COMMAND_BLOCK;
+        primary = false;
+    } else if (addr >= sec_ctrl_addr &&
+               addr < (sec_ctrl_addr + sec_ctrl_size)) {
+        offset -= sec_ctrl_addr;
+        type = CONTROL_BLOCK;
+        primary = false;
+    } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
+        offset -= bmi_addr;
+        type = BMI_BLOCK;
+        primary = (offset < BMIC1) ? true : false;
+    } else {
+        panic("IDE controller access to invalid address: %#x\n", addr);
+    }
+}
+
+int
+IdeController::getDisk(bool primary)
+{
+    int disk = 0;
+    uint8_t *devBit = &dev[0];
+
+    if (!primary) {
+        disk += 2;
+        devBit = &dev[1];
+    }
+
+    disk += *devBit;
+
+    assert(*devBit == 0 || *devBit == 1);
+
+    return disk;
+}
+
+int
+IdeController::getDisk(IdeDisk *diskPtr)
+{
+    for (int i = 0; i < 4; i++) {
+        if ((long)diskPtr == (long)disks[i])
+            return i;
+    }
+    return -1;
+}
+
 ////
 // Command completion
 ////
@@ -523,11 +589,53 @@ IdeController::write(MemReqPtr &req, const uint8_t *data)
 void
 IdeController::serialize(std::ostream &os)
 {
+    // Serialize register addresses and sizes
+    SERIALIZE_SCALAR(pri_cmd_addr);
+    SERIALIZE_SCALAR(pri_cmd_size);
+    SERIALIZE_SCALAR(pri_ctrl_addr);
+    SERIALIZE_SCALAR(pri_ctrl_size);
+    SERIALIZE_SCALAR(sec_cmd_addr);
+    SERIALIZE_SCALAR(sec_cmd_size);
+    SERIALIZE_SCALAR(sec_ctrl_addr);
+    SERIALIZE_SCALAR(sec_ctrl_size);
+    SERIALIZE_SCALAR(bmi_addr);
+    SERIALIZE_SCALAR(bmi_size);
+
+    // Serialize registers
+    SERIALIZE_ARRAY(bmi_regs, 16);
+    SERIALIZE_ARRAY(dev, 2);
+    SERIALIZE_ARRAY(pci_regs, 8);
+
+    // Serialize internal state
+    SERIALIZE_SCALAR(io_enabled);
+    SERIALIZE_SCALAR(bm_enabled);
+    SERIALIZE_ARRAY(cmd_in_progress, 4);
 }
 
 void
 IdeController::unserialize(Checkpoint *cp, const std::string &section)
 {
+    // Unserialize register addresses and sizes
+    UNSERIALIZE_SCALAR(pri_cmd_addr);
+    UNSERIALIZE_SCALAR(pri_cmd_size);
+    UNSERIALIZE_SCALAR(pri_ctrl_addr);
+    UNSERIALIZE_SCALAR(pri_ctrl_size);
+    UNSERIALIZE_SCALAR(sec_cmd_addr);
+    UNSERIALIZE_SCALAR(sec_cmd_size);
+    UNSERIALIZE_SCALAR(sec_ctrl_addr);
+    UNSERIALIZE_SCALAR(sec_ctrl_size);
+    UNSERIALIZE_SCALAR(bmi_addr);
+    UNSERIALIZE_SCALAR(bmi_size);
+
+    // Unserialize registers
+    UNSERIALIZE_ARRAY(bmi_regs, 16);
+    UNSERIALIZE_ARRAY(dev, 2);
+    UNSERIALIZE_ARRAY(pci_regs, 8);
+
+    // Unserialize internal state
+    UNSERIALIZE_SCALAR(io_enabled);
+    UNSERIALIZE_SCALAR(bm_enabled);
+    UNSERIALIZE_ARRAY(cmd_in_progress, 4);
 }
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
index b4de9703602802d061053a7be66d8e102af37e33..9698724c1c7e326048eeb0984778a06559080e6f 100644 (file)
@@ -27,7 +27,8 @@
  */
 
 /** @file
- * Simple PCI IDE controller with bus mastering capability
+ * Simple PCI IDE controller with bus mastering capability and UDMA
+ * modeled after controller in the Intel PIIX4 chip
  */
 
 #ifndef __IDE_CTRL_HH__
@@ -139,65 +140,13 @@ class IdeController : public PciDev
   private:
     /** Parse the access address to pass on to device */
     void parseAddr(const Addr &addr, Addr &offset, bool &primary,
-                   RegType_t &type)
-    {
-        offset = addr;
-
-        if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
-            offset -= pri_cmd_addr;
-            type = COMMAND_BLOCK;
-            primary = true;
-        } else if (addr >= pri_ctrl_addr &&
-                   addr < (pri_ctrl_addr + pri_ctrl_size)) {
-            offset -= pri_ctrl_addr;
-            type = CONTROL_BLOCK;
-            primary = true;
-        } else if (addr >= sec_cmd_addr &&
-                   addr < (sec_cmd_addr + sec_cmd_size)) {
-            offset -= sec_cmd_addr;
-            type = COMMAND_BLOCK;
-            primary = false;
-        } else if (addr >= sec_ctrl_addr &&
-                   addr < (sec_ctrl_addr + sec_ctrl_size)) {
-            offset -= sec_ctrl_addr;
-            type = CONTROL_BLOCK;
-            primary = false;
-        } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
-            offset -= bmi_addr;
-            type = BMI_BLOCK;
-            primary = (offset < BMIC1) ? true : false;
-        } else {
-            panic("IDE controller access to invalid address: %#x\n", addr);
-        }
-    };
+                   RegType_t &type);
 
     /** Select the disk based on the channel and device bit */
-    int getDisk(bool primary)
-    {
-        int disk = 0;
-        uint8_t *devBit = &dev[0];
-
-        if (!primary) {
-            disk += 2;
-            devBit = &dev[1];
-        }
-
-        disk += *devBit;
-
-        assert(*devBit == 0 || *devBit == 1);
-
-        return disk;
-    };
+    int getDisk(bool primary);
 
     /** Select the disk based on a pointer */
-    int getDisk(IdeDisk *diskPtr)
-    {
-        for (int i = 0; i < 4; i++) {
-            if ((long)diskPtr == (long)disks[i])
-                return i;
-        }
-        return -1;
-    }
+    int getDisk(IdeDisk *diskPtr);
 
   public:
     /**
index 38d6a919be0de5893f577d440ce65e7dfe2777f6..0d12e797d3ff8ed02e981566be7f7d1e74a2571c 100644 (file)
@@ -61,6 +61,7 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
       dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
       dmaReadEvent(this), dmaWriteEvent(this)
 {
+    // calculate disk delay in microseconds
     diskDelay = (delay * ticksPerSecond / 100000);
 
     // initialize the data buffer and shadow registers
@@ -70,6 +71,7 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
     memset(&cmdReg, 0, sizeof(CommandReg_t));
     memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
 
+    dmaInterfaceBytes = 0;
     curPrdAddr = 0;
     curSector = 0;
     curCommand = 0;
@@ -154,8 +156,12 @@ IdeDisk::~IdeDisk()
     delete [] dataBuffer;
 }
 
+////
+// Utility functions
+////
+
 Addr
-IdeDisk::pciToDma(Addr &pciAddr)
+IdeDisk::pciToDma(Addr pciAddr)
 {
     if (ctrl)
         return ctrl->tsunami->pchip->translatePciToDma(pciAddr);
@@ -163,6 +169,29 @@ IdeDisk::pciToDma(Addr &pciAddr)
         panic("Access to unset controller!\n");
 }
 
+uint32_t
+IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft)
+{
+    uint32_t bytesInPage = 0;
+
+    // First calculate how many bytes could be in the page
+    if (bytesLeft > ALPHA_PGBYTES)
+        bytesInPage = ALPHA_PGBYTES;
+    else
+        bytesInPage = bytesLeft;
+
+    // Next, see if we have crossed a page boundary, and adjust
+    Addr upperBound = curAddr + bytesInPage;
+    Addr pageBound = alpha_trunc_page(curAddr) + ALPHA_PGBYTES;
+
+    assert(upperBound >= curAddr && "DMA read wraps around address space!\n");
+
+    if (upperBound >= pageBound)
+        bytesInPage = pageBound - curAddr;
+
+    return bytesInPage;
+}
+
 ////
 // Device registers read/write
 ////
@@ -297,7 +326,7 @@ IdeDisk::dmaPrdReadDone()
 void
 IdeDisk::doDmaRead()
 {
-    Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
+    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
 
     if (dmaInterface) {
         if (dmaInterface->busy()) {
@@ -306,9 +335,14 @@ IdeDisk::doDmaRead()
             return;
         }
 
-        Addr dmaAddr =
-            ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
-        dmaInterface->doDMA(Read, dmaAddr, curPrd.getByteCount(),
+        Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
+
+        uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
+                                              (uint32_t)curPrd.getByteCount());
+
+        dmaInterfaceBytes = bytesInPage;
+
+        dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
                             curTick + totalDiskDelay, &dmaReadEvent);
     } else {
         // schedule dmaReadEvent with sectorDelay (dmaReadDone)
@@ -323,6 +357,28 @@ IdeDisk::dmaReadDone()
     Addr curAddr = 0, dmaAddr = 0;
     uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0;
 
+    // continue to use the DMA interface until all pages are read
+    if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
+        // see if the interface is busy
+        if (dmaInterface->busy()) {
+            // reschedule after waiting period
+            dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+            return;
+        }
+
+        uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
+        curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
+        dmaAddr = pciToDma(curAddr);
+
+        bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
+        dmaInterfaceBytes += bytesInPage;
+
+        dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
+                            curTick, &dmaReadEvent);
+
+        return;
+    }
+
     // set initial address
     curAddr = curPrd.getBaseAddr();
 
@@ -338,15 +394,9 @@ IdeDisk::dmaReadDone()
 
         // calculate how many bytes are in the current page
         bytesLeft = curPrd.getByteCount() - bytesWritten;
-        bytesInPage = (bytesLeft > ALPHA_PGBYTES) ? ALPHA_PGBYTES : bytesLeft;
-        // check to make sure we don't cross a page boundary
-        if ((curAddr + bytesInPage) >
-            (alpha_trunc_page(curAddr) + ALPHA_PGBYTES))
-
-            bytesInPage = alpha_round_page(curAddr) - curAddr;
+        bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
 
         // copy the data from memory into the data buffer
-        /** @todo Use real DMA with interfaces here */
         memcpy((void *)(dataBuffer + bytesWritten),
                physmem->dma_addr(dmaAddr, bytesInPage),
                bytesInPage);
@@ -359,9 +409,10 @@ IdeDisk::dmaReadDone()
     // write the data to the disk image
     for (bytesWritten = 0;
          bytesWritten < curPrd.getByteCount();
-         bytesWritten += SectorSize)
+         bytesWritten += SectorSize) {
 
         writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
+    }
 
 #if 0
     // actually copy the data from memory to data buffer
@@ -397,7 +448,7 @@ IdeDisk::dmaReadDone()
 void
 IdeDisk::doDmaWrite()
 {
-    Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize);
+    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
 
     if (dmaInterface) {
         if (dmaInterface->busy()) {
@@ -406,10 +457,15 @@ IdeDisk::doDmaWrite()
             return;
         }
 
-        Addr dmaAddr =
-            ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
+        Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
+
+        uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
+                                              (uint32_t)curPrd.getByteCount());
+
+        dmaInterfaceBytes = bytesInPage;
+
         dmaInterface->doDMA(WriteInvalidate, dmaAddr,
-                            curPrd.getByteCount(), curTick + totalDiskDelay,
+                            bytesInPage, curTick + totalDiskDelay,
                             &dmaWriteEvent);
     } else {
         // schedule event with disk delay (dmaWriteDone)
@@ -423,6 +479,29 @@ IdeDisk::dmaWriteDone()
     Addr curAddr = 0, pageAddr = 0, dmaAddr = 0;
     uint32_t bytesRead = 0, bytesInPage = 0;
 
+    // continue to use the DMA interface until all pages are read
+    if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
+        // see if the interface is busy
+        if (dmaInterface->busy()) {
+            // reschedule after waiting period
+            dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+            return;
+        }
+
+        uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
+        curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
+        dmaAddr = pciToDma(curAddr);
+
+        bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
+        dmaInterfaceBytes += bytesInPage;
+
+        dmaInterface->doDMA(WriteInvalidate, dmaAddr,
+                            bytesInPage, curTick,
+                            &dmaWriteEvent);
+
+        return;
+    }
+
     // setup the initial page and DMA address
     curAddr = curPrd.getBaseAddr();
     pageAddr = alpha_trunc_page(curAddr);
@@ -435,7 +514,6 @@ IdeDisk::dmaWriteDone()
         // see if we have crossed into a new page
         if (pageAddr != alpha_trunc_page(curAddr)) {
             // write the data to memory
-            /** @todo Do real DMA using interfaces here */
             memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
                    (void *)(dataBuffer + (bytesRead - bytesInPage)),
                    bytesInPage);
@@ -459,7 +537,6 @@ IdeDisk::dmaWriteDone()
     }
 
     // write the last page worth read to memory
-    /** @todo Do real DMA using interfaces here */
     if (bytesInPage != 0) {
         memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
                (void *)(dataBuffer + (bytesRead - bytesInPage)),
@@ -521,7 +598,7 @@ IdeDisk::startDma(const uint32_t &prdTableBase)
     if (devState != Transfer_Data_Dma)
         panic("Inconsistent device state for DMA start!\n");
 
-    curPrdAddr = ctrl->tsunami->pchip->translatePciToDma(prdTableBase);
+    curPrdAddr = pciToDma((Addr)prdTableBase);
 
     dmaState = Dma_Transfer;
 
@@ -927,11 +1004,115 @@ IdeDisk::updateState(DevAction_t action)
 void
 IdeDisk::serialize(ostream &os)
 {
+    // Check all outstanding events to see if they are scheduled
+    // these are all mutually exclusive
+    Tick reschedule = 0;
+    Events_t event = None;
+
+    if (dmaTransferEvent.scheduled()) {
+        reschedule = dmaTransferEvent.when();
+        event = Transfer;
+    } else if (dmaReadWaitEvent.scheduled()) {
+        reschedule = dmaReadWaitEvent.when();
+        event = ReadWait;
+    } else if (dmaWriteWaitEvent.scheduled()) {
+        reschedule = dmaWriteWaitEvent.when();
+        event = WriteWait;
+    } else if (dmaPrdReadEvent.scheduled()) {
+        reschedule = dmaPrdReadEvent.when();
+        event = PrdRead;
+    } else if (dmaReadEvent.scheduled()) {
+        reschedule = dmaReadEvent.when();
+        event = DmaRead;
+    } else if (dmaWriteEvent.scheduled()) {
+        reschedule = dmaWriteEvent.when();
+        event = DmaWrite;
+    }
+
+    SERIALIZE_SCALAR(reschedule);
+    SERIALIZE_ENUM(event);
+
+    // Serialize device registers
+    SERIALIZE_SCALAR(cmdReg.data0);
+    SERIALIZE_SCALAR(cmdReg.data1);
+    SERIALIZE_SCALAR(cmdReg.sec_count);
+    SERIALIZE_SCALAR(cmdReg.sec_num);
+    SERIALIZE_SCALAR(cmdReg.cyl_low);
+    SERIALIZE_SCALAR(cmdReg.cyl_high);
+    SERIALIZE_SCALAR(cmdReg.drive);
+    SERIALIZE_SCALAR(cmdReg.status);
+    SERIALIZE_SCALAR(nIENBit);
+    SERIALIZE_SCALAR(devID);
+
+    // Serialize the PRD related information
+    SERIALIZE_SCALAR(curPrd.entry.baseAddr);
+    SERIALIZE_SCALAR(curPrd.entry.byteCount);
+    SERIALIZE_SCALAR(curPrd.entry.endOfTable);
+    SERIALIZE_SCALAR(curPrdAddr);
+
+    // Serialize current transfer related information
+    SERIALIZE_SCALAR(cmdBytesLeft);
+    SERIALIZE_SCALAR(drqBytesLeft);
+    SERIALIZE_SCALAR(curSector);
+    SERIALIZE_SCALAR(curCommand);
+    SERIALIZE_SCALAR(dmaRead);
+    SERIALIZE_SCALAR(dmaInterfaceBytes);
+    SERIALIZE_SCALAR(intrPending);
+    SERIALIZE_ENUM(devState);
+    SERIALIZE_ENUM(dmaState);
+    SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
 }
 
 void
 IdeDisk::unserialize(Checkpoint *cp, const string &section)
 {
+    // Reschedule events that were outstanding
+    // these are all mutually exclusive
+    Tick reschedule = 0;
+    Events_t event = None;
+
+    UNSERIALIZE_SCALAR(reschedule);
+    UNSERIALIZE_ENUM(event);
+
+    switch (event) {
+      case None : break;
+      case Transfer : dmaTransferEvent.schedule(reschedule); break;
+      case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
+      case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
+      case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
+      case DmaRead : dmaReadEvent.schedule(reschedule); break;
+      case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
+    }
+
+    // Unserialize device registers
+    UNSERIALIZE_SCALAR(cmdReg.data0);
+    UNSERIALIZE_SCALAR(cmdReg.data1);
+    UNSERIALIZE_SCALAR(cmdReg.sec_count);
+    UNSERIALIZE_SCALAR(cmdReg.sec_num);
+    UNSERIALIZE_SCALAR(cmdReg.cyl_low);
+    UNSERIALIZE_SCALAR(cmdReg.cyl_high);
+    UNSERIALIZE_SCALAR(cmdReg.drive);
+    UNSERIALIZE_SCALAR(cmdReg.status);
+    UNSERIALIZE_SCALAR(nIENBit);
+    UNSERIALIZE_SCALAR(devID);
+
+    // Unserialize the PRD related information
+    UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
+    UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
+    UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
+    UNSERIALIZE_SCALAR(curPrdAddr);
+
+    // Unserialize current transfer related information
+    UNSERIALIZE_SCALAR(cmdBytesLeft);
+    UNSERIALIZE_SCALAR(drqBytesLeft);
+    UNSERIALIZE_SCALAR(curSector);
+    UNSERIALIZE_SCALAR(curCommand);
+    UNSERIALIZE_SCALAR(dmaRead);
+    UNSERIALIZE_SCALAR(dmaInterfaceBytes);
+    UNSERIALIZE_SCALAR(intrPending);
+    UNSERIALIZE_ENUM(devState);
+    UNSERIALIZE_ENUM(dmaState);
+    UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
 }
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -950,7 +1131,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
     INIT_PARAM(image, "Disk image"),
     INIT_PARAM(physmem, "Physical memory"),
     INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"),
-    INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in milliseconds", 0)
+    INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in microseconds", 1)
 
 END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
 
index 88a492cbc41c566f782dc86d2847a629475594bc..35e7404d578e38223f4f3ea411de21fd295aa17d 100644 (file)
@@ -94,7 +94,7 @@ class PrdTableEntry {
 #define STATUS_BSY_BIT  0x80
 #define STATUS_DRDY_BIT 0x40
 #define STATUS_DRQ_BIT  0x08
-#define DRIVE_LBA_BIT  0x40
+#define DRIVE_LBA_BIT   0x40
 
 #define DEV0 (0)
 #define DEV1 (1)
@@ -120,6 +120,16 @@ typedef struct CommandReg {
     };
 } CommandReg_t;
 
+typedef enum Events {
+    None = 0,
+    Transfer,
+    ReadWait,
+    WriteWait,
+    PrdRead,
+    DmaRead,
+    DmaWrite
+} Events_t;
+
 typedef enum DevAction {
     ACT_NONE = 0,
     ACT_CMD_WRITE,
@@ -184,7 +194,7 @@ class IdeDisk : public SimObject
     PhysicalMemory *physmem;
 
   protected:
-    /** The disk delay in milliseconds. */
+    /** The disk delay in microseconds. */
     int diskDelay;
 
   private:
@@ -214,6 +224,8 @@ class IdeDisk : public SimObject
     uint32_t curPrdAddr;
     /** PRD entry */
     PrdTableEntry curPrd;
+    /** Number of bytes transfered by DMA interface for current transfer */
+    uint32_t dmaInterfaceBytes;
     /** Device ID (master=0/slave=1) */
     int devID;
     /** Interrupt pending */
@@ -313,7 +325,9 @@ class IdeDisk : public SimObject
                        (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
     }
 
-    inline Addr pciToDma(Addr &pciAddr);
+    inline Addr pciToDma(Addr pciAddr);
+
+    uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft);
 
     /**
      * Serialize this object to the given output stream.