ide_disk.cc revision 12392
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), 7112087Sspwilson2@wisc.edu dmaTransferEvent([this]{ doDmaTransfer(); }, name()), 7212087Sspwilson2@wisc.edu dmaReadCG(NULL), 7312087Sspwilson2@wisc.edu dmaReadWaitEvent([this]{ doDmaRead(); }, name()), 7412087Sspwilson2@wisc.edu dmaWriteCG(NULL), 7512087Sspwilson2@wisc.edu dmaWriteWaitEvent([this]{ doDmaWrite(); }, name()), 7612087Sspwilson2@wisc.edu dmaPrdReadEvent([this]{ dmaPrdReadDone(); }, name()), 7712087Sspwilson2@wisc.edu dmaReadEvent([this]{ dmaReadDone(); }, name()), 7812087Sspwilson2@wisc.edu dmaWriteEvent([this]{ dmaWriteDone(); }, name()) 79848SN/A{ 80893SN/A // Reset the device state 815034SN/A reset(p->driveID); 82893SN/A 83849SN/A // fill out the drive ID structure 841722SN/A memset(&driveID, 0, sizeof(struct ataparams)); 85849SN/A 86849SN/A // Calculate LBA and C/H/S values 87849SN/A uint16_t cylinders; 88849SN/A uint8_t heads; 89849SN/A uint8_t sectors; 90849SN/A 91849SN/A uint32_t lba_size = image->size(); 92849SN/A if (lba_size >= 16383*16*63) { 93849SN/A cylinders = 16383; 94849SN/A heads = 16; 95849SN/A sectors = 63; 96849SN/A } else { 97849SN/A if (lba_size >= 63) 98849SN/A sectors = 63; 9911101SN/A else if (lba_size == 0) 10011101SN/A panic("Bad IDE image size: 0\n"); 101849SN/A else 102849SN/A sectors = lba_size; 103849SN/A 104849SN/A if ((lba_size / sectors) >= 16) 105849SN/A heads = 16; 106849SN/A else 107849SN/A heads = (lba_size / sectors); 108849SN/A 109849SN/A cylinders = lba_size / (heads * sectors); 110849SN/A } 111849SN/A 112849SN/A // Setup the model name 1131853SN/A strncpy((char *)driveID.atap_model, "5MI EDD si k", 1141853SN/A sizeof(driveID.atap_model)); 115849SN/A // Set the maximum multisector transfer size 1161722SN/A driveID.atap_multi = MAX_MULTSECT; 117849SN/A // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 1181722SN/A driveID.atap_capabilities1 = 0x7; 119849SN/A // UDMA support, EIDE support 1201722SN/A driveID.atap_extensions = 0x6; 121849SN/A // Setup default C/H/S settings 1221722SN/A driveID.atap_cylinders = cylinders; 1231722SN/A driveID.atap_sectors = sectors; 1241722SN/A driveID.atap_heads = heads; 125849SN/A // Setup the current multisector transfer size 1261722SN/A driveID.atap_curmulti = MAX_MULTSECT; 1271722SN/A driveID.atap_curmulti_valid = 0x1; 128849SN/A // Number of sectors on disk 1291722SN/A driveID.atap_capacity = lba_size; 130849SN/A // Multiword DMA mode 2 and below supported 1312989SN/A driveID.atap_dmamode_supp = 0x4; 132849SN/A // Set PIO mode 4 and 3 supported 1331722SN/A driveID.atap_piomode_supp = 0x3; 134849SN/A // Set DMA mode 4 and below supported 1351886SN/A driveID.atap_udmamode_supp = 0x1f; 136849SN/A // Statically set hardware config word 1371722SN/A driveID.atap_hwreset_res = 0x4001; 1381817SN/A 1391817SN/A //arbitrary for now... 1401817SN/A driveID.atap_ata_major = WDC_VER_ATA7; 141893SN/A} 142893SN/A 143893SN/AIdeDisk::~IdeDisk() 144893SN/A{ 145893SN/A // destroy the data buffer 146893SN/A delete [] dataBuffer; 147893SN/A} 148893SN/A 149893SN/Avoid 150893SN/AIdeDisk::reset(int id) 151893SN/A{ 152893SN/A // initialize the data buffer and shadow registers 153893SN/A dataBuffer = new uint8_t[MAX_DMA_SIZE]; 154893SN/A 155893SN/A memset(dataBuffer, 0, MAX_DMA_SIZE); 156893SN/A memset(&cmdReg, 0, sizeof(CommandReg_t)); 157893SN/A memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 158893SN/A 159893SN/A curPrdAddr = 0; 160893SN/A curSector = 0; 161893SN/A cmdBytes = 0; 162893SN/A cmdBytesLeft = 0; 163893SN/A drqBytesLeft = 0; 164893SN/A dmaRead = false; 165893SN/A intrPending = false; 1669956SN/A dmaAborted = false; 167849SN/A 168849SN/A // set the device state to idle 169849SN/A dmaState = Dma_Idle; 170849SN/A 171849SN/A if (id == DEV0) { 172849SN/A devState = Device_Idle_S; 173849SN/A devID = DEV0; 174849SN/A } else if (id == DEV1) { 175849SN/A devState = Device_Idle_NS; 176849SN/A devID = DEV1; 177849SN/A } else { 178849SN/A panic("Invalid device ID: %#x\n", id); 179849SN/A } 180849SN/A 181849SN/A // set the device ready bit 182893SN/A status = STATUS_DRDY_BIT; 1831817SN/A 1841817SN/A /* The error register must be set to 0x1 on start-up to 1851817SN/A indicate that no diagnostic error was detected */ 1861817SN/A cmdReg.error = 0x1; 187849SN/A} 188849SN/A 189864SN/A//// 190864SN/A// Utility functions 191864SN/A//// 192864SN/A 193929SN/Abool 194929SN/AIdeDisk::isDEVSelect() 195929SN/A{ 196929SN/A return ctrl->isDiskSelected(this); 197929SN/A} 198929SN/A 199861SN/AAddr 200864SN/AIdeDisk::pciToDma(Addr pciAddr) 201861SN/A{ 202861SN/A if (ctrl) 2035772SN/A return ctrl->pciToDma(pciAddr); 204861SN/A else 205861SN/A panic("Access to unset controller!\n"); 206861SN/A} 207861SN/A 208849SN/A//// 209849SN/A// Device registers read/write 210849SN/A//// 211849SN/A 212849SN/Avoid 2135772SN/AIdeDisk::readCommand(const Addr offset, int size, uint8_t *data) 214849SN/A{ 2155772SN/A if (offset == DATA_OFFSET) { 2165772SN/A if (size == sizeof(uint16_t)) { 2175772SN/A *(uint16_t *)data = cmdReg.data; 2185772SN/A } else if (size == sizeof(uint32_t)) { 2195772SN/A *(uint16_t *)data = cmdReg.data; 2205772SN/A updateState(ACT_DATA_READ_SHORT); 2215772SN/A *((uint16_t *)data + 1) = cmdReg.data; 2225772SN/A } else { 2235772SN/A panic("Data read of unsupported size %d.\n", size); 2241817SN/A } 2255772SN/A updateState(ACT_DATA_READ_SHORT); 2265772SN/A return; 2275772SN/A } 2285772SN/A assert(size == sizeof(uint8_t)); 2295772SN/A switch (offset) { 2305772SN/A case ERROR_OFFSET: 2315772SN/A *data = cmdReg.error; 2321817SN/A break; 2335772SN/A case NSECTOR_OFFSET: 2345772SN/A *data = cmdReg.sec_count; 2355772SN/A break; 2365772SN/A case SECTOR_OFFSET: 2375772SN/A *data = cmdReg.sec_num; 2385772SN/A break; 2395772SN/A case LCYL_OFFSET: 2405772SN/A *data = cmdReg.cyl_low; 2415772SN/A break; 2425772SN/A case HCYL_OFFSET: 2435772SN/A *data = cmdReg.cyl_high; 2445772SN/A break; 2455772SN/A case DRIVE_OFFSET: 2465772SN/A *data = cmdReg.drive; 2475772SN/A break; 2485772SN/A case STATUS_OFFSET: 2495772SN/A *data = status; 2505772SN/A updateState(ACT_STAT_READ); 2511817SN/A break; 2521817SN/A default: 2535772SN/A panic("Invalid IDE command register offset: %#x\n", offset); 254849SN/A } 2555772SN/A DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data); 256849SN/A} 257849SN/A 258849SN/Avoid 2595772SN/AIdeDisk::readControl(const Addr offset, int size, uint8_t *data) 260849SN/A{ 2615772SN/A assert(size == sizeof(uint8_t)); 2625772SN/A *data = status; 2635772SN/A if (offset != ALTSTAT_OFFSET) 2645772SN/A panic("Invalid IDE control register offset: %#x\n", offset); 2655772SN/A DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data); 2665772SN/A} 267849SN/A 2685772SN/Avoid 2695772SN/AIdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data) 2705772SN/A{ 2715772SN/A if (offset == DATA_OFFSET) { 2725772SN/A if (size == sizeof(uint16_t)) { 2735772SN/A cmdReg.data = *(const uint16_t *)data; 2745772SN/A } else if (size == sizeof(uint32_t)) { 2755772SN/A cmdReg.data = *(const uint16_t *)data; 2765772SN/A updateState(ACT_DATA_WRITE_SHORT); 2775772SN/A cmdReg.data = *((const uint16_t *)data + 1); 2785772SN/A } else { 2795772SN/A panic("Data write of unsupported size %d.\n", size); 2801817SN/A } 2815772SN/A updateState(ACT_DATA_WRITE_SHORT); 2825772SN/A return; 2835772SN/A } 2845772SN/A 2855772SN/A assert(size == sizeof(uint8_t)); 2865772SN/A switch (offset) { 2875772SN/A case FEATURES_OFFSET: 2881817SN/A break; 2895772SN/A case NSECTOR_OFFSET: 2905772SN/A cmdReg.sec_count = *data; 2915772SN/A break; 2925772SN/A case SECTOR_OFFSET: 2935772SN/A cmdReg.sec_num = *data; 2945772SN/A break; 2955772SN/A case LCYL_OFFSET: 2965772SN/A cmdReg.cyl_low = *data; 2975772SN/A break; 2985772SN/A case HCYL_OFFSET: 2995772SN/A cmdReg.cyl_high = *data; 3005772SN/A break; 3015772SN/A case DRIVE_OFFSET: 3025772SN/A cmdReg.drive = *data; 3035772SN/A updateState(ACT_SELECT_WRITE); 3045772SN/A break; 3055772SN/A case COMMAND_OFFSET: 3065772SN/A cmdReg.command = *data; 3075772SN/A updateState(ACT_CMD_WRITE); 3081817SN/A break; 3091817SN/A default: 3105772SN/A panic("Invalid IDE command register offset: %#x\n", offset); 311849SN/A } 3125772SN/A DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, 3135772SN/A (uint32_t)*data); 3145772SN/A} 3155772SN/A 3165772SN/Avoid 3175772SN/AIdeDisk::writeControl(const Addr offset, int size, const uint8_t *data) 3185772SN/A{ 3195772SN/A if (offset != CONTROL_OFFSET) 3205772SN/A panic("Invalid IDE control register offset: %#x\n", offset); 3215772SN/A 3225772SN/A if (*data & CONTROL_RST_BIT) { 3235772SN/A // force the device into the reset state 3245772SN/A devState = Device_Srst; 3255772SN/A updateState(ACT_SRST_SET); 3265772SN/A } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) { 3275772SN/A updateState(ACT_SRST_CLEAR); 3285772SN/A } 3295772SN/A 3305772SN/A nIENBit = *data & CONTROL_IEN_BIT; 331849SN/A 3322566SN/A DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, 3332566SN/A (uint32_t)*data); 334849SN/A} 335849SN/A 336849SN/A//// 337849SN/A// Perform DMA transactions 338849SN/A//// 339849SN/A 340849SN/Avoid 341849SN/AIdeDisk::doDmaTransfer() 342849SN/A{ 3439956SN/A if (dmaAborted) { 3449956SN/A DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n"); 3459956SN/A updateState(ACT_CMD_ERROR); 3469956SN/A return; 3479956SN/A } 3489956SN/A 349849SN/A if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 350849SN/A panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 351849SN/A dmaState, devState); 352849SN/A 35310913SN/A if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 3547823SN/A schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD); 3552565SN/A return; 3562565SN/A } else 3572565SN/A ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent, 3582565SN/A (uint8_t*)&curPrd.entry); 359849SN/A} 360849SN/A 361849SN/Avoid 362849SN/AIdeDisk::dmaPrdReadDone() 363849SN/A{ 3649956SN/A if (dmaAborted) { 3659956SN/A DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n"); 3669956SN/A updateState(ACT_CMD_ERROR); 3679956SN/A return; 3689956SN/A } 3698522SN/A 3701625SN/A DPRINTF(IdeDisk, 3711625SN/A "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", 372896SN/A curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), 373896SN/A curPrd.getByteCount(), (cmdBytesLeft/SectorSize), 374896SN/A curPrd.getEOT(), curSector); 375896SN/A 376989SN/A // the prd pointer has already been translated, so just do an increment 377989SN/A curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); 378849SN/A 379849SN/A if (dmaRead) 3802565SN/A doDmaDataRead(); 381849SN/A else 3822565SN/A doDmaDataWrite(); 383849SN/A} 384849SN/A 385849SN/Avoid 3862565SN/AIdeDisk::doDmaDataRead() 387849SN/A{ 3881763SN/A /** @todo we need to figure out what the delay actually will be */ 389864SN/A Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 390849SN/A 3911634SN/A DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", 3921634SN/A diskDelay, totalDiskDelay); 393849SN/A 3947823SN/A schedule(dmaReadWaitEvent, curTick() + totalDiskDelay); 3952565SN/A} 396864SN/A 3972627SN/Avoid 3982627SN/AIdeDisk::regStats() 3992627SN/A{ 40011522Sstephan.diestelhorst@arm.com SimObject::regStats(); 40111522Sstephan.diestelhorst@arm.com 4022627SN/A using namespace Stats; 4032627SN/A dmaReadFullPages 4042627SN/A .name(name() + ".dma_read_full_pages") 4052627SN/A .desc("Number of full page size DMA reads (not PRD).") 4062627SN/A ; 4072627SN/A dmaReadBytes 4082627SN/A .name(name() + ".dma_read_bytes") 4092627SN/A .desc("Number of bytes transfered via DMA reads (not PRD).") 4102627SN/A ; 4112627SN/A dmaReadTxs 4122627SN/A .name(name() + ".dma_read_txs") 4132627SN/A .desc("Number of DMA read transactions (not PRD).") 4142627SN/A ; 4152627SN/A 4162627SN/A dmaWriteFullPages 4172627SN/A .name(name() + ".dma_write_full_pages") 4182627SN/A .desc("Number of full page size DMA writes.") 4192627SN/A ; 4202627SN/A dmaWriteBytes 4212627SN/A .name(name() + ".dma_write_bytes") 4222627SN/A .desc("Number of bytes transfered via DMA writes.") 4232627SN/A ; 4242627SN/A dmaWriteTxs 4252627SN/A .name(name() + ".dma_write_txs") 4262627SN/A .desc("Number of DMA write transactions.") 4272627SN/A ; 4282627SN/A} 429864SN/A 4302565SN/Avoid 4312565SN/AIdeDisk::doDmaRead() 4322565SN/A{ 4339956SN/A if (dmaAborted) { 4349956SN/A DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n"); 4359956SN/A if (dmaReadCG) 4369956SN/A delete dmaReadCG; 4379956SN/A dmaReadCG = NULL; 4389956SN/A updateState(ACT_CMD_ERROR); 4399956SN/A return; 4409956SN/A } 441864SN/A 4422565SN/A if (!dmaReadCG) { 4432565SN/A // clear out the data buffer 4442565SN/A memset(dataBuffer, 0, MAX_DMA_SIZE); 4452565SN/A dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(), 4462565SN/A curPrd.getByteCount(), TheISA::PageBytes); 4472565SN/A 4482565SN/A } 44910913SN/A if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 4507823SN/A schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD); 4512565SN/A return; 4522565SN/A } else if (!dmaReadCG->done()) { 4532565SN/A assert(dmaReadCG->complete() < MAX_DMA_SIZE); 4542565SN/A ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(), 4552565SN/A &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete()); 4562627SN/A dmaReadBytes += dmaReadCG->size(); 4572627SN/A dmaReadTxs++; 4582627SN/A if (dmaReadCG->size() == TheISA::PageBytes) 4592627SN/A dmaReadFullPages++; 4602565SN/A dmaReadCG->next(); 461849SN/A } else { 4622565SN/A assert(dmaReadCG->done()); 4632565SN/A delete dmaReadCG; 4642565SN/A dmaReadCG = NULL; 4652565SN/A dmaReadDone(); 466849SN/A } 467849SN/A} 468849SN/A 469849SN/Avoid 470849SN/AIdeDisk::dmaReadDone() 471849SN/A{ 4722565SN/A uint32_t bytesWritten = 0; 473861SN/A 474861SN/A // write the data to the disk image 4752565SN/A for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); 476864SN/A bytesWritten += SectorSize) { 477861SN/A 4782565SN/A cmdBytesLeft -= SectorSize; 479861SN/A writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 480864SN/A } 481861SN/A 482849SN/A // check for the EOT 483920SN/A if (curPrd.getEOT()) { 484849SN/A assert(cmdBytesLeft == 0); 485849SN/A dmaState = Dma_Idle; 486849SN/A updateState(ACT_DMA_DONE); 487849SN/A } else { 488849SN/A doDmaTransfer(); 489849SN/A } 490849SN/A} 491849SN/A 492849SN/Avoid 4932565SN/AIdeDisk::doDmaDataWrite() 494849SN/A{ 4951763SN/A /** @todo we need to figure out what the delay actually will be */ 496864SN/A Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 4972565SN/A uint32_t bytesRead = 0; 498849SN/A 4991634SN/A DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", 5001634SN/A diskDelay, totalDiskDelay); 5011634SN/A 5022565SN/A memset(dataBuffer, 0, MAX_DMA_SIZE); 5032565SN/A assert(cmdBytesLeft <= MAX_DMA_SIZE); 5042565SN/A while (bytesRead < curPrd.getByteCount()) { 5052565SN/A readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 5062565SN/A bytesRead += SectorSize; 5072565SN/A cmdBytesLeft -= SectorSize; 5082565SN/A } 5098522SN/A DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n", 5108522SN/A bytesRead, cmdBytesLeft); 511849SN/A 5127823SN/A schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay); 5132565SN/A} 514864SN/A 5152565SN/Avoid 5162565SN/AIdeDisk::doDmaWrite() 5172565SN/A{ 5189956SN/A if (dmaAborted) { 5199956SN/A DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n"); 5209956SN/A if (dmaWriteCG) 5219956SN/A delete dmaWriteCG; 5229956SN/A dmaWriteCG = NULL; 5239956SN/A updateState(ACT_CMD_ERROR); 5249956SN/A return; 5259956SN/A } 5262565SN/A if (!dmaWriteCG) { 5272565SN/A // clear out the data buffer 5282565SN/A dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), 5292565SN/A curPrd.getByteCount(), TheISA::PageBytes); 5302565SN/A } 53110913SN/A if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 5327823SN/A schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD); 5338522SN/A DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n"); 5342565SN/A return; 5352565SN/A } else if (!dmaWriteCG->done()) { 5362565SN/A assert(dmaWriteCG->complete() < MAX_DMA_SIZE); 5372565SN/A ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(), 5382565SN/A &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete()); 5398522SN/A DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n", 5408522SN/A curPrd.getByteCount(), curPrd.getEOT()); 5412627SN/A dmaWriteBytes += dmaWriteCG->size(); 5422627SN/A dmaWriteTxs++; 5432627SN/A if (dmaWriteCG->size() == TheISA::PageBytes) 5442627SN/A dmaWriteFullPages++; 5452565SN/A dmaWriteCG->next(); 546849SN/A } else { 5478522SN/A DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n", 5488522SN/A curPrd.getByteCount(), curPrd.getEOT()); 5492565SN/A assert(dmaWriteCG->done()); 5502565SN/A delete dmaWriteCG; 5512565SN/A dmaWriteCG = NULL; 5522565SN/A dmaWriteDone(); 553849SN/A } 554849SN/A} 555849SN/A 556849SN/Avoid 557849SN/AIdeDisk::dmaWriteDone() 558849SN/A{ 5598522SN/A DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n", 5608522SN/A curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft); 561849SN/A // check for the EOT 562849SN/A if (curPrd.getEOT()) { 563849SN/A assert(cmdBytesLeft == 0); 564849SN/A dmaState = Dma_Idle; 565849SN/A updateState(ACT_DMA_DONE); 566849SN/A } else { 567849SN/A doDmaTransfer(); 568849SN/A } 569849SN/A} 570849SN/A 571849SN/A//// 572849SN/A// Disk utility routines 573849SN/A/// 574849SN/A 575849SN/Avoid 576849SN/AIdeDisk::readDisk(uint32_t sector, uint8_t *data) 577849SN/A{ 578849SN/A uint32_t bytesRead = image->read(data, sector); 579849SN/A 580849SN/A if (bytesRead != SectorSize) 581849SN/A panic("Can't read from %s. Only %d of %d read. errno=%d\n", 582849SN/A name(), bytesRead, SectorSize, errno); 583849SN/A} 584849SN/A 585849SN/Avoid 586849SN/AIdeDisk::writeDisk(uint32_t sector, uint8_t *data) 587849SN/A{ 588849SN/A uint32_t bytesWritten = image->write(data, sector); 589849SN/A 590849SN/A if (bytesWritten != SectorSize) 591849SN/A panic("Can't write to %s. Only %d of %d written. errno=%d\n", 592849SN/A name(), bytesWritten, SectorSize, errno); 593849SN/A} 594849SN/A 595849SN/A//// 596849SN/A// Setup and handle commands 597849SN/A//// 598849SN/A 599849SN/Avoid 600849SN/AIdeDisk::startDma(const uint32_t &prdTableBase) 601849SN/A{ 602849SN/A if (dmaState != Dma_Start) 603849SN/A panic("Inconsistent DMA state, should be in Dma_Start!\n"); 604849SN/A 605849SN/A if (devState != Transfer_Data_Dma) 606849SN/A panic("Inconsistent device state for DMA start!\n"); 607849SN/A 608896SN/A // PRD base address is given by bits 31:2 609896SN/A curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); 610849SN/A 611849SN/A dmaState = Dma_Transfer; 612849SN/A 613849SN/A // schedule dma transfer (doDmaTransfer) 6147823SN/A schedule(dmaTransferEvent, curTick() + 1); 615849SN/A} 616849SN/A 617849SN/Avoid 618849SN/AIdeDisk::abortDma() 619849SN/A{ 620849SN/A if (dmaState == Dma_Idle) 6211625SN/A panic("Inconsistent DMA state, should be Start or Transfer!"); 622849SN/A 623849SN/A if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 6241625SN/A panic("Inconsistent device state, should be Transfer or Prepare!\n"); 625849SN/A 626849SN/A updateState(ACT_CMD_ERROR); 627849SN/A} 628849SN/A 629849SN/Avoid 630849SN/AIdeDisk::startCommand() 631849SN/A{ 632849SN/A DevAction_t action = ACT_NONE; 633849SN/A uint32_t size = 0; 634849SN/A dmaRead = false; 635849SN/A 636849SN/A // Decode commands 637849SN/A switch (cmdReg.command) { 638849SN/A // Supported non-data commands 6391722SN/A case WDSF_READ_NATIVE_MAX: 6409533SN/A size = (uint32_t)image->size() - 1; 641849SN/A cmdReg.sec_num = (size & 0xff); 642849SN/A cmdReg.cyl_low = ((size & 0xff00) >> 8); 643849SN/A cmdReg.cyl_high = ((size & 0xff0000) >> 16); 644849SN/A cmdReg.head = ((size & 0xf000000) >> 24); 645849SN/A 646849SN/A devState = Command_Execution; 647849SN/A action = ACT_CMD_COMPLETE; 648849SN/A break; 649849SN/A 6501722SN/A case WDCC_RECAL: 6511722SN/A case WDCC_IDP: 6521722SN/A case WDCC_STANDBY_IMMED: 6531722SN/A case WDCC_FLUSHCACHE: 6541722SN/A case WDSF_VERIFY: 6551722SN/A case WDSF_SEEK: 6561722SN/A case SET_FEATURES: 6571722SN/A case WDCC_SETMULTI: 65810587SN/A case WDCC_IDLE: 659849SN/A devState = Command_Execution; 660849SN/A action = ACT_CMD_COMPLETE; 661849SN/A break; 662849SN/A 663849SN/A // Supported PIO data-in commands 6641722SN/A case WDCC_IDENTIFY: 66511980Sjason@lowepower.com case ATAPI_IDENTIFY_DEVICE: 6661722SN/A cmdBytes = cmdBytesLeft = sizeof(struct ataparams); 667849SN/A devState = Prepare_Data_In; 668849SN/A action = ACT_DATA_READY; 669849SN/A break; 670849SN/A 6711722SN/A case WDCC_READMULTI: 6721722SN/A case WDCC_READ: 673849SN/A if (!(cmdReg.drive & DRIVE_LBA_BIT)) 674849SN/A panic("Attempt to perform CHS access, only supports LBA\n"); 675849SN/A 676849SN/A if (cmdReg.sec_count == 0) 677893SN/A cmdBytes = cmdBytesLeft = (256 * SectorSize); 678849SN/A else 679893SN/A cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 680849SN/A 681849SN/A curSector = getLBABase(); 682849SN/A 683877SN/A /** @todo make this a scheduled event to simulate disk delay */ 684849SN/A devState = Prepare_Data_In; 685849SN/A action = ACT_DATA_READY; 686849SN/A break; 687849SN/A 688849SN/A // Supported PIO data-out commands 6891722SN/A case WDCC_WRITEMULTI: 6901722SN/A case WDCC_WRITE: 691849SN/A if (!(cmdReg.drive & DRIVE_LBA_BIT)) 692849SN/A panic("Attempt to perform CHS access, only supports LBA\n"); 693849SN/A 694849SN/A if (cmdReg.sec_count == 0) 695893SN/A cmdBytes = cmdBytesLeft = (256 * SectorSize); 696849SN/A else 697893SN/A cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 6988522SN/A DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft); 699849SN/A curSector = getLBABase(); 700849SN/A 701849SN/A devState = Prepare_Data_Out; 702849SN/A action = ACT_DATA_READY; 703849SN/A break; 704849SN/A 705849SN/A // Supported DMA commands 7061722SN/A case WDCC_WRITEDMA: 707849SN/A dmaRead = true; // a write to the disk is a DMA read from memory 70812392Sjason@lowepower.com M5_FALLTHROUGH; 7091722SN/A case WDCC_READDMA: 710849SN/A if (!(cmdReg.drive & DRIVE_LBA_BIT)) 711849SN/A panic("Attempt to perform CHS access, only supports LBA\n"); 712849SN/A 713849SN/A if (cmdReg.sec_count == 0) 714893SN/A cmdBytes = cmdBytesLeft = (256 * SectorSize); 715849SN/A else 716893SN/A cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 7178522SN/A DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft); 718849SN/A 719849SN/A curSector = getLBABase(); 720849SN/A 721849SN/A devState = Prepare_Data_Dma; 722849SN/A action = ACT_DMA_READY; 723849SN/A break; 724849SN/A 725849SN/A default: 726849SN/A panic("Unsupported ATA command: %#x\n", cmdReg.command); 727849SN/A } 728849SN/A 729849SN/A if (action != ACT_NONE) { 730849SN/A // set the BSY bit 731893SN/A status |= STATUS_BSY_BIT; 732849SN/A // clear the DRQ bit 733893SN/A status &= ~STATUS_DRQ_BIT; 734893SN/A // clear the DF bit 735893SN/A status &= ~STATUS_DF_BIT; 736849SN/A 737849SN/A updateState(action); 738849SN/A } 739849SN/A} 740849SN/A 741849SN/A//// 742849SN/A// Handle setting and clearing interrupts 743849SN/A//// 744849SN/A 745849SN/Avoid 746849SN/AIdeDisk::intrPost() 747849SN/A{ 7481625SN/A DPRINTF(IdeDisk, "Posting Interrupt\n"); 749849SN/A if (intrPending) 750849SN/A panic("Attempt to post an interrupt with one pending\n"); 751849SN/A 752849SN/A intrPending = true; 753849SN/A 754849SN/A // talk to controller to set interrupt 7551817SN/A if (ctrl) { 756849SN/A ctrl->intrPost(); 7571817SN/A } 758849SN/A} 759849SN/A 760849SN/Avoid 761849SN/AIdeDisk::intrClear() 762849SN/A{ 7631625SN/A DPRINTF(IdeDisk, "Clearing Interrupt\n"); 764849SN/A if (!intrPending) 765849SN/A panic("Attempt to clear a non-pending interrupt\n"); 766849SN/A 767849SN/A intrPending = false; 768849SN/A 769849SN/A // talk to controller to clear interrupt 770849SN/A if (ctrl) 771849SN/A ctrl->intrClear(); 772849SN/A} 773849SN/A 774849SN/A//// 775849SN/A// Manage the device internal state machine 776849SN/A//// 777849SN/A 778849SN/Avoid 779849SN/AIdeDisk::updateState(DevAction_t action) 780849SN/A{ 781849SN/A switch (devState) { 782893SN/A case Device_Srst: 783893SN/A if (action == ACT_SRST_SET) { 784893SN/A // set the BSY bit 785893SN/A status |= STATUS_BSY_BIT; 786893SN/A } else if (action == ACT_SRST_CLEAR) { 787893SN/A // clear the BSY bit 788893SN/A status &= ~STATUS_BSY_BIT; 789893SN/A 790893SN/A // reset the device state 791893SN/A reset(devID); 792893SN/A } 793893SN/A break; 794893SN/A 795849SN/A case Device_Idle_S: 796893SN/A if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 797849SN/A devState = Device_Idle_NS; 798893SN/A } else if (action == ACT_CMD_WRITE) { 799849SN/A startCommand(); 800893SN/A } 801849SN/A 802849SN/A break; 803849SN/A 804849SN/A case Device_Idle_SI: 805893SN/A if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 806849SN/A devState = Device_Idle_NS; 807849SN/A intrClear(); 808849SN/A } else if (action == ACT_STAT_READ || isIENSet()) { 809849SN/A devState = Device_Idle_S; 810849SN/A intrClear(); 811849SN/A } else if (action == ACT_CMD_WRITE) { 812849SN/A intrClear(); 813849SN/A startCommand(); 814849SN/A } 815849SN/A 816849SN/A break; 817849SN/A 818849SN/A case Device_Idle_NS: 819893SN/A if (action == ACT_SELECT_WRITE && isDEVSelect()) { 820849SN/A if (!isIENSet() && intrPending) { 821849SN/A devState = Device_Idle_SI; 822849SN/A intrPost(); 823849SN/A } 824849SN/A if (isIENSet() || !intrPending) { 825849SN/A devState = Device_Idle_S; 826849SN/A } 827849SN/A } 828849SN/A break; 829849SN/A 830849SN/A case Command_Execution: 831849SN/A if (action == ACT_CMD_COMPLETE) { 832849SN/A // clear the BSY bit 833849SN/A setComplete(); 834849SN/A 835849SN/A if (!isIENSet()) { 836849SN/A devState = Device_Idle_SI; 837849SN/A intrPost(); 838849SN/A } else { 839849SN/A devState = Device_Idle_S; 840849SN/A } 841849SN/A } 842849SN/A break; 843849SN/A 844849SN/A case Prepare_Data_In: 845849SN/A if (action == ACT_CMD_ERROR) { 846849SN/A // clear the BSY bit 847849SN/A setComplete(); 848849SN/A 849849SN/A if (!isIENSet()) { 850849SN/A devState = Device_Idle_SI; 851849SN/A intrPost(); 852849SN/A } else { 853849SN/A devState = Device_Idle_S; 854849SN/A } 855849SN/A } else if (action == ACT_DATA_READY) { 856849SN/A // clear the BSY bit 857893SN/A status &= ~STATUS_BSY_BIT; 858849SN/A // set the DRQ bit 859893SN/A status |= STATUS_DRQ_BIT; 860849SN/A 861877SN/A // copy the data into the data buffer 86211980Sjason@lowepower.com if (cmdReg.command == WDCC_IDENTIFY || 86311980Sjason@lowepower.com cmdReg.command == ATAPI_IDENTIFY_DEVICE) { 864877SN/A // Reset the drqBytes for this block 8651722SN/A drqBytesLeft = sizeof(struct ataparams); 866877SN/A 867877SN/A memcpy((void *)dataBuffer, (void *)&driveID, 8681722SN/A sizeof(struct ataparams)); 869877SN/A } else { 870877SN/A // Reset the drqBytes for this block 871877SN/A drqBytesLeft = SectorSize; 872877SN/A 873877SN/A readDisk(curSector++, dataBuffer); 874877SN/A } 875877SN/A 876849SN/A // put the first two bytes into the data register 8771817SN/A memcpy((void *)&cmdReg.data, (void *)dataBuffer, 878857SN/A sizeof(uint16_t)); 879857SN/A 880849SN/A if (!isIENSet()) { 881849SN/A devState = Data_Ready_INTRQ_In; 882849SN/A intrPost(); 883849SN/A } else { 884849SN/A devState = Transfer_Data_In; 885849SN/A } 886849SN/A } 887849SN/A break; 888849SN/A 889849SN/A case Data_Ready_INTRQ_In: 890849SN/A if (action == ACT_STAT_READ) { 891849SN/A devState = Transfer_Data_In; 892849SN/A intrClear(); 893849SN/A } 894849SN/A break; 895849SN/A 896849SN/A case Transfer_Data_In: 897849SN/A if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 898849SN/A if (action == ACT_DATA_READ_BYTE) { 899849SN/A panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 900849SN/A } else { 901849SN/A drqBytesLeft -= 2; 902849SN/A cmdBytesLeft -= 2; 903849SN/A 904849SN/A // copy next short into data registers 905877SN/A if (drqBytesLeft) 9061817SN/A memcpy((void *)&cmdReg.data, 907877SN/A (void *)&dataBuffer[SectorSize - drqBytesLeft], 908877SN/A sizeof(uint16_t)); 909849SN/A } 910849SN/A 911849SN/A if (drqBytesLeft == 0) { 912849SN/A if (cmdBytesLeft == 0) { 913849SN/A // Clear the BSY bit 914849SN/A setComplete(); 915849SN/A devState = Device_Idle_S; 916849SN/A } else { 917849SN/A devState = Prepare_Data_In; 918877SN/A // set the BSY_BIT 919893SN/A status |= STATUS_BSY_BIT; 920877SN/A // clear the DRQ_BIT 921893SN/A status &= ~STATUS_DRQ_BIT; 922877SN/A 923877SN/A /** @todo change this to a scheduled event to simulate 924877SN/A disk delay */ 925877SN/A updateState(ACT_DATA_READY); 926849SN/A } 927849SN/A } 928849SN/A } 929849SN/A break; 930849SN/A 931849SN/A case Prepare_Data_Out: 932849SN/A if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 933849SN/A // clear the BSY bit 934849SN/A setComplete(); 935849SN/A 936849SN/A if (!isIENSet()) { 937849SN/A devState = Device_Idle_SI; 938849SN/A intrPost(); 939849SN/A } else { 940849SN/A devState = Device_Idle_S; 941849SN/A } 942893SN/A } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { 943849SN/A // clear the BSY bit 944893SN/A status &= ~STATUS_BSY_BIT; 945849SN/A // set the DRQ bit 946893SN/A status |= STATUS_DRQ_BIT; 947849SN/A 948849SN/A // clear the data buffer to get it ready for writes 949849SN/A memset(dataBuffer, 0, MAX_DMA_SIZE); 950849SN/A 951893SN/A // reset the drqBytes for this block 952893SN/A drqBytesLeft = SectorSize; 953893SN/A 954893SN/A if (cmdBytesLeft == cmdBytes || isIENSet()) { 955893SN/A devState = Transfer_Data_Out; 956893SN/A } else { 957849SN/A devState = Data_Ready_INTRQ_Out; 958849SN/A intrPost(); 959849SN/A } 960849SN/A } 961849SN/A break; 962849SN/A 963849SN/A case Data_Ready_INTRQ_Out: 964849SN/A if (action == ACT_STAT_READ) { 965849SN/A devState = Transfer_Data_Out; 966849SN/A intrClear(); 967849SN/A } 968849SN/A break; 969849SN/A 970849SN/A case Transfer_Data_Out: 971857SN/A if (action == ACT_DATA_WRITE_BYTE || 972857SN/A action == ACT_DATA_WRITE_SHORT) { 973857SN/A 974849SN/A if (action == ACT_DATA_READ_BYTE) { 975849SN/A panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 976849SN/A } else { 977849SN/A // copy the latest short into the data buffer 978849SN/A memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 9791817SN/A (void *)&cmdReg.data, 980849SN/A sizeof(uint16_t)); 981849SN/A 982849SN/A drqBytesLeft -= 2; 983849SN/A cmdBytesLeft -= 2; 984849SN/A } 985849SN/A 986849SN/A if (drqBytesLeft == 0) { 987849SN/A // copy the block to the disk 988849SN/A writeDisk(curSector++, dataBuffer); 989849SN/A 990849SN/A // set the BSY bit 991893SN/A status |= STATUS_BSY_BIT; 992893SN/A // set the seek bit 993893SN/A status |= STATUS_SEEK_BIT; 994849SN/A // clear the DRQ bit 995893SN/A status &= ~STATUS_DRQ_BIT; 996849SN/A 997849SN/A devState = Prepare_Data_Out; 998878SN/A 999878SN/A /** @todo change this to a scheduled event to simulate 1000878SN/A disk delay */ 1001878SN/A updateState(ACT_DATA_READY); 1002849SN/A } 1003849SN/A } 1004849SN/A break; 1005849SN/A 1006849SN/A case Prepare_Data_Dma: 1007849SN/A if (action == ACT_CMD_ERROR) { 1008849SN/A // clear the BSY bit 1009849SN/A setComplete(); 1010849SN/A 1011849SN/A if (!isIENSet()) { 1012849SN/A devState = Device_Idle_SI; 1013849SN/A intrPost(); 1014849SN/A } else { 1015849SN/A devState = Device_Idle_S; 1016849SN/A } 1017849SN/A } else if (action == ACT_DMA_READY) { 1018849SN/A // clear the BSY bit 1019893SN/A status &= ~STATUS_BSY_BIT; 1020849SN/A // set the DRQ bit 1021893SN/A status |= STATUS_DRQ_BIT; 1022849SN/A 1023849SN/A devState = Transfer_Data_Dma; 1024849SN/A 1025849SN/A if (dmaState != Dma_Idle) 1026849SN/A panic("Inconsistent DMA state, should be Dma_Idle\n"); 1027849SN/A 1028849SN/A dmaState = Dma_Start; 1029849SN/A // wait for the write to the DMA start bit 1030849SN/A } 1031849SN/A break; 1032849SN/A 1033849SN/A case Transfer_Data_Dma: 10349956SN/A if (action == ACT_CMD_ERROR) { 10359956SN/A dmaAborted = true; 10369956SN/A devState = Device_Dma_Abort; 10379956SN/A } else if (action == ACT_DMA_DONE) { 1038849SN/A // clear the BSY bit 1039849SN/A setComplete(); 1040849SN/A // set the seek bit 1041893SN/A status |= STATUS_SEEK_BIT; 1042849SN/A // clear the controller state for DMA transfer 1043849SN/A ctrl->setDmaComplete(this); 1044849SN/A 1045849SN/A if (!isIENSet()) { 1046849SN/A devState = Device_Idle_SI; 1047849SN/A intrPost(); 1048849SN/A } else { 1049849SN/A devState = Device_Idle_S; 1050849SN/A } 1051849SN/A } 1052849SN/A break; 1053849SN/A 10549956SN/A case Device_Dma_Abort: 10559956SN/A if (action == ACT_CMD_ERROR) { 10569956SN/A setComplete(); 10579956SN/A status |= STATUS_SEEK_BIT; 10589956SN/A ctrl->setDmaComplete(this); 10599956SN/A dmaAborted = false; 10609956SN/A dmaState = Dma_Idle; 10619956SN/A 10629956SN/A if (!isIENSet()) { 10639956SN/A devState = Device_Idle_SI; 10649956SN/A intrPost(); 10659956SN/A } else { 10669956SN/A devState = Device_Idle_S; 10679956SN/A } 10689956SN/A } else { 10699956SN/A DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n"); 10709956SN/A } 10719956SN/A break; 10729956SN/A 1073849SN/A default: 1074849SN/A panic("Unknown IDE device state: %#x\n", devState); 1075849SN/A } 1076848SN/A} 1077848SN/A 1078848SN/Avoid 107910905SN/AIdeDisk::serialize(CheckpointOut &cp) const 1080848SN/A{ 1081864SN/A // Check all outstanding events to see if they are scheduled 1082864SN/A // these are all mutually exclusive 1083864SN/A Tick reschedule = 0; 1084864SN/A Events_t event = None; 1085864SN/A 1086920SN/A int eventCount = 0; 1087920SN/A 1088864SN/A if (dmaTransferEvent.scheduled()) { 1089864SN/A reschedule = dmaTransferEvent.when(); 1090864SN/A event = Transfer; 1091920SN/A eventCount++; 1092920SN/A } 1093920SN/A if (dmaReadWaitEvent.scheduled()) { 1094864SN/A reschedule = dmaReadWaitEvent.when(); 1095864SN/A event = ReadWait; 1096920SN/A eventCount++; 1097920SN/A } 1098920SN/A if (dmaWriteWaitEvent.scheduled()) { 1099864SN/A reschedule = dmaWriteWaitEvent.when(); 1100864SN/A event = WriteWait; 1101920SN/A eventCount++; 1102920SN/A } 1103920SN/A if (dmaPrdReadEvent.scheduled()) { 1104864SN/A reschedule = dmaPrdReadEvent.when(); 1105864SN/A event = PrdRead; 1106920SN/A eventCount++; 1107920SN/A } 1108920SN/A if (dmaReadEvent.scheduled()) { 1109864SN/A reschedule = dmaReadEvent.when(); 1110864SN/A event = DmaRead; 1111920SN/A eventCount++; 1112920SN/A } 1113920SN/A if (dmaWriteEvent.scheduled()) { 1114864SN/A reschedule = dmaWriteEvent.when(); 1115864SN/A event = DmaWrite; 1116920SN/A eventCount++; 1117864SN/A } 1118864SN/A 1119920SN/A assert(eventCount <= 1); 1120920SN/A 1121864SN/A SERIALIZE_SCALAR(reschedule); 1122864SN/A SERIALIZE_ENUM(event); 1123864SN/A 1124864SN/A // Serialize device registers 11251817SN/A SERIALIZE_SCALAR(cmdReg.data); 1126864SN/A SERIALIZE_SCALAR(cmdReg.sec_count); 1127864SN/A SERIALIZE_SCALAR(cmdReg.sec_num); 1128864SN/A SERIALIZE_SCALAR(cmdReg.cyl_low); 1129864SN/A SERIALIZE_SCALAR(cmdReg.cyl_high); 1130864SN/A SERIALIZE_SCALAR(cmdReg.drive); 1131920SN/A SERIALIZE_SCALAR(cmdReg.command); 1132893SN/A SERIALIZE_SCALAR(status); 1133864SN/A SERIALIZE_SCALAR(nIENBit); 1134864SN/A SERIALIZE_SCALAR(devID); 1135864SN/A 1136864SN/A // Serialize the PRD related information 1137864SN/A SERIALIZE_SCALAR(curPrd.entry.baseAddr); 1138864SN/A SERIALIZE_SCALAR(curPrd.entry.byteCount); 1139864SN/A SERIALIZE_SCALAR(curPrd.entry.endOfTable); 1140864SN/A SERIALIZE_SCALAR(curPrdAddr); 1141864SN/A 11422565SN/A /** @todo need to serialized chunk generator stuff!! */ 1143864SN/A // Serialize current transfer related information 1144864SN/A SERIALIZE_SCALAR(cmdBytesLeft); 1145893SN/A SERIALIZE_SCALAR(cmdBytes); 1146864SN/A SERIALIZE_SCALAR(drqBytesLeft); 1147864SN/A SERIALIZE_SCALAR(curSector); 1148864SN/A SERIALIZE_SCALAR(dmaRead); 1149864SN/A SERIALIZE_SCALAR(intrPending); 11509956SN/A SERIALIZE_SCALAR(dmaAborted); 1151864SN/A SERIALIZE_ENUM(devState); 1152864SN/A SERIALIZE_ENUM(dmaState); 1153864SN/A SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1154848SN/A} 1155848SN/A 1156848SN/Avoid 115710905SN/AIdeDisk::unserialize(CheckpointIn &cp) 1158848SN/A{ 1159864SN/A // Reschedule events that were outstanding 1160864SN/A // these are all mutually exclusive 1161864SN/A Tick reschedule = 0; 1162864SN/A Events_t event = None; 1163864SN/A 1164864SN/A UNSERIALIZE_SCALAR(reschedule); 1165864SN/A UNSERIALIZE_ENUM(event); 1166864SN/A 1167864SN/A switch (event) { 1168864SN/A case None : break; 11695606SN/A case Transfer : schedule(dmaTransferEvent, reschedule); break; 11705606SN/A case ReadWait : schedule(dmaReadWaitEvent, reschedule); break; 11715606SN/A case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break; 11725606SN/A case PrdRead : schedule(dmaPrdReadEvent, reschedule); break; 11735606SN/A case DmaRead : schedule(dmaReadEvent, reschedule); break; 11745606SN/A case DmaWrite : schedule(dmaWriteEvent, reschedule); break; 1175864SN/A } 1176864SN/A 1177864SN/A // Unserialize device registers 11781817SN/A UNSERIALIZE_SCALAR(cmdReg.data); 1179864SN/A UNSERIALIZE_SCALAR(cmdReg.sec_count); 1180864SN/A UNSERIALIZE_SCALAR(cmdReg.sec_num); 1181864SN/A UNSERIALIZE_SCALAR(cmdReg.cyl_low); 1182864SN/A UNSERIALIZE_SCALAR(cmdReg.cyl_high); 1183864SN/A UNSERIALIZE_SCALAR(cmdReg.drive); 1184920SN/A UNSERIALIZE_SCALAR(cmdReg.command); 1185893SN/A UNSERIALIZE_SCALAR(status); 1186864SN/A UNSERIALIZE_SCALAR(nIENBit); 1187864SN/A UNSERIALIZE_SCALAR(devID); 1188864SN/A 1189864SN/A // Unserialize the PRD related information 1190864SN/A UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); 1191864SN/A UNSERIALIZE_SCALAR(curPrd.entry.byteCount); 1192864SN/A UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); 1193864SN/A UNSERIALIZE_SCALAR(curPrdAddr); 1194864SN/A 11952565SN/A /** @todo need to serialized chunk generator stuff!! */ 1196864SN/A // Unserialize current transfer related information 1197893SN/A UNSERIALIZE_SCALAR(cmdBytes); 1198864SN/A UNSERIALIZE_SCALAR(cmdBytesLeft); 1199864SN/A UNSERIALIZE_SCALAR(drqBytesLeft); 1200864SN/A UNSERIALIZE_SCALAR(curSector); 1201864SN/A UNSERIALIZE_SCALAR(dmaRead); 1202864SN/A UNSERIALIZE_SCALAR(intrPending); 12039956SN/A UNSERIALIZE_SCALAR(dmaAborted); 1204864SN/A UNSERIALIZE_ENUM(devState); 1205864SN/A UNSERIALIZE_ENUM(dmaState); 1206864SN/A UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1207848SN/A} 1208848SN/A 12094762SN/AIdeDisk * 12104762SN/AIdeDiskParams::create() 1211848SN/A{ 12125034SN/A return new IdeDisk(this); 1213848SN/A} 1214