ide_disk.cc revision 11522
1848SN/A/*
29956SN/A * Copyright (c) 2013 ARM Limited
39956SN/A * All rights reserved
49956SN/A *
59956SN/A * The license below extends only to copyright in the software and shall
69956SN/A * not be construed as granting a license to any other intellectual
79956SN/A * property including but not limited to intellectual property relating
89956SN/A * to a hardware implementation of the functionality of the software
99956SN/A * licensed hereunder.  You may use the software subject to the license
109956SN/A * terms below provided that you ensure that this notice is replicated
119956SN/A * unmodified and in its entirety in all distributions of the software,
129956SN/A * modified or unmodified, in source code or in binary form.
139956SN/A *
141762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
15848SN/A * All rights reserved.
16848SN/A *
17848SN/A * Redistribution and use in source and binary forms, with or without
18848SN/A * modification, are permitted provided that the following conditions are
19848SN/A * met: redistributions of source code must retain the above copyright
20848SN/A * notice, this list of conditions and the following disclaimer;
21848SN/A * redistributions in binary form must reproduce the above copyright
22848SN/A * notice, this list of conditions and the following disclaimer in the
23848SN/A * documentation and/or other materials provided with the distribution;
24848SN/A * neither the name of the copyright holders nor the names of its
25848SN/A * contributors may be used to endorse or promote products derived from
26848SN/A * this software without specific prior written permission.
27848SN/A *
28848SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29848SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30848SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31848SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32848SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33848SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34848SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35848SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36848SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37848SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38848SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392665SN/A *
402665SN/A * Authors: Andrew Schultz
412665SN/A *          Ali Saidi
42848SN/A */
43848SN/A
44848SN/A/** @file
45848SN/A * Device model implementation for an IDE disk
46848SN/A */
47848SN/A
4811264Sandreas.sandberg@arm.com#include "dev/storage/ide_disk.hh"
4911264Sandreas.sandberg@arm.com
50848SN/A#include <cerrno>
51848SN/A#include <cstring>
52848SN/A#include <deque>
53848SN/A#include <string>
54848SN/A
554762SN/A#include "arch/isa_traits.hh"
562565SN/A#include "base/chunk_generator.hh"
57848SN/A#include "base/cprintf.hh" // csprintf
58848SN/A#include "base/trace.hh"
598229SN/A#include "config/the_isa.hh"
608232SN/A#include "debug/IdeDisk.hh"
6111264Sandreas.sandberg@arm.com#include "dev/storage/disk_image.hh"
6211264Sandreas.sandberg@arm.com#include "dev/storage/ide_ctrl.hh"
634762SN/A#include "sim/core.hh"
64848SN/A#include "sim/sim_object.hh"
65848SN/A
66848SN/Ausing namespace std;
672107SN/Ausing namespace TheISA;
68848SN/A
695034SN/AIdeDisk::IdeDisk(const Params *p)
705034SN/A    : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),
712565SN/A      dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
722565SN/A      dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
73849SN/A      dmaReadEvent(this), dmaWriteEvent(this)
74848SN/A{
75893SN/A    // Reset the device state
765034SN/A    reset(p->driveID);
77893SN/A
78849SN/A    // fill out the drive ID structure
791722SN/A    memset(&driveID, 0, sizeof(struct ataparams));
80849SN/A
81849SN/A    // Calculate LBA and C/H/S values
82849SN/A    uint16_t cylinders;
83849SN/A    uint8_t heads;
84849SN/A    uint8_t sectors;
85849SN/A
86849SN/A    uint32_t lba_size = image->size();
87849SN/A    if (lba_size >= 16383*16*63) {
88849SN/A        cylinders = 16383;
89849SN/A        heads = 16;
90849SN/A        sectors = 63;
91849SN/A    } else {
92849SN/A        if (lba_size >= 63)
93849SN/A            sectors = 63;
9411101SN/A        else if (lba_size == 0)
9511101SN/A            panic("Bad IDE image size: 0\n");
96849SN/A        else
97849SN/A            sectors = lba_size;
98849SN/A
99849SN/A        if ((lba_size / sectors) >= 16)
100849SN/A            heads = 16;
101849SN/A        else
102849SN/A            heads = (lba_size / sectors);
103849SN/A
104849SN/A        cylinders = lba_size / (heads * sectors);
105849SN/A    }
106849SN/A
107849SN/A    // Setup the model name
1081853SN/A    strncpy((char *)driveID.atap_model, "5MI EDD si k",
1091853SN/A            sizeof(driveID.atap_model));
110849SN/A    // Set the maximum multisector transfer size
1111722SN/A    driveID.atap_multi = MAX_MULTSECT;
112849SN/A    // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
1131722SN/A    driveID.atap_capabilities1 = 0x7;
114849SN/A    // UDMA support, EIDE support
1151722SN/A    driveID.atap_extensions = 0x6;
116849SN/A    // Setup default C/H/S settings
1171722SN/A    driveID.atap_cylinders = cylinders;
1181722SN/A    driveID.atap_sectors = sectors;
1191722SN/A    driveID.atap_heads = heads;
120849SN/A    // Setup the current multisector transfer size
1211722SN/A    driveID.atap_curmulti = MAX_MULTSECT;
1221722SN/A    driveID.atap_curmulti_valid = 0x1;
123849SN/A    // Number of sectors on disk
1241722SN/A    driveID.atap_capacity = lba_size;
125849SN/A    // Multiword DMA mode 2 and below supported
1262989SN/A    driveID.atap_dmamode_supp = 0x4;
127849SN/A    // Set PIO mode 4 and 3 supported
1281722SN/A    driveID.atap_piomode_supp = 0x3;
129849SN/A    // Set DMA mode 4 and below supported
1301886SN/A    driveID.atap_udmamode_supp = 0x1f;
131849SN/A    // Statically set hardware config word
1321722SN/A    driveID.atap_hwreset_res = 0x4001;
1331817SN/A
1341817SN/A    //arbitrary for now...
1351817SN/A    driveID.atap_ata_major = WDC_VER_ATA7;
136893SN/A}
137893SN/A
138893SN/AIdeDisk::~IdeDisk()
139893SN/A{
140893SN/A    // destroy the data buffer
141893SN/A    delete [] dataBuffer;
142893SN/A}
143893SN/A
144893SN/Avoid
145893SN/AIdeDisk::reset(int id)
146893SN/A{
147893SN/A    // initialize the data buffer and shadow registers
148893SN/A    dataBuffer = new uint8_t[MAX_DMA_SIZE];
149893SN/A
150893SN/A    memset(dataBuffer, 0, MAX_DMA_SIZE);
151893SN/A    memset(&cmdReg, 0, sizeof(CommandReg_t));
152893SN/A    memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
153893SN/A
154893SN/A    curPrdAddr = 0;
155893SN/A    curSector = 0;
156893SN/A    cmdBytes = 0;
157893SN/A    cmdBytesLeft = 0;
158893SN/A    drqBytesLeft = 0;
159893SN/A    dmaRead = false;
160893SN/A    intrPending = false;
1619956SN/A    dmaAborted = false;
162849SN/A
163849SN/A    // set the device state to idle
164849SN/A    dmaState = Dma_Idle;
165849SN/A
166849SN/A    if (id == DEV0) {
167849SN/A        devState = Device_Idle_S;
168849SN/A        devID = DEV0;
169849SN/A    } else if (id == DEV1) {
170849SN/A        devState = Device_Idle_NS;
171849SN/A        devID = DEV1;
172849SN/A    } else {
173849SN/A        panic("Invalid device ID: %#x\n", id);
174849SN/A    }
175849SN/A
176849SN/A    // set the device ready bit
177893SN/A    status = STATUS_DRDY_BIT;
1781817SN/A
1791817SN/A    /* The error register must be set to 0x1 on start-up to
1801817SN/A       indicate that no diagnostic error was detected */
1811817SN/A    cmdReg.error = 0x1;
182849SN/A}
183849SN/A
184864SN/A////
185864SN/A// Utility functions
186864SN/A////
187864SN/A
188929SN/Abool
189929SN/AIdeDisk::isDEVSelect()
190929SN/A{
191929SN/A    return ctrl->isDiskSelected(this);
192929SN/A}
193929SN/A
194861SN/AAddr
195864SN/AIdeDisk::pciToDma(Addr pciAddr)
196861SN/A{
197861SN/A    if (ctrl)
1985772SN/A        return ctrl->pciToDma(pciAddr);
199861SN/A    else
200861SN/A        panic("Access to unset controller!\n");
201861SN/A}
202861SN/A
203849SN/A////
204849SN/A// Device registers read/write
205849SN/A////
206849SN/A
207849SN/Avoid
2085772SN/AIdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
209849SN/A{
2105772SN/A    if (offset == DATA_OFFSET) {
2115772SN/A        if (size == sizeof(uint16_t)) {
2125772SN/A            *(uint16_t *)data = cmdReg.data;
2135772SN/A        } else if (size == sizeof(uint32_t)) {
2145772SN/A            *(uint16_t *)data = cmdReg.data;
2155772SN/A            updateState(ACT_DATA_READ_SHORT);
2165772SN/A            *((uint16_t *)data + 1) = cmdReg.data;
2175772SN/A        } else {
2185772SN/A            panic("Data read of unsupported size %d.\n", size);
2191817SN/A        }
2205772SN/A        updateState(ACT_DATA_READ_SHORT);
2215772SN/A        return;
2225772SN/A    }
2235772SN/A    assert(size == sizeof(uint8_t));
2245772SN/A    switch (offset) {
2255772SN/A      case ERROR_OFFSET:
2265772SN/A        *data = cmdReg.error;
2271817SN/A        break;
2285772SN/A      case NSECTOR_OFFSET:
2295772SN/A        *data = cmdReg.sec_count;
2305772SN/A        break;
2315772SN/A      case SECTOR_OFFSET:
2325772SN/A        *data = cmdReg.sec_num;
2335772SN/A        break;
2345772SN/A      case LCYL_OFFSET:
2355772SN/A        *data = cmdReg.cyl_low;
2365772SN/A        break;
2375772SN/A      case HCYL_OFFSET:
2385772SN/A        *data = cmdReg.cyl_high;
2395772SN/A        break;
2405772SN/A      case DRIVE_OFFSET:
2415772SN/A        *data = cmdReg.drive;
2425772SN/A        break;
2435772SN/A      case STATUS_OFFSET:
2445772SN/A        *data = status;
2455772SN/A        updateState(ACT_STAT_READ);
2461817SN/A        break;
2471817SN/A      default:
2485772SN/A        panic("Invalid IDE command register offset: %#x\n", offset);
249849SN/A    }
2505772SN/A    DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
251849SN/A}
252849SN/A
253849SN/Avoid
2545772SN/AIdeDisk::readControl(const Addr offset, int size, uint8_t *data)
255849SN/A{
2565772SN/A    assert(size == sizeof(uint8_t));
2575772SN/A    *data = status;
2585772SN/A    if (offset != ALTSTAT_OFFSET)
2595772SN/A        panic("Invalid IDE control register offset: %#x\n", offset);
2605772SN/A    DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
2615772SN/A}
262849SN/A
2635772SN/Avoid
2645772SN/AIdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
2655772SN/A{
2665772SN/A    if (offset == DATA_OFFSET) {
2675772SN/A        if (size == sizeof(uint16_t)) {
2685772SN/A            cmdReg.data = *(const uint16_t *)data;
2695772SN/A        } else if (size == sizeof(uint32_t)) {
2705772SN/A            cmdReg.data = *(const uint16_t *)data;
2715772SN/A            updateState(ACT_DATA_WRITE_SHORT);
2725772SN/A            cmdReg.data = *((const uint16_t *)data + 1);
2735772SN/A        } else {
2745772SN/A            panic("Data write of unsupported size %d.\n", size);
2751817SN/A        }
2765772SN/A        updateState(ACT_DATA_WRITE_SHORT);
2775772SN/A        return;
2785772SN/A    }
2795772SN/A
2805772SN/A    assert(size == sizeof(uint8_t));
2815772SN/A    switch (offset) {
2825772SN/A      case FEATURES_OFFSET:
2831817SN/A        break;
2845772SN/A      case NSECTOR_OFFSET:
2855772SN/A        cmdReg.sec_count = *data;
2865772SN/A        break;
2875772SN/A      case SECTOR_OFFSET:
2885772SN/A        cmdReg.sec_num = *data;
2895772SN/A        break;
2905772SN/A      case LCYL_OFFSET:
2915772SN/A        cmdReg.cyl_low = *data;
2925772SN/A        break;
2935772SN/A      case HCYL_OFFSET:
2945772SN/A        cmdReg.cyl_high = *data;
2955772SN/A        break;
2965772SN/A      case DRIVE_OFFSET:
2975772SN/A        cmdReg.drive = *data;
2985772SN/A        updateState(ACT_SELECT_WRITE);
2995772SN/A        break;
3005772SN/A      case COMMAND_OFFSET:
3015772SN/A        cmdReg.command = *data;
3025772SN/A        updateState(ACT_CMD_WRITE);
3031817SN/A        break;
3041817SN/A      default:
3055772SN/A        panic("Invalid IDE command register offset: %#x\n", offset);
306849SN/A    }
3075772SN/A    DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
3085772SN/A            (uint32_t)*data);
3095772SN/A}
3105772SN/A
3115772SN/Avoid
3125772SN/AIdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
3135772SN/A{
3145772SN/A    if (offset != CONTROL_OFFSET)
3155772SN/A        panic("Invalid IDE control register offset: %#x\n", offset);
3165772SN/A
3175772SN/A    if (*data & CONTROL_RST_BIT) {
3185772SN/A        // force the device into the reset state
3195772SN/A        devState = Device_Srst;
3205772SN/A        updateState(ACT_SRST_SET);
3215772SN/A    } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
3225772SN/A        updateState(ACT_SRST_CLEAR);
3235772SN/A    }
3245772SN/A
3255772SN/A    nIENBit = *data & CONTROL_IEN_BIT;
326849SN/A
3272566SN/A    DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
3282566SN/A            (uint32_t)*data);
329849SN/A}
330849SN/A
331849SN/A////
332849SN/A// Perform DMA transactions
333849SN/A////
334849SN/A
335849SN/Avoid
336849SN/AIdeDisk::doDmaTransfer()
337849SN/A{
3389956SN/A    if (dmaAborted) {
3399956SN/A        DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
3409956SN/A        updateState(ACT_CMD_ERROR);
3419956SN/A        return;
3429956SN/A    }
3439956SN/A
344849SN/A    if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
345849SN/A        panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
346849SN/A              dmaState, devState);
347849SN/A
34810913SN/A    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
3497823SN/A        schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
3502565SN/A        return;
3512565SN/A    } else
3522565SN/A        ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
3532565SN/A                (uint8_t*)&curPrd.entry);
354849SN/A}
355849SN/A
356849SN/Avoid
357849SN/AIdeDisk::dmaPrdReadDone()
358849SN/A{
3599956SN/A    if (dmaAborted) {
3609956SN/A        DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
3619956SN/A        updateState(ACT_CMD_ERROR);
3629956SN/A        return;
3639956SN/A    }
3648522SN/A
3651625SN/A    DPRINTF(IdeDisk,
3661625SN/A            "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
367896SN/A            curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
368896SN/A            curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
369896SN/A            curPrd.getEOT(), curSector);
370896SN/A
371989SN/A    // the prd pointer has already been translated, so just do an increment
372989SN/A    curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
373849SN/A
374849SN/A    if (dmaRead)
3752565SN/A        doDmaDataRead();
376849SN/A    else
3772565SN/A        doDmaDataWrite();
378849SN/A}
379849SN/A
380849SN/Avoid
3812565SN/AIdeDisk::doDmaDataRead()
382849SN/A{
3831763SN/A    /** @todo we need to figure out what the delay actually will be */
384864SN/A    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
385849SN/A
3861634SN/A    DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
3871634SN/A            diskDelay, totalDiskDelay);
388849SN/A
3897823SN/A    schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
3902565SN/A}
391864SN/A
3922627SN/Avoid
3932627SN/AIdeDisk::regStats()
3942627SN/A{
39511522Sstephan.diestelhorst@arm.com    SimObject::regStats();
39611522Sstephan.diestelhorst@arm.com
3972627SN/A    using namespace Stats;
3982627SN/A    dmaReadFullPages
3992627SN/A        .name(name() + ".dma_read_full_pages")
4002627SN/A        .desc("Number of full page size DMA reads (not PRD).")
4012627SN/A        ;
4022627SN/A    dmaReadBytes
4032627SN/A        .name(name() + ".dma_read_bytes")
4042627SN/A        .desc("Number of bytes transfered via DMA reads (not PRD).")
4052627SN/A        ;
4062627SN/A    dmaReadTxs
4072627SN/A        .name(name() + ".dma_read_txs")
4082627SN/A        .desc("Number of DMA read transactions (not PRD).")
4092627SN/A        ;
4102627SN/A
4112627SN/A    dmaWriteFullPages
4122627SN/A        .name(name() + ".dma_write_full_pages")
4132627SN/A        .desc("Number of full page size DMA writes.")
4142627SN/A        ;
4152627SN/A    dmaWriteBytes
4162627SN/A        .name(name() + ".dma_write_bytes")
4172627SN/A        .desc("Number of bytes transfered via DMA writes.")
4182627SN/A        ;
4192627SN/A    dmaWriteTxs
4202627SN/A        .name(name() + ".dma_write_txs")
4212627SN/A        .desc("Number of DMA write transactions.")
4222627SN/A        ;
4232627SN/A}
424864SN/A
4252565SN/Avoid
4262565SN/AIdeDisk::doDmaRead()
4272565SN/A{
4289956SN/A    if (dmaAborted) {
4299956SN/A        DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
4309956SN/A        if (dmaReadCG)
4319956SN/A            delete dmaReadCG;
4329956SN/A        dmaReadCG = NULL;
4339956SN/A        updateState(ACT_CMD_ERROR);
4349956SN/A        return;
4359956SN/A    }
436864SN/A
4372565SN/A    if (!dmaReadCG) {
4382565SN/A        // clear out the data buffer
4392565SN/A        memset(dataBuffer, 0, MAX_DMA_SIZE);
4402565SN/A        dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
4412565SN/A                curPrd.getByteCount(), TheISA::PageBytes);
4422565SN/A
4432565SN/A    }
44410913SN/A    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
4457823SN/A        schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
4462565SN/A        return;
4472565SN/A    } else if (!dmaReadCG->done()) {
4482565SN/A        assert(dmaReadCG->complete() < MAX_DMA_SIZE);
4492565SN/A        ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
4502565SN/A                &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
4512627SN/A        dmaReadBytes += dmaReadCG->size();
4522627SN/A        dmaReadTxs++;
4532627SN/A        if (dmaReadCG->size() == TheISA::PageBytes)
4542627SN/A            dmaReadFullPages++;
4552565SN/A        dmaReadCG->next();
456849SN/A    } else {
4572565SN/A        assert(dmaReadCG->done());
4582565SN/A        delete dmaReadCG;
4592565SN/A        dmaReadCG = NULL;
4602565SN/A        dmaReadDone();
461849SN/A    }
462849SN/A}
463849SN/A
464849SN/Avoid
465849SN/AIdeDisk::dmaReadDone()
466849SN/A{
4672565SN/A    uint32_t bytesWritten = 0;
468861SN/A
469861SN/A    // write the data to the disk image
4702565SN/A    for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
471864SN/A         bytesWritten += SectorSize) {
472861SN/A
4732565SN/A        cmdBytesLeft -= SectorSize;
474861SN/A        writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
475864SN/A    }
476861SN/A
477849SN/A    // check for the EOT
478920SN/A    if (curPrd.getEOT()) {
479849SN/A        assert(cmdBytesLeft == 0);
480849SN/A        dmaState = Dma_Idle;
481849SN/A        updateState(ACT_DMA_DONE);
482849SN/A    } else {
483849SN/A        doDmaTransfer();
484849SN/A    }
485849SN/A}
486849SN/A
487849SN/Avoid
4882565SN/AIdeDisk::doDmaDataWrite()
489849SN/A{
4901763SN/A    /** @todo we need to figure out what the delay actually will be */
491864SN/A    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
4922565SN/A    uint32_t bytesRead = 0;
493849SN/A
4941634SN/A    DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
4951634SN/A            diskDelay, totalDiskDelay);
4961634SN/A
4972565SN/A    memset(dataBuffer, 0, MAX_DMA_SIZE);
4982565SN/A    assert(cmdBytesLeft <= MAX_DMA_SIZE);
4992565SN/A    while (bytesRead < curPrd.getByteCount()) {
5002565SN/A        readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
5012565SN/A        bytesRead += SectorSize;
5022565SN/A        cmdBytesLeft -= SectorSize;
5032565SN/A    }
5048522SN/A    DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
5058522SN/A            bytesRead, cmdBytesLeft);
506849SN/A
5077823SN/A    schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
5082565SN/A}
509864SN/A
5102565SN/Avoid
5112565SN/AIdeDisk::doDmaWrite()
5122565SN/A{
5139956SN/A    if (dmaAborted) {
5149956SN/A        DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
5159956SN/A        if (dmaWriteCG)
5169956SN/A            delete dmaWriteCG;
5179956SN/A        dmaWriteCG = NULL;
5189956SN/A        updateState(ACT_CMD_ERROR);
5199956SN/A        return;
5209956SN/A    }
5212565SN/A    if (!dmaWriteCG) {
5222565SN/A        // clear out the data buffer
5232565SN/A        dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
5242565SN/A                curPrd.getByteCount(), TheISA::PageBytes);
5252565SN/A    }
52610913SN/A    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
5277823SN/A        schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
5288522SN/A        DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
5292565SN/A        return;
5302565SN/A    } else if (!dmaWriteCG->done()) {
5312565SN/A        assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
5322565SN/A        ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
5332565SN/A                &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
5348522SN/A        DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
5358522SN/A                curPrd.getByteCount(), curPrd.getEOT());
5362627SN/A        dmaWriteBytes += dmaWriteCG->size();
5372627SN/A        dmaWriteTxs++;
5382627SN/A        if (dmaWriteCG->size() == TheISA::PageBytes)
5392627SN/A            dmaWriteFullPages++;
5402565SN/A        dmaWriteCG->next();
541849SN/A    } else {
5428522SN/A        DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
5438522SN/A                curPrd.getByteCount(), curPrd.getEOT());
5442565SN/A        assert(dmaWriteCG->done());
5452565SN/A        delete dmaWriteCG;
5462565SN/A        dmaWriteCG = NULL;
5472565SN/A        dmaWriteDone();
548849SN/A    }
549849SN/A}
550849SN/A
551849SN/Avoid
552849SN/AIdeDisk::dmaWriteDone()
553849SN/A{
5548522SN/A    DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
5558522SN/A                curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft);
556849SN/A    // check for the EOT
557849SN/A    if (curPrd.getEOT()) {
558849SN/A        assert(cmdBytesLeft == 0);
559849SN/A        dmaState = Dma_Idle;
560849SN/A        updateState(ACT_DMA_DONE);
561849SN/A    } else {
562849SN/A        doDmaTransfer();
563849SN/A    }
564849SN/A}
565849SN/A
566849SN/A////
567849SN/A// Disk utility routines
568849SN/A///
569849SN/A
570849SN/Avoid
571849SN/AIdeDisk::readDisk(uint32_t sector, uint8_t *data)
572849SN/A{
573849SN/A    uint32_t bytesRead = image->read(data, sector);
574849SN/A
575849SN/A    if (bytesRead != SectorSize)
576849SN/A        panic("Can't read from %s. Only %d of %d read. errno=%d\n",
577849SN/A              name(), bytesRead, SectorSize, errno);
578849SN/A}
579849SN/A
580849SN/Avoid
581849SN/AIdeDisk::writeDisk(uint32_t sector, uint8_t *data)
582849SN/A{
583849SN/A    uint32_t bytesWritten = image->write(data, sector);
584849SN/A
585849SN/A    if (bytesWritten != SectorSize)
586849SN/A        panic("Can't write to %s. Only %d of %d written. errno=%d\n",
587849SN/A              name(), bytesWritten, SectorSize, errno);
588849SN/A}
589849SN/A
590849SN/A////
591849SN/A// Setup and handle commands
592849SN/A////
593849SN/A
594849SN/Avoid
595849SN/AIdeDisk::startDma(const uint32_t &prdTableBase)
596849SN/A{
597849SN/A    if (dmaState != Dma_Start)
598849SN/A        panic("Inconsistent DMA state, should be in Dma_Start!\n");
599849SN/A
600849SN/A    if (devState != Transfer_Data_Dma)
601849SN/A        panic("Inconsistent device state for DMA start!\n");
602849SN/A
603896SN/A    // PRD base address is given by bits 31:2
604896SN/A    curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
605849SN/A
606849SN/A    dmaState = Dma_Transfer;
607849SN/A
608849SN/A    // schedule dma transfer (doDmaTransfer)
6097823SN/A    schedule(dmaTransferEvent, curTick() + 1);
610849SN/A}
611849SN/A
612849SN/Avoid
613849SN/AIdeDisk::abortDma()
614849SN/A{
615849SN/A    if (dmaState == Dma_Idle)
6161625SN/A        panic("Inconsistent DMA state, should be Start or Transfer!");
617849SN/A
618849SN/A    if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
6191625SN/A        panic("Inconsistent device state, should be Transfer or Prepare!\n");
620849SN/A
621849SN/A    updateState(ACT_CMD_ERROR);
622849SN/A}
623849SN/A
624849SN/Avoid
625849SN/AIdeDisk::startCommand()
626849SN/A{
627849SN/A    DevAction_t action = ACT_NONE;
628849SN/A    uint32_t size = 0;
629849SN/A    dmaRead = false;
630849SN/A
631849SN/A    // Decode commands
632849SN/A    switch (cmdReg.command) {
633849SN/A        // Supported non-data commands
6341722SN/A      case WDSF_READ_NATIVE_MAX:
6359533SN/A        size = (uint32_t)image->size() - 1;
636849SN/A        cmdReg.sec_num = (size & 0xff);
637849SN/A        cmdReg.cyl_low = ((size & 0xff00) >> 8);
638849SN/A        cmdReg.cyl_high = ((size & 0xff0000) >> 16);
639849SN/A        cmdReg.head = ((size & 0xf000000) >> 24);
640849SN/A
641849SN/A        devState = Command_Execution;
642849SN/A        action = ACT_CMD_COMPLETE;
643849SN/A        break;
644849SN/A
6451722SN/A      case WDCC_RECAL:
6461722SN/A      case WDCC_IDP:
6471722SN/A      case WDCC_STANDBY_IMMED:
6481722SN/A      case WDCC_FLUSHCACHE:
6491722SN/A      case WDSF_VERIFY:
6501722SN/A      case WDSF_SEEK:
6511722SN/A      case SET_FEATURES:
6521722SN/A      case WDCC_SETMULTI:
65310587SN/A      case WDCC_IDLE:
654849SN/A        devState = Command_Execution;
655849SN/A        action = ACT_CMD_COMPLETE;
656849SN/A        break;
657849SN/A
658849SN/A        // Supported PIO data-in commands
6591722SN/A      case WDCC_IDENTIFY:
6601722SN/A        cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
661849SN/A        devState = Prepare_Data_In;
662849SN/A        action = ACT_DATA_READY;
663849SN/A        break;
664849SN/A
6651722SN/A      case WDCC_READMULTI:
6661722SN/A      case WDCC_READ:
667849SN/A        if (!(cmdReg.drive & DRIVE_LBA_BIT))
668849SN/A            panic("Attempt to perform CHS access, only supports LBA\n");
669849SN/A
670849SN/A        if (cmdReg.sec_count == 0)
671893SN/A            cmdBytes = cmdBytesLeft = (256 * SectorSize);
672849SN/A        else
673893SN/A            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
674849SN/A
675849SN/A        curSector = getLBABase();
676849SN/A
677877SN/A        /** @todo make this a scheduled event to simulate disk delay */
678849SN/A        devState = Prepare_Data_In;
679849SN/A        action = ACT_DATA_READY;
680849SN/A        break;
681849SN/A
682849SN/A        // Supported PIO data-out commands
6831722SN/A      case WDCC_WRITEMULTI:
6841722SN/A      case WDCC_WRITE:
685849SN/A        if (!(cmdReg.drive & DRIVE_LBA_BIT))
686849SN/A            panic("Attempt to perform CHS access, only supports LBA\n");
687849SN/A
688849SN/A        if (cmdReg.sec_count == 0)
689893SN/A            cmdBytes = cmdBytesLeft = (256 * SectorSize);
690849SN/A        else
691893SN/A            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
6928522SN/A        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
693849SN/A        curSector = getLBABase();
694849SN/A
695849SN/A        devState = Prepare_Data_Out;
696849SN/A        action = ACT_DATA_READY;
697849SN/A        break;
698849SN/A
699849SN/A        // Supported DMA commands
7001722SN/A      case WDCC_WRITEDMA:
701849SN/A        dmaRead = true;  // a write to the disk is a DMA read from memory
7021722SN/A      case WDCC_READDMA:
703849SN/A        if (!(cmdReg.drive & DRIVE_LBA_BIT))
704849SN/A            panic("Attempt to perform CHS access, only supports LBA\n");
705849SN/A
706849SN/A        if (cmdReg.sec_count == 0)
707893SN/A            cmdBytes = cmdBytesLeft = (256 * SectorSize);
708849SN/A        else
709893SN/A            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
7108522SN/A        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
711849SN/A
712849SN/A        curSector = getLBABase();
713849SN/A
714849SN/A        devState = Prepare_Data_Dma;
715849SN/A        action = ACT_DMA_READY;
716849SN/A        break;
717849SN/A
718849SN/A      default:
719849SN/A        panic("Unsupported ATA command: %#x\n", cmdReg.command);
720849SN/A    }
721849SN/A
722849SN/A    if (action != ACT_NONE) {
723849SN/A        // set the BSY bit
724893SN/A        status |= STATUS_BSY_BIT;
725849SN/A        // clear the DRQ bit
726893SN/A        status &= ~STATUS_DRQ_BIT;
727893SN/A        // clear the DF bit
728893SN/A        status &= ~STATUS_DF_BIT;
729849SN/A
730849SN/A        updateState(action);
731849SN/A    }
732849SN/A}
733849SN/A
734849SN/A////
735849SN/A// Handle setting and clearing interrupts
736849SN/A////
737849SN/A
738849SN/Avoid
739849SN/AIdeDisk::intrPost()
740849SN/A{
7411625SN/A    DPRINTF(IdeDisk, "Posting Interrupt\n");
742849SN/A    if (intrPending)
743849SN/A        panic("Attempt to post an interrupt with one pending\n");
744849SN/A
745849SN/A    intrPending = true;
746849SN/A
747849SN/A    // talk to controller to set interrupt
7481817SN/A    if (ctrl) {
749849SN/A        ctrl->intrPost();
7501817SN/A    }
751849SN/A}
752849SN/A
753849SN/Avoid
754849SN/AIdeDisk::intrClear()
755849SN/A{
7561625SN/A    DPRINTF(IdeDisk, "Clearing Interrupt\n");
757849SN/A    if (!intrPending)
758849SN/A        panic("Attempt to clear a non-pending interrupt\n");
759849SN/A
760849SN/A    intrPending = false;
761849SN/A
762849SN/A    // talk to controller to clear interrupt
763849SN/A    if (ctrl)
764849SN/A        ctrl->intrClear();
765849SN/A}
766849SN/A
767849SN/A////
768849SN/A// Manage the device internal state machine
769849SN/A////
770849SN/A
771849SN/Avoid
772849SN/AIdeDisk::updateState(DevAction_t action)
773849SN/A{
774849SN/A    switch (devState) {
775893SN/A      case Device_Srst:
776893SN/A        if (action == ACT_SRST_SET) {
777893SN/A            // set the BSY bit
778893SN/A            status |= STATUS_BSY_BIT;
779893SN/A        } else if (action == ACT_SRST_CLEAR) {
780893SN/A            // clear the BSY bit
781893SN/A            status &= ~STATUS_BSY_BIT;
782893SN/A
783893SN/A            // reset the device state
784893SN/A            reset(devID);
785893SN/A        }
786893SN/A        break;
787893SN/A
788849SN/A      case Device_Idle_S:
789893SN/A        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
790849SN/A            devState = Device_Idle_NS;
791893SN/A        } else if (action == ACT_CMD_WRITE) {
792849SN/A            startCommand();
793893SN/A        }
794849SN/A
795849SN/A        break;
796849SN/A
797849SN/A      case Device_Idle_SI:
798893SN/A        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
799849SN/A            devState = Device_Idle_NS;
800849SN/A            intrClear();
801849SN/A        } else if (action == ACT_STAT_READ || isIENSet()) {
802849SN/A            devState = Device_Idle_S;
803849SN/A            intrClear();
804849SN/A        } else if (action == ACT_CMD_WRITE) {
805849SN/A            intrClear();
806849SN/A            startCommand();
807849SN/A        }
808849SN/A
809849SN/A        break;
810849SN/A
811849SN/A      case Device_Idle_NS:
812893SN/A        if (action == ACT_SELECT_WRITE && isDEVSelect()) {
813849SN/A            if (!isIENSet() && intrPending) {
814849SN/A                devState = Device_Idle_SI;
815849SN/A                intrPost();
816849SN/A            }
817849SN/A            if (isIENSet() || !intrPending) {
818849SN/A                devState = Device_Idle_S;
819849SN/A            }
820849SN/A        }
821849SN/A        break;
822849SN/A
823849SN/A      case Command_Execution:
824849SN/A        if (action == ACT_CMD_COMPLETE) {
825849SN/A            // clear the BSY bit
826849SN/A            setComplete();
827849SN/A
828849SN/A            if (!isIENSet()) {
829849SN/A                devState = Device_Idle_SI;
830849SN/A                intrPost();
831849SN/A            } else {
832849SN/A                devState = Device_Idle_S;
833849SN/A            }
834849SN/A        }
835849SN/A        break;
836849SN/A
837849SN/A      case Prepare_Data_In:
838849SN/A        if (action == ACT_CMD_ERROR) {
839849SN/A            // clear the BSY bit
840849SN/A            setComplete();
841849SN/A
842849SN/A            if (!isIENSet()) {
843849SN/A                devState = Device_Idle_SI;
844849SN/A                intrPost();
845849SN/A            } else {
846849SN/A                devState = Device_Idle_S;
847849SN/A            }
848849SN/A        } else if (action == ACT_DATA_READY) {
849849SN/A            // clear the BSY bit
850893SN/A            status &= ~STATUS_BSY_BIT;
851849SN/A            // set the DRQ bit
852893SN/A            status |= STATUS_DRQ_BIT;
853849SN/A
854877SN/A            // copy the data into the data buffer
8551722SN/A            if (cmdReg.command == WDCC_IDENTIFY) {
856877SN/A                // Reset the drqBytes for this block
8571722SN/A                drqBytesLeft = sizeof(struct ataparams);
858877SN/A
859877SN/A                memcpy((void *)dataBuffer, (void *)&driveID,
8601722SN/A                       sizeof(struct ataparams));
861877SN/A            } else {
862877SN/A                // Reset the drqBytes for this block
863877SN/A                drqBytesLeft = SectorSize;
864877SN/A
865877SN/A                readDisk(curSector++, dataBuffer);
866877SN/A            }
867877SN/A
868849SN/A            // put the first two bytes into the data register
8691817SN/A            memcpy((void *)&cmdReg.data, (void *)dataBuffer,
870857SN/A                   sizeof(uint16_t));
871857SN/A
872849SN/A            if (!isIENSet()) {
873849SN/A                devState = Data_Ready_INTRQ_In;
874849SN/A                intrPost();
875849SN/A            } else {
876849SN/A                devState = Transfer_Data_In;
877849SN/A            }
878849SN/A        }
879849SN/A        break;
880849SN/A
881849SN/A      case Data_Ready_INTRQ_In:
882849SN/A        if (action == ACT_STAT_READ) {
883849SN/A            devState = Transfer_Data_In;
884849SN/A            intrClear();
885849SN/A        }
886849SN/A        break;
887849SN/A
888849SN/A      case Transfer_Data_In:
889849SN/A        if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
890849SN/A            if (action == ACT_DATA_READ_BYTE) {
891849SN/A                panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
892849SN/A            } else {
893849SN/A                drqBytesLeft -= 2;
894849SN/A                cmdBytesLeft -= 2;
895849SN/A
896849SN/A                // copy next short into data registers
897877SN/A                if (drqBytesLeft)
8981817SN/A                    memcpy((void *)&cmdReg.data,
899877SN/A                           (void *)&dataBuffer[SectorSize - drqBytesLeft],
900877SN/A                           sizeof(uint16_t));
901849SN/A            }
902849SN/A
903849SN/A            if (drqBytesLeft == 0) {
904849SN/A                if (cmdBytesLeft == 0) {
905849SN/A                    // Clear the BSY bit
906849SN/A                    setComplete();
907849SN/A                    devState = Device_Idle_S;
908849SN/A                } else {
909849SN/A                    devState = Prepare_Data_In;
910877SN/A                    // set the BSY_BIT
911893SN/A                    status |= STATUS_BSY_BIT;
912877SN/A                    // clear the DRQ_BIT
913893SN/A                    status &= ~STATUS_DRQ_BIT;
914877SN/A
915877SN/A                    /** @todo change this to a scheduled event to simulate
916877SN/A                        disk delay */
917877SN/A                    updateState(ACT_DATA_READY);
918849SN/A                }
919849SN/A            }
920849SN/A        }
921849SN/A        break;
922849SN/A
923849SN/A      case Prepare_Data_Out:
924849SN/A        if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
925849SN/A            // clear the BSY bit
926849SN/A            setComplete();
927849SN/A
928849SN/A            if (!isIENSet()) {
929849SN/A                devState = Device_Idle_SI;
930849SN/A                intrPost();
931849SN/A            } else {
932849SN/A                devState = Device_Idle_S;
933849SN/A            }
934893SN/A        } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
935849SN/A            // clear the BSY bit
936893SN/A            status &= ~STATUS_BSY_BIT;
937849SN/A            // set the DRQ bit
938893SN/A            status |= STATUS_DRQ_BIT;
939849SN/A
940849SN/A            // clear the data buffer to get it ready for writes
941849SN/A            memset(dataBuffer, 0, MAX_DMA_SIZE);
942849SN/A
943893SN/A            // reset the drqBytes for this block
944893SN/A            drqBytesLeft = SectorSize;
945893SN/A
946893SN/A            if (cmdBytesLeft == cmdBytes || isIENSet()) {
947893SN/A                devState = Transfer_Data_Out;
948893SN/A            } else {
949849SN/A                devState = Data_Ready_INTRQ_Out;
950849SN/A                intrPost();
951849SN/A            }
952849SN/A        }
953849SN/A        break;
954849SN/A
955849SN/A      case Data_Ready_INTRQ_Out:
956849SN/A        if (action == ACT_STAT_READ) {
957849SN/A            devState = Transfer_Data_Out;
958849SN/A            intrClear();
959849SN/A        }
960849SN/A        break;
961849SN/A
962849SN/A      case Transfer_Data_Out:
963857SN/A        if (action == ACT_DATA_WRITE_BYTE ||
964857SN/A            action == ACT_DATA_WRITE_SHORT) {
965857SN/A
966849SN/A            if (action == ACT_DATA_READ_BYTE) {
967849SN/A                panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
968849SN/A            } else {
969849SN/A                // copy the latest short into the data buffer
970849SN/A                memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
9711817SN/A                       (void *)&cmdReg.data,
972849SN/A                       sizeof(uint16_t));
973849SN/A
974849SN/A                drqBytesLeft -= 2;
975849SN/A                cmdBytesLeft -= 2;
976849SN/A            }
977849SN/A
978849SN/A            if (drqBytesLeft == 0) {
979849SN/A                // copy the block to the disk
980849SN/A                writeDisk(curSector++, dataBuffer);
981849SN/A
982849SN/A                // set the BSY bit
983893SN/A                status |= STATUS_BSY_BIT;
984893SN/A                // set the seek bit
985893SN/A                status |= STATUS_SEEK_BIT;
986849SN/A                // clear the DRQ bit
987893SN/A                status &= ~STATUS_DRQ_BIT;
988849SN/A
989849SN/A                devState = Prepare_Data_Out;
990878SN/A
991878SN/A                /** @todo change this to a scheduled event to simulate
992878SN/A                    disk delay */
993878SN/A                updateState(ACT_DATA_READY);
994849SN/A            }
995849SN/A        }
996849SN/A        break;
997849SN/A
998849SN/A      case Prepare_Data_Dma:
999849SN/A        if (action == ACT_CMD_ERROR) {
1000849SN/A            // clear the BSY bit
1001849SN/A            setComplete();
1002849SN/A
1003849SN/A            if (!isIENSet()) {
1004849SN/A                devState = Device_Idle_SI;
1005849SN/A                intrPost();
1006849SN/A            } else {
1007849SN/A                devState = Device_Idle_S;
1008849SN/A            }
1009849SN/A        } else if (action == ACT_DMA_READY) {
1010849SN/A            // clear the BSY bit
1011893SN/A            status &= ~STATUS_BSY_BIT;
1012849SN/A            // set the DRQ bit
1013893SN/A            status |= STATUS_DRQ_BIT;
1014849SN/A
1015849SN/A            devState = Transfer_Data_Dma;
1016849SN/A
1017849SN/A            if (dmaState != Dma_Idle)
1018849SN/A                panic("Inconsistent DMA state, should be Dma_Idle\n");
1019849SN/A
1020849SN/A            dmaState = Dma_Start;
1021849SN/A            // wait for the write to the DMA start bit
1022849SN/A        }
1023849SN/A        break;
1024849SN/A
1025849SN/A      case Transfer_Data_Dma:
10269956SN/A        if (action == ACT_CMD_ERROR) {
10279956SN/A            dmaAborted = true;
10289956SN/A            devState = Device_Dma_Abort;
10299956SN/A        } else if (action == ACT_DMA_DONE) {
1030849SN/A            // clear the BSY bit
1031849SN/A            setComplete();
1032849SN/A            // set the seek bit
1033893SN/A            status |= STATUS_SEEK_BIT;
1034849SN/A            // clear the controller state for DMA transfer
1035849SN/A            ctrl->setDmaComplete(this);
1036849SN/A
1037849SN/A            if (!isIENSet()) {
1038849SN/A                devState = Device_Idle_SI;
1039849SN/A                intrPost();
1040849SN/A            } else {
1041849SN/A                devState = Device_Idle_S;
1042849SN/A            }
1043849SN/A        }
1044849SN/A        break;
1045849SN/A
10469956SN/A      case Device_Dma_Abort:
10479956SN/A        if (action == ACT_CMD_ERROR) {
10489956SN/A            setComplete();
10499956SN/A            status |= STATUS_SEEK_BIT;
10509956SN/A            ctrl->setDmaComplete(this);
10519956SN/A            dmaAborted = false;
10529956SN/A            dmaState = Dma_Idle;
10539956SN/A
10549956SN/A            if (!isIENSet()) {
10559956SN/A                devState = Device_Idle_SI;
10569956SN/A                intrPost();
10579956SN/A            } else {
10589956SN/A                devState = Device_Idle_S;
10599956SN/A            }
10609956SN/A        } else {
10619956SN/A            DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
10629956SN/A        }
10639956SN/A        break;
10649956SN/A
1065849SN/A      default:
1066849SN/A        panic("Unknown IDE device state: %#x\n", devState);
1067849SN/A    }
1068848SN/A}
1069848SN/A
1070848SN/Avoid
107110905SN/AIdeDisk::serialize(CheckpointOut &cp) const
1072848SN/A{
1073864SN/A    // Check all outstanding events to see if they are scheduled
1074864SN/A    // these are all mutually exclusive
1075864SN/A    Tick reschedule = 0;
1076864SN/A    Events_t event = None;
1077864SN/A
1078920SN/A    int eventCount = 0;
1079920SN/A
1080864SN/A    if (dmaTransferEvent.scheduled()) {
1081864SN/A        reschedule = dmaTransferEvent.when();
1082864SN/A        event = Transfer;
1083920SN/A        eventCount++;
1084920SN/A    }
1085920SN/A    if (dmaReadWaitEvent.scheduled()) {
1086864SN/A        reschedule = dmaReadWaitEvent.when();
1087864SN/A        event = ReadWait;
1088920SN/A        eventCount++;
1089920SN/A    }
1090920SN/A    if (dmaWriteWaitEvent.scheduled()) {
1091864SN/A        reschedule = dmaWriteWaitEvent.when();
1092864SN/A        event = WriteWait;
1093920SN/A        eventCount++;
1094920SN/A    }
1095920SN/A    if (dmaPrdReadEvent.scheduled()) {
1096864SN/A        reschedule = dmaPrdReadEvent.when();
1097864SN/A        event = PrdRead;
1098920SN/A        eventCount++;
1099920SN/A    }
1100920SN/A    if (dmaReadEvent.scheduled()) {
1101864SN/A        reschedule = dmaReadEvent.when();
1102864SN/A        event = DmaRead;
1103920SN/A        eventCount++;
1104920SN/A    }
1105920SN/A    if (dmaWriteEvent.scheduled()) {
1106864SN/A        reschedule = dmaWriteEvent.when();
1107864SN/A        event = DmaWrite;
1108920SN/A        eventCount++;
1109864SN/A    }
1110864SN/A
1111920SN/A    assert(eventCount <= 1);
1112920SN/A
1113864SN/A    SERIALIZE_SCALAR(reschedule);
1114864SN/A    SERIALIZE_ENUM(event);
1115864SN/A
1116864SN/A    // Serialize device registers
11171817SN/A    SERIALIZE_SCALAR(cmdReg.data);
1118864SN/A    SERIALIZE_SCALAR(cmdReg.sec_count);
1119864SN/A    SERIALIZE_SCALAR(cmdReg.sec_num);
1120864SN/A    SERIALIZE_SCALAR(cmdReg.cyl_low);
1121864SN/A    SERIALIZE_SCALAR(cmdReg.cyl_high);
1122864SN/A    SERIALIZE_SCALAR(cmdReg.drive);
1123920SN/A    SERIALIZE_SCALAR(cmdReg.command);
1124893SN/A    SERIALIZE_SCALAR(status);
1125864SN/A    SERIALIZE_SCALAR(nIENBit);
1126864SN/A    SERIALIZE_SCALAR(devID);
1127864SN/A
1128864SN/A    // Serialize the PRD related information
1129864SN/A    SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1130864SN/A    SERIALIZE_SCALAR(curPrd.entry.byteCount);
1131864SN/A    SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1132864SN/A    SERIALIZE_SCALAR(curPrdAddr);
1133864SN/A
11342565SN/A    /** @todo need to serialized chunk generator stuff!! */
1135864SN/A    // Serialize current transfer related information
1136864SN/A    SERIALIZE_SCALAR(cmdBytesLeft);
1137893SN/A    SERIALIZE_SCALAR(cmdBytes);
1138864SN/A    SERIALIZE_SCALAR(drqBytesLeft);
1139864SN/A    SERIALIZE_SCALAR(curSector);
1140864SN/A    SERIALIZE_SCALAR(dmaRead);
1141864SN/A    SERIALIZE_SCALAR(intrPending);
11429956SN/A    SERIALIZE_SCALAR(dmaAborted);
1143864SN/A    SERIALIZE_ENUM(devState);
1144864SN/A    SERIALIZE_ENUM(dmaState);
1145864SN/A    SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1146848SN/A}
1147848SN/A
1148848SN/Avoid
114910905SN/AIdeDisk::unserialize(CheckpointIn &cp)
1150848SN/A{
1151864SN/A    // Reschedule events that were outstanding
1152864SN/A    // these are all mutually exclusive
1153864SN/A    Tick reschedule = 0;
1154864SN/A    Events_t event = None;
1155864SN/A
1156864SN/A    UNSERIALIZE_SCALAR(reschedule);
1157864SN/A    UNSERIALIZE_ENUM(event);
1158864SN/A
1159864SN/A    switch (event) {
1160864SN/A      case None : break;
11615606SN/A      case Transfer : schedule(dmaTransferEvent, reschedule); break;
11625606SN/A      case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
11635606SN/A      case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
11645606SN/A      case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
11655606SN/A      case DmaRead : schedule(dmaReadEvent, reschedule); break;
11665606SN/A      case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1167864SN/A    }
1168864SN/A
1169864SN/A    // Unserialize device registers
11701817SN/A    UNSERIALIZE_SCALAR(cmdReg.data);
1171864SN/A    UNSERIALIZE_SCALAR(cmdReg.sec_count);
1172864SN/A    UNSERIALIZE_SCALAR(cmdReg.sec_num);
1173864SN/A    UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1174864SN/A    UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1175864SN/A    UNSERIALIZE_SCALAR(cmdReg.drive);
1176920SN/A    UNSERIALIZE_SCALAR(cmdReg.command);
1177893SN/A    UNSERIALIZE_SCALAR(status);
1178864SN/A    UNSERIALIZE_SCALAR(nIENBit);
1179864SN/A    UNSERIALIZE_SCALAR(devID);
1180864SN/A
1181864SN/A    // Unserialize the PRD related information
1182864SN/A    UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1183864SN/A    UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1184864SN/A    UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1185864SN/A    UNSERIALIZE_SCALAR(curPrdAddr);
1186864SN/A
11872565SN/A    /** @todo need to serialized chunk generator stuff!! */
1188864SN/A    // Unserialize current transfer related information
1189893SN/A    UNSERIALIZE_SCALAR(cmdBytes);
1190864SN/A    UNSERIALIZE_SCALAR(cmdBytesLeft);
1191864SN/A    UNSERIALIZE_SCALAR(drqBytesLeft);
1192864SN/A    UNSERIALIZE_SCALAR(curSector);
1193864SN/A    UNSERIALIZE_SCALAR(dmaRead);
1194864SN/A    UNSERIALIZE_SCALAR(intrPending);
11959956SN/A    UNSERIALIZE_SCALAR(dmaAborted);
1196864SN/A    UNSERIALIZE_ENUM(devState);
1197864SN/A    UNSERIALIZE_ENUM(dmaState);
1198864SN/A    UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1199848SN/A}
1200848SN/A
12014762SN/AIdeDisk *
12024762SN/AIdeDiskParams::create()
1203848SN/A{
12045034SN/A    return new IdeDisk(this);
1205848SN/A}
1206