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