ide_disk.cc revision 11264
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{
3952627SN/A    using namespace Stats;
3962627SN/A    dmaReadFullPages
3972627SN/A        .name(name() + ".dma_read_full_pages")
3982627SN/A        .desc("Number of full page size DMA reads (not PRD).")
3992627SN/A        ;
4002627SN/A    dmaReadBytes
4012627SN/A        .name(name() + ".dma_read_bytes")
4022627SN/A        .desc("Number of bytes transfered via DMA reads (not PRD).")
4032627SN/A        ;
4042627SN/A    dmaReadTxs
4052627SN/A        .name(name() + ".dma_read_txs")
4062627SN/A        .desc("Number of DMA read transactions (not PRD).")
4072627SN/A        ;
4082627SN/A
4092627SN/A    dmaWriteFullPages
4102627SN/A        .name(name() + ".dma_write_full_pages")
4112627SN/A        .desc("Number of full page size DMA writes.")
4122627SN/A        ;
4132627SN/A    dmaWriteBytes
4142627SN/A        .name(name() + ".dma_write_bytes")
4152627SN/A        .desc("Number of bytes transfered via DMA writes.")
4162627SN/A        ;
4172627SN/A    dmaWriteTxs
4182627SN/A        .name(name() + ".dma_write_txs")
4192627SN/A        .desc("Number of DMA write transactions.")
4202627SN/A        ;
4212627SN/A}
422864SN/A
4232565SN/Avoid
4242565SN/AIdeDisk::doDmaRead()
4252565SN/A{
4269956SN/A    if (dmaAborted) {
4279956SN/A        DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
4289956SN/A        if (dmaReadCG)
4299956SN/A            delete dmaReadCG;
4309956SN/A        dmaReadCG = NULL;
4319956SN/A        updateState(ACT_CMD_ERROR);
4329956SN/A        return;
4339956SN/A    }
434864SN/A
4352565SN/A    if (!dmaReadCG) {
4362565SN/A        // clear out the data buffer
4372565SN/A        memset(dataBuffer, 0, MAX_DMA_SIZE);
4382565SN/A        dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
4392565SN/A                curPrd.getByteCount(), TheISA::PageBytes);
4402565SN/A
4412565SN/A    }
44210913SN/A    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
4437823SN/A        schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
4442565SN/A        return;
4452565SN/A    } else if (!dmaReadCG->done()) {
4462565SN/A        assert(dmaReadCG->complete() < MAX_DMA_SIZE);
4472565SN/A        ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
4482565SN/A                &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
4492627SN/A        dmaReadBytes += dmaReadCG->size();
4502627SN/A        dmaReadTxs++;
4512627SN/A        if (dmaReadCG->size() == TheISA::PageBytes)
4522627SN/A            dmaReadFullPages++;
4532565SN/A        dmaReadCG->next();
454849SN/A    } else {
4552565SN/A        assert(dmaReadCG->done());
4562565SN/A        delete dmaReadCG;
4572565SN/A        dmaReadCG = NULL;
4582565SN/A        dmaReadDone();
459849SN/A    }
460849SN/A}
461849SN/A
462849SN/Avoid
463849SN/AIdeDisk::dmaReadDone()
464849SN/A{
4652565SN/A    uint32_t bytesWritten = 0;
466861SN/A
467861SN/A    // write the data to the disk image
4682565SN/A    for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
469864SN/A         bytesWritten += SectorSize) {
470861SN/A
4712565SN/A        cmdBytesLeft -= SectorSize;
472861SN/A        writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
473864SN/A    }
474861SN/A
475849SN/A    // check for the EOT
476920SN/A    if (curPrd.getEOT()) {
477849SN/A        assert(cmdBytesLeft == 0);
478849SN/A        dmaState = Dma_Idle;
479849SN/A        updateState(ACT_DMA_DONE);
480849SN/A    } else {
481849SN/A        doDmaTransfer();
482849SN/A    }
483849SN/A}
484849SN/A
485849SN/Avoid
4862565SN/AIdeDisk::doDmaDataWrite()
487849SN/A{
4881763SN/A    /** @todo we need to figure out what the delay actually will be */
489864SN/A    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
4902565SN/A    uint32_t bytesRead = 0;
491849SN/A
4921634SN/A    DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
4931634SN/A            diskDelay, totalDiskDelay);
4941634SN/A
4952565SN/A    memset(dataBuffer, 0, MAX_DMA_SIZE);
4962565SN/A    assert(cmdBytesLeft <= MAX_DMA_SIZE);
4972565SN/A    while (bytesRead < curPrd.getByteCount()) {
4982565SN/A        readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
4992565SN/A        bytesRead += SectorSize;
5002565SN/A        cmdBytesLeft -= SectorSize;
5012565SN/A    }
5028522SN/A    DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
5038522SN/A            bytesRead, cmdBytesLeft);
504849SN/A
5057823SN/A    schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
5062565SN/A}
507864SN/A
5082565SN/Avoid
5092565SN/AIdeDisk::doDmaWrite()
5102565SN/A{
5119956SN/A    if (dmaAborted) {
5129956SN/A        DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
5139956SN/A        if (dmaWriteCG)
5149956SN/A            delete dmaWriteCG;
5159956SN/A        dmaWriteCG = NULL;
5169956SN/A        updateState(ACT_CMD_ERROR);
5179956SN/A        return;
5189956SN/A    }
5192565SN/A    if (!dmaWriteCG) {
5202565SN/A        // clear out the data buffer
5212565SN/A        dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
5222565SN/A                curPrd.getByteCount(), TheISA::PageBytes);
5232565SN/A    }
52410913SN/A    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
5257823SN/A        schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
5268522SN/A        DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
5272565SN/A        return;
5282565SN/A    } else if (!dmaWriteCG->done()) {
5292565SN/A        assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
5302565SN/A        ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
5312565SN/A                &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
5328522SN/A        DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
5338522SN/A                curPrd.getByteCount(), curPrd.getEOT());
5342627SN/A        dmaWriteBytes += dmaWriteCG->size();
5352627SN/A        dmaWriteTxs++;
5362627SN/A        if (dmaWriteCG->size() == TheISA::PageBytes)
5372627SN/A            dmaWriteFullPages++;
5382565SN/A        dmaWriteCG->next();
539849SN/A    } else {
5408522SN/A        DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
5418522SN/A                curPrd.getByteCount(), curPrd.getEOT());
5422565SN/A        assert(dmaWriteCG->done());
5432565SN/A        delete dmaWriteCG;
5442565SN/A        dmaWriteCG = NULL;
5452565SN/A        dmaWriteDone();
546849SN/A    }
547849SN/A}
548849SN/A
549849SN/Avoid
550849SN/AIdeDisk::dmaWriteDone()
551849SN/A{
5528522SN/A    DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
5538522SN/A                curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft);
554849SN/A    // check for the EOT
555849SN/A    if (curPrd.getEOT()) {
556849SN/A        assert(cmdBytesLeft == 0);
557849SN/A        dmaState = Dma_Idle;
558849SN/A        updateState(ACT_DMA_DONE);
559849SN/A    } else {
560849SN/A        doDmaTransfer();
561849SN/A    }
562849SN/A}
563849SN/A
564849SN/A////
565849SN/A// Disk utility routines
566849SN/A///
567849SN/A
568849SN/Avoid
569849SN/AIdeDisk::readDisk(uint32_t sector, uint8_t *data)
570849SN/A{
571849SN/A    uint32_t bytesRead = image->read(data, sector);
572849SN/A
573849SN/A    if (bytesRead != SectorSize)
574849SN/A        panic("Can't read from %s. Only %d of %d read. errno=%d\n",
575849SN/A              name(), bytesRead, SectorSize, errno);
576849SN/A}
577849SN/A
578849SN/Avoid
579849SN/AIdeDisk::writeDisk(uint32_t sector, uint8_t *data)
580849SN/A{
581849SN/A    uint32_t bytesWritten = image->write(data, sector);
582849SN/A
583849SN/A    if (bytesWritten != SectorSize)
584849SN/A        panic("Can't write to %s. Only %d of %d written. errno=%d\n",
585849SN/A              name(), bytesWritten, SectorSize, errno);
586849SN/A}
587849SN/A
588849SN/A////
589849SN/A// Setup and handle commands
590849SN/A////
591849SN/A
592849SN/Avoid
593849SN/AIdeDisk::startDma(const uint32_t &prdTableBase)
594849SN/A{
595849SN/A    if (dmaState != Dma_Start)
596849SN/A        panic("Inconsistent DMA state, should be in Dma_Start!\n");
597849SN/A
598849SN/A    if (devState != Transfer_Data_Dma)
599849SN/A        panic("Inconsistent device state for DMA start!\n");
600849SN/A
601896SN/A    // PRD base address is given by bits 31:2
602896SN/A    curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
603849SN/A
604849SN/A    dmaState = Dma_Transfer;
605849SN/A
606849SN/A    // schedule dma transfer (doDmaTransfer)
6077823SN/A    schedule(dmaTransferEvent, curTick() + 1);
608849SN/A}
609849SN/A
610849SN/Avoid
611849SN/AIdeDisk::abortDma()
612849SN/A{
613849SN/A    if (dmaState == Dma_Idle)
6141625SN/A        panic("Inconsistent DMA state, should be Start or Transfer!");
615849SN/A
616849SN/A    if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
6171625SN/A        panic("Inconsistent device state, should be Transfer or Prepare!\n");
618849SN/A
619849SN/A    updateState(ACT_CMD_ERROR);
620849SN/A}
621849SN/A
622849SN/Avoid
623849SN/AIdeDisk::startCommand()
624849SN/A{
625849SN/A    DevAction_t action = ACT_NONE;
626849SN/A    uint32_t size = 0;
627849SN/A    dmaRead = false;
628849SN/A
629849SN/A    // Decode commands
630849SN/A    switch (cmdReg.command) {
631849SN/A        // Supported non-data commands
6321722SN/A      case WDSF_READ_NATIVE_MAX:
6339533SN/A        size = (uint32_t)image->size() - 1;
634849SN/A        cmdReg.sec_num = (size & 0xff);
635849SN/A        cmdReg.cyl_low = ((size & 0xff00) >> 8);
636849SN/A        cmdReg.cyl_high = ((size & 0xff0000) >> 16);
637849SN/A        cmdReg.head = ((size & 0xf000000) >> 24);
638849SN/A
639849SN/A        devState = Command_Execution;
640849SN/A        action = ACT_CMD_COMPLETE;
641849SN/A        break;
642849SN/A
6431722SN/A      case WDCC_RECAL:
6441722SN/A      case WDCC_IDP:
6451722SN/A      case WDCC_STANDBY_IMMED:
6461722SN/A      case WDCC_FLUSHCACHE:
6471722SN/A      case WDSF_VERIFY:
6481722SN/A      case WDSF_SEEK:
6491722SN/A      case SET_FEATURES:
6501722SN/A      case WDCC_SETMULTI:
65110587SN/A      case WDCC_IDLE:
652849SN/A        devState = Command_Execution;
653849SN/A        action = ACT_CMD_COMPLETE;
654849SN/A        break;
655849SN/A
656849SN/A        // Supported PIO data-in commands
6571722SN/A      case WDCC_IDENTIFY:
6581722SN/A        cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
659849SN/A        devState = Prepare_Data_In;
660849SN/A        action = ACT_DATA_READY;
661849SN/A        break;
662849SN/A
6631722SN/A      case WDCC_READMULTI:
6641722SN/A      case WDCC_READ:
665849SN/A        if (!(cmdReg.drive & DRIVE_LBA_BIT))
666849SN/A            panic("Attempt to perform CHS access, only supports LBA\n");
667849SN/A
668849SN/A        if (cmdReg.sec_count == 0)
669893SN/A            cmdBytes = cmdBytesLeft = (256 * SectorSize);
670849SN/A        else
671893SN/A            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
672849SN/A
673849SN/A        curSector = getLBABase();
674849SN/A
675877SN/A        /** @todo make this a scheduled event to simulate disk delay */
676849SN/A        devState = Prepare_Data_In;
677849SN/A        action = ACT_DATA_READY;
678849SN/A        break;
679849SN/A
680849SN/A        // Supported PIO data-out commands
6811722SN/A      case WDCC_WRITEMULTI:
6821722SN/A      case WDCC_WRITE:
683849SN/A        if (!(cmdReg.drive & DRIVE_LBA_BIT))
684849SN/A            panic("Attempt to perform CHS access, only supports LBA\n");
685849SN/A
686849SN/A        if (cmdReg.sec_count == 0)
687893SN/A            cmdBytes = cmdBytesLeft = (256 * SectorSize);
688849SN/A        else
689893SN/A            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
6908522SN/A        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
691849SN/A        curSector = getLBABase();
692849SN/A
693849SN/A        devState = Prepare_Data_Out;
694849SN/A        action = ACT_DATA_READY;
695849SN/A        break;
696849SN/A
697849SN/A        // Supported DMA commands
6981722SN/A      case WDCC_WRITEDMA:
699849SN/A        dmaRead = true;  // a write to the disk is a DMA read from memory
7001722SN/A      case WDCC_READDMA:
701849SN/A        if (!(cmdReg.drive & DRIVE_LBA_BIT))
702849SN/A            panic("Attempt to perform CHS access, only supports LBA\n");
703849SN/A
704849SN/A        if (cmdReg.sec_count == 0)
705893SN/A            cmdBytes = cmdBytesLeft = (256 * SectorSize);
706849SN/A        else
707893SN/A            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
7088522SN/A        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
709849SN/A
710849SN/A        curSector = getLBABase();
711849SN/A
712849SN/A        devState = Prepare_Data_Dma;
713849SN/A        action = ACT_DMA_READY;
714849SN/A        break;
715849SN/A
716849SN/A      default:
717849SN/A        panic("Unsupported ATA command: %#x\n", cmdReg.command);
718849SN/A    }
719849SN/A
720849SN/A    if (action != ACT_NONE) {
721849SN/A        // set the BSY bit
722893SN/A        status |= STATUS_BSY_BIT;
723849SN/A        // clear the DRQ bit
724893SN/A        status &= ~STATUS_DRQ_BIT;
725893SN/A        // clear the DF bit
726893SN/A        status &= ~STATUS_DF_BIT;
727849SN/A
728849SN/A        updateState(action);
729849SN/A    }
730849SN/A}
731849SN/A
732849SN/A////
733849SN/A// Handle setting and clearing interrupts
734849SN/A////
735849SN/A
736849SN/Avoid
737849SN/AIdeDisk::intrPost()
738849SN/A{
7391625SN/A    DPRINTF(IdeDisk, "Posting Interrupt\n");
740849SN/A    if (intrPending)
741849SN/A        panic("Attempt to post an interrupt with one pending\n");
742849SN/A
743849SN/A    intrPending = true;
744849SN/A
745849SN/A    // talk to controller to set interrupt
7461817SN/A    if (ctrl) {
747849SN/A        ctrl->intrPost();
7481817SN/A    }
749849SN/A}
750849SN/A
751849SN/Avoid
752849SN/AIdeDisk::intrClear()
753849SN/A{
7541625SN/A    DPRINTF(IdeDisk, "Clearing Interrupt\n");
755849SN/A    if (!intrPending)
756849SN/A        panic("Attempt to clear a non-pending interrupt\n");
757849SN/A
758849SN/A    intrPending = false;
759849SN/A
760849SN/A    // talk to controller to clear interrupt
761849SN/A    if (ctrl)
762849SN/A        ctrl->intrClear();
763849SN/A}
764849SN/A
765849SN/A////
766849SN/A// Manage the device internal state machine
767849SN/A////
768849SN/A
769849SN/Avoid
770849SN/AIdeDisk::updateState(DevAction_t action)
771849SN/A{
772849SN/A    switch (devState) {
773893SN/A      case Device_Srst:
774893SN/A        if (action == ACT_SRST_SET) {
775893SN/A            // set the BSY bit
776893SN/A            status |= STATUS_BSY_BIT;
777893SN/A        } else if (action == ACT_SRST_CLEAR) {
778893SN/A            // clear the BSY bit
779893SN/A            status &= ~STATUS_BSY_BIT;
780893SN/A
781893SN/A            // reset the device state
782893SN/A            reset(devID);
783893SN/A        }
784893SN/A        break;
785893SN/A
786849SN/A      case Device_Idle_S:
787893SN/A        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
788849SN/A            devState = Device_Idle_NS;
789893SN/A        } else if (action == ACT_CMD_WRITE) {
790849SN/A            startCommand();
791893SN/A        }
792849SN/A
793849SN/A        break;
794849SN/A
795849SN/A      case Device_Idle_SI:
796893SN/A        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
797849SN/A            devState = Device_Idle_NS;
798849SN/A            intrClear();
799849SN/A        } else if (action == ACT_STAT_READ || isIENSet()) {
800849SN/A            devState = Device_Idle_S;
801849SN/A            intrClear();
802849SN/A        } else if (action == ACT_CMD_WRITE) {
803849SN/A            intrClear();
804849SN/A            startCommand();
805849SN/A        }
806849SN/A
807849SN/A        break;
808849SN/A
809849SN/A      case Device_Idle_NS:
810893SN/A        if (action == ACT_SELECT_WRITE && isDEVSelect()) {
811849SN/A            if (!isIENSet() && intrPending) {
812849SN/A                devState = Device_Idle_SI;
813849SN/A                intrPost();
814849SN/A            }
815849SN/A            if (isIENSet() || !intrPending) {
816849SN/A                devState = Device_Idle_S;
817849SN/A            }
818849SN/A        }
819849SN/A        break;
820849SN/A
821849SN/A      case Command_Execution:
822849SN/A        if (action == ACT_CMD_COMPLETE) {
823849SN/A            // clear the BSY bit
824849SN/A            setComplete();
825849SN/A
826849SN/A            if (!isIENSet()) {
827849SN/A                devState = Device_Idle_SI;
828849SN/A                intrPost();
829849SN/A            } else {
830849SN/A                devState = Device_Idle_S;
831849SN/A            }
832849SN/A        }
833849SN/A        break;
834849SN/A
835849SN/A      case Prepare_Data_In:
836849SN/A        if (action == ACT_CMD_ERROR) {
837849SN/A            // clear the BSY bit
838849SN/A            setComplete();
839849SN/A
840849SN/A            if (!isIENSet()) {
841849SN/A                devState = Device_Idle_SI;
842849SN/A                intrPost();
843849SN/A            } else {
844849SN/A                devState = Device_Idle_S;
845849SN/A            }
846849SN/A        } else if (action == ACT_DATA_READY) {
847849SN/A            // clear the BSY bit
848893SN/A            status &= ~STATUS_BSY_BIT;
849849SN/A            // set the DRQ bit
850893SN/A            status |= STATUS_DRQ_BIT;
851849SN/A
852877SN/A            // copy the data into the data buffer
8531722SN/A            if (cmdReg.command == WDCC_IDENTIFY) {
854877SN/A                // Reset the drqBytes for this block
8551722SN/A                drqBytesLeft = sizeof(struct ataparams);
856877SN/A
857877SN/A                memcpy((void *)dataBuffer, (void *)&driveID,
8581722SN/A                       sizeof(struct ataparams));
859877SN/A            } else {
860877SN/A                // Reset the drqBytes for this block
861877SN/A                drqBytesLeft = SectorSize;
862877SN/A
863877SN/A                readDisk(curSector++, dataBuffer);
864877SN/A            }
865877SN/A
866849SN/A            // put the first two bytes into the data register
8671817SN/A            memcpy((void *)&cmdReg.data, (void *)dataBuffer,
868857SN/A                   sizeof(uint16_t));
869857SN/A
870849SN/A            if (!isIENSet()) {
871849SN/A                devState = Data_Ready_INTRQ_In;
872849SN/A                intrPost();
873849SN/A            } else {
874849SN/A                devState = Transfer_Data_In;
875849SN/A            }
876849SN/A        }
877849SN/A        break;
878849SN/A
879849SN/A      case Data_Ready_INTRQ_In:
880849SN/A        if (action == ACT_STAT_READ) {
881849SN/A            devState = Transfer_Data_In;
882849SN/A            intrClear();
883849SN/A        }
884849SN/A        break;
885849SN/A
886849SN/A      case Transfer_Data_In:
887849SN/A        if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
888849SN/A            if (action == ACT_DATA_READ_BYTE) {
889849SN/A                panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
890849SN/A            } else {
891849SN/A                drqBytesLeft -= 2;
892849SN/A                cmdBytesLeft -= 2;
893849SN/A
894849SN/A                // copy next short into data registers
895877SN/A                if (drqBytesLeft)
8961817SN/A                    memcpy((void *)&cmdReg.data,
897877SN/A                           (void *)&dataBuffer[SectorSize - drqBytesLeft],
898877SN/A                           sizeof(uint16_t));
899849SN/A            }
900849SN/A
901849SN/A            if (drqBytesLeft == 0) {
902849SN/A                if (cmdBytesLeft == 0) {
903849SN/A                    // Clear the BSY bit
904849SN/A                    setComplete();
905849SN/A                    devState = Device_Idle_S;
906849SN/A                } else {
907849SN/A                    devState = Prepare_Data_In;
908877SN/A                    // set the BSY_BIT
909893SN/A                    status |= STATUS_BSY_BIT;
910877SN/A                    // clear the DRQ_BIT
911893SN/A                    status &= ~STATUS_DRQ_BIT;
912877SN/A
913877SN/A                    /** @todo change this to a scheduled event to simulate
914877SN/A                        disk delay */
915877SN/A                    updateState(ACT_DATA_READY);
916849SN/A                }
917849SN/A            }
918849SN/A        }
919849SN/A        break;
920849SN/A
921849SN/A      case Prepare_Data_Out:
922849SN/A        if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
923849SN/A            // clear the BSY bit
924849SN/A            setComplete();
925849SN/A
926849SN/A            if (!isIENSet()) {
927849SN/A                devState = Device_Idle_SI;
928849SN/A                intrPost();
929849SN/A            } else {
930849SN/A                devState = Device_Idle_S;
931849SN/A            }
932893SN/A        } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
933849SN/A            // clear the BSY bit
934893SN/A            status &= ~STATUS_BSY_BIT;
935849SN/A            // set the DRQ bit
936893SN/A            status |= STATUS_DRQ_BIT;
937849SN/A
938849SN/A            // clear the data buffer to get it ready for writes
939849SN/A            memset(dataBuffer, 0, MAX_DMA_SIZE);
940849SN/A
941893SN/A            // reset the drqBytes for this block
942893SN/A            drqBytesLeft = SectorSize;
943893SN/A
944893SN/A            if (cmdBytesLeft == cmdBytes || isIENSet()) {
945893SN/A                devState = Transfer_Data_Out;
946893SN/A            } else {
947849SN/A                devState = Data_Ready_INTRQ_Out;
948849SN/A                intrPost();
949849SN/A            }
950849SN/A        }
951849SN/A        break;
952849SN/A
953849SN/A      case Data_Ready_INTRQ_Out:
954849SN/A        if (action == ACT_STAT_READ) {
955849SN/A            devState = Transfer_Data_Out;
956849SN/A            intrClear();
957849SN/A        }
958849SN/A        break;
959849SN/A
960849SN/A      case Transfer_Data_Out:
961857SN/A        if (action == ACT_DATA_WRITE_BYTE ||
962857SN/A            action == ACT_DATA_WRITE_SHORT) {
963857SN/A
964849SN/A            if (action == ACT_DATA_READ_BYTE) {
965849SN/A                panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
966849SN/A            } else {
967849SN/A                // copy the latest short into the data buffer
968849SN/A                memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
9691817SN/A                       (void *)&cmdReg.data,
970849SN/A                       sizeof(uint16_t));
971849SN/A
972849SN/A                drqBytesLeft -= 2;
973849SN/A                cmdBytesLeft -= 2;
974849SN/A            }
975849SN/A
976849SN/A            if (drqBytesLeft == 0) {
977849SN/A                // copy the block to the disk
978849SN/A                writeDisk(curSector++, dataBuffer);
979849SN/A
980849SN/A                // set the BSY bit
981893SN/A                status |= STATUS_BSY_BIT;
982893SN/A                // set the seek bit
983893SN/A                status |= STATUS_SEEK_BIT;
984849SN/A                // clear the DRQ bit
985893SN/A                status &= ~STATUS_DRQ_BIT;
986849SN/A
987849SN/A                devState = Prepare_Data_Out;
988878SN/A
989878SN/A                /** @todo change this to a scheduled event to simulate
990878SN/A                    disk delay */
991878SN/A                updateState(ACT_DATA_READY);
992849SN/A            }
993849SN/A        }
994849SN/A        break;
995849SN/A
996849SN/A      case Prepare_Data_Dma:
997849SN/A        if (action == ACT_CMD_ERROR) {
998849SN/A            // clear the BSY bit
999849SN/A            setComplete();
1000849SN/A
1001849SN/A            if (!isIENSet()) {
1002849SN/A                devState = Device_Idle_SI;
1003849SN/A                intrPost();
1004849SN/A            } else {
1005849SN/A                devState = Device_Idle_S;
1006849SN/A            }
1007849SN/A        } else if (action == ACT_DMA_READY) {
1008849SN/A            // clear the BSY bit
1009893SN/A            status &= ~STATUS_BSY_BIT;
1010849SN/A            // set the DRQ bit
1011893SN/A            status |= STATUS_DRQ_BIT;
1012849SN/A
1013849SN/A            devState = Transfer_Data_Dma;
1014849SN/A
1015849SN/A            if (dmaState != Dma_Idle)
1016849SN/A                panic("Inconsistent DMA state, should be Dma_Idle\n");
1017849SN/A
1018849SN/A            dmaState = Dma_Start;
1019849SN/A            // wait for the write to the DMA start bit
1020849SN/A        }
1021849SN/A        break;
1022849SN/A
1023849SN/A      case Transfer_Data_Dma:
10249956SN/A        if (action == ACT_CMD_ERROR) {
10259956SN/A            dmaAborted = true;
10269956SN/A            devState = Device_Dma_Abort;
10279956SN/A        } else if (action == ACT_DMA_DONE) {
1028849SN/A            // clear the BSY bit
1029849SN/A            setComplete();
1030849SN/A            // set the seek bit
1031893SN/A            status |= STATUS_SEEK_BIT;
1032849SN/A            // clear the controller state for DMA transfer
1033849SN/A            ctrl->setDmaComplete(this);
1034849SN/A
1035849SN/A            if (!isIENSet()) {
1036849SN/A                devState = Device_Idle_SI;
1037849SN/A                intrPost();
1038849SN/A            } else {
1039849SN/A                devState = Device_Idle_S;
1040849SN/A            }
1041849SN/A        }
1042849SN/A        break;
1043849SN/A
10449956SN/A      case Device_Dma_Abort:
10459956SN/A        if (action == ACT_CMD_ERROR) {
10469956SN/A            setComplete();
10479956SN/A            status |= STATUS_SEEK_BIT;
10489956SN/A            ctrl->setDmaComplete(this);
10499956SN/A            dmaAborted = false;
10509956SN/A            dmaState = Dma_Idle;
10519956SN/A
10529956SN/A            if (!isIENSet()) {
10539956SN/A                devState = Device_Idle_SI;
10549956SN/A                intrPost();
10559956SN/A            } else {
10569956SN/A                devState = Device_Idle_S;
10579956SN/A            }
10589956SN/A        } else {
10599956SN/A            DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
10609956SN/A        }
10619956SN/A        break;
10629956SN/A
1063849SN/A      default:
1064849SN/A        panic("Unknown IDE device state: %#x\n", devState);
1065849SN/A    }
1066848SN/A}
1067848SN/A
1068848SN/Avoid
106910905SN/AIdeDisk::serialize(CheckpointOut &cp) const
1070848SN/A{
1071864SN/A    // Check all outstanding events to see if they are scheduled
1072864SN/A    // these are all mutually exclusive
1073864SN/A    Tick reschedule = 0;
1074864SN/A    Events_t event = None;
1075864SN/A
1076920SN/A    int eventCount = 0;
1077920SN/A
1078864SN/A    if (dmaTransferEvent.scheduled()) {
1079864SN/A        reschedule = dmaTransferEvent.when();
1080864SN/A        event = Transfer;
1081920SN/A        eventCount++;
1082920SN/A    }
1083920SN/A    if (dmaReadWaitEvent.scheduled()) {
1084864SN/A        reschedule = dmaReadWaitEvent.when();
1085864SN/A        event = ReadWait;
1086920SN/A        eventCount++;
1087920SN/A    }
1088920SN/A    if (dmaWriteWaitEvent.scheduled()) {
1089864SN/A        reschedule = dmaWriteWaitEvent.when();
1090864SN/A        event = WriteWait;
1091920SN/A        eventCount++;
1092920SN/A    }
1093920SN/A    if (dmaPrdReadEvent.scheduled()) {
1094864SN/A        reschedule = dmaPrdReadEvent.when();
1095864SN/A        event = PrdRead;
1096920SN/A        eventCount++;
1097920SN/A    }
1098920SN/A    if (dmaReadEvent.scheduled()) {
1099864SN/A        reschedule = dmaReadEvent.when();
1100864SN/A        event = DmaRead;
1101920SN/A        eventCount++;
1102920SN/A    }
1103920SN/A    if (dmaWriteEvent.scheduled()) {
1104864SN/A        reschedule = dmaWriteEvent.when();
1105864SN/A        event = DmaWrite;
1106920SN/A        eventCount++;
1107864SN/A    }
1108864SN/A
1109920SN/A    assert(eventCount <= 1);
1110920SN/A
1111864SN/A    SERIALIZE_SCALAR(reschedule);
1112864SN/A    SERIALIZE_ENUM(event);
1113864SN/A
1114864SN/A    // Serialize device registers
11151817SN/A    SERIALIZE_SCALAR(cmdReg.data);
1116864SN/A    SERIALIZE_SCALAR(cmdReg.sec_count);
1117864SN/A    SERIALIZE_SCALAR(cmdReg.sec_num);
1118864SN/A    SERIALIZE_SCALAR(cmdReg.cyl_low);
1119864SN/A    SERIALIZE_SCALAR(cmdReg.cyl_high);
1120864SN/A    SERIALIZE_SCALAR(cmdReg.drive);
1121920SN/A    SERIALIZE_SCALAR(cmdReg.command);
1122893SN/A    SERIALIZE_SCALAR(status);
1123864SN/A    SERIALIZE_SCALAR(nIENBit);
1124864SN/A    SERIALIZE_SCALAR(devID);
1125864SN/A
1126864SN/A    // Serialize the PRD related information
1127864SN/A    SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1128864SN/A    SERIALIZE_SCALAR(curPrd.entry.byteCount);
1129864SN/A    SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1130864SN/A    SERIALIZE_SCALAR(curPrdAddr);
1131864SN/A
11322565SN/A    /** @todo need to serialized chunk generator stuff!! */
1133864SN/A    // Serialize current transfer related information
1134864SN/A    SERIALIZE_SCALAR(cmdBytesLeft);
1135893SN/A    SERIALIZE_SCALAR(cmdBytes);
1136864SN/A    SERIALIZE_SCALAR(drqBytesLeft);
1137864SN/A    SERIALIZE_SCALAR(curSector);
1138864SN/A    SERIALIZE_SCALAR(dmaRead);
1139864SN/A    SERIALIZE_SCALAR(intrPending);
11409956SN/A    SERIALIZE_SCALAR(dmaAborted);
1141864SN/A    SERIALIZE_ENUM(devState);
1142864SN/A    SERIALIZE_ENUM(dmaState);
1143864SN/A    SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1144848SN/A}
1145848SN/A
1146848SN/Avoid
114710905SN/AIdeDisk::unserialize(CheckpointIn &cp)
1148848SN/A{
1149864SN/A    // Reschedule events that were outstanding
1150864SN/A    // these are all mutually exclusive
1151864SN/A    Tick reschedule = 0;
1152864SN/A    Events_t event = None;
1153864SN/A
1154864SN/A    UNSERIALIZE_SCALAR(reschedule);
1155864SN/A    UNSERIALIZE_ENUM(event);
1156864SN/A
1157864SN/A    switch (event) {
1158864SN/A      case None : break;
11595606SN/A      case Transfer : schedule(dmaTransferEvent, reschedule); break;
11605606SN/A      case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
11615606SN/A      case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
11625606SN/A      case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
11635606SN/A      case DmaRead : schedule(dmaReadEvent, reschedule); break;
11645606SN/A      case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1165864SN/A    }
1166864SN/A
1167864SN/A    // Unserialize device registers
11681817SN/A    UNSERIALIZE_SCALAR(cmdReg.data);
1169864SN/A    UNSERIALIZE_SCALAR(cmdReg.sec_count);
1170864SN/A    UNSERIALIZE_SCALAR(cmdReg.sec_num);
1171864SN/A    UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1172864SN/A    UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1173864SN/A    UNSERIALIZE_SCALAR(cmdReg.drive);
1174920SN/A    UNSERIALIZE_SCALAR(cmdReg.command);
1175893SN/A    UNSERIALIZE_SCALAR(status);
1176864SN/A    UNSERIALIZE_SCALAR(nIENBit);
1177864SN/A    UNSERIALIZE_SCALAR(devID);
1178864SN/A
1179864SN/A    // Unserialize the PRD related information
1180864SN/A    UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1181864SN/A    UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1182864SN/A    UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1183864SN/A    UNSERIALIZE_SCALAR(curPrdAddr);
1184864SN/A
11852565SN/A    /** @todo need to serialized chunk generator stuff!! */
1186864SN/A    // Unserialize current transfer related information
1187893SN/A    UNSERIALIZE_SCALAR(cmdBytes);
1188864SN/A    UNSERIALIZE_SCALAR(cmdBytesLeft);
1189864SN/A    UNSERIALIZE_SCALAR(drqBytesLeft);
1190864SN/A    UNSERIALIZE_SCALAR(curSector);
1191864SN/A    UNSERIALIZE_SCALAR(dmaRead);
1192864SN/A    UNSERIALIZE_SCALAR(intrPending);
11939956SN/A    UNSERIALIZE_SCALAR(dmaAborted);
1194864SN/A    UNSERIALIZE_ENUM(devState);
1195864SN/A    UNSERIALIZE_ENUM(dmaState);
1196864SN/A    UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1197848SN/A}
1198848SN/A
11994762SN/AIdeDisk *
12004762SN/AIdeDiskParams::create()
1201848SN/A{
12025034SN/A    return new IdeDisk(this);
1203848SN/A}
1204