ide_disk.cc revision 11980
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:
66011980Sjason@lowepower.com      case ATAPI_IDENTIFY_DEVICE:
6611722SN/A        cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
662849SN/A        devState = Prepare_Data_In;
663849SN/A        action = ACT_DATA_READY;
664849SN/A        break;
665849SN/A
6661722SN/A      case WDCC_READMULTI:
6671722SN/A      case WDCC_READ:
668849SN/A        if (!(cmdReg.drive & DRIVE_LBA_BIT))
669849SN/A            panic("Attempt to perform CHS access, only supports LBA\n");
670849SN/A
671849SN/A        if (cmdReg.sec_count == 0)
672893SN/A            cmdBytes = cmdBytesLeft = (256 * SectorSize);
673849SN/A        else
674893SN/A            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
675849SN/A
676849SN/A        curSector = getLBABase();
677849SN/A
678877SN/A        /** @todo make this a scheduled event to simulate disk delay */
679849SN/A        devState = Prepare_Data_In;
680849SN/A        action = ACT_DATA_READY;
681849SN/A        break;
682849SN/A
683849SN/A        // Supported PIO data-out commands
6841722SN/A      case WDCC_WRITEMULTI:
6851722SN/A      case WDCC_WRITE:
686849SN/A        if (!(cmdReg.drive & DRIVE_LBA_BIT))
687849SN/A            panic("Attempt to perform CHS access, only supports LBA\n");
688849SN/A
689849SN/A        if (cmdReg.sec_count == 0)
690893SN/A            cmdBytes = cmdBytesLeft = (256 * SectorSize);
691849SN/A        else
692893SN/A            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
6938522SN/A        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
694849SN/A        curSector = getLBABase();
695849SN/A
696849SN/A        devState = Prepare_Data_Out;
697849SN/A        action = ACT_DATA_READY;
698849SN/A        break;
699849SN/A
700849SN/A        // Supported DMA commands
7011722SN/A      case WDCC_WRITEDMA:
702849SN/A        dmaRead = true;  // a write to the disk is a DMA read from memory
7031722SN/A      case WDCC_READDMA:
704849SN/A        if (!(cmdReg.drive & DRIVE_LBA_BIT))
705849SN/A            panic("Attempt to perform CHS access, only supports LBA\n");
706849SN/A
707849SN/A        if (cmdReg.sec_count == 0)
708893SN/A            cmdBytes = cmdBytesLeft = (256 * SectorSize);
709849SN/A        else
710893SN/A            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
7118522SN/A        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
712849SN/A
713849SN/A        curSector = getLBABase();
714849SN/A
715849SN/A        devState = Prepare_Data_Dma;
716849SN/A        action = ACT_DMA_READY;
717849SN/A        break;
718849SN/A
719849SN/A      default:
720849SN/A        panic("Unsupported ATA command: %#x\n", cmdReg.command);
721849SN/A    }
722849SN/A
723849SN/A    if (action != ACT_NONE) {
724849SN/A        // set the BSY bit
725893SN/A        status |= STATUS_BSY_BIT;
726849SN/A        // clear the DRQ bit
727893SN/A        status &= ~STATUS_DRQ_BIT;
728893SN/A        // clear the DF bit
729893SN/A        status &= ~STATUS_DF_BIT;
730849SN/A
731849SN/A        updateState(action);
732849SN/A    }
733849SN/A}
734849SN/A
735849SN/A////
736849SN/A// Handle setting and clearing interrupts
737849SN/A////
738849SN/A
739849SN/Avoid
740849SN/AIdeDisk::intrPost()
741849SN/A{
7421625SN/A    DPRINTF(IdeDisk, "Posting Interrupt\n");
743849SN/A    if (intrPending)
744849SN/A        panic("Attempt to post an interrupt with one pending\n");
745849SN/A
746849SN/A    intrPending = true;
747849SN/A
748849SN/A    // talk to controller to set interrupt
7491817SN/A    if (ctrl) {
750849SN/A        ctrl->intrPost();
7511817SN/A    }
752849SN/A}
753849SN/A
754849SN/Avoid
755849SN/AIdeDisk::intrClear()
756849SN/A{
7571625SN/A    DPRINTF(IdeDisk, "Clearing Interrupt\n");
758849SN/A    if (!intrPending)
759849SN/A        panic("Attempt to clear a non-pending interrupt\n");
760849SN/A
761849SN/A    intrPending = false;
762849SN/A
763849SN/A    // talk to controller to clear interrupt
764849SN/A    if (ctrl)
765849SN/A        ctrl->intrClear();
766849SN/A}
767849SN/A
768849SN/A////
769849SN/A// Manage the device internal state machine
770849SN/A////
771849SN/A
772849SN/Avoid
773849SN/AIdeDisk::updateState(DevAction_t action)
774849SN/A{
775849SN/A    switch (devState) {
776893SN/A      case Device_Srst:
777893SN/A        if (action == ACT_SRST_SET) {
778893SN/A            // set the BSY bit
779893SN/A            status |= STATUS_BSY_BIT;
780893SN/A        } else if (action == ACT_SRST_CLEAR) {
781893SN/A            // clear the BSY bit
782893SN/A            status &= ~STATUS_BSY_BIT;
783893SN/A
784893SN/A            // reset the device state
785893SN/A            reset(devID);
786893SN/A        }
787893SN/A        break;
788893SN/A
789849SN/A      case Device_Idle_S:
790893SN/A        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
791849SN/A            devState = Device_Idle_NS;
792893SN/A        } else if (action == ACT_CMD_WRITE) {
793849SN/A            startCommand();
794893SN/A        }
795849SN/A
796849SN/A        break;
797849SN/A
798849SN/A      case Device_Idle_SI:
799893SN/A        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
800849SN/A            devState = Device_Idle_NS;
801849SN/A            intrClear();
802849SN/A        } else if (action == ACT_STAT_READ || isIENSet()) {
803849SN/A            devState = Device_Idle_S;
804849SN/A            intrClear();
805849SN/A        } else if (action == ACT_CMD_WRITE) {
806849SN/A            intrClear();
807849SN/A            startCommand();
808849SN/A        }
809849SN/A
810849SN/A        break;
811849SN/A
812849SN/A      case Device_Idle_NS:
813893SN/A        if (action == ACT_SELECT_WRITE && isDEVSelect()) {
814849SN/A            if (!isIENSet() && intrPending) {
815849SN/A                devState = Device_Idle_SI;
816849SN/A                intrPost();
817849SN/A            }
818849SN/A            if (isIENSet() || !intrPending) {
819849SN/A                devState = Device_Idle_S;
820849SN/A            }
821849SN/A        }
822849SN/A        break;
823849SN/A
824849SN/A      case Command_Execution:
825849SN/A        if (action == ACT_CMD_COMPLETE) {
826849SN/A            // clear the BSY bit
827849SN/A            setComplete();
828849SN/A
829849SN/A            if (!isIENSet()) {
830849SN/A                devState = Device_Idle_SI;
831849SN/A                intrPost();
832849SN/A            } else {
833849SN/A                devState = Device_Idle_S;
834849SN/A            }
835849SN/A        }
836849SN/A        break;
837849SN/A
838849SN/A      case Prepare_Data_In:
839849SN/A        if (action == ACT_CMD_ERROR) {
840849SN/A            // clear the BSY bit
841849SN/A            setComplete();
842849SN/A
843849SN/A            if (!isIENSet()) {
844849SN/A                devState = Device_Idle_SI;
845849SN/A                intrPost();
846849SN/A            } else {
847849SN/A                devState = Device_Idle_S;
848849SN/A            }
849849SN/A        } else if (action == ACT_DATA_READY) {
850849SN/A            // clear the BSY bit
851893SN/A            status &= ~STATUS_BSY_BIT;
852849SN/A            // set the DRQ bit
853893SN/A            status |= STATUS_DRQ_BIT;
854849SN/A
855877SN/A            // copy the data into the data buffer
85611980Sjason@lowepower.com            if (cmdReg.command == WDCC_IDENTIFY ||
85711980Sjason@lowepower.com                cmdReg.command == ATAPI_IDENTIFY_DEVICE) {
858877SN/A                // Reset the drqBytes for this block
8591722SN/A                drqBytesLeft = sizeof(struct ataparams);
860877SN/A
861877SN/A                memcpy((void *)dataBuffer, (void *)&driveID,
8621722SN/A                       sizeof(struct ataparams));
863877SN/A            } else {
864877SN/A                // Reset the drqBytes for this block
865877SN/A                drqBytesLeft = SectorSize;
866877SN/A
867877SN/A                readDisk(curSector++, dataBuffer);
868877SN/A            }
869877SN/A
870849SN/A            // put the first two bytes into the data register
8711817SN/A            memcpy((void *)&cmdReg.data, (void *)dataBuffer,
872857SN/A                   sizeof(uint16_t));
873857SN/A
874849SN/A            if (!isIENSet()) {
875849SN/A                devState = Data_Ready_INTRQ_In;
876849SN/A                intrPost();
877849SN/A            } else {
878849SN/A                devState = Transfer_Data_In;
879849SN/A            }
880849SN/A        }
881849SN/A        break;
882849SN/A
883849SN/A      case Data_Ready_INTRQ_In:
884849SN/A        if (action == ACT_STAT_READ) {
885849SN/A            devState = Transfer_Data_In;
886849SN/A            intrClear();
887849SN/A        }
888849SN/A        break;
889849SN/A
890849SN/A      case Transfer_Data_In:
891849SN/A        if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
892849SN/A            if (action == ACT_DATA_READ_BYTE) {
893849SN/A                panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
894849SN/A            } else {
895849SN/A                drqBytesLeft -= 2;
896849SN/A                cmdBytesLeft -= 2;
897849SN/A
898849SN/A                // copy next short into data registers
899877SN/A                if (drqBytesLeft)
9001817SN/A                    memcpy((void *)&cmdReg.data,
901877SN/A                           (void *)&dataBuffer[SectorSize - drqBytesLeft],
902877SN/A                           sizeof(uint16_t));
903849SN/A            }
904849SN/A
905849SN/A            if (drqBytesLeft == 0) {
906849SN/A                if (cmdBytesLeft == 0) {
907849SN/A                    // Clear the BSY bit
908849SN/A                    setComplete();
909849SN/A                    devState = Device_Idle_S;
910849SN/A                } else {
911849SN/A                    devState = Prepare_Data_In;
912877SN/A                    // set the BSY_BIT
913893SN/A                    status |= STATUS_BSY_BIT;
914877SN/A                    // clear the DRQ_BIT
915893SN/A                    status &= ~STATUS_DRQ_BIT;
916877SN/A
917877SN/A                    /** @todo change this to a scheduled event to simulate
918877SN/A                        disk delay */
919877SN/A                    updateState(ACT_DATA_READY);
920849SN/A                }
921849SN/A            }
922849SN/A        }
923849SN/A        break;
924849SN/A
925849SN/A      case Prepare_Data_Out:
926849SN/A        if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
927849SN/A            // clear the BSY bit
928849SN/A            setComplete();
929849SN/A
930849SN/A            if (!isIENSet()) {
931849SN/A                devState = Device_Idle_SI;
932849SN/A                intrPost();
933849SN/A            } else {
934849SN/A                devState = Device_Idle_S;
935849SN/A            }
936893SN/A        } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
937849SN/A            // clear the BSY bit
938893SN/A            status &= ~STATUS_BSY_BIT;
939849SN/A            // set the DRQ bit
940893SN/A            status |= STATUS_DRQ_BIT;
941849SN/A
942849SN/A            // clear the data buffer to get it ready for writes
943849SN/A            memset(dataBuffer, 0, MAX_DMA_SIZE);
944849SN/A
945893SN/A            // reset the drqBytes for this block
946893SN/A            drqBytesLeft = SectorSize;
947893SN/A
948893SN/A            if (cmdBytesLeft == cmdBytes || isIENSet()) {
949893SN/A                devState = Transfer_Data_Out;
950893SN/A            } else {
951849SN/A                devState = Data_Ready_INTRQ_Out;
952849SN/A                intrPost();
953849SN/A            }
954849SN/A        }
955849SN/A        break;
956849SN/A
957849SN/A      case Data_Ready_INTRQ_Out:
958849SN/A        if (action == ACT_STAT_READ) {
959849SN/A            devState = Transfer_Data_Out;
960849SN/A            intrClear();
961849SN/A        }
962849SN/A        break;
963849SN/A
964849SN/A      case Transfer_Data_Out:
965857SN/A        if (action == ACT_DATA_WRITE_BYTE ||
966857SN/A            action == ACT_DATA_WRITE_SHORT) {
967857SN/A
968849SN/A            if (action == ACT_DATA_READ_BYTE) {
969849SN/A                panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
970849SN/A            } else {
971849SN/A                // copy the latest short into the data buffer
972849SN/A                memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
9731817SN/A                       (void *)&cmdReg.data,
974849SN/A                       sizeof(uint16_t));
975849SN/A
976849SN/A                drqBytesLeft -= 2;
977849SN/A                cmdBytesLeft -= 2;
978849SN/A            }
979849SN/A
980849SN/A            if (drqBytesLeft == 0) {
981849SN/A                // copy the block to the disk
982849SN/A                writeDisk(curSector++, dataBuffer);
983849SN/A
984849SN/A                // set the BSY bit
985893SN/A                status |= STATUS_BSY_BIT;
986893SN/A                // set the seek bit
987893SN/A                status |= STATUS_SEEK_BIT;
988849SN/A                // clear the DRQ bit
989893SN/A                status &= ~STATUS_DRQ_BIT;
990849SN/A
991849SN/A                devState = Prepare_Data_Out;
992878SN/A
993878SN/A                /** @todo change this to a scheduled event to simulate
994878SN/A                    disk delay */
995878SN/A                updateState(ACT_DATA_READY);
996849SN/A            }
997849SN/A        }
998849SN/A        break;
999849SN/A
1000849SN/A      case Prepare_Data_Dma:
1001849SN/A        if (action == ACT_CMD_ERROR) {
1002849SN/A            // clear the BSY bit
1003849SN/A            setComplete();
1004849SN/A
1005849SN/A            if (!isIENSet()) {
1006849SN/A                devState = Device_Idle_SI;
1007849SN/A                intrPost();
1008849SN/A            } else {
1009849SN/A                devState = Device_Idle_S;
1010849SN/A            }
1011849SN/A        } else if (action == ACT_DMA_READY) {
1012849SN/A            // clear the BSY bit
1013893SN/A            status &= ~STATUS_BSY_BIT;
1014849SN/A            // set the DRQ bit
1015893SN/A            status |= STATUS_DRQ_BIT;
1016849SN/A
1017849SN/A            devState = Transfer_Data_Dma;
1018849SN/A
1019849SN/A            if (dmaState != Dma_Idle)
1020849SN/A                panic("Inconsistent DMA state, should be Dma_Idle\n");
1021849SN/A
1022849SN/A            dmaState = Dma_Start;
1023849SN/A            // wait for the write to the DMA start bit
1024849SN/A        }
1025849SN/A        break;
1026849SN/A
1027849SN/A      case Transfer_Data_Dma:
10289956SN/A        if (action == ACT_CMD_ERROR) {
10299956SN/A            dmaAborted = true;
10309956SN/A            devState = Device_Dma_Abort;
10319956SN/A        } else if (action == ACT_DMA_DONE) {
1032849SN/A            // clear the BSY bit
1033849SN/A            setComplete();
1034849SN/A            // set the seek bit
1035893SN/A            status |= STATUS_SEEK_BIT;
1036849SN/A            // clear the controller state for DMA transfer
1037849SN/A            ctrl->setDmaComplete(this);
1038849SN/A
1039849SN/A            if (!isIENSet()) {
1040849SN/A                devState = Device_Idle_SI;
1041849SN/A                intrPost();
1042849SN/A            } else {
1043849SN/A                devState = Device_Idle_S;
1044849SN/A            }
1045849SN/A        }
1046849SN/A        break;
1047849SN/A
10489956SN/A      case Device_Dma_Abort:
10499956SN/A        if (action == ACT_CMD_ERROR) {
10509956SN/A            setComplete();
10519956SN/A            status |= STATUS_SEEK_BIT;
10529956SN/A            ctrl->setDmaComplete(this);
10539956SN/A            dmaAborted = false;
10549956SN/A            dmaState = Dma_Idle;
10559956SN/A
10569956SN/A            if (!isIENSet()) {
10579956SN/A                devState = Device_Idle_SI;
10589956SN/A                intrPost();
10599956SN/A            } else {
10609956SN/A                devState = Device_Idle_S;
10619956SN/A            }
10629956SN/A        } else {
10639956SN/A            DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
10649956SN/A        }
10659956SN/A        break;
10669956SN/A
1067849SN/A      default:
1068849SN/A        panic("Unknown IDE device state: %#x\n", devState);
1069849SN/A    }
1070848SN/A}
1071848SN/A
1072848SN/Avoid
107310905SN/AIdeDisk::serialize(CheckpointOut &cp) const
1074848SN/A{
1075864SN/A    // Check all outstanding events to see if they are scheduled
1076864SN/A    // these are all mutually exclusive
1077864SN/A    Tick reschedule = 0;
1078864SN/A    Events_t event = None;
1079864SN/A
1080920SN/A    int eventCount = 0;
1081920SN/A
1082864SN/A    if (dmaTransferEvent.scheduled()) {
1083864SN/A        reschedule = dmaTransferEvent.when();
1084864SN/A        event = Transfer;
1085920SN/A        eventCount++;
1086920SN/A    }
1087920SN/A    if (dmaReadWaitEvent.scheduled()) {
1088864SN/A        reschedule = dmaReadWaitEvent.when();
1089864SN/A        event = ReadWait;
1090920SN/A        eventCount++;
1091920SN/A    }
1092920SN/A    if (dmaWriteWaitEvent.scheduled()) {
1093864SN/A        reschedule = dmaWriteWaitEvent.when();
1094864SN/A        event = WriteWait;
1095920SN/A        eventCount++;
1096920SN/A    }
1097920SN/A    if (dmaPrdReadEvent.scheduled()) {
1098864SN/A        reschedule = dmaPrdReadEvent.when();
1099864SN/A        event = PrdRead;
1100920SN/A        eventCount++;
1101920SN/A    }
1102920SN/A    if (dmaReadEvent.scheduled()) {
1103864SN/A        reschedule = dmaReadEvent.when();
1104864SN/A        event = DmaRead;
1105920SN/A        eventCount++;
1106920SN/A    }
1107920SN/A    if (dmaWriteEvent.scheduled()) {
1108864SN/A        reschedule = dmaWriteEvent.when();
1109864SN/A        event = DmaWrite;
1110920SN/A        eventCount++;
1111864SN/A    }
1112864SN/A
1113920SN/A    assert(eventCount <= 1);
1114920SN/A
1115864SN/A    SERIALIZE_SCALAR(reschedule);
1116864SN/A    SERIALIZE_ENUM(event);
1117864SN/A
1118864SN/A    // Serialize device registers
11191817SN/A    SERIALIZE_SCALAR(cmdReg.data);
1120864SN/A    SERIALIZE_SCALAR(cmdReg.sec_count);
1121864SN/A    SERIALIZE_SCALAR(cmdReg.sec_num);
1122864SN/A    SERIALIZE_SCALAR(cmdReg.cyl_low);
1123864SN/A    SERIALIZE_SCALAR(cmdReg.cyl_high);
1124864SN/A    SERIALIZE_SCALAR(cmdReg.drive);
1125920SN/A    SERIALIZE_SCALAR(cmdReg.command);
1126893SN/A    SERIALIZE_SCALAR(status);
1127864SN/A    SERIALIZE_SCALAR(nIENBit);
1128864SN/A    SERIALIZE_SCALAR(devID);
1129864SN/A
1130864SN/A    // Serialize the PRD related information
1131864SN/A    SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1132864SN/A    SERIALIZE_SCALAR(curPrd.entry.byteCount);
1133864SN/A    SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1134864SN/A    SERIALIZE_SCALAR(curPrdAddr);
1135864SN/A
11362565SN/A    /** @todo need to serialized chunk generator stuff!! */
1137864SN/A    // Serialize current transfer related information
1138864SN/A    SERIALIZE_SCALAR(cmdBytesLeft);
1139893SN/A    SERIALIZE_SCALAR(cmdBytes);
1140864SN/A    SERIALIZE_SCALAR(drqBytesLeft);
1141864SN/A    SERIALIZE_SCALAR(curSector);
1142864SN/A    SERIALIZE_SCALAR(dmaRead);
1143864SN/A    SERIALIZE_SCALAR(intrPending);
11449956SN/A    SERIALIZE_SCALAR(dmaAborted);
1145864SN/A    SERIALIZE_ENUM(devState);
1146864SN/A    SERIALIZE_ENUM(dmaState);
1147864SN/A    SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1148848SN/A}
1149848SN/A
1150848SN/Avoid
115110905SN/AIdeDisk::unserialize(CheckpointIn &cp)
1152848SN/A{
1153864SN/A    // Reschedule events that were outstanding
1154864SN/A    // these are all mutually exclusive
1155864SN/A    Tick reschedule = 0;
1156864SN/A    Events_t event = None;
1157864SN/A
1158864SN/A    UNSERIALIZE_SCALAR(reschedule);
1159864SN/A    UNSERIALIZE_ENUM(event);
1160864SN/A
1161864SN/A    switch (event) {
1162864SN/A      case None : break;
11635606SN/A      case Transfer : schedule(dmaTransferEvent, reschedule); break;
11645606SN/A      case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
11655606SN/A      case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
11665606SN/A      case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
11675606SN/A      case DmaRead : schedule(dmaReadEvent, reschedule); break;
11685606SN/A      case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1169864SN/A    }
1170864SN/A
1171864SN/A    // Unserialize device registers
11721817SN/A    UNSERIALIZE_SCALAR(cmdReg.data);
1173864SN/A    UNSERIALIZE_SCALAR(cmdReg.sec_count);
1174864SN/A    UNSERIALIZE_SCALAR(cmdReg.sec_num);
1175864SN/A    UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1176864SN/A    UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1177864SN/A    UNSERIALIZE_SCALAR(cmdReg.drive);
1178920SN/A    UNSERIALIZE_SCALAR(cmdReg.command);
1179893SN/A    UNSERIALIZE_SCALAR(status);
1180864SN/A    UNSERIALIZE_SCALAR(nIENBit);
1181864SN/A    UNSERIALIZE_SCALAR(devID);
1182864SN/A
1183864SN/A    // Unserialize the PRD related information
1184864SN/A    UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1185864SN/A    UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1186864SN/A    UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1187864SN/A    UNSERIALIZE_SCALAR(curPrdAddr);
1188864SN/A
11892565SN/A    /** @todo need to serialized chunk generator stuff!! */
1190864SN/A    // Unserialize current transfer related information
1191893SN/A    UNSERIALIZE_SCALAR(cmdBytes);
1192864SN/A    UNSERIALIZE_SCALAR(cmdBytesLeft);
1193864SN/A    UNSERIALIZE_SCALAR(drqBytesLeft);
1194864SN/A    UNSERIALIZE_SCALAR(curSector);
1195864SN/A    UNSERIALIZE_SCALAR(dmaRead);
1196864SN/A    UNSERIALIZE_SCALAR(intrPending);
11979956SN/A    UNSERIALIZE_SCALAR(dmaAborted);
1198864SN/A    UNSERIALIZE_ENUM(devState);
1199864SN/A    UNSERIALIZE_ENUM(dmaState);
1200864SN/A    UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1201848SN/A}
1202848SN/A
12034762SN/AIdeDisk *
12044762SN/AIdeDiskParams::create()
1205848SN/A{
12065034SN/A    return new IdeDisk(this);
1207848SN/A}
1208