ide_disk.cc revision 2565
1955SN/A/* 2955SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 313576Sciro.santilli@arm.com * All rights reserved. 413576Sciro.santilli@arm.com * 513576Sciro.santilli@arm.com * Redistribution and use in source and binary forms, with or without 613576Sciro.santilli@arm.com * modification, are permitted provided that the following conditions are 713576Sciro.santilli@arm.com * met: redistributions of source code must retain the above copyright 813576Sciro.santilli@arm.com * notice, this list of conditions and the following disclaimer; 913576Sciro.santilli@arm.com * redistributions in binary form must reproduce the above copyright 1013576Sciro.santilli@arm.com * notice, this list of conditions and the following disclaimer in the 1113576Sciro.santilli@arm.com * documentation and/or other materials provided with the distribution; 1213576Sciro.santilli@arm.com * neither the name of the copyright holders nor the names of its 1313576Sciro.santilli@arm.com * contributors may be used to endorse or promote products derived from 141762SN/A * this software without specific prior written permission. 15955SN/A * 16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27955SN/A */ 28955SN/A 29955SN/A/** @file 30955SN/A * Device model implementation for an IDE disk 31955SN/A */ 32955SN/A 33955SN/A#include <cerrno> 34955SN/A#include <cstring> 35955SN/A#include <deque> 36955SN/A#include <string> 37955SN/A 38955SN/A#include "base/chunk_generator.hh" 392665Ssaidi@eecs.umich.edu#include "base/cprintf.hh" // csprintf 404762Snate@binkert.org#include "base/trace.hh" 41955SN/A#include "dev/disk_image.hh" 4212563Sgabeblack@google.com#include "dev/ide_disk.hh" 4312563Sgabeblack@google.com#include "dev/ide_ctrl.hh" 445522Snate@binkert.org#include "dev/tsunami.hh" 456143Snate@binkert.org#include "dev/tsunami_pchip.hh" 4612371Sgabeblack@google.com#include "mem/packet.hh" 474762Snate@binkert.org#include "sim/builder.hh" 485522Snate@binkert.org#include "sim/sim_object.hh" 49955SN/A#include "sim/root.hh" 505522Snate@binkert.org#include "arch/isa_traits.hh" 5111974Sgabeblack@google.com 52955SN/Ausing namespace std; 535522Snate@binkert.orgusing namespace TheISA; 544202Sbinkertn@umich.edu 555742Snate@binkert.orgIdeDisk::IdeDisk(const string &name, DiskImage *img, 56955SN/A int id, Tick delay) 574381Sbinkertn@umich.edu : SimObject(name), ctrl(NULL), image(img), diskDelay(delay), 584381Sbinkertn@umich.edu dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this), 5912246Sgabeblack@google.com dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this), 6012246Sgabeblack@google.com dmaReadEvent(this), dmaWriteEvent(this) 618334Snate@binkert.org{ 62955SN/A // Reset the device state 63955SN/A reset(id); 644202Sbinkertn@umich.edu 65955SN/A // fill out the drive ID structure 664382Sbinkertn@umich.edu memset(&driveID, 0, sizeof(struct ataparams)); 674382Sbinkertn@umich.edu 684382Sbinkertn@umich.edu // Calculate LBA and C/H/S values 696654Snate@binkert.org uint16_t cylinders; 705517Snate@binkert.org uint8_t heads; 718614Sgblack@eecs.umich.edu uint8_t sectors; 727674Snate@binkert.org 736143Snate@binkert.org uint32_t lba_size = image->size(); 746143Snate@binkert.org if (lba_size >= 16383*16*63) { 756143Snate@binkert.org cylinders = 16383; 7612302Sgabeblack@google.com heads = 16; 7712302Sgabeblack@google.com sectors = 63; 7812302Sgabeblack@google.com } else { 7912371Sgabeblack@google.com if (lba_size >= 63) 8012371Sgabeblack@google.com sectors = 63; 8112371Sgabeblack@google.com else 8212371Sgabeblack@google.com sectors = lba_size; 8312371Sgabeblack@google.com 8412371Sgabeblack@google.com if ((lba_size / sectors) >= 16) 8512371Sgabeblack@google.com heads = 16; 8612371Sgabeblack@google.com else 8712371Sgabeblack@google.com heads = (lba_size / sectors); 8812371Sgabeblack@google.com 8912371Sgabeblack@google.com cylinders = lba_size / (heads * sectors); 9012371Sgabeblack@google.com } 9112371Sgabeblack@google.com 9212371Sgabeblack@google.com // Setup the model name 9312371Sgabeblack@google.com strncpy((char *)driveID.atap_model, "5MI EDD si k", 9412371Sgabeblack@google.com sizeof(driveID.atap_model)); 9512371Sgabeblack@google.com // Set the maximum multisector transfer size 9612371Sgabeblack@google.com driveID.atap_multi = MAX_MULTSECT; 9712371Sgabeblack@google.com // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 9812371Sgabeblack@google.com driveID.atap_capabilities1 = 0x7; 9912371Sgabeblack@google.com // UDMA support, EIDE support 10012371Sgabeblack@google.com driveID.atap_extensions = 0x6; 10112371Sgabeblack@google.com // Setup default C/H/S settings 10212371Sgabeblack@google.com driveID.atap_cylinders = cylinders; 10312371Sgabeblack@google.com driveID.atap_sectors = sectors; 10412371Sgabeblack@google.com driveID.atap_heads = heads; 10512371Sgabeblack@google.com // Setup the current multisector transfer size 10612371Sgabeblack@google.com driveID.atap_curmulti = MAX_MULTSECT; 10712371Sgabeblack@google.com driveID.atap_curmulti_valid = 0x1; 10812371Sgabeblack@google.com // Number of sectors on disk 10912371Sgabeblack@google.com driveID.atap_capacity = lba_size; 11012371Sgabeblack@google.com // Multiword DMA mode 2 and below supported 11112371Sgabeblack@google.com driveID.atap_dmamode_supp = 0x400; 11212371Sgabeblack@google.com // Set PIO mode 4 and 3 supported 11312371Sgabeblack@google.com driveID.atap_piomode_supp = 0x3; 11412371Sgabeblack@google.com // Set DMA mode 4 and below supported 11512371Sgabeblack@google.com driveID.atap_udmamode_supp = 0x1f; 11612371Sgabeblack@google.com // Statically set hardware config word 11712371Sgabeblack@google.com driveID.atap_hwreset_res = 0x4001; 11812371Sgabeblack@google.com 11912371Sgabeblack@google.com //arbitrary for now... 12012371Sgabeblack@google.com driveID.atap_ata_major = WDC_VER_ATA7; 12112371Sgabeblack@google.com} 12212371Sgabeblack@google.com 12312371Sgabeblack@google.comIdeDisk::~IdeDisk() 12412371Sgabeblack@google.com{ 12512371Sgabeblack@google.com // destroy the data buffer 12612302Sgabeblack@google.com delete [] dataBuffer; 12712371Sgabeblack@google.com} 12812302Sgabeblack@google.com 12912371Sgabeblack@google.comvoid 13012302Sgabeblack@google.comIdeDisk::reset(int id) 13112302Sgabeblack@google.com{ 13212371Sgabeblack@google.com // initialize the data buffer and shadow registers 13312371Sgabeblack@google.com dataBuffer = new uint8_t[MAX_DMA_SIZE]; 13412371Sgabeblack@google.com 13512371Sgabeblack@google.com memset(dataBuffer, 0, MAX_DMA_SIZE); 13612302Sgabeblack@google.com memset(&cmdReg, 0, sizeof(CommandReg_t)); 13712371Sgabeblack@google.com memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 13812371Sgabeblack@google.com 13912371Sgabeblack@google.com curPrdAddr = 0; 14012371Sgabeblack@google.com curSector = 0; 14111983Sgabeblack@google.com cmdBytes = 0; 1426143Snate@binkert.org cmdBytesLeft = 0; 1438233Snate@binkert.org drqBytesLeft = 0; 14412302Sgabeblack@google.com dmaRead = false; 1456143Snate@binkert.org intrPending = false; 1466143Snate@binkert.org 14712302Sgabeblack@google.com // set the device state to idle 1484762Snate@binkert.org dmaState = Dma_Idle; 1496143Snate@binkert.org 1508233Snate@binkert.org if (id == DEV0) { 1518233Snate@binkert.org devState = Device_Idle_S; 15212302Sgabeblack@google.com devID = DEV0; 15312302Sgabeblack@google.com } else if (id == DEV1) { 1546143Snate@binkert.org devState = Device_Idle_NS; 15512362Sgabeblack@google.com devID = DEV1; 15612362Sgabeblack@google.com } else { 15712362Sgabeblack@google.com panic("Invalid device ID: %#x\n", id); 15812362Sgabeblack@google.com } 15912302Sgabeblack@google.com 16012302Sgabeblack@google.com // set the device ready bit 16112302Sgabeblack@google.com status = STATUS_DRDY_BIT; 16212302Sgabeblack@google.com 16312302Sgabeblack@google.com /* The error register must be set to 0x1 on start-up to 16412363Sgabeblack@google.com indicate that no diagnostic error was detected */ 16512363Sgabeblack@google.com cmdReg.error = 0x1; 16612363Sgabeblack@google.com} 16712363Sgabeblack@google.com 16812302Sgabeblack@google.com//// 16912363Sgabeblack@google.com// Utility functions 17012363Sgabeblack@google.com//// 17112363Sgabeblack@google.com 17212363Sgabeblack@google.combool 17312363Sgabeblack@google.comIdeDisk::isDEVSelect() 1748233Snate@binkert.org{ 1756143Snate@binkert.org return ctrl->isDiskSelected(this); 1766143Snate@binkert.org} 1776143Snate@binkert.org 1786143Snate@binkert.orgAddr 1796143Snate@binkert.orgIdeDisk::pciToDma(Addr pciAddr) 1806143Snate@binkert.org{ 1816143Snate@binkert.org if (ctrl) 1826143Snate@binkert.org return ctrl->plat->pciToDma(pciAddr); 1836143Snate@binkert.org else 1847065Snate@binkert.org panic("Access to unset controller!\n"); 1856143Snate@binkert.org} 18612362Sgabeblack@google.com 18712362Sgabeblack@google.com//// 18812362Sgabeblack@google.com// Device registers read/write 18912362Sgabeblack@google.com//// 19012362Sgabeblack@google.com 19112362Sgabeblack@google.comvoid 19212362Sgabeblack@google.comIdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data) 19312362Sgabeblack@google.com{ 19412362Sgabeblack@google.com DevAction_t action = ACT_NONE; 19512362Sgabeblack@google.com 19612362Sgabeblack@google.com switch (reg_type) { 19712362Sgabeblack@google.com case COMMAND_BLOCK: 1988233Snate@binkert.org switch (offset) { 1998233Snate@binkert.org // Data transfers occur two bytes at a time 2008233Snate@binkert.org case DATA_OFFSET: 2018233Snate@binkert.org *(uint16_t*)data = cmdReg.data; 2028233Snate@binkert.org action = ACT_DATA_READ_SHORT; 2038233Snate@binkert.org break; 2048233Snate@binkert.org case ERROR_OFFSET: 2058233Snate@binkert.org *data = cmdReg.error; 2068233Snate@binkert.org break; 2078233Snate@binkert.org case NSECTOR_OFFSET: 2088233Snate@binkert.org *data = cmdReg.sec_count; 2098233Snate@binkert.org break; 2108233Snate@binkert.org case SECTOR_OFFSET: 2118233Snate@binkert.org *data = cmdReg.sec_num; 2128233Snate@binkert.org break; 2138233Snate@binkert.org case LCYL_OFFSET: 2148233Snate@binkert.org *data = cmdReg.cyl_low; 2158233Snate@binkert.org break; 2168233Snate@binkert.org case HCYL_OFFSET: 2178233Snate@binkert.org *data = cmdReg.cyl_high; 2188233Snate@binkert.org break; 2196143Snate@binkert.org case DRIVE_OFFSET: 2206143Snate@binkert.org *data = cmdReg.drive; 2216143Snate@binkert.org break; 2226143Snate@binkert.org case STATUS_OFFSET: 2236143Snate@binkert.org *data = status; 2246143Snate@binkert.org action = ACT_STAT_READ; 2259982Satgutier@umich.edu break; 22613576Sciro.santilli@arm.com default: 22713576Sciro.santilli@arm.com panic("Invalid IDE command register offset: %#x\n", offset); 22813576Sciro.santilli@arm.com } 22913576Sciro.santilli@arm.com break; 23013576Sciro.santilli@arm.com case CONTROL_BLOCK: 23113576Sciro.santilli@arm.com if (offset == ALTSTAT_OFFSET) 23213576Sciro.santilli@arm.com *data = status; 23313576Sciro.santilli@arm.com else 23413576Sciro.santilli@arm.com panic("Invalid IDE control register offset: %#x\n", offset); 23513576Sciro.santilli@arm.com break; 23613576Sciro.santilli@arm.com default: 23713576Sciro.santilli@arm.com panic("Unknown register block!\n"); 23813576Sciro.santilli@arm.com } 23913576Sciro.santilli@arm.com 24013576Sciro.santilli@arm.com if (action != ACT_NONE) 24113576Sciro.santilli@arm.com updateState(action); 24213576Sciro.santilli@arm.com} 24313576Sciro.santilli@arm.com 24413576Sciro.santilli@arm.comvoid 24513576Sciro.santilli@arm.comIdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data) 24613576Sciro.santilli@arm.com{ 24713576Sciro.santilli@arm.com DevAction_t action = ACT_NONE; 24813576Sciro.santilli@arm.com 24913576Sciro.santilli@arm.com switch (reg_type) { 25013576Sciro.santilli@arm.com case COMMAND_BLOCK: 25113576Sciro.santilli@arm.com switch (offset) { 25213576Sciro.santilli@arm.com case DATA_OFFSET: 25313576Sciro.santilli@arm.com cmdReg.data = *(uint16_t*)data; 25413576Sciro.santilli@arm.com action = ACT_DATA_WRITE_SHORT; 25513576Sciro.santilli@arm.com break; 25613576Sciro.santilli@arm.com case FEATURES_OFFSET: 25713576Sciro.santilli@arm.com break; 25813630Sciro.santilli@arm.com case NSECTOR_OFFSET: 25913630Sciro.santilli@arm.com cmdReg.sec_count = *data; 26013576Sciro.santilli@arm.com break; 26113576Sciro.santilli@arm.com case SECTOR_OFFSET: 26213576Sciro.santilli@arm.com cmdReg.sec_num = *data; 26313576Sciro.santilli@arm.com break; 26413576Sciro.santilli@arm.com case LCYL_OFFSET: 26513576Sciro.santilli@arm.com cmdReg.cyl_low = *data; 26613576Sciro.santilli@arm.com break; 26713576Sciro.santilli@arm.com case HCYL_OFFSET: 26813576Sciro.santilli@arm.com cmdReg.cyl_high = *data; 26913576Sciro.santilli@arm.com break; 27013576Sciro.santilli@arm.com case DRIVE_OFFSET: 27113576Sciro.santilli@arm.com cmdReg.drive = *data; 27213576Sciro.santilli@arm.com action = ACT_SELECT_WRITE; 27313576Sciro.santilli@arm.com break; 27413576Sciro.santilli@arm.com case COMMAND_OFFSET: 27513576Sciro.santilli@arm.com cmdReg.command = *data; 27613576Sciro.santilli@arm.com action = ACT_CMD_WRITE; 27713576Sciro.santilli@arm.com break; 27813576Sciro.santilli@arm.com default: 27913576Sciro.santilli@arm.com panic("Invalid IDE command register offset: %#x\n", offset); 28013576Sciro.santilli@arm.com } 28113576Sciro.santilli@arm.com break; 28213576Sciro.santilli@arm.com case CONTROL_BLOCK: 28313576Sciro.santilli@arm.com if (offset == CONTROL_OFFSET) { 28413576Sciro.santilli@arm.com if (*data & CONTROL_RST_BIT) { 28513576Sciro.santilli@arm.com // force the device into the reset state 28613576Sciro.santilli@arm.com devState = Device_Srst; 28713576Sciro.santilli@arm.com action = ACT_SRST_SET; 28813576Sciro.santilli@arm.com } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) 28913576Sciro.santilli@arm.com action = ACT_SRST_CLEAR; 29013576Sciro.santilli@arm.com 29113576Sciro.santilli@arm.com nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; 29213576Sciro.santilli@arm.com } 29313576Sciro.santilli@arm.com else 29413576Sciro.santilli@arm.com panic("Invalid IDE control register offset: %#x\n", offset); 29513576Sciro.santilli@arm.com break; 29613576Sciro.santilli@arm.com default: 29713577Sciro.santilli@arm.com panic("Unknown register block!\n"); 29813577Sciro.santilli@arm.com } 29913577Sciro.santilli@arm.com 3006143Snate@binkert.org if (action != ACT_NONE) 30112302Sgabeblack@google.com updateState(action); 30212302Sgabeblack@google.com} 30312302Sgabeblack@google.com 30412302Sgabeblack@google.com//// 30512302Sgabeblack@google.com// Perform DMA transactions 30612302Sgabeblack@google.com//// 30712302Sgabeblack@google.com 30812302Sgabeblack@google.comvoid 30911983Sgabeblack@google.comIdeDisk::doDmaTransfer() 31011983Sgabeblack@google.com{ 31111983Sgabeblack@google.com if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 31212302Sgabeblack@google.com panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 31312302Sgabeblack@google.com dmaState, devState); 31412302Sgabeblack@google.com 31512302Sgabeblack@google.com if (ctrl->dmaPending()) { 31612302Sgabeblack@google.com dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 31712302Sgabeblack@google.com return; 31811983Sgabeblack@google.com } else 3196143Snate@binkert.org ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent, 32012305Sgabeblack@google.com (uint8_t*)&curPrd.entry); 32112302Sgabeblack@google.com} 32212302Sgabeblack@google.com 32312302Sgabeblack@google.comvoid 3246143Snate@binkert.orgIdeDisk::dmaPrdReadDone() 3256143Snate@binkert.org{ 3266143Snate@binkert.org DPRINTF(IdeDisk, 3275522Snate@binkert.org "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", 3286143Snate@binkert.org curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), 3296143Snate@binkert.org curPrd.getByteCount(), (cmdBytesLeft/SectorSize), 3306143Snate@binkert.org curPrd.getEOT(), curSector); 3319982Satgutier@umich.edu 33212302Sgabeblack@google.com // the prd pointer has already been translated, so just do an increment 33312302Sgabeblack@google.com curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); 33412302Sgabeblack@google.com 3356143Snate@binkert.org if (dmaRead) 3366143Snate@binkert.org doDmaDataRead(); 3376143Snate@binkert.org else 3386143Snate@binkert.org doDmaDataWrite(); 3395522Snate@binkert.org} 3405522Snate@binkert.org 3415522Snate@binkert.orgvoid 3425522Snate@binkert.orgIdeDisk::doDmaDataRead() 3435604Snate@binkert.org{ 3445604Snate@binkert.org /** @todo we need to figure out what the delay actually will be */ 3456143Snate@binkert.org Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 3466143Snate@binkert.org 3474762Snate@binkert.org DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", 3484762Snate@binkert.org diskDelay, totalDiskDelay); 3496143Snate@binkert.org 3506727Ssteve.reinhardt@amd.com dmaReadWaitEvent.schedule(curTick + totalDiskDelay); 3516727Ssteve.reinhardt@amd.com} 3526727Ssteve.reinhardt@amd.com 3534762Snate@binkert.org 3546143Snate@binkert.orgvoid 3556143Snate@binkert.orgIdeDisk::doDmaRead() 3566143Snate@binkert.org{ 3576143Snate@binkert.org 3586727Ssteve.reinhardt@amd.com if (!dmaReadCG) { 3596143Snate@binkert.org // clear out the data buffer 3607674Snate@binkert.org memset(dataBuffer, 0, MAX_DMA_SIZE); 3617674Snate@binkert.org dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(), 3625604Snate@binkert.org curPrd.getByteCount(), TheISA::PageBytes); 3636143Snate@binkert.org 3646143Snate@binkert.org } 3656143Snate@binkert.org if (ctrl->dmaPending()) { 3664762Snate@binkert.org panic("shouldn't be reentant??"); 3676143Snate@binkert.org dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 3684762Snate@binkert.org return; 3694762Snate@binkert.org } else if (!dmaReadCG->done()) { 3704762Snate@binkert.org assert(dmaReadCG->complete() < MAX_DMA_SIZE); 3716143Snate@binkert.org ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(), 3726143Snate@binkert.org &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete()); 3734762Snate@binkert.org dmaReadCG->next(); 37412302Sgabeblack@google.com } else { 37512302Sgabeblack@google.com assert(dmaReadCG->done()); 3768233Snate@binkert.org delete dmaReadCG; 37712302Sgabeblack@google.com dmaReadCG = NULL; 3786143Snate@binkert.org dmaReadDone(); 3796143Snate@binkert.org } 3804762Snate@binkert.org} 3816143Snate@binkert.org 3824762Snate@binkert.orgvoid 3839396Sandreas.hansson@arm.comIdeDisk::dmaReadDone() 3849396Sandreas.hansson@arm.com{ 3859396Sandreas.hansson@arm.com 38612302Sgabeblack@google.com uint32_t bytesWritten = 0; 38712302Sgabeblack@google.com 38812302Sgabeblack@google.com 3899396Sandreas.hansson@arm.com // write the data to the disk image 3909396Sandreas.hansson@arm.com for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); 3919396Sandreas.hansson@arm.com bytesWritten += SectorSize) { 3929396Sandreas.hansson@arm.com 3939396Sandreas.hansson@arm.com cmdBytesLeft -= SectorSize; 3949396Sandreas.hansson@arm.com writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 3959396Sandreas.hansson@arm.com } 3969930Sandreas.hansson@arm.com 3979930Sandreas.hansson@arm.com // check for the EOT 3989396Sandreas.hansson@arm.com if (curPrd.getEOT()) { 3996143Snate@binkert.org assert(cmdBytesLeft == 0); 40012797Sgabeblack@google.com dmaState = Dma_Idle; 40112797Sgabeblack@google.com updateState(ACT_DMA_DONE); 40212797Sgabeblack@google.com } else { 4038235Snate@binkert.org doDmaTransfer(); 40412797Sgabeblack@google.com } 40512797Sgabeblack@google.com} 40612797Sgabeblack@google.com 40712797Sgabeblack@google.comvoid 40812797Sgabeblack@google.comIdeDisk::doDmaDataWrite() 40912797Sgabeblack@google.com{ 41012797Sgabeblack@google.com /** @todo we need to figure out what the delay actually will be */ 41112797Sgabeblack@google.com Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 41212797Sgabeblack@google.com uint32_t bytesRead = 0; 41312797Sgabeblack@google.com 41412797Sgabeblack@google.com DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", 41512797Sgabeblack@google.com diskDelay, totalDiskDelay); 41612797Sgabeblack@google.com 41712797Sgabeblack@google.com memset(dataBuffer, 0, MAX_DMA_SIZE); 41812797Sgabeblack@google.com assert(cmdBytesLeft <= MAX_DMA_SIZE); 41912757Sgabeblack@google.com while (bytesRead < curPrd.getByteCount()) { 42012757Sgabeblack@google.com readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 42112797Sgabeblack@google.com bytesRead += SectorSize; 42212797Sgabeblack@google.com cmdBytesLeft -= SectorSize; 42312797Sgabeblack@google.com } 42412757Sgabeblack@google.com 42512757Sgabeblack@google.com dmaWriteWaitEvent.schedule(curTick + totalDiskDelay); 42612757Sgabeblack@google.com} 42712757Sgabeblack@google.com 4288235Snate@binkert.orgvoid 42912302Sgabeblack@google.comIdeDisk::doDmaWrite() 4308235Snate@binkert.org{ 4318235Snate@binkert.org 43212757Sgabeblack@google.com if (!dmaWriteCG) { 4338235Snate@binkert.org // clear out the data buffer 4348235Snate@binkert.org dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), 4358235Snate@binkert.org curPrd.getByteCount(), TheISA::PageBytes); 43612757Sgabeblack@google.com } 43712313Sgabeblack@google.com if (ctrl->dmaPending()) { 43812797Sgabeblack@google.com panic("shouldn't be reentant??"); 43912797Sgabeblack@google.com dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 44012797Sgabeblack@google.com return; 44112797Sgabeblack@google.com } else if (!dmaWriteCG->done()) { 44212797Sgabeblack@google.com assert(dmaWriteCG->complete() < MAX_DMA_SIZE); 44312797Sgabeblack@google.com ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(), 44412797Sgabeblack@google.com &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete()); 44512797Sgabeblack@google.com dmaWriteCG->next(); 44612797Sgabeblack@google.com } else { 44712797Sgabeblack@google.com assert(dmaWriteCG->done()); 44812797Sgabeblack@google.com delete dmaWriteCG; 44912797Sgabeblack@google.com dmaWriteCG = NULL; 45012797Sgabeblack@google.com dmaWriteDone(); 45112797Sgabeblack@google.com } 45212797Sgabeblack@google.com} 45312797Sgabeblack@google.com 45412797Sgabeblack@google.comvoid 45512797Sgabeblack@google.comIdeDisk::dmaWriteDone() 45612797Sgabeblack@google.com{ 45712797Sgabeblack@google.com // check for the EOT 45812797Sgabeblack@google.com if (curPrd.getEOT()) { 45912797Sgabeblack@google.com assert(cmdBytesLeft == 0); 46012797Sgabeblack@google.com dmaState = Dma_Idle; 46112797Sgabeblack@google.com updateState(ACT_DMA_DONE); 46212797Sgabeblack@google.com } else { 46312797Sgabeblack@google.com doDmaTransfer(); 46412797Sgabeblack@google.com } 46512797Sgabeblack@google.com} 46612797Sgabeblack@google.com 46712797Sgabeblack@google.com//// 46812797Sgabeblack@google.com// Disk utility routines 46912797Sgabeblack@google.com/// 47012797Sgabeblack@google.com 47112797Sgabeblack@google.comvoid 47212797Sgabeblack@google.comIdeDisk::readDisk(uint32_t sector, uint8_t *data) 47312797Sgabeblack@google.com{ 47412797Sgabeblack@google.com uint32_t bytesRead = image->read(data, sector); 47513656Sgabeblack@google.com 47612797Sgabeblack@google.com if (bytesRead != SectorSize) 47712797Sgabeblack@google.com panic("Can't read from %s. Only %d of %d read. errno=%d\n", 47812797Sgabeblack@google.com name(), bytesRead, SectorSize, errno); 47912797Sgabeblack@google.com} 48012797Sgabeblack@google.com 48112797Sgabeblack@google.comvoid 48212313Sgabeblack@google.comIdeDisk::writeDisk(uint32_t sector, uint8_t *data) 48312313Sgabeblack@google.com{ 48412797Sgabeblack@google.com uint32_t bytesWritten = image->write(data, sector); 48512797Sgabeblack@google.com 48612797Sgabeblack@google.com if (bytesWritten != SectorSize) 48712371Sgabeblack@google.com panic("Can't write to %s. Only %d of %d written. errno=%d\n", 4885584Snate@binkert.org name(), bytesWritten, SectorSize, errno); 48912797Sgabeblack@google.com} 49012797Sgabeblack@google.com 49112797Sgabeblack@google.com//// 49212797Sgabeblack@google.com// Setup and handle commands 49312797Sgabeblack@google.com//// 49412797Sgabeblack@google.com 49512797Sgabeblack@google.comvoid 49612797Sgabeblack@google.comIdeDisk::startDma(const uint32_t &prdTableBase) 49712797Sgabeblack@google.com{ 49812797Sgabeblack@google.com if (dmaState != Dma_Start) 49912797Sgabeblack@google.com panic("Inconsistent DMA state, should be in Dma_Start!\n"); 50012797Sgabeblack@google.com 50112797Sgabeblack@google.com if (devState != Transfer_Data_Dma) 50212797Sgabeblack@google.com panic("Inconsistent device state for DMA start!\n"); 50312797Sgabeblack@google.com 50412797Sgabeblack@google.com // PRD base address is given by bits 31:2 50512797Sgabeblack@google.com curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); 50612797Sgabeblack@google.com 50712797Sgabeblack@google.com dmaState = Dma_Transfer; 50812797Sgabeblack@google.com 50912797Sgabeblack@google.com // schedule dma transfer (doDmaTransfer) 51012797Sgabeblack@google.com dmaTransferEvent.schedule(curTick + 1); 51112797Sgabeblack@google.com} 51212797Sgabeblack@google.com 51312797Sgabeblack@google.comvoid 51412797Sgabeblack@google.comIdeDisk::abortDma() 51512797Sgabeblack@google.com{ 51612797Sgabeblack@google.com if (dmaState == Dma_Idle) 51712797Sgabeblack@google.com panic("Inconsistent DMA state, should be Start or Transfer!"); 51812797Sgabeblack@google.com 51912797Sgabeblack@google.com if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 52012797Sgabeblack@google.com panic("Inconsistent device state, should be Transfer or Prepare!\n"); 52112797Sgabeblack@google.com 52212797Sgabeblack@google.com updateState(ACT_CMD_ERROR); 52312797Sgabeblack@google.com} 52412797Sgabeblack@google.com 52512797Sgabeblack@google.comvoid 52612797Sgabeblack@google.comIdeDisk::startCommand() 5274382Sbinkertn@umich.edu{ 52813576Sciro.santilli@arm.com DevAction_t action = ACT_NONE; 52913577Sciro.santilli@arm.com uint32_t size = 0; 5304202Sbinkertn@umich.edu dmaRead = false; 5314382Sbinkertn@umich.edu 5324382Sbinkertn@umich.edu // Decode commands 5339396Sandreas.hansson@arm.com switch (cmdReg.command) { 53412797Sgabeblack@google.com // Supported non-data commands 5355584Snate@binkert.org case WDSF_READ_NATIVE_MAX: 53612313Sgabeblack@google.com size = image->size() - 1; 5374382Sbinkertn@umich.edu cmdReg.sec_num = (size & 0xff); 5384382Sbinkertn@umich.edu cmdReg.cyl_low = ((size & 0xff00) >> 8); 5394382Sbinkertn@umich.edu cmdReg.cyl_high = ((size & 0xff0000) >> 16); 5408232Snate@binkert.org cmdReg.head = ((size & 0xf000000) >> 24); 5415192Ssaidi@eecs.umich.edu 5428232Snate@binkert.org devState = Command_Execution; 5438232Snate@binkert.org action = ACT_CMD_COMPLETE; 5448232Snate@binkert.org break; 5455192Ssaidi@eecs.umich.edu 5468232Snate@binkert.org case WDCC_RECAL: 5475192Ssaidi@eecs.umich.edu case WDCC_IDP: 5485799Snate@binkert.org case WDCC_STANDBY_IMMED: 5498232Snate@binkert.org case WDCC_FLUSHCACHE: 5505192Ssaidi@eecs.umich.edu case WDSF_VERIFY: 5515192Ssaidi@eecs.umich.edu case WDSF_SEEK: 5525192Ssaidi@eecs.umich.edu case SET_FEATURES: 5538232Snate@binkert.org case WDCC_SETMULTI: 5545192Ssaidi@eecs.umich.edu devState = Command_Execution; 5558232Snate@binkert.org action = ACT_CMD_COMPLETE; 5565192Ssaidi@eecs.umich.edu break; 5575192Ssaidi@eecs.umich.edu 5585192Ssaidi@eecs.umich.edu // Supported PIO data-in commands 5595192Ssaidi@eecs.umich.edu case WDCC_IDENTIFY: 5604382Sbinkertn@umich.edu cmdBytes = cmdBytesLeft = sizeof(struct ataparams); 5614382Sbinkertn@umich.edu devState = Prepare_Data_In; 5624382Sbinkertn@umich.edu action = ACT_DATA_READY; 5632667Sstever@eecs.umich.edu break; 5642667Sstever@eecs.umich.edu 5652667Sstever@eecs.umich.edu case WDCC_READMULTI: 5662667Sstever@eecs.umich.edu case WDCC_READ: 5672667Sstever@eecs.umich.edu if (!(cmdReg.drive & DRIVE_LBA_BIT)) 5682667Sstever@eecs.umich.edu panic("Attempt to perform CHS access, only supports LBA\n"); 5695742Snate@binkert.org 5705742Snate@binkert.org if (cmdReg.sec_count == 0) 5715742Snate@binkert.org cmdBytes = cmdBytesLeft = (256 * SectorSize); 5725793Snate@binkert.org else 5738334Snate@binkert.org cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 5745793Snate@binkert.org 5755793Snate@binkert.org curSector = getLBABase(); 5765793Snate@binkert.org 5774382Sbinkertn@umich.edu /** @todo make this a scheduled event to simulate disk delay */ 5784762Snate@binkert.org devState = Prepare_Data_In; 5795344Sstever@gmail.com action = ACT_DATA_READY; 5804382Sbinkertn@umich.edu break; 5815341Sstever@gmail.com 5825742Snate@binkert.org // Supported PIO data-out commands 5835742Snate@binkert.org case WDCC_WRITEMULTI: 5845742Snate@binkert.org case WDCC_WRITE: 5855742Snate@binkert.org if (!(cmdReg.drive & DRIVE_LBA_BIT)) 5865742Snate@binkert.org panic("Attempt to perform CHS access, only supports LBA\n"); 5874762Snate@binkert.org 5885742Snate@binkert.org if (cmdReg.sec_count == 0) 5895742Snate@binkert.org cmdBytes = cmdBytesLeft = (256 * SectorSize); 59011984Sgabeblack@google.com else 5917722Sgblack@eecs.umich.edu cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 5925742Snate@binkert.org 5935742Snate@binkert.org curSector = getLBABase(); 5945742Snate@binkert.org 5959930Sandreas.hansson@arm.com devState = Prepare_Data_Out; 5969930Sandreas.hansson@arm.com action = ACT_DATA_READY; 5979930Sandreas.hansson@arm.com break; 5989930Sandreas.hansson@arm.com 5999930Sandreas.hansson@arm.com // Supported DMA commands 6005742Snate@binkert.org case WDCC_WRITEDMA: 6018242Sbradley.danofsky@amd.com dmaRead = true; // a write to the disk is a DMA read from memory 6028242Sbradley.danofsky@amd.com case WDCC_READDMA: 6038242Sbradley.danofsky@amd.com if (!(cmdReg.drive & DRIVE_LBA_BIT)) 6048242Sbradley.danofsky@amd.com panic("Attempt to perform CHS access, only supports LBA\n"); 6055341Sstever@gmail.com 6065742Snate@binkert.org if (cmdReg.sec_count == 0) 6077722Sgblack@eecs.umich.edu cmdBytes = cmdBytesLeft = (256 * SectorSize); 6084773Snate@binkert.org else 6096108Snate@binkert.org cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 6101858SN/A 6111085SN/A curSector = getLBABase(); 6126658Snate@binkert.org 6136658Snate@binkert.org devState = Prepare_Data_Dma; 6147673Snate@binkert.org action = ACT_DMA_READY; 6156658Snate@binkert.org break; 6166658Snate@binkert.org 61711308Santhony.gutierrez@amd.com default: 6186658Snate@binkert.org panic("Unsupported ATA command: %#x\n", cmdReg.command); 61911308Santhony.gutierrez@amd.com } 6206658Snate@binkert.org 6216658Snate@binkert.org if (action != ACT_NONE) { 6227673Snate@binkert.org // set the BSY bit 6237673Snate@binkert.org status |= STATUS_BSY_BIT; 6247673Snate@binkert.org // clear the DRQ bit 6257673Snate@binkert.org status &= ~STATUS_DRQ_BIT; 6267673Snate@binkert.org // clear the DF bit 6277673Snate@binkert.org status &= ~STATUS_DF_BIT; 6287673Snate@binkert.org 62910467Sandreas.hansson@arm.com updateState(action); 6306658Snate@binkert.org } 6317673Snate@binkert.org} 63210467Sandreas.hansson@arm.com 63310467Sandreas.hansson@arm.com//// 63410467Sandreas.hansson@arm.com// Handle setting and clearing interrupts 63510467Sandreas.hansson@arm.com//// 63610467Sandreas.hansson@arm.com 63710467Sandreas.hansson@arm.comvoid 63810467Sandreas.hansson@arm.comIdeDisk::intrPost() 63910467Sandreas.hansson@arm.com{ 64010467Sandreas.hansson@arm.com DPRINTF(IdeDisk, "Posting Interrupt\n"); 64110467Sandreas.hansson@arm.com if (intrPending) 64210467Sandreas.hansson@arm.com panic("Attempt to post an interrupt with one pending\n"); 6437673Snate@binkert.org 6447673Snate@binkert.org intrPending = true; 6457673Snate@binkert.org 6467673Snate@binkert.org // talk to controller to set interrupt 6477673Snate@binkert.org if (ctrl) { 6489048SAli.Saidi@ARM.com ctrl->bmi_regs.bmis0 |= IDEINTS; 6497673Snate@binkert.org ctrl->intrPost(); 6507673Snate@binkert.org } 6517673Snate@binkert.org} 6527673Snate@binkert.org 6536658Snate@binkert.orgvoid 6547756SAli.Saidi@ARM.comIdeDisk::intrClear() 6557816Ssteve.reinhardt@amd.com{ 6566658Snate@binkert.org DPRINTF(IdeDisk, "Clearing Interrupt\n"); 65711308Santhony.gutierrez@amd.com if (!intrPending) 65811308Santhony.gutierrez@amd.com panic("Attempt to clear a non-pending interrupt\n"); 65911308Santhony.gutierrez@amd.com 66011308Santhony.gutierrez@amd.com intrPending = false; 66111308Santhony.gutierrez@amd.com 66211308Santhony.gutierrez@amd.com // talk to controller to clear interrupt 66311308Santhony.gutierrez@amd.com if (ctrl) 66411308Santhony.gutierrez@amd.com ctrl->intrClear(); 66511308Santhony.gutierrez@amd.com} 66611308Santhony.gutierrez@amd.com 66711308Santhony.gutierrez@amd.com//// 66811308Santhony.gutierrez@amd.com// Manage the device internal state machine 66911308Santhony.gutierrez@amd.com//// 67011308Santhony.gutierrez@amd.com 67111308Santhony.gutierrez@amd.comvoid 67211308Santhony.gutierrez@amd.comIdeDisk::updateState(DevAction_t action) 67311308Santhony.gutierrez@amd.com{ 67411308Santhony.gutierrez@amd.com switch (devState) { 67511308Santhony.gutierrez@amd.com case Device_Srst: 67611308Santhony.gutierrez@amd.com if (action == ACT_SRST_SET) { 67711308Santhony.gutierrez@amd.com // set the BSY bit 67811308Santhony.gutierrez@amd.com status |= STATUS_BSY_BIT; 67911308Santhony.gutierrez@amd.com } else if (action == ACT_SRST_CLEAR) { 68011308Santhony.gutierrez@amd.com // clear the BSY bit 68111308Santhony.gutierrez@amd.com status &= ~STATUS_BSY_BIT; 68211308Santhony.gutierrez@amd.com 68311308Santhony.gutierrez@amd.com // reset the device state 68411308Santhony.gutierrez@amd.com reset(devID); 68511308Santhony.gutierrez@amd.com } 68611308Santhony.gutierrez@amd.com break; 68711308Santhony.gutierrez@amd.com 68811308Santhony.gutierrez@amd.com case Device_Idle_S: 68911308Santhony.gutierrez@amd.com if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 69011308Santhony.gutierrez@amd.com devState = Device_Idle_NS; 69111308Santhony.gutierrez@amd.com } else if (action == ACT_CMD_WRITE) { 69211308Santhony.gutierrez@amd.com startCommand(); 69311308Santhony.gutierrez@amd.com } 69411308Santhony.gutierrez@amd.com 69511308Santhony.gutierrez@amd.com break; 69611308Santhony.gutierrez@amd.com 69711308Santhony.gutierrez@amd.com case Device_Idle_SI: 69811308Santhony.gutierrez@amd.com if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 69911308Santhony.gutierrez@amd.com devState = Device_Idle_NS; 70011308Santhony.gutierrez@amd.com intrClear(); 70111308Santhony.gutierrez@amd.com } else if (action == ACT_STAT_READ || isIENSet()) { 7024382Sbinkertn@umich.edu devState = Device_Idle_S; 7034382Sbinkertn@umich.edu intrClear(); 7044762Snate@binkert.org } else if (action == ACT_CMD_WRITE) { 7054762Snate@binkert.org intrClear(); 7064762Snate@binkert.org startCommand(); 7076654Snate@binkert.org } 7086654Snate@binkert.org 7095517Snate@binkert.org break; 7105517Snate@binkert.org 7115517Snate@binkert.org case Device_Idle_NS: 7125517Snate@binkert.org if (action == ACT_SELECT_WRITE && isDEVSelect()) { 7135517Snate@binkert.org if (!isIENSet() && intrPending) { 7145517Snate@binkert.org devState = Device_Idle_SI; 7155517Snate@binkert.org intrPost(); 7165517Snate@binkert.org } 7175517Snate@binkert.org if (isIENSet() || !intrPending) { 7185517Snate@binkert.org devState = Device_Idle_S; 7195517Snate@binkert.org } 7205517Snate@binkert.org } 7215517Snate@binkert.org break; 7225517Snate@binkert.org 7235517Snate@binkert.org case Command_Execution: 7245517Snate@binkert.org if (action == ACT_CMD_COMPLETE) { 7255517Snate@binkert.org // clear the BSY bit 7266654Snate@binkert.org setComplete(); 7275517Snate@binkert.org 7285517Snate@binkert.org if (!isIENSet()) { 7295517Snate@binkert.org devState = Device_Idle_SI; 7305517Snate@binkert.org intrPost(); 7315517Snate@binkert.org } else { 73211802Sandreas.sandberg@arm.com devState = Device_Idle_S; 7335517Snate@binkert.org } 7345517Snate@binkert.org } 7356143Snate@binkert.org break; 7366654Snate@binkert.org 7375517Snate@binkert.org case Prepare_Data_In: 7385517Snate@binkert.org if (action == ACT_CMD_ERROR) { 7395517Snate@binkert.org // clear the BSY bit 7405517Snate@binkert.org setComplete(); 7415517Snate@binkert.org 7425517Snate@binkert.org if (!isIENSet()) { 7435517Snate@binkert.org devState = Device_Idle_SI; 7445517Snate@binkert.org intrPost(); 7455517Snate@binkert.org } else { 7465517Snate@binkert.org devState = Device_Idle_S; 7475517Snate@binkert.org } 7485517Snate@binkert.org } else if (action == ACT_DATA_READY) { 7495517Snate@binkert.org // clear the BSY bit 7505517Snate@binkert.org status &= ~STATUS_BSY_BIT; 7516654Snate@binkert.org // set the DRQ bit 7526654Snate@binkert.org status |= STATUS_DRQ_BIT; 7535517Snate@binkert.org 7545517Snate@binkert.org // copy the data into the data buffer 7556143Snate@binkert.org if (cmdReg.command == WDCC_IDENTIFY) { 7566143Snate@binkert.org // Reset the drqBytes for this block 7576143Snate@binkert.org drqBytesLeft = sizeof(struct ataparams); 7586727Ssteve.reinhardt@amd.com 7595517Snate@binkert.org memcpy((void *)dataBuffer, (void *)&driveID, 7606727Ssteve.reinhardt@amd.com sizeof(struct ataparams)); 7615517Snate@binkert.org } else { 7625517Snate@binkert.org // Reset the drqBytes for this block 7635517Snate@binkert.org drqBytesLeft = SectorSize; 7646654Snate@binkert.org 7656654Snate@binkert.org readDisk(curSector++, dataBuffer); 7667673Snate@binkert.org } 7676654Snate@binkert.org 7686654Snate@binkert.org // put the first two bytes into the data register 7696654Snate@binkert.org memcpy((void *)&cmdReg.data, (void *)dataBuffer, 7706654Snate@binkert.org sizeof(uint16_t)); 7715517Snate@binkert.org 7725517Snate@binkert.org if (!isIENSet()) { 7735517Snate@binkert.org devState = Data_Ready_INTRQ_In; 7746143Snate@binkert.org intrPost(); 7755517Snate@binkert.org } else { 7764762Snate@binkert.org devState = Transfer_Data_In; 7775517Snate@binkert.org } 7785517Snate@binkert.org } 7796143Snate@binkert.org break; 7806143Snate@binkert.org 7815517Snate@binkert.org case Data_Ready_INTRQ_In: 7825517Snate@binkert.org if (action == ACT_STAT_READ) { 7835517Snate@binkert.org devState = Transfer_Data_In; 7845517Snate@binkert.org intrClear(); 7855517Snate@binkert.org } 7865517Snate@binkert.org break; 7875517Snate@binkert.org 7885517Snate@binkert.org case Transfer_Data_In: 7895517Snate@binkert.org if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 7906143Snate@binkert.org if (action == ACT_DATA_READ_BYTE) { 7915517Snate@binkert.org panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 7926654Snate@binkert.org } else { 7936654Snate@binkert.org drqBytesLeft -= 2; 7946654Snate@binkert.org cmdBytesLeft -= 2; 7956654Snate@binkert.org 7966654Snate@binkert.org // copy next short into data registers 7976654Snate@binkert.org if (drqBytesLeft) 7984762Snate@binkert.org memcpy((void *)&cmdReg.data, 7994762Snate@binkert.org (void *)&dataBuffer[SectorSize - drqBytesLeft], 8004762Snate@binkert.org sizeof(uint16_t)); 8014762Snate@binkert.org } 8024762Snate@binkert.org 8037675Snate@binkert.org if (drqBytesLeft == 0) { 80410584Sandreas.hansson@arm.com if (cmdBytesLeft == 0) { 8054762Snate@binkert.org // Clear the BSY bit 8064762Snate@binkert.org setComplete(); 8074762Snate@binkert.org devState = Device_Idle_S; 8084762Snate@binkert.org } else { 8094382Sbinkertn@umich.edu devState = Prepare_Data_In; 8104382Sbinkertn@umich.edu // set the BSY_BIT 8115517Snate@binkert.org status |= STATUS_BSY_BIT; 8126654Snate@binkert.org // clear the DRQ_BIT 8135517Snate@binkert.org status &= ~STATUS_DRQ_BIT; 8148126Sgblack@eecs.umich.edu 8156654Snate@binkert.org /** @todo change this to a scheduled event to simulate 8167673Snate@binkert.org disk delay */ 8176654Snate@binkert.org updateState(ACT_DATA_READY); 81811802Sandreas.sandberg@arm.com } 8196654Snate@binkert.org } 8206654Snate@binkert.org } 8216654Snate@binkert.org break; 8226654Snate@binkert.org 82311802Sandreas.sandberg@arm.com case Prepare_Data_Out: 8246669Snate@binkert.org if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 82511802Sandreas.sandberg@arm.com // clear the BSY bit 8266669Snate@binkert.org setComplete(); 8276669Snate@binkert.org 8286669Snate@binkert.org if (!isIENSet()) { 8296669Snate@binkert.org devState = Device_Idle_SI; 8306654Snate@binkert.org intrPost(); 8317673Snate@binkert.org } else { 8325517Snate@binkert.org devState = Device_Idle_S; 8338126Sgblack@eecs.umich.edu } 8345798Snate@binkert.org } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { 8357756SAli.Saidi@ARM.com // clear the BSY bit 8367816Ssteve.reinhardt@amd.com status &= ~STATUS_BSY_BIT; 8375798Snate@binkert.org // set the DRQ bit 8385798Snate@binkert.org status |= STATUS_DRQ_BIT; 8395517Snate@binkert.org 8405517Snate@binkert.org // clear the data buffer to get it ready for writes 8417673Snate@binkert.org memset(dataBuffer, 0, MAX_DMA_SIZE); 8425517Snate@binkert.org 8435517Snate@binkert.org // reset the drqBytes for this block 8447673Snate@binkert.org drqBytesLeft = SectorSize; 8457673Snate@binkert.org 8465517Snate@binkert.org if (cmdBytesLeft == cmdBytes || isIENSet()) { 8475798Snate@binkert.org devState = Transfer_Data_Out; 8485798Snate@binkert.org } else { 8498333Snate@binkert.org devState = Data_Ready_INTRQ_Out; 8507816Ssteve.reinhardt@amd.com intrPost(); 8515798Snate@binkert.org } 8525798Snate@binkert.org } 8534762Snate@binkert.org break; 8544762Snate@binkert.org 8554762Snate@binkert.org case Data_Ready_INTRQ_Out: 8564762Snate@binkert.org if (action == ACT_STAT_READ) { 8574762Snate@binkert.org devState = Transfer_Data_Out; 8588596Ssteve.reinhardt@amd.com intrClear(); 8595517Snate@binkert.org } 8605517Snate@binkert.org break; 86111997Sgabeblack@google.com 8625517Snate@binkert.org case Transfer_Data_Out: 8635517Snate@binkert.org if (action == ACT_DATA_WRITE_BYTE || 8647673Snate@binkert.org action == ACT_DATA_WRITE_SHORT) { 8658596Ssteve.reinhardt@amd.com 8667673Snate@binkert.org if (action == ACT_DATA_READ_BYTE) { 8675517Snate@binkert.org panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 86810458Sandreas.hansson@arm.com } else { 86910458Sandreas.hansson@arm.com // copy the latest short into the data buffer 87010458Sandreas.hansson@arm.com memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 87110458Sandreas.hansson@arm.com (void *)&cmdReg.data, 87210458Sandreas.hansson@arm.com sizeof(uint16_t)); 87310458Sandreas.hansson@arm.com 87410458Sandreas.hansson@arm.com drqBytesLeft -= 2; 87510458Sandreas.hansson@arm.com cmdBytesLeft -= 2; 87610458Sandreas.hansson@arm.com } 87710458Sandreas.hansson@arm.com 87810458Sandreas.hansson@arm.com if (drqBytesLeft == 0) { 87910458Sandreas.hansson@arm.com // copy the block to the disk 8805517Snate@binkert.org writeDisk(curSector++, dataBuffer); 88111996Sgabeblack@google.com 8825517Snate@binkert.org // set the BSY bit 88311997Sgabeblack@google.com status |= STATUS_BSY_BIT; 88411996Sgabeblack@google.com // set the seek bit 8855517Snate@binkert.org status |= STATUS_SEEK_BIT; 8865517Snate@binkert.org // clear the DRQ bit 8877673Snate@binkert.org status &= ~STATUS_DRQ_BIT; 8887673Snate@binkert.org 88911996Sgabeblack@google.com devState = Prepare_Data_Out; 89011988Sandreas.sandberg@arm.com 8917673Snate@binkert.org /** @todo change this to a scheduled event to simulate 8925517Snate@binkert.org disk delay */ 8938596Ssteve.reinhardt@amd.com updateState(ACT_DATA_READY); 8945517Snate@binkert.org } 8955517Snate@binkert.org } 89611997Sgabeblack@google.com break; 8975517Snate@binkert.org 8985517Snate@binkert.org case Prepare_Data_Dma: 8997673Snate@binkert.org if (action == ACT_CMD_ERROR) { 9007673Snate@binkert.org // clear the BSY bit 9017673Snate@binkert.org setComplete(); 9025517Snate@binkert.org 90311988Sandreas.sandberg@arm.com if (!isIENSet()) { 90411997Sgabeblack@google.com devState = Device_Idle_SI; 9058596Ssteve.reinhardt@amd.com intrPost(); 9068596Ssteve.reinhardt@amd.com } else { 9078596Ssteve.reinhardt@amd.com devState = Device_Idle_S; 90811988Sandreas.sandberg@arm.com } 9098596Ssteve.reinhardt@amd.com } else if (action == ACT_DMA_READY) { 9108596Ssteve.reinhardt@amd.com // clear the BSY bit 9118596Ssteve.reinhardt@amd.com status &= ~STATUS_BSY_BIT; 9124762Snate@binkert.org // set the DRQ bit 9136143Snate@binkert.org status |= STATUS_DRQ_BIT; 9146143Snate@binkert.org 9156143Snate@binkert.org devState = Transfer_Data_Dma; 9164762Snate@binkert.org 9174762Snate@binkert.org if (dmaState != Dma_Idle) 9184762Snate@binkert.org panic("Inconsistent DMA state, should be Dma_Idle\n"); 9197756SAli.Saidi@ARM.com 9208596Ssteve.reinhardt@amd.com dmaState = Dma_Start; 9214762Snate@binkert.org // wait for the write to the DMA start bit 9224762Snate@binkert.org } 92310458Sandreas.hansson@arm.com break; 92410458Sandreas.hansson@arm.com 92510458Sandreas.hansson@arm.com case Transfer_Data_Dma: 92610458Sandreas.hansson@arm.com if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { 92710458Sandreas.hansson@arm.com // clear the BSY bit 92810458Sandreas.hansson@arm.com setComplete(); 92910458Sandreas.hansson@arm.com // set the seek bit 93010458Sandreas.hansson@arm.com status |= STATUS_SEEK_BIT; 93110458Sandreas.hansson@arm.com // clear the controller state for DMA transfer 93210458Sandreas.hansson@arm.com ctrl->setDmaComplete(this); 93310458Sandreas.hansson@arm.com 93410458Sandreas.hansson@arm.com if (!isIENSet()) { 93510458Sandreas.hansson@arm.com devState = Device_Idle_SI; 93610458Sandreas.hansson@arm.com intrPost(); 93710458Sandreas.hansson@arm.com } else { 93810458Sandreas.hansson@arm.com devState = Device_Idle_S; 93910458Sandreas.hansson@arm.com } 94010458Sandreas.hansson@arm.com } 94110458Sandreas.hansson@arm.com break; 94210458Sandreas.hansson@arm.com 94310458Sandreas.hansson@arm.com default: 94410458Sandreas.hansson@arm.com panic("Unknown IDE device state: %#x\n", devState); 94510458Sandreas.hansson@arm.com } 94610458Sandreas.hansson@arm.com} 94710458Sandreas.hansson@arm.com 94810458Sandreas.hansson@arm.comvoid 94910458Sandreas.hansson@arm.comIdeDisk::serialize(ostream &os) 95010458Sandreas.hansson@arm.com{ 95110458Sandreas.hansson@arm.com // Check all outstanding events to see if they are scheduled 95210458Sandreas.hansson@arm.com // these are all mutually exclusive 95310458Sandreas.hansson@arm.com Tick reschedule = 0; 95410458Sandreas.hansson@arm.com Events_t event = None; 95510458Sandreas.hansson@arm.com 95610458Sandreas.hansson@arm.com int eventCount = 0; 95710458Sandreas.hansson@arm.com 95810458Sandreas.hansson@arm.com if (dmaTransferEvent.scheduled()) { 95910458Sandreas.hansson@arm.com reschedule = dmaTransferEvent.when(); 96010458Sandreas.hansson@arm.com event = Transfer; 96110458Sandreas.hansson@arm.com eventCount++; 96210458Sandreas.hansson@arm.com } 96310458Sandreas.hansson@arm.com if (dmaReadWaitEvent.scheduled()) { 96410458Sandreas.hansson@arm.com reschedule = dmaReadWaitEvent.when(); 96510458Sandreas.hansson@arm.com event = ReadWait; 96610458Sandreas.hansson@arm.com eventCount++; 96710458Sandreas.hansson@arm.com } 96810458Sandreas.hansson@arm.com if (dmaWriteWaitEvent.scheduled()) { 96910458Sandreas.hansson@arm.com reschedule = dmaWriteWaitEvent.when(); 97010458Sandreas.hansson@arm.com event = WriteWait; 97110458Sandreas.hansson@arm.com eventCount++; 97210584Sandreas.hansson@arm.com } 97310458Sandreas.hansson@arm.com if (dmaPrdReadEvent.scheduled()) { 97410458Sandreas.hansson@arm.com reschedule = dmaPrdReadEvent.when(); 97510458Sandreas.hansson@arm.com event = PrdRead; 97610458Sandreas.hansson@arm.com eventCount++; 97710458Sandreas.hansson@arm.com } 9784762Snate@binkert.org if (dmaReadEvent.scheduled()) { 9796143Snate@binkert.org reschedule = dmaReadEvent.when(); 9806143Snate@binkert.org event = DmaRead; 9816143Snate@binkert.org eventCount++; 9824762Snate@binkert.org } 9834762Snate@binkert.org if (dmaWriteEvent.scheduled()) { 98411996Sgabeblack@google.com reschedule = dmaWriteEvent.when(); 9857816Ssteve.reinhardt@amd.com event = DmaWrite; 9864762Snate@binkert.org eventCount++; 9874762Snate@binkert.org } 9884762Snate@binkert.org 9894762Snate@binkert.org assert(eventCount <= 1); 9907756SAli.Saidi@ARM.com 9918596Ssteve.reinhardt@amd.com SERIALIZE_SCALAR(reschedule); 9924762Snate@binkert.org SERIALIZE_ENUM(event); 9934762Snate@binkert.org 99411988Sandreas.sandberg@arm.com // Serialize device registers 99511988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(cmdReg.data); 99611988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(cmdReg.sec_count); 99711988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(cmdReg.sec_num); 99811988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(cmdReg.cyl_low); 99911988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(cmdReg.cyl_high); 100011988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(cmdReg.drive); 100111988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(cmdReg.command); 100211988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(status); 100311988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(nIENBit); 100411988Sandreas.sandberg@arm.com SERIALIZE_SCALAR(devID); 10054382Sbinkertn@umich.edu 10069396Sandreas.hansson@arm.com // Serialize the PRD related information 10079396Sandreas.hansson@arm.com SERIALIZE_SCALAR(curPrd.entry.baseAddr); 10089396Sandreas.hansson@arm.com SERIALIZE_SCALAR(curPrd.entry.byteCount); 10099396Sandreas.hansson@arm.com SERIALIZE_SCALAR(curPrd.entry.endOfTable); 10109396Sandreas.hansson@arm.com SERIALIZE_SCALAR(curPrdAddr); 10119396Sandreas.hansson@arm.com 10129396Sandreas.hansson@arm.com /** @todo need to serialized chunk generator stuff!! */ 10139396Sandreas.hansson@arm.com // Serialize current transfer related information 10149396Sandreas.hansson@arm.com SERIALIZE_SCALAR(cmdBytesLeft); 10159396Sandreas.hansson@arm.com SERIALIZE_SCALAR(cmdBytes); 10169396Sandreas.hansson@arm.com SERIALIZE_SCALAR(drqBytesLeft); 10179396Sandreas.hansson@arm.com SERIALIZE_SCALAR(curSector); 10189396Sandreas.hansson@arm.com SERIALIZE_SCALAR(dmaRead); 101912302Sgabeblack@google.com SERIALIZE_SCALAR(intrPending); 10209396Sandreas.hansson@arm.com SERIALIZE_ENUM(devState); 102112563Sgabeblack@google.com SERIALIZE_ENUM(dmaState); 10229396Sandreas.hansson@arm.com SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 10239396Sandreas.hansson@arm.com} 10248232Snate@binkert.org 10258232Snate@binkert.orgvoid 10268232Snate@binkert.orgIdeDisk::unserialize(Checkpoint *cp, const string §ion) 10278232Snate@binkert.org{ 10288232Snate@binkert.org // Reschedule events that were outstanding 10296229Snate@binkert.org // these are all mutually exclusive 103010455SCurtis.Dunham@arm.com Tick reschedule = 0; 10316229Snate@binkert.org Events_t event = None; 103210455SCurtis.Dunham@arm.com 103310455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(reschedule); 103410455SCurtis.Dunham@arm.com UNSERIALIZE_ENUM(event); 10355517Snate@binkert.org 10365517Snate@binkert.org switch (event) { 10377673Snate@binkert.org case None : break; 10385517Snate@binkert.org case Transfer : dmaTransferEvent.schedule(reschedule); break; 103910455SCurtis.Dunham@arm.com case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; 10405517Snate@binkert.org case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; 10415517Snate@binkert.org case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; 10428232Snate@binkert.org case DmaRead : dmaReadEvent.schedule(reschedule); break; 104310455SCurtis.Dunham@arm.com case DmaWrite : dmaWriteEvent.schedule(reschedule); break; 104410455SCurtis.Dunham@arm.com } 104510455SCurtis.Dunham@arm.com 10467673Snate@binkert.org // Unserialize device registers 10477673Snate@binkert.org UNSERIALIZE_SCALAR(cmdReg.data); 104810455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(cmdReg.sec_count); 104910455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(cmdReg.sec_num); 105010455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(cmdReg.cyl_low); 10515517Snate@binkert.org UNSERIALIZE_SCALAR(cmdReg.cyl_high); 105210455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(cmdReg.drive); 105310455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(cmdReg.command); 105410455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(status); 105510455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(nIENBit); 105610455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(devID); 105710455SCurtis.Dunham@arm.com 105810455SCurtis.Dunham@arm.com // Unserialize the PRD related information 105910455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); 106010685Sandreas.hansson@arm.com UNSERIALIZE_SCALAR(curPrd.entry.byteCount); 106110455SCurtis.Dunham@arm.com UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); 106210685Sandreas.hansson@arm.com UNSERIALIZE_SCALAR(curPrdAddr); 106310455SCurtis.Dunham@arm.com 10645517Snate@binkert.org /** @todo need to serialized chunk generator stuff!! */ 106510455SCurtis.Dunham@arm.com // Unserialize current transfer related information 10668232Snate@binkert.org UNSERIALIZE_SCALAR(cmdBytes); 10678232Snate@binkert.org UNSERIALIZE_SCALAR(cmdBytesLeft); 10685517Snate@binkert.org UNSERIALIZE_SCALAR(drqBytesLeft); 10697673Snate@binkert.org UNSERIALIZE_SCALAR(curSector); 10705517Snate@binkert.org UNSERIALIZE_SCALAR(dmaRead); 10718232Snate@binkert.org UNSERIALIZE_SCALAR(intrPending); 10728232Snate@binkert.org UNSERIALIZE_ENUM(devState); 10735517Snate@binkert.org UNSERIALIZE_ENUM(dmaState); 10748232Snate@binkert.org UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 10758232Snate@binkert.org} 10768232Snate@binkert.org 10777673Snate@binkert.org#ifndef DOXYGEN_SHOULD_SKIP_THIS 10785517Snate@binkert.org 10795517Snate@binkert.orgenum DriveID { master, slave }; 10807673Snate@binkert.orgstatic const char *DriveID_strings[] = { "master", "slave" }; 10815517Snate@binkert.orgBEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 108210455SCurtis.Dunham@arm.com 10835517Snate@binkert.org SimObjectParam<DiskImage *> image; 10845517Snate@binkert.org SimpleEnumParam<DriveID> driveID; 10858232Snate@binkert.org Param<int> delay; 10868232Snate@binkert.org 10875517Snate@binkert.orgEND_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 10888232Snate@binkert.org 10898232Snate@binkert.orgBEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) 10905517Snate@binkert.org 10918232Snate@binkert.org INIT_PARAM(image, "Disk image"), 10928232Snate@binkert.org INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings), 10938232Snate@binkert.org INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1) 10945517Snate@binkert.org 10958232Snate@binkert.orgEND_INIT_SIM_OBJECT_PARAMS(IdeDisk) 10968232Snate@binkert.org 10978232Snate@binkert.org 10988232Snate@binkert.orgCREATE_SIM_OBJECT(IdeDisk) 10998232Snate@binkert.org{ 11008232Snate@binkert.org return new IdeDisk(getInstanceName(), image, driveID, delay); 11015517Snate@binkert.org} 11028232Snate@binkert.org 11038232Snate@binkert.orgREGISTER_SIM_OBJECT("IdeDisk", IdeDisk) 11045517Snate@binkert.org 11058232Snate@binkert.org#endif //DOXYGEN_SHOULD_SKIP_THIS 11067673Snate@binkert.org