ide_disk.cc revision 11264
1/* 2 * Copyright (c) 2013 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2004-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Andrew Schultz 41 * Ali Saidi 42 */ 43 44/** @file 45 * Device model implementation for an IDE disk 46 */ 47 48#include "dev/storage/ide_disk.hh" 49 50#include <cerrno> 51#include <cstring> 52#include <deque> 53#include <string> 54 55#include "arch/isa_traits.hh" 56#include "base/chunk_generator.hh" 57#include "base/cprintf.hh" // csprintf 58#include "base/trace.hh" 59#include "config/the_isa.hh" 60#include "debug/IdeDisk.hh" 61#include "dev/storage/disk_image.hh" 62#include "dev/storage/ide_ctrl.hh" 63#include "sim/core.hh" 64#include "sim/sim_object.hh" 65 66using namespace std; 67using namespace TheISA; 68 69IdeDisk::IdeDisk(const Params *p) 70 : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay), 71 dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this), 72 dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this), 73 dmaReadEvent(this), dmaWriteEvent(this) 74{ 75 // Reset the device state 76 reset(p->driveID); 77 78 // fill out the drive ID structure 79 memset(&driveID, 0, sizeof(struct ataparams)); 80 81 // Calculate LBA and C/H/S values 82 uint16_t cylinders; 83 uint8_t heads; 84 uint8_t sectors; 85 86 uint32_t lba_size = image->size(); 87 if (lba_size >= 16383*16*63) { 88 cylinders = 16383; 89 heads = 16; 90 sectors = 63; 91 } else { 92 if (lba_size >= 63) 93 sectors = 63; 94 else if (lba_size == 0) 95 panic("Bad IDE image size: 0\n"); 96 else 97 sectors = lba_size; 98 99 if ((lba_size / sectors) >= 16) 100 heads = 16; 101 else 102 heads = (lba_size / sectors); 103 104 cylinders = lba_size / (heads * sectors); 105 } 106 107 // Setup the model name 108 strncpy((char *)driveID.atap_model, "5MI EDD si k", 109 sizeof(driveID.atap_model)); 110 // Set the maximum multisector transfer size 111 driveID.atap_multi = MAX_MULTSECT; 112 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 113 driveID.atap_capabilities1 = 0x7; 114 // UDMA support, EIDE support 115 driveID.atap_extensions = 0x6; 116 // Setup default C/H/S settings 117 driveID.atap_cylinders = cylinders; 118 driveID.atap_sectors = sectors; 119 driveID.atap_heads = heads; 120 // Setup the current multisector transfer size 121 driveID.atap_curmulti = MAX_MULTSECT; 122 driveID.atap_curmulti_valid = 0x1; 123 // Number of sectors on disk 124 driveID.atap_capacity = lba_size; 125 // Multiword DMA mode 2 and below supported 126 driveID.atap_dmamode_supp = 0x4; 127 // Set PIO mode 4 and 3 supported 128 driveID.atap_piomode_supp = 0x3; 129 // Set DMA mode 4 and below supported 130 driveID.atap_udmamode_supp = 0x1f; 131 // Statically set hardware config word 132 driveID.atap_hwreset_res = 0x4001; 133 134 //arbitrary for now... 135 driveID.atap_ata_major = WDC_VER_ATA7; 136} 137 138IdeDisk::~IdeDisk() 139{ 140 // destroy the data buffer 141 delete [] dataBuffer; 142} 143 144void 145IdeDisk::reset(int id) 146{ 147 // initialize the data buffer and shadow registers 148 dataBuffer = new uint8_t[MAX_DMA_SIZE]; 149 150 memset(dataBuffer, 0, MAX_DMA_SIZE); 151 memset(&cmdReg, 0, sizeof(CommandReg_t)); 152 memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 153 154 curPrdAddr = 0; 155 curSector = 0; 156 cmdBytes = 0; 157 cmdBytesLeft = 0; 158 drqBytesLeft = 0; 159 dmaRead = false; 160 intrPending = false; 161 dmaAborted = false; 162 163 // set the device state to idle 164 dmaState = Dma_Idle; 165 166 if (id == DEV0) { 167 devState = Device_Idle_S; 168 devID = DEV0; 169 } else if (id == DEV1) { 170 devState = Device_Idle_NS; 171 devID = DEV1; 172 } else { 173 panic("Invalid device ID: %#x\n", id); 174 } 175 176 // set the device ready bit 177 status = STATUS_DRDY_BIT; 178 179 /* The error register must be set to 0x1 on start-up to 180 indicate that no diagnostic error was detected */ 181 cmdReg.error = 0x1; 182} 183 184//// 185// Utility functions 186//// 187 188bool 189IdeDisk::isDEVSelect() 190{ 191 return ctrl->isDiskSelected(this); 192} 193 194Addr 195IdeDisk::pciToDma(Addr pciAddr) 196{ 197 if (ctrl) 198 return ctrl->pciToDma(pciAddr); 199 else 200 panic("Access to unset controller!\n"); 201} 202 203//// 204// Device registers read/write 205//// 206 207void 208IdeDisk::readCommand(const Addr offset, int size, uint8_t *data) 209{ 210 if (offset == DATA_OFFSET) { 211 if (size == sizeof(uint16_t)) { 212 *(uint16_t *)data = cmdReg.data; 213 } else if (size == sizeof(uint32_t)) { 214 *(uint16_t *)data = cmdReg.data; 215 updateState(ACT_DATA_READ_SHORT); 216 *((uint16_t *)data + 1) = cmdReg.data; 217 } else { 218 panic("Data read of unsupported size %d.\n", size); 219 } 220 updateState(ACT_DATA_READ_SHORT); 221 return; 222 } 223 assert(size == sizeof(uint8_t)); 224 switch (offset) { 225 case ERROR_OFFSET: 226 *data = cmdReg.error; 227 break; 228 case NSECTOR_OFFSET: 229 *data = cmdReg.sec_count; 230 break; 231 case SECTOR_OFFSET: 232 *data = cmdReg.sec_num; 233 break; 234 case LCYL_OFFSET: 235 *data = cmdReg.cyl_low; 236 break; 237 case HCYL_OFFSET: 238 *data = cmdReg.cyl_high; 239 break; 240 case DRIVE_OFFSET: 241 *data = cmdReg.drive; 242 break; 243 case STATUS_OFFSET: 244 *data = status; 245 updateState(ACT_STAT_READ); 246 break; 247 default: 248 panic("Invalid IDE command register offset: %#x\n", offset); 249 } 250 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data); 251} 252 253void 254IdeDisk::readControl(const Addr offset, int size, uint8_t *data) 255{ 256 assert(size == sizeof(uint8_t)); 257 *data = status; 258 if (offset != ALTSTAT_OFFSET) 259 panic("Invalid IDE control register offset: %#x\n", offset); 260 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data); 261} 262 263void 264IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data) 265{ 266 if (offset == DATA_OFFSET) { 267 if (size == sizeof(uint16_t)) { 268 cmdReg.data = *(const uint16_t *)data; 269 } else if (size == sizeof(uint32_t)) { 270 cmdReg.data = *(const uint16_t *)data; 271 updateState(ACT_DATA_WRITE_SHORT); 272 cmdReg.data = *((const uint16_t *)data + 1); 273 } else { 274 panic("Data write of unsupported size %d.\n", size); 275 } 276 updateState(ACT_DATA_WRITE_SHORT); 277 return; 278 } 279 280 assert(size == sizeof(uint8_t)); 281 switch (offset) { 282 case FEATURES_OFFSET: 283 break; 284 case NSECTOR_OFFSET: 285 cmdReg.sec_count = *data; 286 break; 287 case SECTOR_OFFSET: 288 cmdReg.sec_num = *data; 289 break; 290 case LCYL_OFFSET: 291 cmdReg.cyl_low = *data; 292 break; 293 case HCYL_OFFSET: 294 cmdReg.cyl_high = *data; 295 break; 296 case DRIVE_OFFSET: 297 cmdReg.drive = *data; 298 updateState(ACT_SELECT_WRITE); 299 break; 300 case COMMAND_OFFSET: 301 cmdReg.command = *data; 302 updateState(ACT_CMD_WRITE); 303 break; 304 default: 305 panic("Invalid IDE command register offset: %#x\n", offset); 306 } 307 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, 308 (uint32_t)*data); 309} 310 311void 312IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data) 313{ 314 if (offset != CONTROL_OFFSET) 315 panic("Invalid IDE control register offset: %#x\n", offset); 316 317 if (*data & CONTROL_RST_BIT) { 318 // force the device into the reset state 319 devState = Device_Srst; 320 updateState(ACT_SRST_SET); 321 } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) { 322 updateState(ACT_SRST_CLEAR); 323 } 324 325 nIENBit = *data & CONTROL_IEN_BIT; 326 327 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, 328 (uint32_t)*data); 329} 330 331//// 332// Perform DMA transactions 333//// 334 335void 336IdeDisk::doDmaTransfer() 337{ 338 if (dmaAborted) { 339 DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n"); 340 updateState(ACT_CMD_ERROR); 341 return; 342 } 343 344 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 345 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 346 dmaState, devState); 347 348 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 349 schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD); 350 return; 351 } else 352 ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent, 353 (uint8_t*)&curPrd.entry); 354} 355 356void 357IdeDisk::dmaPrdReadDone() 358{ 359 if (dmaAborted) { 360 DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n"); 361 updateState(ACT_CMD_ERROR); 362 return; 363 } 364 365 DPRINTF(IdeDisk, 366 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", 367 curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), 368 curPrd.getByteCount(), (cmdBytesLeft/SectorSize), 369 curPrd.getEOT(), curSector); 370 371 // the prd pointer has already been translated, so just do an increment 372 curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); 373 374 if (dmaRead) 375 doDmaDataRead(); 376 else 377 doDmaDataWrite(); 378} 379 380void 381IdeDisk::doDmaDataRead() 382{ 383 /** @todo we need to figure out what the delay actually will be */ 384 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 385 386 DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", 387 diskDelay, totalDiskDelay); 388 389 schedule(dmaReadWaitEvent, curTick() + totalDiskDelay); 390} 391 392void 393IdeDisk::regStats() 394{ 395 using namespace Stats; 396 dmaReadFullPages 397 .name(name() + ".dma_read_full_pages") 398 .desc("Number of full page size DMA reads (not PRD).") 399 ; 400 dmaReadBytes 401 .name(name() + ".dma_read_bytes") 402 .desc("Number of bytes transfered via DMA reads (not PRD).") 403 ; 404 dmaReadTxs 405 .name(name() + ".dma_read_txs") 406 .desc("Number of DMA read transactions (not PRD).") 407 ; 408 409 dmaWriteFullPages 410 .name(name() + ".dma_write_full_pages") 411 .desc("Number of full page size DMA writes.") 412 ; 413 dmaWriteBytes 414 .name(name() + ".dma_write_bytes") 415 .desc("Number of bytes transfered via DMA writes.") 416 ; 417 dmaWriteTxs 418 .name(name() + ".dma_write_txs") 419 .desc("Number of DMA write transactions.") 420 ; 421} 422 423void 424IdeDisk::doDmaRead() 425{ 426 if (dmaAborted) { 427 DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n"); 428 if (dmaReadCG) 429 delete dmaReadCG; 430 dmaReadCG = NULL; 431 updateState(ACT_CMD_ERROR); 432 return; 433 } 434 435 if (!dmaReadCG) { 436 // clear out the data buffer 437 memset(dataBuffer, 0, MAX_DMA_SIZE); 438 dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(), 439 curPrd.getByteCount(), TheISA::PageBytes); 440 441 } 442 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 443 schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD); 444 return; 445 } else if (!dmaReadCG->done()) { 446 assert(dmaReadCG->complete() < MAX_DMA_SIZE); 447 ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(), 448 &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete()); 449 dmaReadBytes += dmaReadCG->size(); 450 dmaReadTxs++; 451 if (dmaReadCG->size() == TheISA::PageBytes) 452 dmaReadFullPages++; 453 dmaReadCG->next(); 454 } else { 455 assert(dmaReadCG->done()); 456 delete dmaReadCG; 457 dmaReadCG = NULL; 458 dmaReadDone(); 459 } 460} 461 462void 463IdeDisk::dmaReadDone() 464{ 465 uint32_t bytesWritten = 0; 466 467 // write the data to the disk image 468 for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); 469 bytesWritten += SectorSize) { 470 471 cmdBytesLeft -= SectorSize; 472 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 473 } 474 475 // check for the EOT 476 if (curPrd.getEOT()) { 477 assert(cmdBytesLeft == 0); 478 dmaState = Dma_Idle; 479 updateState(ACT_DMA_DONE); 480 } else { 481 doDmaTransfer(); 482 } 483} 484 485void 486IdeDisk::doDmaDataWrite() 487{ 488 /** @todo we need to figure out what the delay actually will be */ 489 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 490 uint32_t bytesRead = 0; 491 492 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", 493 diskDelay, totalDiskDelay); 494 495 memset(dataBuffer, 0, MAX_DMA_SIZE); 496 assert(cmdBytesLeft <= MAX_DMA_SIZE); 497 while (bytesRead < curPrd.getByteCount()) { 498 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 499 bytesRead += SectorSize; 500 cmdBytesLeft -= SectorSize; 501 } 502 DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n", 503 bytesRead, cmdBytesLeft); 504 505 schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay); 506} 507 508void 509IdeDisk::doDmaWrite() 510{ 511 if (dmaAborted) { 512 DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n"); 513 if (dmaWriteCG) 514 delete dmaWriteCG; 515 dmaWriteCG = NULL; 516 updateState(ACT_CMD_ERROR); 517 return; 518 } 519 if (!dmaWriteCG) { 520 // clear out the data buffer 521 dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), 522 curPrd.getByteCount(), TheISA::PageBytes); 523 } 524 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 525 schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD); 526 DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n"); 527 return; 528 } else if (!dmaWriteCG->done()) { 529 assert(dmaWriteCG->complete() < MAX_DMA_SIZE); 530 ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(), 531 &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete()); 532 DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n", 533 curPrd.getByteCount(), curPrd.getEOT()); 534 dmaWriteBytes += dmaWriteCG->size(); 535 dmaWriteTxs++; 536 if (dmaWriteCG->size() == TheISA::PageBytes) 537 dmaWriteFullPages++; 538 dmaWriteCG->next(); 539 } else { 540 DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n", 541 curPrd.getByteCount(), curPrd.getEOT()); 542 assert(dmaWriteCG->done()); 543 delete dmaWriteCG; 544 dmaWriteCG = NULL; 545 dmaWriteDone(); 546 } 547} 548 549void 550IdeDisk::dmaWriteDone() 551{ 552 DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n", 553 curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft); 554 // check for the EOT 555 if (curPrd.getEOT()) { 556 assert(cmdBytesLeft == 0); 557 dmaState = Dma_Idle; 558 updateState(ACT_DMA_DONE); 559 } else { 560 doDmaTransfer(); 561 } 562} 563 564//// 565// Disk utility routines 566/// 567 568void 569IdeDisk::readDisk(uint32_t sector, uint8_t *data) 570{ 571 uint32_t bytesRead = image->read(data, sector); 572 573 if (bytesRead != SectorSize) 574 panic("Can't read from %s. Only %d of %d read. errno=%d\n", 575 name(), bytesRead, SectorSize, errno); 576} 577 578void 579IdeDisk::writeDisk(uint32_t sector, uint8_t *data) 580{ 581 uint32_t bytesWritten = image->write(data, sector); 582 583 if (bytesWritten != SectorSize) 584 panic("Can't write to %s. Only %d of %d written. errno=%d\n", 585 name(), bytesWritten, SectorSize, errno); 586} 587 588//// 589// Setup and handle commands 590//// 591 592void 593IdeDisk::startDma(const uint32_t &prdTableBase) 594{ 595 if (dmaState != Dma_Start) 596 panic("Inconsistent DMA state, should be in Dma_Start!\n"); 597 598 if (devState != Transfer_Data_Dma) 599 panic("Inconsistent device state for DMA start!\n"); 600 601 // PRD base address is given by bits 31:2 602 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); 603 604 dmaState = Dma_Transfer; 605 606 // schedule dma transfer (doDmaTransfer) 607 schedule(dmaTransferEvent, curTick() + 1); 608} 609 610void 611IdeDisk::abortDma() 612{ 613 if (dmaState == Dma_Idle) 614 panic("Inconsistent DMA state, should be Start or Transfer!"); 615 616 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 617 panic("Inconsistent device state, should be Transfer or Prepare!\n"); 618 619 updateState(ACT_CMD_ERROR); 620} 621 622void 623IdeDisk::startCommand() 624{ 625 DevAction_t action = ACT_NONE; 626 uint32_t size = 0; 627 dmaRead = false; 628 629 // Decode commands 630 switch (cmdReg.command) { 631 // Supported non-data commands 632 case WDSF_READ_NATIVE_MAX: 633 size = (uint32_t)image->size() - 1; 634 cmdReg.sec_num = (size & 0xff); 635 cmdReg.cyl_low = ((size & 0xff00) >> 8); 636 cmdReg.cyl_high = ((size & 0xff0000) >> 16); 637 cmdReg.head = ((size & 0xf000000) >> 24); 638 639 devState = Command_Execution; 640 action = ACT_CMD_COMPLETE; 641 break; 642 643 case WDCC_RECAL: 644 case WDCC_IDP: 645 case WDCC_STANDBY_IMMED: 646 case WDCC_FLUSHCACHE: 647 case WDSF_VERIFY: 648 case WDSF_SEEK: 649 case SET_FEATURES: 650 case WDCC_SETMULTI: 651 case WDCC_IDLE: 652 devState = Command_Execution; 653 action = ACT_CMD_COMPLETE; 654 break; 655 656 // Supported PIO data-in commands 657 case WDCC_IDENTIFY: 658 cmdBytes = cmdBytesLeft = sizeof(struct ataparams); 659 devState = Prepare_Data_In; 660 action = ACT_DATA_READY; 661 break; 662 663 case WDCC_READMULTI: 664 case WDCC_READ: 665 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 666 panic("Attempt to perform CHS access, only supports LBA\n"); 667 668 if (cmdReg.sec_count == 0) 669 cmdBytes = cmdBytesLeft = (256 * SectorSize); 670 else 671 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 672 673 curSector = getLBABase(); 674 675 /** @todo make this a scheduled event to simulate disk delay */ 676 devState = Prepare_Data_In; 677 action = ACT_DATA_READY; 678 break; 679 680 // Supported PIO data-out commands 681 case WDCC_WRITEMULTI: 682 case WDCC_WRITE: 683 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 684 panic("Attempt to perform CHS access, only supports LBA\n"); 685 686 if (cmdReg.sec_count == 0) 687 cmdBytes = cmdBytesLeft = (256 * SectorSize); 688 else 689 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 690 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft); 691 curSector = getLBABase(); 692 693 devState = Prepare_Data_Out; 694 action = ACT_DATA_READY; 695 break; 696 697 // Supported DMA commands 698 case WDCC_WRITEDMA: 699 dmaRead = true; // a write to the disk is a DMA read from memory 700 case WDCC_READDMA: 701 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 702 panic("Attempt to perform CHS access, only supports LBA\n"); 703 704 if (cmdReg.sec_count == 0) 705 cmdBytes = cmdBytesLeft = (256 * SectorSize); 706 else 707 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 708 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft); 709 710 curSector = getLBABase(); 711 712 devState = Prepare_Data_Dma; 713 action = ACT_DMA_READY; 714 break; 715 716 default: 717 panic("Unsupported ATA command: %#x\n", cmdReg.command); 718 } 719 720 if (action != ACT_NONE) { 721 // set the BSY bit 722 status |= STATUS_BSY_BIT; 723 // clear the DRQ bit 724 status &= ~STATUS_DRQ_BIT; 725 // clear the DF bit 726 status &= ~STATUS_DF_BIT; 727 728 updateState(action); 729 } 730} 731 732//// 733// Handle setting and clearing interrupts 734//// 735 736void 737IdeDisk::intrPost() 738{ 739 DPRINTF(IdeDisk, "Posting Interrupt\n"); 740 if (intrPending) 741 panic("Attempt to post an interrupt with one pending\n"); 742 743 intrPending = true; 744 745 // talk to controller to set interrupt 746 if (ctrl) { 747 ctrl->intrPost(); 748 } 749} 750 751void 752IdeDisk::intrClear() 753{ 754 DPRINTF(IdeDisk, "Clearing Interrupt\n"); 755 if (!intrPending) 756 panic("Attempt to clear a non-pending interrupt\n"); 757 758 intrPending = false; 759 760 // talk to controller to clear interrupt 761 if (ctrl) 762 ctrl->intrClear(); 763} 764 765//// 766// Manage the device internal state machine 767//// 768 769void 770IdeDisk::updateState(DevAction_t action) 771{ 772 switch (devState) { 773 case Device_Srst: 774 if (action == ACT_SRST_SET) { 775 // set the BSY bit 776 status |= STATUS_BSY_BIT; 777 } else if (action == ACT_SRST_CLEAR) { 778 // clear the BSY bit 779 status &= ~STATUS_BSY_BIT; 780 781 // reset the device state 782 reset(devID); 783 } 784 break; 785 786 case Device_Idle_S: 787 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 788 devState = Device_Idle_NS; 789 } else if (action == ACT_CMD_WRITE) { 790 startCommand(); 791 } 792 793 break; 794 795 case Device_Idle_SI: 796 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 797 devState = Device_Idle_NS; 798 intrClear(); 799 } else if (action == ACT_STAT_READ || isIENSet()) { 800 devState = Device_Idle_S; 801 intrClear(); 802 } else if (action == ACT_CMD_WRITE) { 803 intrClear(); 804 startCommand(); 805 } 806 807 break; 808 809 case Device_Idle_NS: 810 if (action == ACT_SELECT_WRITE && isDEVSelect()) { 811 if (!isIENSet() && intrPending) { 812 devState = Device_Idle_SI; 813 intrPost(); 814 } 815 if (isIENSet() || !intrPending) { 816 devState = Device_Idle_S; 817 } 818 } 819 break; 820 821 case Command_Execution: 822 if (action == ACT_CMD_COMPLETE) { 823 // clear the BSY bit 824 setComplete(); 825 826 if (!isIENSet()) { 827 devState = Device_Idle_SI; 828 intrPost(); 829 } else { 830 devState = Device_Idle_S; 831 } 832 } 833 break; 834 835 case Prepare_Data_In: 836 if (action == ACT_CMD_ERROR) { 837 // clear the BSY bit 838 setComplete(); 839 840 if (!isIENSet()) { 841 devState = Device_Idle_SI; 842 intrPost(); 843 } else { 844 devState = Device_Idle_S; 845 } 846 } else if (action == ACT_DATA_READY) { 847 // clear the BSY bit 848 status &= ~STATUS_BSY_BIT; 849 // set the DRQ bit 850 status |= STATUS_DRQ_BIT; 851 852 // copy the data into the data buffer 853 if (cmdReg.command == WDCC_IDENTIFY) { 854 // Reset the drqBytes for this block 855 drqBytesLeft = sizeof(struct ataparams); 856 857 memcpy((void *)dataBuffer, (void *)&driveID, 858 sizeof(struct ataparams)); 859 } else { 860 // Reset the drqBytes for this block 861 drqBytesLeft = SectorSize; 862 863 readDisk(curSector++, dataBuffer); 864 } 865 866 // put the first two bytes into the data register 867 memcpy((void *)&cmdReg.data, (void *)dataBuffer, 868 sizeof(uint16_t)); 869 870 if (!isIENSet()) { 871 devState = Data_Ready_INTRQ_In; 872 intrPost(); 873 } else { 874 devState = Transfer_Data_In; 875 } 876 } 877 break; 878 879 case Data_Ready_INTRQ_In: 880 if (action == ACT_STAT_READ) { 881 devState = Transfer_Data_In; 882 intrClear(); 883 } 884 break; 885 886 case Transfer_Data_In: 887 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 888 if (action == ACT_DATA_READ_BYTE) { 889 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 890 } else { 891 drqBytesLeft -= 2; 892 cmdBytesLeft -= 2; 893 894 // copy next short into data registers 895 if (drqBytesLeft) 896 memcpy((void *)&cmdReg.data, 897 (void *)&dataBuffer[SectorSize - drqBytesLeft], 898 sizeof(uint16_t)); 899 } 900 901 if (drqBytesLeft == 0) { 902 if (cmdBytesLeft == 0) { 903 // Clear the BSY bit 904 setComplete(); 905 devState = Device_Idle_S; 906 } else { 907 devState = Prepare_Data_In; 908 // set the BSY_BIT 909 status |= STATUS_BSY_BIT; 910 // clear the DRQ_BIT 911 status &= ~STATUS_DRQ_BIT; 912 913 /** @todo change this to a scheduled event to simulate 914 disk delay */ 915 updateState(ACT_DATA_READY); 916 } 917 } 918 } 919 break; 920 921 case Prepare_Data_Out: 922 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 923 // clear the BSY bit 924 setComplete(); 925 926 if (!isIENSet()) { 927 devState = Device_Idle_SI; 928 intrPost(); 929 } else { 930 devState = Device_Idle_S; 931 } 932 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { 933 // clear the BSY bit 934 status &= ~STATUS_BSY_BIT; 935 // set the DRQ bit 936 status |= STATUS_DRQ_BIT; 937 938 // clear the data buffer to get it ready for writes 939 memset(dataBuffer, 0, MAX_DMA_SIZE); 940 941 // reset the drqBytes for this block 942 drqBytesLeft = SectorSize; 943 944 if (cmdBytesLeft == cmdBytes || isIENSet()) { 945 devState = Transfer_Data_Out; 946 } else { 947 devState = Data_Ready_INTRQ_Out; 948 intrPost(); 949 } 950 } 951 break; 952 953 case Data_Ready_INTRQ_Out: 954 if (action == ACT_STAT_READ) { 955 devState = Transfer_Data_Out; 956 intrClear(); 957 } 958 break; 959 960 case Transfer_Data_Out: 961 if (action == ACT_DATA_WRITE_BYTE || 962 action == ACT_DATA_WRITE_SHORT) { 963 964 if (action == ACT_DATA_READ_BYTE) { 965 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 966 } else { 967 // copy the latest short into the data buffer 968 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 969 (void *)&cmdReg.data, 970 sizeof(uint16_t)); 971 972 drqBytesLeft -= 2; 973 cmdBytesLeft -= 2; 974 } 975 976 if (drqBytesLeft == 0) { 977 // copy the block to the disk 978 writeDisk(curSector++, dataBuffer); 979 980 // set the BSY bit 981 status |= STATUS_BSY_BIT; 982 // set the seek bit 983 status |= STATUS_SEEK_BIT; 984 // clear the DRQ bit 985 status &= ~STATUS_DRQ_BIT; 986 987 devState = Prepare_Data_Out; 988 989 /** @todo change this to a scheduled event to simulate 990 disk delay */ 991 updateState(ACT_DATA_READY); 992 } 993 } 994 break; 995 996 case Prepare_Data_Dma: 997 if (action == ACT_CMD_ERROR) { 998 // clear the BSY bit 999 setComplete(); 1000 1001 if (!isIENSet()) { 1002 devState = Device_Idle_SI; 1003 intrPost(); 1004 } else { 1005 devState = Device_Idle_S; 1006 } 1007 } else if (action == ACT_DMA_READY) { 1008 // clear the BSY bit 1009 status &= ~STATUS_BSY_BIT; 1010 // set the DRQ bit 1011 status |= STATUS_DRQ_BIT; 1012 1013 devState = Transfer_Data_Dma; 1014 1015 if (dmaState != Dma_Idle) 1016 panic("Inconsistent DMA state, should be Dma_Idle\n"); 1017 1018 dmaState = Dma_Start; 1019 // wait for the write to the DMA start bit 1020 } 1021 break; 1022 1023 case Transfer_Data_Dma: 1024 if (action == ACT_CMD_ERROR) { 1025 dmaAborted = true; 1026 devState = Device_Dma_Abort; 1027 } else if (action == ACT_DMA_DONE) { 1028 // clear the BSY bit 1029 setComplete(); 1030 // set the seek bit 1031 status |= STATUS_SEEK_BIT; 1032 // clear the controller state for DMA transfer 1033 ctrl->setDmaComplete(this); 1034 1035 if (!isIENSet()) { 1036 devState = Device_Idle_SI; 1037 intrPost(); 1038 } else { 1039 devState = Device_Idle_S; 1040 } 1041 } 1042 break; 1043 1044 case Device_Dma_Abort: 1045 if (action == ACT_CMD_ERROR) { 1046 setComplete(); 1047 status |= STATUS_SEEK_BIT; 1048 ctrl->setDmaComplete(this); 1049 dmaAborted = false; 1050 dmaState = Dma_Idle; 1051 1052 if (!isIENSet()) { 1053 devState = Device_Idle_SI; 1054 intrPost(); 1055 } else { 1056 devState = Device_Idle_S; 1057 } 1058 } else { 1059 DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n"); 1060 } 1061 break; 1062 1063 default: 1064 panic("Unknown IDE device state: %#x\n", devState); 1065 } 1066} 1067 1068void 1069IdeDisk::serialize(CheckpointOut &cp) const 1070{ 1071 // Check all outstanding events to see if they are scheduled 1072 // these are all mutually exclusive 1073 Tick reschedule = 0; 1074 Events_t event = None; 1075 1076 int eventCount = 0; 1077 1078 if (dmaTransferEvent.scheduled()) { 1079 reschedule = dmaTransferEvent.when(); 1080 event = Transfer; 1081 eventCount++; 1082 } 1083 if (dmaReadWaitEvent.scheduled()) { 1084 reschedule = dmaReadWaitEvent.when(); 1085 event = ReadWait; 1086 eventCount++; 1087 } 1088 if (dmaWriteWaitEvent.scheduled()) { 1089 reschedule = dmaWriteWaitEvent.when(); 1090 event = WriteWait; 1091 eventCount++; 1092 } 1093 if (dmaPrdReadEvent.scheduled()) { 1094 reschedule = dmaPrdReadEvent.when(); 1095 event = PrdRead; 1096 eventCount++; 1097 } 1098 if (dmaReadEvent.scheduled()) { 1099 reschedule = dmaReadEvent.when(); 1100 event = DmaRead; 1101 eventCount++; 1102 } 1103 if (dmaWriteEvent.scheduled()) { 1104 reschedule = dmaWriteEvent.when(); 1105 event = DmaWrite; 1106 eventCount++; 1107 } 1108 1109 assert(eventCount <= 1); 1110 1111 SERIALIZE_SCALAR(reschedule); 1112 SERIALIZE_ENUM(event); 1113 1114 // Serialize device registers 1115 SERIALIZE_SCALAR(cmdReg.data); 1116 SERIALIZE_SCALAR(cmdReg.sec_count); 1117 SERIALIZE_SCALAR(cmdReg.sec_num); 1118 SERIALIZE_SCALAR(cmdReg.cyl_low); 1119 SERIALIZE_SCALAR(cmdReg.cyl_high); 1120 SERIALIZE_SCALAR(cmdReg.drive); 1121 SERIALIZE_SCALAR(cmdReg.command); 1122 SERIALIZE_SCALAR(status); 1123 SERIALIZE_SCALAR(nIENBit); 1124 SERIALIZE_SCALAR(devID); 1125 1126 // Serialize the PRD related information 1127 SERIALIZE_SCALAR(curPrd.entry.baseAddr); 1128 SERIALIZE_SCALAR(curPrd.entry.byteCount); 1129 SERIALIZE_SCALAR(curPrd.entry.endOfTable); 1130 SERIALIZE_SCALAR(curPrdAddr); 1131 1132 /** @todo need to serialized chunk generator stuff!! */ 1133 // Serialize current transfer related information 1134 SERIALIZE_SCALAR(cmdBytesLeft); 1135 SERIALIZE_SCALAR(cmdBytes); 1136 SERIALIZE_SCALAR(drqBytesLeft); 1137 SERIALIZE_SCALAR(curSector); 1138 SERIALIZE_SCALAR(dmaRead); 1139 SERIALIZE_SCALAR(intrPending); 1140 SERIALIZE_SCALAR(dmaAborted); 1141 SERIALIZE_ENUM(devState); 1142 SERIALIZE_ENUM(dmaState); 1143 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1144} 1145 1146void 1147IdeDisk::unserialize(CheckpointIn &cp) 1148{ 1149 // Reschedule events that were outstanding 1150 // these are all mutually exclusive 1151 Tick reschedule = 0; 1152 Events_t event = None; 1153 1154 UNSERIALIZE_SCALAR(reschedule); 1155 UNSERIALIZE_ENUM(event); 1156 1157 switch (event) { 1158 case None : break; 1159 case Transfer : schedule(dmaTransferEvent, reschedule); break; 1160 case ReadWait : schedule(dmaReadWaitEvent, reschedule); break; 1161 case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break; 1162 case PrdRead : schedule(dmaPrdReadEvent, reschedule); break; 1163 case DmaRead : schedule(dmaReadEvent, reschedule); break; 1164 case DmaWrite : schedule(dmaWriteEvent, reschedule); break; 1165 } 1166 1167 // Unserialize device registers 1168 UNSERIALIZE_SCALAR(cmdReg.data); 1169 UNSERIALIZE_SCALAR(cmdReg.sec_count); 1170 UNSERIALIZE_SCALAR(cmdReg.sec_num); 1171 UNSERIALIZE_SCALAR(cmdReg.cyl_low); 1172 UNSERIALIZE_SCALAR(cmdReg.cyl_high); 1173 UNSERIALIZE_SCALAR(cmdReg.drive); 1174 UNSERIALIZE_SCALAR(cmdReg.command); 1175 UNSERIALIZE_SCALAR(status); 1176 UNSERIALIZE_SCALAR(nIENBit); 1177 UNSERIALIZE_SCALAR(devID); 1178 1179 // Unserialize the PRD related information 1180 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); 1181 UNSERIALIZE_SCALAR(curPrd.entry.byteCount); 1182 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); 1183 UNSERIALIZE_SCALAR(curPrdAddr); 1184 1185 /** @todo need to serialized chunk generator stuff!! */ 1186 // Unserialize current transfer related information 1187 UNSERIALIZE_SCALAR(cmdBytes); 1188 UNSERIALIZE_SCALAR(cmdBytesLeft); 1189 UNSERIALIZE_SCALAR(drqBytesLeft); 1190 UNSERIALIZE_SCALAR(curSector); 1191 UNSERIALIZE_SCALAR(dmaRead); 1192 UNSERIALIZE_SCALAR(intrPending); 1193 UNSERIALIZE_SCALAR(dmaAborted); 1194 UNSERIALIZE_ENUM(devState); 1195 UNSERIALIZE_ENUM(dmaState); 1196 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1197} 1198 1199IdeDisk * 1200IdeDiskParams::create() 1201{ 1202 return new IdeDisk(this); 1203} 1204