ide_disk.cc revision 2627
12391SN/A/* 22391SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 32391SN/A * All rights reserved. 42391SN/A * 52391SN/A * Redistribution and use in source and binary forms, with or without 62391SN/A * modification, are permitted provided that the following conditions are 72391SN/A * met: redistributions of source code must retain the above copyright 82391SN/A * notice, this list of conditions and the following disclaimer; 92391SN/A * redistributions in binary form must reproduce the above copyright 102391SN/A * notice, this list of conditions and the following disclaimer in the 112391SN/A * documentation and/or other materials provided with the distribution; 122391SN/A * neither the name of the copyright holders nor the names of its 132391SN/A * contributors may be used to endorse or promote products derived from 142391SN/A * this software without specific prior written permission. 152391SN/A * 162391SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252391SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262391SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292391SN/A/** @file 302391SN/A * Device model implementation for an IDE disk 312391SN/A */ 322391SN/A 332391SN/A#include <cerrno> 342391SN/A#include <cstring> 352391SN/A#include <deque> 362391SN/A#include <string> 372391SN/A 382391SN/A#include "base/chunk_generator.hh" 392391SN/A#include "base/cprintf.hh" // csprintf 402391SN/A#include "base/trace.hh" 412391SN/A#include "dev/disk_image.hh" 422391SN/A#include "dev/ide_disk.hh" 432391SN/A#include "dev/ide_ctrl.hh" 442592SN/A#include "dev/tsunami.hh" 452394SN/A#include "dev/tsunami_pchip.hh" 462391SN/A#include "sim/builder.hh" 472391SN/A#include "sim/sim_object.hh" 482415SN/A#include "sim/root.hh" 492423SN/A#include "arch/isa_traits.hh" 502391SN/A 512394SN/Ausing namespace std; 522391SN/Ausing namespace TheISA; 532423SN/A 542391SN/AIdeDisk::IdeDisk(const string &name, DiskImage *img, 552630SN/A int id, Tick delay) 562415SN/A : SimObject(name), ctrl(NULL), image(img), diskDelay(delay), 572415SN/A dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this), 582415SN/A dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this), 592415SN/A dmaReadEvent(this), dmaWriteEvent(this) 602415SN/A{ 612415SN/A // Reset the device state 622415SN/A reset(id); 632415SN/A 642415SN/A // fill out the drive ID structure 652415SN/A memset(&driveID, 0, sizeof(struct ataparams)); 662415SN/A 672415SN/A // Calculate LBA and C/H/S values 682415SN/A uint16_t cylinders; 692415SN/A uint8_t heads; 702415SN/A uint8_t sectors; 712415SN/A 722415SN/A uint32_t lba_size = image->size(); 732415SN/A if (lba_size >= 16383*16*63) { 742565SN/A cylinders = 16383; 752565SN/A heads = 16; 762391SN/A sectors = 63; 772391SN/A } else { 782391SN/A if (lba_size >= 63) 792391SN/A sectors = 63; 802391SN/A else 812391SN/A sectors = lba_size; 822391SN/A 832391SN/A if ((lba_size / sectors) >= 16) 842391SN/A heads = 16; 852391SN/A else 862391SN/A heads = (lba_size / sectors); 872391SN/A 882391SN/A cylinders = lba_size / (heads * sectors); 892391SN/A } 902391SN/A 912391SN/A // Setup the model name 922391SN/A strncpy((char *)driveID.atap_model, "5MI EDD si k", 932391SN/A sizeof(driveID.atap_model)); 942391SN/A // Set the maximum multisector transfer size 952541SN/A driveID.atap_multi = MAX_MULTSECT; 962541SN/A // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 972541SN/A driveID.atap_capabilities1 = 0x7; 982541SN/A // UDMA support, EIDE support 992541SN/A driveID.atap_extensions = 0x6; 1002541SN/A // Setup default C/H/S settings 1012541SN/A driveID.atap_cylinders = cylinders; 1022541SN/A driveID.atap_sectors = sectors; 1032391SN/A driveID.atap_heads = heads; 1042391SN/A // Setup the current multisector transfer size 1052391SN/A driveID.atap_curmulti = MAX_MULTSECT; 1062391SN/A driveID.atap_curmulti_valid = 0x1; 1072416SN/A // Number of sectors on disk 1082391SN/A driveID.atap_capacity = lba_size; 1092391SN/A // Multiword DMA mode 2 and below supported 1102391SN/A driveID.atap_dmamode_supp = 0x400; 1112391SN/A // Set PIO mode 4 and 3 supported 1122391SN/A driveID.atap_piomode_supp = 0x3; 1132391SN/A // Set DMA mode 4 and below supported 1142391SN/A driveID.atap_udmamode_supp = 0x1f; 1152391SN/A // Statically set hardware config word 1162391SN/A driveID.atap_hwreset_res = 0x4001; 1172391SN/A 1182391SN/A //arbitrary for now... 1192391SN/A driveID.atap_ata_major = WDC_VER_ATA7; 1202408SN/A} 1212408SN/A 1222408SN/AIdeDisk::~IdeDisk() 1232409SN/A{ 1242409SN/A // destroy the data buffer 1252408SN/A delete [] dataBuffer; 1262408SN/A} 1272413SN/A 1282630SN/Avoid 1292413SN/AIdeDisk::reset(int id) 1302413SN/A{ 1312415SN/A // initialize the data buffer and shadow registers 1322639Sstever@eecs.umich.edu dataBuffer = new uint8_t[MAX_DMA_SIZE]; 1332641Sstever@eecs.umich.edu 1342416SN/A memset(dataBuffer, 0, MAX_DMA_SIZE); 1352415SN/A memset(&cmdReg, 0, sizeof(CommandReg_t)); 1362415SN/A memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 1372413SN/A 1382413SN/A curPrdAddr = 0; 1392413SN/A curSector = 0; 1402413SN/A cmdBytes = 0; 1412630SN/A cmdBytesLeft = 0; 1422413SN/A drqBytesLeft = 0; 1432413SN/A dmaRead = false; 1442662Sstever@eecs.umich.edu intrPending = false; 1452413SN/A 1462413SN/A // set the device state to idle 1472413SN/A dmaState = Dma_Idle; 1482630SN/A 1492413SN/A if (id == DEV0) { 1502641Sstever@eecs.umich.edu devState = Device_Idle_S; 1512414SN/A devID = DEV0; 1522630SN/A } else if (id == DEV1) { 1532641Sstever@eecs.umich.edu devState = Device_Idle_NS; 1542641Sstever@eecs.umich.edu devID = DEV1; 1552641Sstever@eecs.umich.edu } else { 1562641Sstever@eecs.umich.edu panic("Invalid device ID: %#x\n", id); 1572418SN/A } 1582641Sstever@eecs.umich.edu 1592641Sstever@eecs.umich.edu // set the device ready bit 1602641Sstever@eecs.umich.edu status = STATUS_DRDY_BIT; 1612641Sstever@eecs.umich.edu 1622631SN/A /* The error register must be set to 0x1 on start-up to 1632631SN/A indicate that no diagnostic error was detected */ 1642631SN/A cmdReg.error = 0x1; 1652631SN/A} 1662631SN/A 1672418SN/A//// 1682413SN/A// Utility functions 1692413SN/A//// 1702413SN/A 1712420SN/Abool 1722641Sstever@eecs.umich.eduIdeDisk::isDEVSelect() 1732413SN/A{ 1742413SN/A return ctrl->isDiskSelected(this); 1752413SN/A} 1762738Sstever@eecs.umich.edu 1772413SN/AAddr 1782738Sstever@eecs.umich.eduIdeDisk::pciToDma(Addr pciAddr) 1792499SN/A{ 1802499SN/A if (ctrl) 1812640Sstever@eecs.umich.edu return ctrl->plat->pciToDma(pciAddr); 1822499SN/A else 1832519SN/A panic("Access to unset controller!\n"); 1842519SN/A} 1852640Sstever@eecs.umich.edu 1862462SN/A//// 1872462SN/A// Device registers read/write 1882462SN/A//// 1892413SN/A 1902413SN/Avoid 1912413SN/AIdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data) 1922413SN/A{ 1932413SN/A DevAction_t action = ACT_NONE; 1942413SN/A 1952413SN/A switch (reg_type) { 1962640Sstever@eecs.umich.edu case COMMAND_BLOCK: 1972640Sstever@eecs.umich.edu switch (offset) { 1982640Sstever@eecs.umich.edu // Data transfers occur two bytes at a time 1992413SN/A case DATA_OFFSET: 2002413SN/A *(uint16_t*)data = cmdReg.data; 2012413SN/A action = ACT_DATA_READ_SHORT; 2022413SN/A break; 2032413SN/A case ERROR_OFFSET: 2042413SN/A *data = cmdReg.error; 2052413SN/A break; 2062413SN/A case NSECTOR_OFFSET: 2072413SN/A *data = cmdReg.sec_count; 2082522SN/A break; 2092522SN/A case SECTOR_OFFSET: 2102413SN/A *data = cmdReg.sec_num; 2112522SN/A break; 2122497SN/A case LCYL_OFFSET: 2132497SN/A *data = cmdReg.cyl_low; 2142497SN/A break; 2152522SN/A case HCYL_OFFSET: 2162497SN/A *data = cmdReg.cyl_high; 2172522SN/A break; 2182522SN/A case DRIVE_OFFSET: 2192522SN/A *data = cmdReg.drive; 2202413SN/A break; 2212413SN/A case STATUS_OFFSET: 2222415SN/A *data = status; 2232415SN/A action = ACT_STAT_READ; 2242415SN/A break; 2252415SN/A default: 2262415SN/A panic("Invalid IDE command register offset: %#x\n", offset); 2272413SN/A } 2282413SN/A break; 2292630SN/A case CONTROL_BLOCK: 2302413SN/A if (offset == ALTSTAT_OFFSET) 2312416SN/A *data = status; 2322413SN/A else 2332413SN/A panic("Invalid IDE control register offset: %#x\n", offset); 2342413SN/A break; 2352630SN/A default: 2362413SN/A panic("Unknown register block!\n"); 2372413SN/A } 2382413SN/A DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, 2392413SN/A (uint32_t)*data); 2402413SN/A 2412630SN/A if (action != ACT_NONE) 2422413SN/A updateState(action); 2432413SN/A} 2442413SN/A 2452413SN/Avoid 2462413SN/AIdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data) 2472413SN/A{ 2482391SN/A DevAction_t action = ACT_NONE; 2492391SN/A 2502391SN/A switch (reg_type) { 2512391SN/A case COMMAND_BLOCK: 2522391SN/A switch (offset) { 2532391SN/A case DATA_OFFSET: 2542391SN/A cmdReg.data = *(uint16_t*)data; 2552391SN/A action = ACT_DATA_WRITE_SHORT; 2562391SN/A break; 2572391SN/A case FEATURES_OFFSET: 2582391SN/A break; 2592391SN/A case NSECTOR_OFFSET: 2602391SN/A cmdReg.sec_count = *data; 2612391SN/A break; 2622391SN/A case SECTOR_OFFSET: 2632391SN/A cmdReg.sec_num = *data; 2642391SN/A break; 2652391SN/A case LCYL_OFFSET: 2662391SN/A cmdReg.cyl_low = *data; 2672391SN/A break; 2682391SN/A case HCYL_OFFSET: 2692391SN/A cmdReg.cyl_high = *data; 2702391SN/A break; 2712391SN/A case DRIVE_OFFSET: 2722391SN/A cmdReg.drive = *data; 2732391SN/A action = ACT_SELECT_WRITE; 2742391SN/A break; 2752391SN/A case COMMAND_OFFSET: 2762391SN/A cmdReg.command = *data; 2772391SN/A action = ACT_CMD_WRITE; 2782391SN/A break; 2792391SN/A default: 2802391SN/A panic("Invalid IDE command register offset: %#x\n", offset); 2812391SN/A } 2822391SN/A break; 2832391SN/A case CONTROL_BLOCK: 2842391SN/A if (offset == CONTROL_OFFSET) { 2852391SN/A if (*data & CONTROL_RST_BIT) { 2862391SN/A // force the device into the reset state 2872391SN/A devState = Device_Srst; 2882391SN/A action = ACT_SRST_SET; 2892391SN/A } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) 2902391SN/A action = ACT_SRST_CLEAR; 2912391SN/A 2922391SN/A nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; 2932391SN/A } 2942391SN/A else 2952391SN/A panic("Invalid IDE control register offset: %#x\n", offset); 2962391SN/A break; 2972391SN/A default: 2982391SN/A panic("Unknown register block!\n"); 2992391SN/A } 3002391SN/A 3012391SN/A DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, 3022391SN/A (uint32_t)*data); 3032391SN/A if (action != ACT_NONE) 3042391SN/A updateState(action); 3052391SN/A} 3062391SN/A 3072391SN/A//// 3082391SN/A// Perform DMA transactions 3092391SN/A//// 3102391SN/A 3112391SN/Avoid 3122391SN/AIdeDisk::doDmaTransfer() 3132391SN/A{ 3142391SN/A if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 3152391SN/A panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 3162391SN/A dmaState, devState); 3172391SN/A 3182391SN/A if (ctrl->dmaPending()) { 3192391SN/A dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 3202391SN/A return; 3212391SN/A } else 3222391SN/A ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent, 3232391SN/A (uint8_t*)&curPrd.entry); 3242391SN/A} 3252391SN/A 3262391SN/Avoid 3272391SN/AIdeDisk::dmaPrdReadDone() 3282391SN/A{ 3292391SN/A DPRINTF(IdeDisk, 3302391SN/A "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", 3312391SN/A curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), 3322391SN/A curPrd.getByteCount(), (cmdBytesLeft/SectorSize), 3332391SN/A curPrd.getEOT(), curSector); 3342391SN/A 3352391SN/A // the prd pointer has already been translated, so just do an increment 3362391SN/A curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); 3372391SN/A 3382391SN/A if (dmaRead) 3392391SN/A doDmaDataRead(); 3402391SN/A else 3412391SN/A doDmaDataWrite(); 3422391SN/A} 3432391SN/A 3442391SN/Avoid 3452391SN/AIdeDisk::doDmaDataRead() 3462391SN/A{ 3472391SN/A /** @todo we need to figure out what the delay actually will be */ 3482391SN/A Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 3492391SN/A 3502391SN/A DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", 3512391SN/A diskDelay, totalDiskDelay); 3522391SN/A 3532391SN/A dmaReadWaitEvent.schedule(curTick + totalDiskDelay); 3542391SN/A} 3552413SN/A 3562391SN/Avoid 3572391SN/AIdeDisk::regStats() 3582391SN/A{ 3592391SN/A using namespace Stats; 3602565SN/A dmaReadFullPages 3612391SN/A .name(name() + ".dma_read_full_pages") 3622391SN/A .desc("Number of full page size DMA reads (not PRD).") 3632391SN/A ; 3642391SN/A dmaReadBytes 3652391SN/A .name(name() + ".dma_read_bytes") 3662391SN/A .desc("Number of bytes transfered via DMA reads (not PRD).") 3672565SN/A ; 3682565SN/A dmaReadTxs 3692391SN/A .name(name() + ".dma_read_txs") 3702391SN/A .desc("Number of DMA read transactions (not PRD).") 3712391SN/A ; 3722391SN/A 3732391SN/A dmaWriteFullPages 3742391SN/A .name(name() + ".dma_write_full_pages") 3752565SN/A .desc("Number of full page size DMA writes.") 3762391SN/A ; 3772391SN/A dmaWriteBytes 3782391SN/A .name(name() + ".dma_write_bytes") 379 .desc("Number of bytes transfered via DMA writes.") 380 ; 381 dmaWriteTxs 382 .name(name() + ".dma_write_txs") 383 .desc("Number of DMA write transactions.") 384 ; 385} 386 387void 388IdeDisk::doDmaRead() 389{ 390 391 if (!dmaReadCG) { 392 // clear out the data buffer 393 memset(dataBuffer, 0, MAX_DMA_SIZE); 394 dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(), 395 curPrd.getByteCount(), TheISA::PageBytes); 396 397 } 398 if (ctrl->dmaPending()) { 399 panic("shouldn't be reentant??"); 400 dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 401 return; 402 } else if (!dmaReadCG->done()) { 403 assert(dmaReadCG->complete() < MAX_DMA_SIZE); 404 ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(), 405 &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete()); 406 dmaReadBytes += dmaReadCG->size(); 407 dmaReadTxs++; 408 if (dmaReadCG->size() == TheISA::PageBytes) 409 dmaReadFullPages++; 410 dmaReadCG->next(); 411 } else { 412 assert(dmaReadCG->done()); 413 delete dmaReadCG; 414 dmaReadCG = NULL; 415 dmaReadDone(); 416 } 417} 418 419void 420IdeDisk::dmaReadDone() 421{ 422 423 uint32_t bytesWritten = 0; 424 425 426 // write the data to the disk image 427 for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); 428 bytesWritten += SectorSize) { 429 430 cmdBytesLeft -= SectorSize; 431 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 432 } 433 434 // check for the EOT 435 if (curPrd.getEOT()) { 436 assert(cmdBytesLeft == 0); 437 dmaState = Dma_Idle; 438 updateState(ACT_DMA_DONE); 439 } else { 440 doDmaTransfer(); 441 } 442} 443 444void 445IdeDisk::doDmaDataWrite() 446{ 447 /** @todo we need to figure out what the delay actually will be */ 448 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 449 uint32_t bytesRead = 0; 450 451 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", 452 diskDelay, totalDiskDelay); 453 454 memset(dataBuffer, 0, MAX_DMA_SIZE); 455 assert(cmdBytesLeft <= MAX_DMA_SIZE); 456 while (bytesRead < curPrd.getByteCount()) { 457 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 458 bytesRead += SectorSize; 459 cmdBytesLeft -= SectorSize; 460 } 461 462 dmaWriteWaitEvent.schedule(curTick + totalDiskDelay); 463} 464 465void 466IdeDisk::doDmaWrite() 467{ 468 469 if (!dmaWriteCG) { 470 // clear out the data buffer 471 dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), 472 curPrd.getByteCount(), TheISA::PageBytes); 473 } 474 if (ctrl->dmaPending()) { 475 panic("shouldn't be reentant??"); 476 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 477 return; 478 } else if (!dmaWriteCG->done()) { 479 assert(dmaWriteCG->complete() < MAX_DMA_SIZE); 480 ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(), 481 &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete()); 482 dmaWriteBytes += dmaWriteCG->size(); 483 dmaWriteTxs++; 484 if (dmaWriteCG->size() == TheISA::PageBytes) 485 dmaWriteFullPages++; 486 dmaWriteCG->next(); 487 } else { 488 assert(dmaWriteCG->done()); 489 delete dmaWriteCG; 490 dmaWriteCG = NULL; 491 dmaWriteDone(); 492 } 493} 494 495void 496IdeDisk::dmaWriteDone() 497{ 498 // check for the EOT 499 if (curPrd.getEOT()) { 500 assert(cmdBytesLeft == 0); 501 dmaState = Dma_Idle; 502 updateState(ACT_DMA_DONE); 503 } else { 504 doDmaTransfer(); 505 } 506} 507 508//// 509// Disk utility routines 510/// 511 512void 513IdeDisk::readDisk(uint32_t sector, uint8_t *data) 514{ 515 uint32_t bytesRead = image->read(data, sector); 516 517 if (bytesRead != SectorSize) 518 panic("Can't read from %s. Only %d of %d read. errno=%d\n", 519 name(), bytesRead, SectorSize, errno); 520} 521 522void 523IdeDisk::writeDisk(uint32_t sector, uint8_t *data) 524{ 525 uint32_t bytesWritten = image->write(data, sector); 526 527 if (bytesWritten != SectorSize) 528 panic("Can't write to %s. Only %d of %d written. errno=%d\n", 529 name(), bytesWritten, SectorSize, errno); 530} 531 532//// 533// Setup and handle commands 534//// 535 536void 537IdeDisk::startDma(const uint32_t &prdTableBase) 538{ 539 if (dmaState != Dma_Start) 540 panic("Inconsistent DMA state, should be in Dma_Start!\n"); 541 542 if (devState != Transfer_Data_Dma) 543 panic("Inconsistent device state for DMA start!\n"); 544 545 // PRD base address is given by bits 31:2 546 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); 547 548 dmaState = Dma_Transfer; 549 550 // schedule dma transfer (doDmaTransfer) 551 dmaTransferEvent.schedule(curTick + 1); 552} 553 554void 555IdeDisk::abortDma() 556{ 557 if (dmaState == Dma_Idle) 558 panic("Inconsistent DMA state, should be Start or Transfer!"); 559 560 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 561 panic("Inconsistent device state, should be Transfer or Prepare!\n"); 562 563 updateState(ACT_CMD_ERROR); 564} 565 566void 567IdeDisk::startCommand() 568{ 569 DevAction_t action = ACT_NONE; 570 uint32_t size = 0; 571 dmaRead = false; 572 573 // Decode commands 574 switch (cmdReg.command) { 575 // Supported non-data commands 576 case WDSF_READ_NATIVE_MAX: 577 size = image->size() - 1; 578 cmdReg.sec_num = (size & 0xff); 579 cmdReg.cyl_low = ((size & 0xff00) >> 8); 580 cmdReg.cyl_high = ((size & 0xff0000) >> 16); 581 cmdReg.head = ((size & 0xf000000) >> 24); 582 583 devState = Command_Execution; 584 action = ACT_CMD_COMPLETE; 585 break; 586 587 case WDCC_RECAL: 588 case WDCC_IDP: 589 case WDCC_STANDBY_IMMED: 590 case WDCC_FLUSHCACHE: 591 case WDSF_VERIFY: 592 case WDSF_SEEK: 593 case SET_FEATURES: 594 case WDCC_SETMULTI: 595 devState = Command_Execution; 596 action = ACT_CMD_COMPLETE; 597 break; 598 599 // Supported PIO data-in commands 600 case WDCC_IDENTIFY: 601 cmdBytes = cmdBytesLeft = sizeof(struct ataparams); 602 devState = Prepare_Data_In; 603 action = ACT_DATA_READY; 604 break; 605 606 case WDCC_READMULTI: 607 case WDCC_READ: 608 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 609 panic("Attempt to perform CHS access, only supports LBA\n"); 610 611 if (cmdReg.sec_count == 0) 612 cmdBytes = cmdBytesLeft = (256 * SectorSize); 613 else 614 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 615 616 curSector = getLBABase(); 617 618 /** @todo make this a scheduled event to simulate disk delay */ 619 devState = Prepare_Data_In; 620 action = ACT_DATA_READY; 621 break; 622 623 // Supported PIO data-out commands 624 case WDCC_WRITEMULTI: 625 case WDCC_WRITE: 626 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 627 panic("Attempt to perform CHS access, only supports LBA\n"); 628 629 if (cmdReg.sec_count == 0) 630 cmdBytes = cmdBytesLeft = (256 * SectorSize); 631 else 632 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 633 634 curSector = getLBABase(); 635 636 devState = Prepare_Data_Out; 637 action = ACT_DATA_READY; 638 break; 639 640 // Supported DMA commands 641 case WDCC_WRITEDMA: 642 dmaRead = true; // a write to the disk is a DMA read from memory 643 case WDCC_READDMA: 644 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 645 panic("Attempt to perform CHS access, only supports LBA\n"); 646 647 if (cmdReg.sec_count == 0) 648 cmdBytes = cmdBytesLeft = (256 * SectorSize); 649 else 650 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 651 652 curSector = getLBABase(); 653 654 devState = Prepare_Data_Dma; 655 action = ACT_DMA_READY; 656 break; 657 658 default: 659 panic("Unsupported ATA command: %#x\n", cmdReg.command); 660 } 661 662 if (action != ACT_NONE) { 663 // set the BSY bit 664 status |= STATUS_BSY_BIT; 665 // clear the DRQ bit 666 status &= ~STATUS_DRQ_BIT; 667 // clear the DF bit 668 status &= ~STATUS_DF_BIT; 669 670 updateState(action); 671 } 672} 673 674//// 675// Handle setting and clearing interrupts 676//// 677 678void 679IdeDisk::intrPost() 680{ 681 DPRINTF(IdeDisk, "Posting Interrupt\n"); 682 if (intrPending) 683 panic("Attempt to post an interrupt with one pending\n"); 684 685 intrPending = true; 686 687 // talk to controller to set interrupt 688 if (ctrl) { 689 ctrl->bmi_regs.bmis0 |= IDEINTS; 690 ctrl->intrPost(); 691 } 692} 693 694void 695IdeDisk::intrClear() 696{ 697 DPRINTF(IdeDisk, "Clearing Interrupt\n"); 698 if (!intrPending) 699 panic("Attempt to clear a non-pending interrupt\n"); 700 701 intrPending = false; 702 703 // talk to controller to clear interrupt 704 if (ctrl) 705 ctrl->intrClear(); 706} 707 708//// 709// Manage the device internal state machine 710//// 711 712void 713IdeDisk::updateState(DevAction_t action) 714{ 715 switch (devState) { 716 case Device_Srst: 717 if (action == ACT_SRST_SET) { 718 // set the BSY bit 719 status |= STATUS_BSY_BIT; 720 } else if (action == ACT_SRST_CLEAR) { 721 // clear the BSY bit 722 status &= ~STATUS_BSY_BIT; 723 724 // reset the device state 725 reset(devID); 726 } 727 break; 728 729 case Device_Idle_S: 730 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 731 devState = Device_Idle_NS; 732 } else if (action == ACT_CMD_WRITE) { 733 startCommand(); 734 } 735 736 break; 737 738 case Device_Idle_SI: 739 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 740 devState = Device_Idle_NS; 741 intrClear(); 742 } else if (action == ACT_STAT_READ || isIENSet()) { 743 devState = Device_Idle_S; 744 intrClear(); 745 } else if (action == ACT_CMD_WRITE) { 746 intrClear(); 747 startCommand(); 748 } 749 750 break; 751 752 case Device_Idle_NS: 753 if (action == ACT_SELECT_WRITE && isDEVSelect()) { 754 if (!isIENSet() && intrPending) { 755 devState = Device_Idle_SI; 756 intrPost(); 757 } 758 if (isIENSet() || !intrPending) { 759 devState = Device_Idle_S; 760 } 761 } 762 break; 763 764 case Command_Execution: 765 if (action == ACT_CMD_COMPLETE) { 766 // clear the BSY bit 767 setComplete(); 768 769 if (!isIENSet()) { 770 devState = Device_Idle_SI; 771 intrPost(); 772 } else { 773 devState = Device_Idle_S; 774 } 775 } 776 break; 777 778 case Prepare_Data_In: 779 if (action == ACT_CMD_ERROR) { 780 // clear the BSY bit 781 setComplete(); 782 783 if (!isIENSet()) { 784 devState = Device_Idle_SI; 785 intrPost(); 786 } else { 787 devState = Device_Idle_S; 788 } 789 } else if (action == ACT_DATA_READY) { 790 // clear the BSY bit 791 status &= ~STATUS_BSY_BIT; 792 // set the DRQ bit 793 status |= STATUS_DRQ_BIT; 794 795 // copy the data into the data buffer 796 if (cmdReg.command == WDCC_IDENTIFY) { 797 // Reset the drqBytes for this block 798 drqBytesLeft = sizeof(struct ataparams); 799 800 memcpy((void *)dataBuffer, (void *)&driveID, 801 sizeof(struct ataparams)); 802 } else { 803 // Reset the drqBytes for this block 804 drqBytesLeft = SectorSize; 805 806 readDisk(curSector++, dataBuffer); 807 } 808 809 // put the first two bytes into the data register 810 memcpy((void *)&cmdReg.data, (void *)dataBuffer, 811 sizeof(uint16_t)); 812 813 if (!isIENSet()) { 814 devState = Data_Ready_INTRQ_In; 815 intrPost(); 816 } else { 817 devState = Transfer_Data_In; 818 } 819 } 820 break; 821 822 case Data_Ready_INTRQ_In: 823 if (action == ACT_STAT_READ) { 824 devState = Transfer_Data_In; 825 intrClear(); 826 } 827 break; 828 829 case Transfer_Data_In: 830 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 831 if (action == ACT_DATA_READ_BYTE) { 832 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 833 } else { 834 drqBytesLeft -= 2; 835 cmdBytesLeft -= 2; 836 837 // copy next short into data registers 838 if (drqBytesLeft) 839 memcpy((void *)&cmdReg.data, 840 (void *)&dataBuffer[SectorSize - drqBytesLeft], 841 sizeof(uint16_t)); 842 } 843 844 if (drqBytesLeft == 0) { 845 if (cmdBytesLeft == 0) { 846 // Clear the BSY bit 847 setComplete(); 848 devState = Device_Idle_S; 849 } else { 850 devState = Prepare_Data_In; 851 // set the BSY_BIT 852 status |= STATUS_BSY_BIT; 853 // clear the DRQ_BIT 854 status &= ~STATUS_DRQ_BIT; 855 856 /** @todo change this to a scheduled event to simulate 857 disk delay */ 858 updateState(ACT_DATA_READY); 859 } 860 } 861 } 862 break; 863 864 case Prepare_Data_Out: 865 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 866 // clear the BSY bit 867 setComplete(); 868 869 if (!isIENSet()) { 870 devState = Device_Idle_SI; 871 intrPost(); 872 } else { 873 devState = Device_Idle_S; 874 } 875 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { 876 // clear the BSY bit 877 status &= ~STATUS_BSY_BIT; 878 // set the DRQ bit 879 status |= STATUS_DRQ_BIT; 880 881 // clear the data buffer to get it ready for writes 882 memset(dataBuffer, 0, MAX_DMA_SIZE); 883 884 // reset the drqBytes for this block 885 drqBytesLeft = SectorSize; 886 887 if (cmdBytesLeft == cmdBytes || isIENSet()) { 888 devState = Transfer_Data_Out; 889 } else { 890 devState = Data_Ready_INTRQ_Out; 891 intrPost(); 892 } 893 } 894 break; 895 896 case Data_Ready_INTRQ_Out: 897 if (action == ACT_STAT_READ) { 898 devState = Transfer_Data_Out; 899 intrClear(); 900 } 901 break; 902 903 case Transfer_Data_Out: 904 if (action == ACT_DATA_WRITE_BYTE || 905 action == ACT_DATA_WRITE_SHORT) { 906 907 if (action == ACT_DATA_READ_BYTE) { 908 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 909 } else { 910 // copy the latest short into the data buffer 911 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 912 (void *)&cmdReg.data, 913 sizeof(uint16_t)); 914 915 drqBytesLeft -= 2; 916 cmdBytesLeft -= 2; 917 } 918 919 if (drqBytesLeft == 0) { 920 // copy the block to the disk 921 writeDisk(curSector++, dataBuffer); 922 923 // set the BSY bit 924 status |= STATUS_BSY_BIT; 925 // set the seek bit 926 status |= STATUS_SEEK_BIT; 927 // clear the DRQ bit 928 status &= ~STATUS_DRQ_BIT; 929 930 devState = Prepare_Data_Out; 931 932 /** @todo change this to a scheduled event to simulate 933 disk delay */ 934 updateState(ACT_DATA_READY); 935 } 936 } 937 break; 938 939 case Prepare_Data_Dma: 940 if (action == ACT_CMD_ERROR) { 941 // clear the BSY bit 942 setComplete(); 943 944 if (!isIENSet()) { 945 devState = Device_Idle_SI; 946 intrPost(); 947 } else { 948 devState = Device_Idle_S; 949 } 950 } else if (action == ACT_DMA_READY) { 951 // clear the BSY bit 952 status &= ~STATUS_BSY_BIT; 953 // set the DRQ bit 954 status |= STATUS_DRQ_BIT; 955 956 devState = Transfer_Data_Dma; 957 958 if (dmaState != Dma_Idle) 959 panic("Inconsistent DMA state, should be Dma_Idle\n"); 960 961 dmaState = Dma_Start; 962 // wait for the write to the DMA start bit 963 } 964 break; 965 966 case Transfer_Data_Dma: 967 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { 968 // clear the BSY bit 969 setComplete(); 970 // set the seek bit 971 status |= STATUS_SEEK_BIT; 972 // clear the controller state for DMA transfer 973 ctrl->setDmaComplete(this); 974 975 if (!isIENSet()) { 976 devState = Device_Idle_SI; 977 intrPost(); 978 } else { 979 devState = Device_Idle_S; 980 } 981 } 982 break; 983 984 default: 985 panic("Unknown IDE device state: %#x\n", devState); 986 } 987} 988 989void 990IdeDisk::serialize(ostream &os) 991{ 992 // Check all outstanding events to see if they are scheduled 993 // these are all mutually exclusive 994 Tick reschedule = 0; 995 Events_t event = None; 996 997 int eventCount = 0; 998 999 if (dmaTransferEvent.scheduled()) { 1000 reschedule = dmaTransferEvent.when(); 1001 event = Transfer; 1002 eventCount++; 1003 } 1004 if (dmaReadWaitEvent.scheduled()) { 1005 reschedule = dmaReadWaitEvent.when(); 1006 event = ReadWait; 1007 eventCount++; 1008 } 1009 if (dmaWriteWaitEvent.scheduled()) { 1010 reschedule = dmaWriteWaitEvent.when(); 1011 event = WriteWait; 1012 eventCount++; 1013 } 1014 if (dmaPrdReadEvent.scheduled()) { 1015 reschedule = dmaPrdReadEvent.when(); 1016 event = PrdRead; 1017 eventCount++; 1018 } 1019 if (dmaReadEvent.scheduled()) { 1020 reschedule = dmaReadEvent.when(); 1021 event = DmaRead; 1022 eventCount++; 1023 } 1024 if (dmaWriteEvent.scheduled()) { 1025 reschedule = dmaWriteEvent.when(); 1026 event = DmaWrite; 1027 eventCount++; 1028 } 1029 1030 assert(eventCount <= 1); 1031 1032 SERIALIZE_SCALAR(reschedule); 1033 SERIALIZE_ENUM(event); 1034 1035 // Serialize device registers 1036 SERIALIZE_SCALAR(cmdReg.data); 1037 SERIALIZE_SCALAR(cmdReg.sec_count); 1038 SERIALIZE_SCALAR(cmdReg.sec_num); 1039 SERIALIZE_SCALAR(cmdReg.cyl_low); 1040 SERIALIZE_SCALAR(cmdReg.cyl_high); 1041 SERIALIZE_SCALAR(cmdReg.drive); 1042 SERIALIZE_SCALAR(cmdReg.command); 1043 SERIALIZE_SCALAR(status); 1044 SERIALIZE_SCALAR(nIENBit); 1045 SERIALIZE_SCALAR(devID); 1046 1047 // Serialize the PRD related information 1048 SERIALIZE_SCALAR(curPrd.entry.baseAddr); 1049 SERIALIZE_SCALAR(curPrd.entry.byteCount); 1050 SERIALIZE_SCALAR(curPrd.entry.endOfTable); 1051 SERIALIZE_SCALAR(curPrdAddr); 1052 1053 /** @todo need to serialized chunk generator stuff!! */ 1054 // Serialize current transfer related information 1055 SERIALIZE_SCALAR(cmdBytesLeft); 1056 SERIALIZE_SCALAR(cmdBytes); 1057 SERIALIZE_SCALAR(drqBytesLeft); 1058 SERIALIZE_SCALAR(curSector); 1059 SERIALIZE_SCALAR(dmaRead); 1060 SERIALIZE_SCALAR(intrPending); 1061 SERIALIZE_ENUM(devState); 1062 SERIALIZE_ENUM(dmaState); 1063 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1064} 1065 1066void 1067IdeDisk::unserialize(Checkpoint *cp, const string §ion) 1068{ 1069 // Reschedule events that were outstanding 1070 // these are all mutually exclusive 1071 Tick reschedule = 0; 1072 Events_t event = None; 1073 1074 UNSERIALIZE_SCALAR(reschedule); 1075 UNSERIALIZE_ENUM(event); 1076 1077 switch (event) { 1078 case None : break; 1079 case Transfer : dmaTransferEvent.schedule(reschedule); break; 1080 case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; 1081 case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; 1082 case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; 1083 case DmaRead : dmaReadEvent.schedule(reschedule); break; 1084 case DmaWrite : dmaWriteEvent.schedule(reschedule); break; 1085 } 1086 1087 // Unserialize device registers 1088 UNSERIALIZE_SCALAR(cmdReg.data); 1089 UNSERIALIZE_SCALAR(cmdReg.sec_count); 1090 UNSERIALIZE_SCALAR(cmdReg.sec_num); 1091 UNSERIALIZE_SCALAR(cmdReg.cyl_low); 1092 UNSERIALIZE_SCALAR(cmdReg.cyl_high); 1093 UNSERIALIZE_SCALAR(cmdReg.drive); 1094 UNSERIALIZE_SCALAR(cmdReg.command); 1095 UNSERIALIZE_SCALAR(status); 1096 UNSERIALIZE_SCALAR(nIENBit); 1097 UNSERIALIZE_SCALAR(devID); 1098 1099 // Unserialize the PRD related information 1100 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); 1101 UNSERIALIZE_SCALAR(curPrd.entry.byteCount); 1102 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); 1103 UNSERIALIZE_SCALAR(curPrdAddr); 1104 1105 /** @todo need to serialized chunk generator stuff!! */ 1106 // Unserialize current transfer related information 1107 UNSERIALIZE_SCALAR(cmdBytes); 1108 UNSERIALIZE_SCALAR(cmdBytesLeft); 1109 UNSERIALIZE_SCALAR(drqBytesLeft); 1110 UNSERIALIZE_SCALAR(curSector); 1111 UNSERIALIZE_SCALAR(dmaRead); 1112 UNSERIALIZE_SCALAR(intrPending); 1113 UNSERIALIZE_ENUM(devState); 1114 UNSERIALIZE_ENUM(dmaState); 1115 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1116} 1117 1118#ifndef DOXYGEN_SHOULD_SKIP_THIS 1119 1120enum DriveID { master, slave }; 1121static const char *DriveID_strings[] = { "master", "slave" }; 1122BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 1123 1124 SimObjectParam<DiskImage *> image; 1125 SimpleEnumParam<DriveID> driveID; 1126 Param<int> delay; 1127 1128END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 1129 1130BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) 1131 1132 INIT_PARAM(image, "Disk image"), 1133 INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings), 1134 INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1) 1135 1136END_INIT_SIM_OBJECT_PARAMS(IdeDisk) 1137 1138 1139CREATE_SIM_OBJECT(IdeDisk) 1140{ 1141 return new IdeDisk(getInstanceName(), image, driveID, delay); 1142} 1143 1144REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) 1145 1146#endif //DOXYGEN_SHOULD_SKIP_THIS 1147