ide_disk.cc revision 2565
17139Sgblack@eecs.umich.edu/*
27139Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan
37139Sgblack@eecs.umich.edu * All rights reserved.
47139Sgblack@eecs.umich.edu *
57139Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67139Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77139Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87139Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97139Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107139Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117139Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127139Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137139Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147139Sgblack@eecs.umich.edu * this software without specific prior written permission.
157139Sgblack@eecs.umich.edu *
167139Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177139Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187139Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197139Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207139Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217139Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227139Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237139Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247139Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257139Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267139Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277139Sgblack@eecs.umich.edu */
287139Sgblack@eecs.umich.edu
297139Sgblack@eecs.umich.edu/** @file
307139Sgblack@eecs.umich.edu * Device model implementation for an IDE disk
317139Sgblack@eecs.umich.edu */
327139Sgblack@eecs.umich.edu
337139Sgblack@eecs.umich.edu#include <cerrno>
347139Sgblack@eecs.umich.edu#include <cstring>
357139Sgblack@eecs.umich.edu#include <deque>
367139Sgblack@eecs.umich.edu#include <string>
377139Sgblack@eecs.umich.edu
387255Sgblack@eecs.umich.edu#include "base/chunk_generator.hh"
397243Sgblack@eecs.umich.edu#include "base/cprintf.hh" // csprintf
407243Sgblack@eecs.umich.edu#include "base/trace.hh"
417255Sgblack@eecs.umich.edu#include "dev/disk_image.hh"
427255Sgblack@eecs.umich.edu#include "dev/ide_disk.hh"
437243Sgblack@eecs.umich.edu#include "dev/ide_ctrl.hh"
447243Sgblack@eecs.umich.edu#include "dev/tsunami.hh"
457255Sgblack@eecs.umich.edu#include "dev/tsunami_pchip.hh"
467255Sgblack@eecs.umich.edu#include "mem/packet.hh"
477255Sgblack@eecs.umich.edu#include "sim/builder.hh"
487255Sgblack@eecs.umich.edu#include "sim/sim_object.hh"
497255Sgblack@eecs.umich.edu#include "sim/root.hh"
507255Sgblack@eecs.umich.edu#include "arch/isa_traits.hh"
517255Sgblack@eecs.umich.edu
527255Sgblack@eecs.umich.eduusing namespace std;
537255Sgblack@eecs.umich.eduusing namespace TheISA;
547255Sgblack@eecs.umich.edu
557255Sgblack@eecs.umich.eduIdeDisk::IdeDisk(const string &name, DiskImage *img,
567255Sgblack@eecs.umich.edu                 int id, Tick delay)
577255Sgblack@eecs.umich.edu    : SimObject(name), ctrl(NULL), image(img), diskDelay(delay),
587255Sgblack@eecs.umich.edu      dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
597255Sgblack@eecs.umich.edu      dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
607255Sgblack@eecs.umich.edu      dmaReadEvent(this), dmaWriteEvent(this)
617255Sgblack@eecs.umich.edu{
627255Sgblack@eecs.umich.edu    // Reset the device state
637255Sgblack@eecs.umich.edu    reset(id);
647255Sgblack@eecs.umich.edu
657255Sgblack@eecs.umich.edu    // fill out the drive ID structure
667255Sgblack@eecs.umich.edu    memset(&driveID, 0, sizeof(struct ataparams));
677243Sgblack@eecs.umich.edu
687255Sgblack@eecs.umich.edu    // Calculate LBA and C/H/S values
697243Sgblack@eecs.umich.edu    uint16_t cylinders;
707243Sgblack@eecs.umich.edu    uint8_t heads;
717243Sgblack@eecs.umich.edu    uint8_t sectors;
727243Sgblack@eecs.umich.edu
737139Sgblack@eecs.umich.edu    uint32_t lba_size = image->size();
747188Sgblack@eecs.umich.edu    if (lba_size >= 16383*16*63) {
757188Sgblack@eecs.umich.edu        cylinders = 16383;
767188Sgblack@eecs.umich.edu        heads = 16;
777188Sgblack@eecs.umich.edu        sectors = 63;
787188Sgblack@eecs.umich.edu    } else {
797139Sgblack@eecs.umich.edu        if (lba_size >= 63)
807139Sgblack@eecs.umich.edu            sectors = 63;
817139Sgblack@eecs.umich.edu        else
827139Sgblack@eecs.umich.edu            sectors = lba_size;
837188Sgblack@eecs.umich.edu
847188Sgblack@eecs.umich.edu        if ((lba_size / sectors) >= 16)
857188Sgblack@eecs.umich.edu            heads = 16;
867188Sgblack@eecs.umich.edu        else
877188Sgblack@eecs.umich.edu            heads = (lba_size / sectors);
887188Sgblack@eecs.umich.edu
897139Sgblack@eecs.umich.edu        cylinders = lba_size / (heads * sectors);
907146Sgblack@eecs.umich.edu    }
917141Sgblack@eecs.umich.edu
927139Sgblack@eecs.umich.edu    // Setup the model name
937139Sgblack@eecs.umich.edu    strncpy((char *)driveID.atap_model, "5MI EDD si k",
947139Sgblack@eecs.umich.edu            sizeof(driveID.atap_model));
957146Sgblack@eecs.umich.edu    // Set the maximum multisector transfer size
967141Sgblack@eecs.umich.edu    driveID.atap_multi = MAX_MULTSECT;
977139Sgblack@eecs.umich.edu    // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
987146Sgblack@eecs.umich.edu    driveID.atap_capabilities1 = 0x7;
997141Sgblack@eecs.umich.edu    // UDMA support, EIDE support
1007139Sgblack@eecs.umich.edu    driveID.atap_extensions = 0x6;
1017139Sgblack@eecs.umich.edu    // Setup default C/H/S settings
1027139Sgblack@eecs.umich.edu    driveID.atap_cylinders = cylinders;
1037139Sgblack@eecs.umich.edu    driveID.atap_sectors = sectors;
1047139Sgblack@eecs.umich.edu    driveID.atap_heads = heads;
1057188Sgblack@eecs.umich.edu    // Setup the current multisector transfer size
1067188Sgblack@eecs.umich.edu    driveID.atap_curmulti = MAX_MULTSECT;
1077188Sgblack@eecs.umich.edu    driveID.atap_curmulti_valid = 0x1;
1087188Sgblack@eecs.umich.edu    // Number of sectors on disk
1097188Sgblack@eecs.umich.edu    driveID.atap_capacity = lba_size;
1107188Sgblack@eecs.umich.edu    // Multiword DMA mode 2 and below supported
1117188Sgblack@eecs.umich.edu    driveID.atap_dmamode_supp = 0x400;
1127188Sgblack@eecs.umich.edu    // Set PIO mode 4 and 3 supported
1137188Sgblack@eecs.umich.edu    driveID.atap_piomode_supp = 0x3;
1147188Sgblack@eecs.umich.edu    // Set DMA mode 4 and below supported
1157188Sgblack@eecs.umich.edu    driveID.atap_udmamode_supp = 0x1f;
1167188Sgblack@eecs.umich.edu    // Statically set hardware config word
1177188Sgblack@eecs.umich.edu    driveID.atap_hwreset_res = 0x4001;
1187188Sgblack@eecs.umich.edu
1197188Sgblack@eecs.umich.edu    //arbitrary for now...
1207188Sgblack@eecs.umich.edu    driveID.atap_ata_major = WDC_VER_ATA7;
1217188Sgblack@eecs.umich.edu}
1227188Sgblack@eecs.umich.edu
1237188Sgblack@eecs.umich.eduIdeDisk::~IdeDisk()
1247188Sgblack@eecs.umich.edu{
1257139Sgblack@eecs.umich.edu    // destroy the data buffer
1267139Sgblack@eecs.umich.edu    delete [] dataBuffer;
1277139Sgblack@eecs.umich.edu}
1287139Sgblack@eecs.umich.edu
1297139Sgblack@eecs.umich.eduvoid
1307139Sgblack@eecs.umich.eduIdeDisk::reset(int id)
1317139Sgblack@eecs.umich.edu{
1327139Sgblack@eecs.umich.edu    // initialize the data buffer and shadow registers
1337139Sgblack@eecs.umich.edu    dataBuffer = new uint8_t[MAX_DMA_SIZE];
1347139Sgblack@eecs.umich.edu
1357139Sgblack@eecs.umich.edu    memset(dataBuffer, 0, MAX_DMA_SIZE);
1367139Sgblack@eecs.umich.edu    memset(&cmdReg, 0, sizeof(CommandReg_t));
1377139Sgblack@eecs.umich.edu    memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
1387139Sgblack@eecs.umich.edu
1397139Sgblack@eecs.umich.edu    curPrdAddr = 0;
1407139Sgblack@eecs.umich.edu    curSector = 0;
1417139Sgblack@eecs.umich.edu    cmdBytes = 0;
1427139Sgblack@eecs.umich.edu    cmdBytesLeft = 0;
1437139Sgblack@eecs.umich.edu    drqBytesLeft = 0;
1447139Sgblack@eecs.umich.edu    dmaRead = false;
1457139Sgblack@eecs.umich.edu    intrPending = false;
1467188Sgblack@eecs.umich.edu
1477188Sgblack@eecs.umich.edu    // set the device state to idle
1487188Sgblack@eecs.umich.edu    dmaState = Dma_Idle;
1497188Sgblack@eecs.umich.edu
1507139Sgblack@eecs.umich.edu    if (id == DEV0) {
1517188Sgblack@eecs.umich.edu        devState = Device_Idle_S;
1527139Sgblack@eecs.umich.edu        devID = DEV0;
1537188Sgblack@eecs.umich.edu    } else if (id == DEV1) {
1547139Sgblack@eecs.umich.edu        devState = Device_Idle_NS;
1557139Sgblack@eecs.umich.edu        devID = DEV1;
1567139Sgblack@eecs.umich.edu    } else {
1577139Sgblack@eecs.umich.edu        panic("Invalid device ID: %#x\n", id);
1587139Sgblack@eecs.umich.edu    }
1597139Sgblack@eecs.umich.edu
1607139Sgblack@eecs.umich.edu    // set the device ready bit
1617139Sgblack@eecs.umich.edu    status = STATUS_DRDY_BIT;
1627210Sgblack@eecs.umich.edu
1637210Sgblack@eecs.umich.edu    /* The error register must be set to 0x1 on start-up to
1647210Sgblack@eecs.umich.edu       indicate that no diagnostic error was detected */
1657210Sgblack@eecs.umich.edu    cmdReg.error = 0x1;
1667210Sgblack@eecs.umich.edu}
1677210Sgblack@eecs.umich.edu
1687210Sgblack@eecs.umich.edu////
1697227Sgblack@eecs.umich.edu// Utility functions
1707227Sgblack@eecs.umich.edu////
1717227Sgblack@eecs.umich.edu
1727227Sgblack@eecs.umich.edubool
1737227Sgblack@eecs.umich.eduIdeDisk::isDEVSelect()
1747227Sgblack@eecs.umich.edu{
1757227Sgblack@eecs.umich.edu    return ctrl->isDiskSelected(this);
1767227Sgblack@eecs.umich.edu}
1777210Sgblack@eecs.umich.edu
1787237Sgblack@eecs.umich.eduAddr
1797237Sgblack@eecs.umich.eduIdeDisk::pciToDma(Addr pciAddr)
1807237Sgblack@eecs.umich.edu{
1817237Sgblack@eecs.umich.edu    if (ctrl)
1827237Sgblack@eecs.umich.edu        return ctrl->plat->pciToDma(pciAddr);
1837237Sgblack@eecs.umich.edu    else
1847237Sgblack@eecs.umich.edu        panic("Access to unset controller!\n");
1857210Sgblack@eecs.umich.edu}
1867227Sgblack@eecs.umich.edu
1877210Sgblack@eecs.umich.edu////
1887227Sgblack@eecs.umich.edu// Device registers read/write
1897210Sgblack@eecs.umich.edu////
1907210Sgblack@eecs.umich.edu
1917210Sgblack@eecs.umich.eduvoid
1927210Sgblack@eecs.umich.eduIdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data)
1937210Sgblack@eecs.umich.edu{
1947240Sgblack@eecs.umich.edu    DevAction_t action = ACT_NONE;
1957235Sgblack@eecs.umich.edu
1967235Sgblack@eecs.umich.edu    switch (reg_type) {
1977235Sgblack@eecs.umich.edu      case COMMAND_BLOCK:
1987235Sgblack@eecs.umich.edu        switch (offset) {
1997235Sgblack@eecs.umich.edu          // Data transfers occur two bytes at a time
2007235Sgblack@eecs.umich.edu          case DATA_OFFSET:
2017240Sgblack@eecs.umich.edu            *(uint16_t*)data = cmdReg.data;
2027240Sgblack@eecs.umich.edu            action = ACT_DATA_READ_SHORT;
2037240Sgblack@eecs.umich.edu            break;
2047240Sgblack@eecs.umich.edu          case ERROR_OFFSET:
2057240Sgblack@eecs.umich.edu            *data = cmdReg.error;
2067240Sgblack@eecs.umich.edu            break;
2077240Sgblack@eecs.umich.edu          case NSECTOR_OFFSET:
2087240Sgblack@eecs.umich.edu            *data = cmdReg.sec_count;
2097240Sgblack@eecs.umich.edu            break;
2107240Sgblack@eecs.umich.edu          case SECTOR_OFFSET:
2117210Sgblack@eecs.umich.edu            *data = cmdReg.sec_num;
2127210Sgblack@eecs.umich.edu            break;
2137210Sgblack@eecs.umich.edu          case LCYL_OFFSET:
2147210Sgblack@eecs.umich.edu            *data = cmdReg.cyl_low;
2157210Sgblack@eecs.umich.edu            break;
2167227Sgblack@eecs.umich.edu          case HCYL_OFFSET:
2177227Sgblack@eecs.umich.edu            *data = cmdReg.cyl_high;
2187227Sgblack@eecs.umich.edu            break;
2197227Sgblack@eecs.umich.edu          case DRIVE_OFFSET:
2207227Sgblack@eecs.umich.edu            *data = cmdReg.drive;
2217227Sgblack@eecs.umich.edu            break;
2227210Sgblack@eecs.umich.edu          case STATUS_OFFSET:
2237235Sgblack@eecs.umich.edu            *data = status;
2247235Sgblack@eecs.umich.edu            action = ACT_STAT_READ;
2257235Sgblack@eecs.umich.edu            break;
2267235Sgblack@eecs.umich.edu          default:
2277235Sgblack@eecs.umich.edu            panic("Invalid IDE command register offset: %#x\n", offset);
2287235Sgblack@eecs.umich.edu        }
2297235Sgblack@eecs.umich.edu        break;
2307235Sgblack@eecs.umich.edu      case CONTROL_BLOCK:
2317210Sgblack@eecs.umich.edu        if (offset == ALTSTAT_OFFSET)
2327235Sgblack@eecs.umich.edu            *data = status;
2337210Sgblack@eecs.umich.edu        else
2347235Sgblack@eecs.umich.edu            panic("Invalid IDE control register offset: %#x\n", offset);
2357210Sgblack@eecs.umich.edu        break;
2367210Sgblack@eecs.umich.edu      default:
2377210Sgblack@eecs.umich.edu        panic("Unknown register block!\n");
2387210Sgblack@eecs.umich.edu    }
2397210Sgblack@eecs.umich.edu
2407211Sgblack@eecs.umich.edu    if (action != ACT_NONE)
2417211Sgblack@eecs.umich.edu        updateState(action);
2427211Sgblack@eecs.umich.edu}
2437210Sgblack@eecs.umich.edu
2447235Sgblack@eecs.umich.eduvoid
2457235Sgblack@eecs.umich.eduIdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data)
2467235Sgblack@eecs.umich.edu{
2477235Sgblack@eecs.umich.edu    DevAction_t action = ACT_NONE;
2487235Sgblack@eecs.umich.edu
2497235Sgblack@eecs.umich.edu    switch (reg_type) {
2507235Sgblack@eecs.umich.edu      case COMMAND_BLOCK:
2517235Sgblack@eecs.umich.edu        switch (offset) {
2527210Sgblack@eecs.umich.edu          case DATA_OFFSET:
2537235Sgblack@eecs.umich.edu            cmdReg.data = *(uint16_t*)data;
2547210Sgblack@eecs.umich.edu            action = ACT_DATA_WRITE_SHORT;
2557235Sgblack@eecs.umich.edu            break;
2567210Sgblack@eecs.umich.edu          case FEATURES_OFFSET:
2577210Sgblack@eecs.umich.edu            break;
2587211Sgblack@eecs.umich.edu          case NSECTOR_OFFSET:
2597211Sgblack@eecs.umich.edu            cmdReg.sec_count = *data;
2607211Sgblack@eecs.umich.edu            break;
2617210Sgblack@eecs.umich.edu          case SECTOR_OFFSET:
2627210Sgblack@eecs.umich.edu            cmdReg.sec_num = *data;
2637210Sgblack@eecs.umich.edu            break;
2647210Sgblack@eecs.umich.edu          case LCYL_OFFSET:
2657235Sgblack@eecs.umich.edu            cmdReg.cyl_low = *data;
2667235Sgblack@eecs.umich.edu            break;
2677235Sgblack@eecs.umich.edu          case HCYL_OFFSET:
2687235Sgblack@eecs.umich.edu            cmdReg.cyl_high = *data;
2697235Sgblack@eecs.umich.edu            break;
2707235Sgblack@eecs.umich.edu          case DRIVE_OFFSET:
2717235Sgblack@eecs.umich.edu            cmdReg.drive = *data;
2727235Sgblack@eecs.umich.edu            action = ACT_SELECT_WRITE;
2737210Sgblack@eecs.umich.edu            break;
2747235Sgblack@eecs.umich.edu          case COMMAND_OFFSET:
2757210Sgblack@eecs.umich.edu            cmdReg.command = *data;
2767235Sgblack@eecs.umich.edu            action = ACT_CMD_WRITE;
2777210Sgblack@eecs.umich.edu            break;
2787210Sgblack@eecs.umich.edu          default:
2797210Sgblack@eecs.umich.edu            panic("Invalid IDE command register offset: %#x\n", offset);
2807210Sgblack@eecs.umich.edu        }
2817210Sgblack@eecs.umich.edu        break;
2827227Sgblack@eecs.umich.edu      case CONTROL_BLOCK:
2837227Sgblack@eecs.umich.edu        if (offset == CONTROL_OFFSET) {
2847227Sgblack@eecs.umich.edu            if (*data & CONTROL_RST_BIT) {
2857227Sgblack@eecs.umich.edu                // force the device into the reset state
2867227Sgblack@eecs.umich.edu                devState = Device_Srst;
2877227Sgblack@eecs.umich.edu                action = ACT_SRST_SET;
2887210Sgblack@eecs.umich.edu            } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT))
2897235Sgblack@eecs.umich.edu                action = ACT_SRST_CLEAR;
2907235Sgblack@eecs.umich.edu
2917235Sgblack@eecs.umich.edu            nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
2927235Sgblack@eecs.umich.edu        }
2937235Sgblack@eecs.umich.edu        else
2947235Sgblack@eecs.umich.edu            panic("Invalid IDE control register offset: %#x\n", offset);
2957235Sgblack@eecs.umich.edu        break;
2967235Sgblack@eecs.umich.edu      default:
2977210Sgblack@eecs.umich.edu        panic("Unknown register block!\n");
2987235Sgblack@eecs.umich.edu    }
2997210Sgblack@eecs.umich.edu
3007235Sgblack@eecs.umich.edu    if (action != ACT_NONE)
3017210Sgblack@eecs.umich.edu        updateState(action);
3027210Sgblack@eecs.umich.edu}
3037210Sgblack@eecs.umich.edu
3047210Sgblack@eecs.umich.edu////
3057250Sgblack@eecs.umich.edu// Perform DMA transactions
3067235Sgblack@eecs.umich.edu////
3077235Sgblack@eecs.umich.edu
3087235Sgblack@eecs.umich.eduvoid
3097235Sgblack@eecs.umich.eduIdeDisk::doDmaTransfer()
3107235Sgblack@eecs.umich.edu{
3117235Sgblack@eecs.umich.edu    if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
3127250Sgblack@eecs.umich.edu        panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
3137250Sgblack@eecs.umich.edu              dmaState, devState);
3147250Sgblack@eecs.umich.edu
3157250Sgblack@eecs.umich.edu    if (ctrl->dmaPending()) {
3167250Sgblack@eecs.umich.edu        dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
3177250Sgblack@eecs.umich.edu        return;
3187250Sgblack@eecs.umich.edu    } else
3197250Sgblack@eecs.umich.edu        ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
3207250Sgblack@eecs.umich.edu                (uint8_t*)&curPrd.entry);
3217250Sgblack@eecs.umich.edu}
3227250Sgblack@eecs.umich.edu
3237250Sgblack@eecs.umich.eduvoid
3247210Sgblack@eecs.umich.eduIdeDisk::dmaPrdReadDone()
3257210Sgblack@eecs.umich.edu{
3267210Sgblack@eecs.umich.edu    DPRINTF(IdeDisk,
3277210Sgblack@eecs.umich.edu            "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
3287210Sgblack@eecs.umich.edu            curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
3297210Sgblack@eecs.umich.edu            curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
3307210Sgblack@eecs.umich.edu            curPrd.getEOT(), curSector);
3317210Sgblack@eecs.umich.edu
3327210Sgblack@eecs.umich.edu    // the prd pointer has already been translated, so just do an increment
3337194Sgblack@eecs.umich.edu    curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
3347194Sgblack@eecs.umich.edu
3357194Sgblack@eecs.umich.edu    if (dmaRead)
3367194Sgblack@eecs.umich.edu        doDmaDataRead();
3377194Sgblack@eecs.umich.edu    else
3387194Sgblack@eecs.umich.edu        doDmaDataWrite();
3397194Sgblack@eecs.umich.edu}
3407194Sgblack@eecs.umich.edu
3417194Sgblack@eecs.umich.eduvoid
3427194Sgblack@eecs.umich.eduIdeDisk::doDmaDataRead()
3437194Sgblack@eecs.umich.edu{
3447194Sgblack@eecs.umich.edu    /** @todo we need to figure out what the delay actually will be */
3457194Sgblack@eecs.umich.edu    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
3467216Sgblack@eecs.umich.edu
3477194Sgblack@eecs.umich.edu    DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
3487224Sgblack@eecs.umich.edu            diskDelay, totalDiskDelay);
3497194Sgblack@eecs.umich.edu
3507224Sgblack@eecs.umich.edu    dmaReadWaitEvent.schedule(curTick + totalDiskDelay);
3517194Sgblack@eecs.umich.edu}
3527218Sgblack@eecs.umich.edu
3537194Sgblack@eecs.umich.edu
3547216Sgblack@eecs.umich.eduvoid
3557194Sgblack@eecs.umich.eduIdeDisk::doDmaRead()
3567218Sgblack@eecs.umich.edu{
3577194Sgblack@eecs.umich.edu
3587194Sgblack@eecs.umich.edu    if (!dmaReadCG) {
3597194Sgblack@eecs.umich.edu        // clear out the data buffer
3607194Sgblack@eecs.umich.edu        memset(dataBuffer, 0, MAX_DMA_SIZE);
3617194Sgblack@eecs.umich.edu        dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
3627194Sgblack@eecs.umich.edu                curPrd.getByteCount(), TheISA::PageBytes);
3637194Sgblack@eecs.umich.edu
3647194Sgblack@eecs.umich.edu    }
3657194Sgblack@eecs.umich.edu    if (ctrl->dmaPending()) {
3667194Sgblack@eecs.umich.edu        panic("shouldn't be reentant??");
3677194Sgblack@eecs.umich.edu        dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
3687194Sgblack@eecs.umich.edu        return;
3697194Sgblack@eecs.umich.edu    } else if (!dmaReadCG->done()) {
3707194Sgblack@eecs.umich.edu        assert(dmaReadCG->complete() < MAX_DMA_SIZE);
3717194Sgblack@eecs.umich.edu        ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
3727194Sgblack@eecs.umich.edu                &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
3737194Sgblack@eecs.umich.edu        dmaReadCG->next();
3747194Sgblack@eecs.umich.edu    } else {
3757194Sgblack@eecs.umich.edu        assert(dmaReadCG->done());
3767194Sgblack@eecs.umich.edu        delete dmaReadCG;
3777194Sgblack@eecs.umich.edu        dmaReadCG = NULL;
3787231Sgblack@eecs.umich.edu        dmaReadDone();
3797194Sgblack@eecs.umich.edu    }
3807231Sgblack@eecs.umich.edu}
3817194Sgblack@eecs.umich.edu
3827231Sgblack@eecs.umich.eduvoid
3837194Sgblack@eecs.umich.eduIdeDisk::dmaReadDone()
3847231Sgblack@eecs.umich.edu{
3857194Sgblack@eecs.umich.edu
3867231Sgblack@eecs.umich.edu    uint32_t bytesWritten = 0;
3877194Sgblack@eecs.umich.edu
3887231Sgblack@eecs.umich.edu
3897194Sgblack@eecs.umich.edu    // write the data to the disk image
3907194Sgblack@eecs.umich.edu    for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
3917194Sgblack@eecs.umich.edu         bytesWritten += SectorSize) {
3927194Sgblack@eecs.umich.edu
3937194Sgblack@eecs.umich.edu        cmdBytesLeft -= SectorSize;
3947194Sgblack@eecs.umich.edu        writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
3957194Sgblack@eecs.umich.edu    }
3967194Sgblack@eecs.umich.edu
3977222Sgblack@eecs.umich.edu    // check for the EOT
3987194Sgblack@eecs.umich.edu    if (curPrd.getEOT()) {
3997222Sgblack@eecs.umich.edu        assert(cmdBytesLeft == 0);
4007194Sgblack@eecs.umich.edu        dmaState = Dma_Idle;
4017222Sgblack@eecs.umich.edu        updateState(ACT_DMA_DONE);
4027194Sgblack@eecs.umich.edu    } else {
4037222Sgblack@eecs.umich.edu        doDmaTransfer();
4047194Sgblack@eecs.umich.edu    }
4057222Sgblack@eecs.umich.edu}
4067194Sgblack@eecs.umich.edu
4077222Sgblack@eecs.umich.eduvoid
4087194Sgblack@eecs.umich.eduIdeDisk::doDmaDataWrite()
4097194Sgblack@eecs.umich.edu{
4107194Sgblack@eecs.umich.edu    /** @todo we need to figure out what the delay actually will be */
4117194Sgblack@eecs.umich.edu    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
4127194Sgblack@eecs.umich.edu    uint32_t bytesRead = 0;
4137220Sgblack@eecs.umich.edu
4147194Sgblack@eecs.umich.edu    DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
4157220Sgblack@eecs.umich.edu            diskDelay, totalDiskDelay);
4167194Sgblack@eecs.umich.edu
4177220Sgblack@eecs.umich.edu    memset(dataBuffer, 0, MAX_DMA_SIZE);
4187194Sgblack@eecs.umich.edu    assert(cmdBytesLeft <= MAX_DMA_SIZE);
4197220Sgblack@eecs.umich.edu    while (bytesRead < curPrd.getByteCount()) {
4207194Sgblack@eecs.umich.edu        readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
4217220Sgblack@eecs.umich.edu        bytesRead += SectorSize;
4227194Sgblack@eecs.umich.edu        cmdBytesLeft -= SectorSize;
4237220Sgblack@eecs.umich.edu    }
4247194Sgblack@eecs.umich.edu
4257194Sgblack@eecs.umich.edu    dmaWriteWaitEvent.schedule(curTick + totalDiskDelay);
4267194Sgblack@eecs.umich.edu}
4277194Sgblack@eecs.umich.edu
4287194Sgblack@eecs.umich.eduvoid
4297231Sgblack@eecs.umich.eduIdeDisk::doDmaWrite()
4307194Sgblack@eecs.umich.edu{
4317231Sgblack@eecs.umich.edu
4327194Sgblack@eecs.umich.edu    if (!dmaWriteCG) {
4337231Sgblack@eecs.umich.edu        // clear out the data buffer
4347194Sgblack@eecs.umich.edu        dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
4357231Sgblack@eecs.umich.edu                curPrd.getByteCount(), TheISA::PageBytes);
4367194Sgblack@eecs.umich.edu    }
4377231Sgblack@eecs.umich.edu    if (ctrl->dmaPending()) {
4387194Sgblack@eecs.umich.edu        panic("shouldn't be reentant??");
4397231Sgblack@eecs.umich.edu        dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
4407194Sgblack@eecs.umich.edu        return;
4417194Sgblack@eecs.umich.edu    } else if (!dmaWriteCG->done()) {
4427194Sgblack@eecs.umich.edu        assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
4437194Sgblack@eecs.umich.edu        ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
4447194Sgblack@eecs.umich.edu                &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
4457194Sgblack@eecs.umich.edu        dmaWriteCG->next();
4467194Sgblack@eecs.umich.edu    } else {
4477194Sgblack@eecs.umich.edu        assert(dmaWriteCG->done());
4487194Sgblack@eecs.umich.edu        delete dmaWriteCG;
4497139Sgblack@eecs.umich.edu        dmaWriteCG = NULL;
4507188Sgblack@eecs.umich.edu        dmaWriteDone();
4517188Sgblack@eecs.umich.edu    }
4527188Sgblack@eecs.umich.edu}
4537188Sgblack@eecs.umich.edu
4547188Sgblack@eecs.umich.eduvoid
4557188Sgblack@eecs.umich.eduIdeDisk::dmaWriteDone()
4567188Sgblack@eecs.umich.edu{
4577188Sgblack@eecs.umich.edu    // check for the EOT
4587139Sgblack@eecs.umich.edu    if (curPrd.getEOT()) {
4597188Sgblack@eecs.umich.edu        assert(cmdBytesLeft == 0);
4607139Sgblack@eecs.umich.edu        dmaState = Dma_Idle;
4617188Sgblack@eecs.umich.edu        updateState(ACT_DMA_DONE);
4627188Sgblack@eecs.umich.edu    } else {
4637188Sgblack@eecs.umich.edu        doDmaTransfer();
4647188Sgblack@eecs.umich.edu    }
4657188Sgblack@eecs.umich.edu}
4667188Sgblack@eecs.umich.edu
4677139Sgblack@eecs.umich.edu////
4687188Sgblack@eecs.umich.edu// Disk utility routines
4697188Sgblack@eecs.umich.edu///
4707188Sgblack@eecs.umich.edu
4717188Sgblack@eecs.umich.eduvoid
4727188Sgblack@eecs.umich.eduIdeDisk::readDisk(uint32_t sector, uint8_t *data)
4737188Sgblack@eecs.umich.edu{
4747139Sgblack@eecs.umich.edu    uint32_t bytesRead = image->read(data, sector);
4757139Sgblack@eecs.umich.edu
4767139Sgblack@eecs.umich.edu    if (bytesRead != SectorSize)
4777139Sgblack@eecs.umich.edu        panic("Can't read from %s. Only %d of %d read. errno=%d\n",
4787188Sgblack@eecs.umich.edu              name(), bytesRead, SectorSize, errno);
4797188Sgblack@eecs.umich.edu}
4807188Sgblack@eecs.umich.edu
4817188Sgblack@eecs.umich.eduvoid
4827188Sgblack@eecs.umich.eduIdeDisk::writeDisk(uint32_t sector, uint8_t *data)
4837188Sgblack@eecs.umich.edu{
4847188Sgblack@eecs.umich.edu    uint32_t bytesWritten = image->write(data, sector);
4857188Sgblack@eecs.umich.edu
4867188Sgblack@eecs.umich.edu    if (bytesWritten != SectorSize)
4877188Sgblack@eecs.umich.edu        panic("Can't write to %s. Only %d of %d written. errno=%d\n",
4887188Sgblack@eecs.umich.edu              name(), bytesWritten, SectorSize, errno);
4897188Sgblack@eecs.umich.edu}
4907188Sgblack@eecs.umich.edu
4917188Sgblack@eecs.umich.edu////
4927188Sgblack@eecs.umich.edu// Setup and handle commands
4937188Sgblack@eecs.umich.edu////
4947188Sgblack@eecs.umich.edu
4957188Sgblack@eecs.umich.eduvoid
4967188Sgblack@eecs.umich.eduIdeDisk::startDma(const uint32_t &prdTableBase)
4977188Sgblack@eecs.umich.edu{
4987188Sgblack@eecs.umich.edu    if (dmaState != Dma_Start)
4997188Sgblack@eecs.umich.edu        panic("Inconsistent DMA state, should be in Dma_Start!\n");
5007188Sgblack@eecs.umich.edu
5017185Sgblack@eecs.umich.edu    if (devState != Transfer_Data_Dma)
5027188Sgblack@eecs.umich.edu        panic("Inconsistent device state for DMA start!\n");
5037188Sgblack@eecs.umich.edu
5047188Sgblack@eecs.umich.edu    // PRD base address is given by bits 31:2
5057188Sgblack@eecs.umich.edu    curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
5067188Sgblack@eecs.umich.edu
5077188Sgblack@eecs.umich.edu    dmaState = Dma_Transfer;
5087188Sgblack@eecs.umich.edu
5097188Sgblack@eecs.umich.edu    // schedule dma transfer (doDmaTransfer)
5107188Sgblack@eecs.umich.edu    dmaTransferEvent.schedule(curTick + 1);
5117188Sgblack@eecs.umich.edu}
5127188Sgblack@eecs.umich.edu
5137188Sgblack@eecs.umich.eduvoid
5147139Sgblack@eecs.umich.eduIdeDisk::abortDma()
5157139Sgblack@eecs.umich.edu{
5167139Sgblack@eecs.umich.edu    if (dmaState == Dma_Idle)
5177139Sgblack@eecs.umich.edu        panic("Inconsistent DMA state, should be Start or Transfer!");
5187139Sgblack@eecs.umich.edu
5197139Sgblack@eecs.umich.edu    if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
5207139Sgblack@eecs.umich.edu        panic("Inconsistent device state, should be Transfer or Prepare!\n");
5217139Sgblack@eecs.umich.edu
5227139Sgblack@eecs.umich.edu    updateState(ACT_CMD_ERROR);
5237139Sgblack@eecs.umich.edu}
5247139Sgblack@eecs.umich.edu
5257139Sgblack@eecs.umich.eduvoid
5267139Sgblack@eecs.umich.eduIdeDisk::startCommand()
5277139Sgblack@eecs.umich.edu{
5287185Sgblack@eecs.umich.edu    DevAction_t action = ACT_NONE;
5297139Sgblack@eecs.umich.edu    uint32_t size = 0;
5307185Sgblack@eecs.umich.edu    dmaRead = false;
5317139Sgblack@eecs.umich.edu
5327139Sgblack@eecs.umich.edu    // Decode commands
5337139Sgblack@eecs.umich.edu    switch (cmdReg.command) {
5347188Sgblack@eecs.umich.edu        // Supported non-data commands
5357188Sgblack@eecs.umich.edu      case WDSF_READ_NATIVE_MAX:
5367188Sgblack@eecs.umich.edu        size = image->size() - 1;
5377188Sgblack@eecs.umich.edu        cmdReg.sec_num = (size & 0xff);
5387139Sgblack@eecs.umich.edu        cmdReg.cyl_low = ((size & 0xff00) >> 8);
5397188Sgblack@eecs.umich.edu        cmdReg.cyl_high = ((size & 0xff0000) >> 16);
5407139Sgblack@eecs.umich.edu        cmdReg.head = ((size & 0xf000000) >> 24);
5417188Sgblack@eecs.umich.edu
5427139Sgblack@eecs.umich.edu        devState = Command_Execution;
5437139Sgblack@eecs.umich.edu        action = ACT_CMD_COMPLETE;
5447139Sgblack@eecs.umich.edu        break;
5457139Sgblack@eecs.umich.edu
5467139Sgblack@eecs.umich.edu      case WDCC_RECAL:
5477139Sgblack@eecs.umich.edu      case WDCC_IDP:
5487139Sgblack@eecs.umich.edu      case WDCC_STANDBY_IMMED:
5497141Sgblack@eecs.umich.edu      case WDCC_FLUSHCACHE:
5507195Sgblack@eecs.umich.edu      case WDSF_VERIFY:
5517195Sgblack@eecs.umich.edu      case WDSF_SEEK:
5527195Sgblack@eecs.umich.edu      case SET_FEATURES:
5537195Sgblack@eecs.umich.edu      case WDCC_SETMULTI:
5547195Sgblack@eecs.umich.edu        devState = Command_Execution;
5557195Sgblack@eecs.umich.edu        action = ACT_CMD_COMPLETE;
5567195Sgblack@eecs.umich.edu        break;
5577195Sgblack@eecs.umich.edu
5587195Sgblack@eecs.umich.edu        // Supported PIO data-in commands
5597195Sgblack@eecs.umich.edu      case WDCC_IDENTIFY:
5607195Sgblack@eecs.umich.edu        cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
5617195Sgblack@eecs.umich.edu        devState = Prepare_Data_In;
5627195Sgblack@eecs.umich.edu        action = ACT_DATA_READY;
5637195Sgblack@eecs.umich.edu        break;
5647195Sgblack@eecs.umich.edu
5657195Sgblack@eecs.umich.edu      case WDCC_READMULTI:
5667195Sgblack@eecs.umich.edu      case WDCC_READ:
5677195Sgblack@eecs.umich.edu        if (!(cmdReg.drive & DRIVE_LBA_BIT))
5687195Sgblack@eecs.umich.edu            panic("Attempt to perform CHS access, only supports LBA\n");
5697195Sgblack@eecs.umich.edu
5707195Sgblack@eecs.umich.edu        if (cmdReg.sec_count == 0)
5717195Sgblack@eecs.umich.edu            cmdBytes = cmdBytesLeft = (256 * SectorSize);
5727213Sgblack@eecs.umich.edu        else
5737213Sgblack@eecs.umich.edu            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
5747213Sgblack@eecs.umich.edu
5757213Sgblack@eecs.umich.edu        curSector = getLBABase();
5767213Sgblack@eecs.umich.edu
5777213Sgblack@eecs.umich.edu        /** @todo make this a scheduled event to simulate disk delay */
5787213Sgblack@eecs.umich.edu        devState = Prepare_Data_In;
5797213Sgblack@eecs.umich.edu        action = ACT_DATA_READY;
5807213Sgblack@eecs.umich.edu        break;
5817213Sgblack@eecs.umich.edu
5827213Sgblack@eecs.umich.edu        // Supported PIO data-out commands
5837213Sgblack@eecs.umich.edu      case WDCC_WRITEMULTI:
5847213Sgblack@eecs.umich.edu      case WDCC_WRITE:
5857213Sgblack@eecs.umich.edu        if (!(cmdReg.drive & DRIVE_LBA_BIT))
5867213Sgblack@eecs.umich.edu            panic("Attempt to perform CHS access, only supports LBA\n");
5877213Sgblack@eecs.umich.edu
5887213Sgblack@eecs.umich.edu        if (cmdReg.sec_count == 0)
5897213Sgblack@eecs.umich.edu            cmdBytes = cmdBytesLeft = (256 * SectorSize);
5907213Sgblack@eecs.umich.edu        else
5917213Sgblack@eecs.umich.edu            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
5927213Sgblack@eecs.umich.edu
5937213Sgblack@eecs.umich.edu        curSector = getLBABase();
5947213Sgblack@eecs.umich.edu
5957213Sgblack@eecs.umich.edu        devState = Prepare_Data_Out;
5967213Sgblack@eecs.umich.edu        action = ACT_DATA_READY;
5977213Sgblack@eecs.umich.edu        break;
5987213Sgblack@eecs.umich.edu
5997213Sgblack@eecs.umich.edu        // Supported DMA commands
6007213Sgblack@eecs.umich.edu      case WDCC_WRITEDMA:
6017213Sgblack@eecs.umich.edu        dmaRead = true;  // a write to the disk is a DMA read from memory
6027213Sgblack@eecs.umich.edu      case WDCC_READDMA:
6037213Sgblack@eecs.umich.edu        if (!(cmdReg.drive & DRIVE_LBA_BIT))
6047213Sgblack@eecs.umich.edu            panic("Attempt to perform CHS access, only supports LBA\n");
6057213Sgblack@eecs.umich.edu
6067213Sgblack@eecs.umich.edu        if (cmdReg.sec_count == 0)
6077213Sgblack@eecs.umich.edu            cmdBytes = cmdBytesLeft = (256 * SectorSize);
6087213Sgblack@eecs.umich.edu        else
6097235Sgblack@eecs.umich.edu            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
6107235Sgblack@eecs.umich.edu
6117235Sgblack@eecs.umich.edu        curSector = getLBABase();
6127235Sgblack@eecs.umich.edu
6137235Sgblack@eecs.umich.edu        devState = Prepare_Data_Dma;
6147235Sgblack@eecs.umich.edu        action = ACT_DMA_READY;
6157235Sgblack@eecs.umich.edu        break;
6167235Sgblack@eecs.umich.edu
6177235Sgblack@eecs.umich.edu      default:
6187235Sgblack@eecs.umich.edu        panic("Unsupported ATA command: %#x\n", cmdReg.command);
6197235Sgblack@eecs.umich.edu    }
6207235Sgblack@eecs.umich.edu
6217235Sgblack@eecs.umich.edu    if (action != ACT_NONE) {
6227235Sgblack@eecs.umich.edu        // set the BSY bit
6237235Sgblack@eecs.umich.edu        status |= STATUS_BSY_BIT;
6247235Sgblack@eecs.umich.edu        // clear the DRQ bit
6257235Sgblack@eecs.umich.edu        status &= ~STATUS_DRQ_BIT;
6267235Sgblack@eecs.umich.edu        // clear the DF bit
6277235Sgblack@eecs.umich.edu        status &= ~STATUS_DF_BIT;
6287235Sgblack@eecs.umich.edu
6297235Sgblack@eecs.umich.edu        updateState(action);
6307235Sgblack@eecs.umich.edu    }
6317235Sgblack@eecs.umich.edu}
6327235Sgblack@eecs.umich.edu
6337235Sgblack@eecs.umich.edu////
6347235Sgblack@eecs.umich.edu// Handle setting and clearing interrupts
6357235Sgblack@eecs.umich.edu////
6367235Sgblack@eecs.umich.edu
6377235Sgblack@eecs.umich.eduvoid
6387235Sgblack@eecs.umich.eduIdeDisk::intrPost()
6397235Sgblack@eecs.umich.edu{
6407235Sgblack@eecs.umich.edu    DPRINTF(IdeDisk, "Posting Interrupt\n");
6417235Sgblack@eecs.umich.edu    if (intrPending)
6427235Sgblack@eecs.umich.edu        panic("Attempt to post an interrupt with one pending\n");
6437235Sgblack@eecs.umich.edu
6447235Sgblack@eecs.umich.edu    intrPending = true;
6457235Sgblack@eecs.umich.edu
6467235Sgblack@eecs.umich.edu    // talk to controller to set interrupt
6477235Sgblack@eecs.umich.edu    if (ctrl) {
6487235Sgblack@eecs.umich.edu        ctrl->bmi_regs.bmis0 |= IDEINTS;
6497235Sgblack@eecs.umich.edu        ctrl->intrPost();
6507235Sgblack@eecs.umich.edu    }
6517235Sgblack@eecs.umich.edu}
6527235Sgblack@eecs.umich.edu
6537235Sgblack@eecs.umich.eduvoid
6547235Sgblack@eecs.umich.eduIdeDisk::intrClear()
6557213Sgblack@eecs.umich.edu{
6567213Sgblack@eecs.umich.edu    DPRINTF(IdeDisk, "Clearing Interrupt\n");
6577213Sgblack@eecs.umich.edu    if (!intrPending)
6587213Sgblack@eecs.umich.edu        panic("Attempt to clear a non-pending interrupt\n");
6597220Sgblack@eecs.umich.edu
6607220Sgblack@eecs.umich.edu    intrPending = false;
6617220Sgblack@eecs.umich.edu
6627220Sgblack@eecs.umich.edu    // talk to controller to clear interrupt
6637213Sgblack@eecs.umich.edu    if (ctrl)
6647213Sgblack@eecs.umich.edu        ctrl->intrClear();
6657213Sgblack@eecs.umich.edu}
6667213Sgblack@eecs.umich.edu
6677213Sgblack@eecs.umich.edu////
6687213Sgblack@eecs.umich.edu// Manage the device internal state machine
6697213Sgblack@eecs.umich.edu////
6707216Sgblack@eecs.umich.edu
6717216Sgblack@eecs.umich.eduvoid
6727213Sgblack@eecs.umich.eduIdeDisk::updateState(DevAction_t action)
6737224Sgblack@eecs.umich.edu{
6747224Sgblack@eecs.umich.edu    switch (devState) {
6757213Sgblack@eecs.umich.edu      case Device_Srst:
6767224Sgblack@eecs.umich.edu        if (action == ACT_SRST_SET) {
6777224Sgblack@eecs.umich.edu            // set the BSY bit
6787213Sgblack@eecs.umich.edu            status |= STATUS_BSY_BIT;
6797218Sgblack@eecs.umich.edu        } else if (action == ACT_SRST_CLEAR) {
6807218Sgblack@eecs.umich.edu            // clear the BSY bit
6817213Sgblack@eecs.umich.edu            status &= ~STATUS_BSY_BIT;
6827216Sgblack@eecs.umich.edu
6837216Sgblack@eecs.umich.edu            // reset the device state
6847213Sgblack@eecs.umich.edu            reset(devID);
6857218Sgblack@eecs.umich.edu        }
6867218Sgblack@eecs.umich.edu        break;
6877213Sgblack@eecs.umich.edu
6887213Sgblack@eecs.umich.edu      case Device_Idle_S:
6897213Sgblack@eecs.umich.edu        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
6907216Sgblack@eecs.umich.edu            devState = Device_Idle_NS;
6917216Sgblack@eecs.umich.edu        } else if (action == ACT_CMD_WRITE) {
6927216Sgblack@eecs.umich.edu            startCommand();
6937216Sgblack@eecs.umich.edu        }
6947216Sgblack@eecs.umich.edu
6957216Sgblack@eecs.umich.edu        break;
6967216Sgblack@eecs.umich.edu
6977216Sgblack@eecs.umich.edu      case Device_Idle_SI:
6987216Sgblack@eecs.umich.edu        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
6997216Sgblack@eecs.umich.edu            devState = Device_Idle_NS;
7007216Sgblack@eecs.umich.edu            intrClear();
7017216Sgblack@eecs.umich.edu        } else if (action == ACT_STAT_READ || isIENSet()) {
7027216Sgblack@eecs.umich.edu            devState = Device_Idle_S;
7037213Sgblack@eecs.umich.edu            intrClear();
7047213Sgblack@eecs.umich.edu        } else if (action == ACT_CMD_WRITE) {
7057213Sgblack@eecs.umich.edu            intrClear();
7067213Sgblack@eecs.umich.edu            startCommand();
7077213Sgblack@eecs.umich.edu        }
7087231Sgblack@eecs.umich.edu
7097213Sgblack@eecs.umich.edu        break;
7107231Sgblack@eecs.umich.edu
7117213Sgblack@eecs.umich.edu      case Device_Idle_NS:
7127231Sgblack@eecs.umich.edu        if (action == ACT_SELECT_WRITE && isDEVSelect()) {
7137213Sgblack@eecs.umich.edu            if (!isIENSet() && intrPending) {
7147231Sgblack@eecs.umich.edu                devState = Device_Idle_SI;
7157213Sgblack@eecs.umich.edu                intrPost();
7167231Sgblack@eecs.umich.edu            }
7177213Sgblack@eecs.umich.edu            if (isIENSet() || !intrPending) {
7187231Sgblack@eecs.umich.edu                devState = Device_Idle_S;
7197213Sgblack@eecs.umich.edu            }
7207213Sgblack@eecs.umich.edu        }
7217213Sgblack@eecs.umich.edu        break;
7227213Sgblack@eecs.umich.edu
7237213Sgblack@eecs.umich.edu      case Command_Execution:
7247213Sgblack@eecs.umich.edu        if (action == ACT_CMD_COMPLETE) {
7257213Sgblack@eecs.umich.edu            // clear the BSY bit
7267213Sgblack@eecs.umich.edu            setComplete();
7277213Sgblack@eecs.umich.edu
7287213Sgblack@eecs.umich.edu            if (!isIENSet()) {
7297222Sgblack@eecs.umich.edu                devState = Device_Idle_SI;
7307222Sgblack@eecs.umich.edu                intrPost();
7317213Sgblack@eecs.umich.edu            } else {
7327222Sgblack@eecs.umich.edu                devState = Device_Idle_S;
7337222Sgblack@eecs.umich.edu            }
7347213Sgblack@eecs.umich.edu        }
7357222Sgblack@eecs.umich.edu        break;
7367222Sgblack@eecs.umich.edu
7377213Sgblack@eecs.umich.edu      case Prepare_Data_In:
7387222Sgblack@eecs.umich.edu        if (action == ACT_CMD_ERROR) {
7397222Sgblack@eecs.umich.edu            // clear the BSY bit
7407213Sgblack@eecs.umich.edu            setComplete();
7417222Sgblack@eecs.umich.edu
7427222Sgblack@eecs.umich.edu            if (!isIENSet()) {
7437213Sgblack@eecs.umich.edu                devState = Device_Idle_SI;
7447222Sgblack@eecs.umich.edu                intrPost();
7457222Sgblack@eecs.umich.edu            } else {
7467213Sgblack@eecs.umich.edu                devState = Device_Idle_S;
7477213Sgblack@eecs.umich.edu            }
7487213Sgblack@eecs.umich.edu        } else if (action == ACT_DATA_READY) {
7497213Sgblack@eecs.umich.edu            // clear the BSY bit
7507213Sgblack@eecs.umich.edu            status &= ~STATUS_BSY_BIT;
7517220Sgblack@eecs.umich.edu            // set the DRQ bit
7527213Sgblack@eecs.umich.edu            status |= STATUS_DRQ_BIT;
7537220Sgblack@eecs.umich.edu
7547213Sgblack@eecs.umich.edu            // copy the data into the data buffer
7557220Sgblack@eecs.umich.edu            if (cmdReg.command == WDCC_IDENTIFY) {
7567213Sgblack@eecs.umich.edu                // Reset the drqBytes for this block
7577220Sgblack@eecs.umich.edu                drqBytesLeft = sizeof(struct ataparams);
7587213Sgblack@eecs.umich.edu
7597220Sgblack@eecs.umich.edu                memcpy((void *)dataBuffer, (void *)&driveID,
7607213Sgblack@eecs.umich.edu                       sizeof(struct ataparams));
7617220Sgblack@eecs.umich.edu            } else {
7627213Sgblack@eecs.umich.edu                // Reset the drqBytes for this block
7637213Sgblack@eecs.umich.edu                drqBytesLeft = SectorSize;
7647213Sgblack@eecs.umich.edu
7657213Sgblack@eecs.umich.edu                readDisk(curSector++, dataBuffer);
7667213Sgblack@eecs.umich.edu            }
7677231Sgblack@eecs.umich.edu
7687213Sgblack@eecs.umich.edu            // put the first two bytes into the data register
7697231Sgblack@eecs.umich.edu            memcpy((void *)&cmdReg.data, (void *)dataBuffer,
7707213Sgblack@eecs.umich.edu                   sizeof(uint16_t));
7717231Sgblack@eecs.umich.edu
7727213Sgblack@eecs.umich.edu            if (!isIENSet()) {
7737231Sgblack@eecs.umich.edu                devState = Data_Ready_INTRQ_In;
7747213Sgblack@eecs.umich.edu                intrPost();
7757231Sgblack@eecs.umich.edu            } else {
7767213Sgblack@eecs.umich.edu                devState = Transfer_Data_In;
7777231Sgblack@eecs.umich.edu            }
7787213Sgblack@eecs.umich.edu        }
7797213Sgblack@eecs.umich.edu        break;
7807213Sgblack@eecs.umich.edu
7817213Sgblack@eecs.umich.edu      case Data_Ready_INTRQ_In:
7827213Sgblack@eecs.umich.edu        if (action == ACT_STAT_READ) {
7837213Sgblack@eecs.umich.edu            devState = Transfer_Data_In;
7847213Sgblack@eecs.umich.edu            intrClear();
7857240Sgblack@eecs.umich.edu        }
7867240Sgblack@eecs.umich.edu        break;
7877240Sgblack@eecs.umich.edu
7887240Sgblack@eecs.umich.edu      case Transfer_Data_In:
7897213Sgblack@eecs.umich.edu        if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
7907213Sgblack@eecs.umich.edu            if (action == ACT_DATA_READ_BYTE) {
7917240Sgblack@eecs.umich.edu                panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
7927240Sgblack@eecs.umich.edu            } else {
7937240Sgblack@eecs.umich.edu                drqBytesLeft -= 2;
7947240Sgblack@eecs.umich.edu                cmdBytesLeft -= 2;
7957240Sgblack@eecs.umich.edu
7967240Sgblack@eecs.umich.edu                // copy next short into data registers
7977240Sgblack@eecs.umich.edu                if (drqBytesLeft)
7987240Sgblack@eecs.umich.edu                    memcpy((void *)&cmdReg.data,
7997240Sgblack@eecs.umich.edu                           (void *)&dataBuffer[SectorSize - drqBytesLeft],
8007240Sgblack@eecs.umich.edu                           sizeof(uint16_t));
8017240Sgblack@eecs.umich.edu            }
8027240Sgblack@eecs.umich.edu
8037240Sgblack@eecs.umich.edu            if (drqBytesLeft == 0) {
8047213Sgblack@eecs.umich.edu                if (cmdBytesLeft == 0) {
8057213Sgblack@eecs.umich.edu                    // Clear the BSY bit
8067213Sgblack@eecs.umich.edu                    setComplete();
8077240Sgblack@eecs.umich.edu                    devState = Device_Idle_S;
8087240Sgblack@eecs.umich.edu                } else {
8097240Sgblack@eecs.umich.edu                    devState = Prepare_Data_In;
8107240Sgblack@eecs.umich.edu                    // set the BSY_BIT
8117240Sgblack@eecs.umich.edu                    status |= STATUS_BSY_BIT;
8127240Sgblack@eecs.umich.edu                    // clear the DRQ_BIT
8137250Sgblack@eecs.umich.edu                    status &= ~STATUS_DRQ_BIT;
8147240Sgblack@eecs.umich.edu
8157240Sgblack@eecs.umich.edu                    /** @todo change this to a scheduled event to simulate
8167213Sgblack@eecs.umich.edu                        disk delay */
8177213Sgblack@eecs.umich.edu                    updateState(ACT_DATA_READY);
8187213Sgblack@eecs.umich.edu                }
8197213Sgblack@eecs.umich.edu            }
8207240Sgblack@eecs.umich.edu        }
8217213Sgblack@eecs.umich.edu        break;
8227213Sgblack@eecs.umich.edu
8237213Sgblack@eecs.umich.edu      case Prepare_Data_Out:
8247213Sgblack@eecs.umich.edu        if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
8257252Sgblack@eecs.umich.edu            // clear the BSY bit
8267213Sgblack@eecs.umich.edu            setComplete();
8277213Sgblack@eecs.umich.edu
8287213Sgblack@eecs.umich.edu            if (!isIENSet()) {
8297213Sgblack@eecs.umich.edu                devState = Device_Idle_SI;
8307213Sgblack@eecs.umich.edu                intrPost();
8317213Sgblack@eecs.umich.edu            } else {
8327213Sgblack@eecs.umich.edu                devState = Device_Idle_S;
8337213Sgblack@eecs.umich.edu            }
8347213Sgblack@eecs.umich.edu        } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
8357141Sgblack@eecs.umich.edu            // clear the BSY bit
8367141Sgblack@eecs.umich.edu            status &= ~STATUS_BSY_BIT;
8377141Sgblack@eecs.umich.edu            // set the DRQ bit
8387141Sgblack@eecs.umich.edu            status |= STATUS_DRQ_BIT;
8397141Sgblack@eecs.umich.edu
8407141Sgblack@eecs.umich.edu            // clear the data buffer to get it ready for writes
8417141Sgblack@eecs.umich.edu            memset(dataBuffer, 0, MAX_DMA_SIZE);
8427141Sgblack@eecs.umich.edu
8437141Sgblack@eecs.umich.edu            // reset the drqBytes for this block
8447141Sgblack@eecs.umich.edu            drqBytesLeft = SectorSize;
8457141Sgblack@eecs.umich.edu
8467141Sgblack@eecs.umich.edu            if (cmdBytesLeft == cmdBytes || isIENSet()) {
8477183Sgblack@eecs.umich.edu                devState = Transfer_Data_Out;
8487141Sgblack@eecs.umich.edu            } else {
8497183Sgblack@eecs.umich.edu                devState = Data_Ready_INTRQ_Out;
8507141Sgblack@eecs.umich.edu                intrPost();
8517183Sgblack@eecs.umich.edu            }
8527141Sgblack@eecs.umich.edu        }
8537141Sgblack@eecs.umich.edu        break;
8547141Sgblack@eecs.umich.edu
8557183Sgblack@eecs.umich.edu      case Data_Ready_INTRQ_Out:
8567141Sgblack@eecs.umich.edu        if (action == ACT_STAT_READ) {
8577183Sgblack@eecs.umich.edu            devState = Transfer_Data_Out;
8587141Sgblack@eecs.umich.edu            intrClear();
8597183Sgblack@eecs.umich.edu        }
8607141Sgblack@eecs.umich.edu        break;
8617183Sgblack@eecs.umich.edu
8627141Sgblack@eecs.umich.edu      case Transfer_Data_Out:
8637141Sgblack@eecs.umich.edu        if (action == ACT_DATA_WRITE_BYTE ||
8647183Sgblack@eecs.umich.edu            action == ACT_DATA_WRITE_SHORT) {
8657141Sgblack@eecs.umich.edu
8667146Sgblack@eecs.umich.edu            if (action == ACT_DATA_READ_BYTE) {
8677141Sgblack@eecs.umich.edu                panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
8687183Sgblack@eecs.umich.edu            } else {
8697141Sgblack@eecs.umich.edu                // copy the latest short into the data buffer
8707183Sgblack@eecs.umich.edu                memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
8717141Sgblack@eecs.umich.edu                       (void *)&cmdReg.data,
8727141Sgblack@eecs.umich.edu                       sizeof(uint16_t));
8737141Sgblack@eecs.umich.edu
8747141Sgblack@eecs.umich.edu                drqBytesLeft -= 2;
8757141Sgblack@eecs.umich.edu                cmdBytesLeft -= 2;
8767141Sgblack@eecs.umich.edu            }
8777141Sgblack@eecs.umich.edu
8787141Sgblack@eecs.umich.edu            if (drqBytesLeft == 0) {
8797141Sgblack@eecs.umich.edu                // copy the block to the disk
8807141Sgblack@eecs.umich.edu                writeDisk(curSector++, dataBuffer);
8817141Sgblack@eecs.umich.edu
8827141Sgblack@eecs.umich.edu                // set the BSY bit
8837183Sgblack@eecs.umich.edu                status |= STATUS_BSY_BIT;
8847141Sgblack@eecs.umich.edu                // set the seek bit
8857183Sgblack@eecs.umich.edu                status |= STATUS_SEEK_BIT;
8867141Sgblack@eecs.umich.edu                // clear the DRQ bit
8877183Sgblack@eecs.umich.edu                status &= ~STATUS_DRQ_BIT;
8887141Sgblack@eecs.umich.edu
8897183Sgblack@eecs.umich.edu                devState = Prepare_Data_Out;
8907141Sgblack@eecs.umich.edu
8917183Sgblack@eecs.umich.edu                /** @todo change this to a scheduled event to simulate
8927141Sgblack@eecs.umich.edu                    disk delay */
8937183Sgblack@eecs.umich.edu                updateState(ACT_DATA_READY);
8947141Sgblack@eecs.umich.edu            }
8957183Sgblack@eecs.umich.edu        }
8967141Sgblack@eecs.umich.edu        break;
8977183Sgblack@eecs.umich.edu
8987141Sgblack@eecs.umich.edu      case Prepare_Data_Dma:
8997183Sgblack@eecs.umich.edu        if (action == ACT_CMD_ERROR) {
9007141Sgblack@eecs.umich.edu            // clear the BSY bit
9017183Sgblack@eecs.umich.edu            setComplete();
9027141Sgblack@eecs.umich.edu
9037183Sgblack@eecs.umich.edu            if (!isIENSet()) {
9047141Sgblack@eecs.umich.edu                devState = Device_Idle_SI;
9057183Sgblack@eecs.umich.edu                intrPost();
9067141Sgblack@eecs.umich.edu            } else {
9077183Sgblack@eecs.umich.edu                devState = Device_Idle_S;
9087141Sgblack@eecs.umich.edu            }
9097183Sgblack@eecs.umich.edu        } else if (action == ACT_DMA_READY) {
9107141Sgblack@eecs.umich.edu            // clear the BSY bit
9117183Sgblack@eecs.umich.edu            status &= ~STATUS_BSY_BIT;
9127141Sgblack@eecs.umich.edu            // set the DRQ bit
9137183Sgblack@eecs.umich.edu            status |= STATUS_DRQ_BIT;
9147141Sgblack@eecs.umich.edu
9157141Sgblack@eecs.umich.edu            devState = Transfer_Data_Dma;
9167141Sgblack@eecs.umich.edu
9177141Sgblack@eecs.umich.edu            if (dmaState != Dma_Idle)
9187141Sgblack@eecs.umich.edu                panic("Inconsistent DMA state, should be Dma_Idle\n");
9197141Sgblack@eecs.umich.edu
9207141Sgblack@eecs.umich.edu            dmaState = Dma_Start;
9217141Sgblack@eecs.umich.edu            // wait for the write to the DMA start bit
9227141Sgblack@eecs.umich.edu        }
9237141Sgblack@eecs.umich.edu        break;
9247141Sgblack@eecs.umich.edu
9257141Sgblack@eecs.umich.edu      case Transfer_Data_Dma:
9267141Sgblack@eecs.umich.edu        if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) {
9277141Sgblack@eecs.umich.edu            // clear the BSY bit
9287146Sgblack@eecs.umich.edu            setComplete();
9297141Sgblack@eecs.umich.edu            // set the seek bit
9307183Sgblack@eecs.umich.edu            status |= STATUS_SEEK_BIT;
9317141Sgblack@eecs.umich.edu            // clear the controller state for DMA transfer
9327146Sgblack@eecs.umich.edu            ctrl->setDmaComplete(this);
9337141Sgblack@eecs.umich.edu
9347154Sgblack@eecs.umich.edu            if (!isIENSet()) {
9357154Sgblack@eecs.umich.edu                devState = Device_Idle_SI;
9367154Sgblack@eecs.umich.edu                intrPost();
9377154Sgblack@eecs.umich.edu            } else {
9387154Sgblack@eecs.umich.edu                devState = Device_Idle_S;
9397154Sgblack@eecs.umich.edu            }
9407154Sgblack@eecs.umich.edu        }
9417154Sgblack@eecs.umich.edu        break;
9427154Sgblack@eecs.umich.edu
9437141Sgblack@eecs.umich.edu      default:
9447141Sgblack@eecs.umich.edu        panic("Unknown IDE device state: %#x\n", devState);
9457141Sgblack@eecs.umich.edu    }
9467141Sgblack@eecs.umich.edu}
9477141Sgblack@eecs.umich.edu
9487141Sgblack@eecs.umich.eduvoid
9497141Sgblack@eecs.umich.eduIdeDisk::serialize(ostream &os)
9507141Sgblack@eecs.umich.edu{
9517141Sgblack@eecs.umich.edu    // Check all outstanding events to see if they are scheduled
9527141Sgblack@eecs.umich.edu    // these are all mutually exclusive
9537185Sgblack@eecs.umich.edu    Tick reschedule = 0;
9547141Sgblack@eecs.umich.edu    Events_t event = None;
9557141Sgblack@eecs.umich.edu
9567141Sgblack@eecs.umich.edu    int eventCount = 0;
9577141Sgblack@eecs.umich.edu
9587141Sgblack@eecs.umich.edu    if (dmaTransferEvent.scheduled()) {
9597141Sgblack@eecs.umich.edu        reschedule = dmaTransferEvent.when();
9607141Sgblack@eecs.umich.edu        event = Transfer;
9617141Sgblack@eecs.umich.edu        eventCount++;
9627141Sgblack@eecs.umich.edu    }
9637146Sgblack@eecs.umich.edu    if (dmaReadWaitEvent.scheduled()) {
9647141Sgblack@eecs.umich.edu        reschedule = dmaReadWaitEvent.when();
9657141Sgblack@eecs.umich.edu        event = ReadWait;
9667141Sgblack@eecs.umich.edu        eventCount++;
9677141Sgblack@eecs.umich.edu    }
9687141Sgblack@eecs.umich.edu    if (dmaWriteWaitEvent.scheduled()) {
9697141Sgblack@eecs.umich.edu        reschedule = dmaWriteWaitEvent.when();
9707141Sgblack@eecs.umich.edu        event = WriteWait;
9717141Sgblack@eecs.umich.edu        eventCount++;
9727141Sgblack@eecs.umich.edu    }
9737141Sgblack@eecs.umich.edu    if (dmaPrdReadEvent.scheduled()) {
9747146Sgblack@eecs.umich.edu        reschedule = dmaPrdReadEvent.when();
9757141Sgblack@eecs.umich.edu        event = PrdRead;
9767141Sgblack@eecs.umich.edu        eventCount++;
9777146Sgblack@eecs.umich.edu    }
9787141Sgblack@eecs.umich.edu    if (dmaReadEvent.scheduled()) {
9797141Sgblack@eecs.umich.edu        reschedule = dmaReadEvent.when();
9807141Sgblack@eecs.umich.edu        event = DmaRead;
9817154Sgblack@eecs.umich.edu        eventCount++;
9827154Sgblack@eecs.umich.edu    }
9837154Sgblack@eecs.umich.edu    if (dmaWriteEvent.scheduled()) {
9847154Sgblack@eecs.umich.edu        reschedule = dmaWriteEvent.when();
9857141Sgblack@eecs.umich.edu        event = DmaWrite;
9867235Sgblack@eecs.umich.edu        eventCount++;
9877235Sgblack@eecs.umich.edu    }
9887235Sgblack@eecs.umich.edu
9897235Sgblack@eecs.umich.edu    assert(eventCount <= 1);
9907235Sgblack@eecs.umich.edu
9917235Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(reschedule);
9927235Sgblack@eecs.umich.edu    SERIALIZE_ENUM(event);
9937235Sgblack@eecs.umich.edu
9947235Sgblack@eecs.umich.edu    // Serialize device registers
9957235Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(cmdReg.data);
9967235Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(cmdReg.sec_count);
9977235Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(cmdReg.sec_num);
9987235Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(cmdReg.cyl_low);
9997235Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(cmdReg.cyl_high);
10007235Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(cmdReg.drive);
10017141Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(cmdReg.command);
10027141Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(status);
10037154Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(nIENBit);
10047154Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(devID);
10057154Sgblack@eecs.umich.edu
10067154Sgblack@eecs.umich.edu    // Serialize the PRD related information
10077141Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(curPrd.entry.baseAddr);
10087141Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(curPrd.entry.byteCount);
10097201Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(curPrd.entry.endOfTable);
10107201Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(curPrdAddr);
10117201Sgblack@eecs.umich.edu
10127201Sgblack@eecs.umich.edu    /** @todo need to serialized chunk generator stuff!! */
10137201Sgblack@eecs.umich.edu    // Serialize current transfer related information
10147201Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(cmdBytesLeft);
10157141Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(cmdBytes);
10167141Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(drqBytesLeft);
10177141Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(curSector);
10187141Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(dmaRead);
10197141Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(intrPending);
10207141Sgblack@eecs.umich.edu    SERIALIZE_ENUM(devState);
10217141Sgblack@eecs.umich.edu    SERIALIZE_ENUM(dmaState);
10227141Sgblack@eecs.umich.edu    SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
10237141Sgblack@eecs.umich.edu}
10247141Sgblack@eecs.umich.edu
10257154Sgblack@eecs.umich.eduvoid
10267154Sgblack@eecs.umich.eduIdeDisk::unserialize(Checkpoint *cp, const string &section)
10277154Sgblack@eecs.umich.edu{
10287154Sgblack@eecs.umich.edu    // Reschedule events that were outstanding
10297141Sgblack@eecs.umich.edu    // these are all mutually exclusive
10307212Sgblack@eecs.umich.edu    Tick reschedule = 0;
10317212Sgblack@eecs.umich.edu    Events_t event = None;
10327212Sgblack@eecs.umich.edu
10337212Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(reschedule);
10347212Sgblack@eecs.umich.edu    UNSERIALIZE_ENUM(event);
10357212Sgblack@eecs.umich.edu
10367212Sgblack@eecs.umich.edu    switch (event) {
10377212Sgblack@eecs.umich.edu      case None : break;
10387212Sgblack@eecs.umich.edu      case Transfer : dmaTransferEvent.schedule(reschedule); break;
10397212Sgblack@eecs.umich.edu      case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
10407212Sgblack@eecs.umich.edu      case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
10417212Sgblack@eecs.umich.edu      case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
10427212Sgblack@eecs.umich.edu      case DmaRead : dmaReadEvent.schedule(reschedule); break;
10437141Sgblack@eecs.umich.edu      case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
10447141Sgblack@eecs.umich.edu    }
10457141Sgblack@eecs.umich.edu
10467154Sgblack@eecs.umich.edu    // Unserialize device registers
10477154Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(cmdReg.data);
10487154Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(cmdReg.sec_count);
10497154Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(cmdReg.sec_num);
10507141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(cmdReg.cyl_low);
10517141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(cmdReg.cyl_high);
10527201Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(cmdReg.drive);
10537201Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(cmdReg.command);
10547201Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(status);
10557201Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(nIENBit);
10567201Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(devID);
10577201Sgblack@eecs.umich.edu
10587141Sgblack@eecs.umich.edu    // Unserialize the PRD related information
10597141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
10607141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
10617141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
10627141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(curPrdAddr);
10637141Sgblack@eecs.umich.edu
10647141Sgblack@eecs.umich.edu    /** @todo need to serialized chunk generator stuff!! */
10657248Sgblack@eecs.umich.edu    // Unserialize current transfer related information
10667141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(cmdBytes);
10677141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(cmdBytesLeft);
10687141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(drqBytesLeft);
10697141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(curSector);
10707141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(dmaRead);
10717141Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(intrPending);
10727141Sgblack@eecs.umich.edu    UNSERIALIZE_ENUM(devState);
10737141Sgblack@eecs.umich.edu    UNSERIALIZE_ENUM(dmaState);
10747141Sgblack@eecs.umich.edu    UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
10757141Sgblack@eecs.umich.edu}
10767141Sgblack@eecs.umich.edu
10777141Sgblack@eecs.umich.edu#ifndef DOXYGEN_SHOULD_SKIP_THIS
10787141Sgblack@eecs.umich.edu
10797141Sgblack@eecs.umich.eduenum DriveID { master, slave };
10807141Sgblack@eecs.umich.edustatic const char *DriveID_strings[] = { "master", "slave" };
10817141Sgblack@eecs.umich.eduBEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
10827141Sgblack@eecs.umich.edu
10837141Sgblack@eecs.umich.edu    SimObjectParam<DiskImage *> image;
10847141Sgblack@eecs.umich.edu    SimpleEnumParam<DriveID> driveID;
10857141Sgblack@eecs.umich.edu    Param<int> delay;
10867141Sgblack@eecs.umich.edu
10877141Sgblack@eecs.umich.eduEND_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
10887141Sgblack@eecs.umich.edu
10897141Sgblack@eecs.umich.eduBEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
10907146Sgblack@eecs.umich.edu
10917183Sgblack@eecs.umich.edu    INIT_PARAM(image, "Disk image"),
10927141Sgblack@eecs.umich.edu    INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings),
10937146Sgblack@eecs.umich.edu    INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1)
10947183Sgblack@eecs.umich.edu
10957141Sgblack@eecs.umich.eduEND_INIT_SIM_OBJECT_PARAMS(IdeDisk)
10967141Sgblack@eecs.umich.edu
10977141Sgblack@eecs.umich.edu
10987141Sgblack@eecs.umich.eduCREATE_SIM_OBJECT(IdeDisk)
10997141Sgblack@eecs.umich.edu{
11007141Sgblack@eecs.umich.edu    return new IdeDisk(getInstanceName(), image, driveID, delay);
11017141Sgblack@eecs.umich.edu}
11027141Sgblack@eecs.umich.edu
11037141Sgblack@eecs.umich.eduREGISTER_SIM_OBJECT("IdeDisk", IdeDisk)
11047141Sgblack@eecs.umich.edu
11057141Sgblack@eecs.umich.edu#endif //DOXYGEN_SHOULD_SKIP_THIS
11067183Sgblack@eecs.umich.edu