ide_disk.cc revision 11522
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 SimObject::regStats(); 396 397 using namespace Stats; 398 dmaReadFullPages 399 .name(name() + ".dma_read_full_pages") 400 .desc("Number of full page size DMA reads (not PRD).") 401 ; 402 dmaReadBytes 403 .name(name() + ".dma_read_bytes") 404 .desc("Number of bytes transfered via DMA reads (not PRD).") 405 ; 406 dmaReadTxs 407 .name(name() + ".dma_read_txs") 408 .desc("Number of DMA read transactions (not PRD).") 409 ; 410 411 dmaWriteFullPages 412 .name(name() + ".dma_write_full_pages") 413 .desc("Number of full page size DMA writes.") 414 ; 415 dmaWriteBytes 416 .name(name() + ".dma_write_bytes") 417 .desc("Number of bytes transfered via DMA writes.") 418 ; 419 dmaWriteTxs 420 .name(name() + ".dma_write_txs") 421 .desc("Number of DMA write transactions.") 422 ; 423} 424 425void 426IdeDisk::doDmaRead() 427{ 428 if (dmaAborted) { 429 DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n"); 430 if (dmaReadCG) 431 delete dmaReadCG; 432 dmaReadCG = NULL; 433 updateState(ACT_CMD_ERROR); 434 return; 435 } 436 437 if (!dmaReadCG) { 438 // clear out the data buffer 439 memset(dataBuffer, 0, MAX_DMA_SIZE); 440 dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(), 441 curPrd.getByteCount(), TheISA::PageBytes); 442 443 } 444 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 445 schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD); 446 return; 447 } else if (!dmaReadCG->done()) { 448 assert(dmaReadCG->complete() < MAX_DMA_SIZE); 449 ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(), 450 &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete()); 451 dmaReadBytes += dmaReadCG->size(); 452 dmaReadTxs++; 453 if (dmaReadCG->size() == TheISA::PageBytes) 454 dmaReadFullPages++; 455 dmaReadCG->next(); 456 } else { 457 assert(dmaReadCG->done()); 458 delete dmaReadCG; 459 dmaReadCG = NULL; 460 dmaReadDone(); 461 } 462} 463 464void 465IdeDisk::dmaReadDone() 466{ 467 uint32_t bytesWritten = 0; 468 469 // write the data to the disk image 470 for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); 471 bytesWritten += SectorSize) { 472 473 cmdBytesLeft -= SectorSize; 474 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 475 } 476 477 // check for the EOT 478 if (curPrd.getEOT()) { 479 assert(cmdBytesLeft == 0); 480 dmaState = Dma_Idle; 481 updateState(ACT_DMA_DONE); 482 } else { 483 doDmaTransfer(); 484 } 485} 486 487void 488IdeDisk::doDmaDataWrite() 489{ 490 /** @todo we need to figure out what the delay actually will be */ 491 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 492 uint32_t bytesRead = 0; 493 494 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", 495 diskDelay, totalDiskDelay); 496 497 memset(dataBuffer, 0, MAX_DMA_SIZE); 498 assert(cmdBytesLeft <= MAX_DMA_SIZE); 499 while (bytesRead < curPrd.getByteCount()) { 500 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 501 bytesRead += SectorSize; 502 cmdBytesLeft -= SectorSize; 503 } 504 DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n", 505 bytesRead, cmdBytesLeft); 506 507 schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay); 508} 509 510void 511IdeDisk::doDmaWrite() 512{ 513 if (dmaAborted) { 514 DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n"); 515 if (dmaWriteCG) 516 delete dmaWriteCG; 517 dmaWriteCG = NULL; 518 updateState(ACT_CMD_ERROR); 519 return; 520 } 521 if (!dmaWriteCG) { 522 // clear out the data buffer 523 dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), 524 curPrd.getByteCount(), TheISA::PageBytes); 525 } 526 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 527 schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD); 528 DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n"); 529 return; 530 } else if (!dmaWriteCG->done()) { 531 assert(dmaWriteCG->complete() < MAX_DMA_SIZE); 532 ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(), 533 &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete()); 534 DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n", 535 curPrd.getByteCount(), curPrd.getEOT()); 536 dmaWriteBytes += dmaWriteCG->size(); 537 dmaWriteTxs++; 538 if (dmaWriteCG->size() == TheISA::PageBytes) 539 dmaWriteFullPages++; 540 dmaWriteCG->next(); 541 } else { 542 DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n", 543 curPrd.getByteCount(), curPrd.getEOT()); 544 assert(dmaWriteCG->done()); 545 delete dmaWriteCG; 546 dmaWriteCG = NULL; 547 dmaWriteDone(); 548 } 549} 550 551void 552IdeDisk::dmaWriteDone() 553{ 554 DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n", 555 curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft); 556 // check for the EOT 557 if (curPrd.getEOT()) { 558 assert(cmdBytesLeft == 0); 559 dmaState = Dma_Idle; 560 updateState(ACT_DMA_DONE); 561 } else { 562 doDmaTransfer(); 563 } 564} 565 566//// 567// Disk utility routines 568/// 569 570void 571IdeDisk::readDisk(uint32_t sector, uint8_t *data) 572{ 573 uint32_t bytesRead = image->read(data, sector); 574 575 if (bytesRead != SectorSize) 576 panic("Can't read from %s. Only %d of %d read. errno=%d\n", 577 name(), bytesRead, SectorSize, errno); 578} 579 580void 581IdeDisk::writeDisk(uint32_t sector, uint8_t *data) 582{ 583 uint32_t bytesWritten = image->write(data, sector); 584 585 if (bytesWritten != SectorSize) 586 panic("Can't write to %s. Only %d of %d written. errno=%d\n", 587 name(), bytesWritten, SectorSize, errno); 588} 589 590//// 591// Setup and handle commands 592//// 593 594void 595IdeDisk::startDma(const uint32_t &prdTableBase) 596{ 597 if (dmaState != Dma_Start) 598 panic("Inconsistent DMA state, should be in Dma_Start!\n"); 599 600 if (devState != Transfer_Data_Dma) 601 panic("Inconsistent device state for DMA start!\n"); 602 603 // PRD base address is given by bits 31:2 604 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); 605 606 dmaState = Dma_Transfer; 607 608 // schedule dma transfer (doDmaTransfer) 609 schedule(dmaTransferEvent, curTick() + 1); 610} 611 612void 613IdeDisk::abortDma() 614{ 615 if (dmaState == Dma_Idle) 616 panic("Inconsistent DMA state, should be Start or Transfer!"); 617 618 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 619 panic("Inconsistent device state, should be Transfer or Prepare!\n"); 620 621 updateState(ACT_CMD_ERROR); 622} 623 624void 625IdeDisk::startCommand() 626{ 627 DevAction_t action = ACT_NONE; 628 uint32_t size = 0; 629 dmaRead = false; 630 631 // Decode commands 632 switch (cmdReg.command) { 633 // Supported non-data commands 634 case WDSF_READ_NATIVE_MAX: 635 size = (uint32_t)image->size() - 1; 636 cmdReg.sec_num = (size & 0xff); 637 cmdReg.cyl_low = ((size & 0xff00) >> 8); 638 cmdReg.cyl_high = ((size & 0xff0000) >> 16); 639 cmdReg.head = ((size & 0xf000000) >> 24); 640 641 devState = Command_Execution; 642 action = ACT_CMD_COMPLETE; 643 break; 644 645 case WDCC_RECAL: 646 case WDCC_IDP: 647 case WDCC_STANDBY_IMMED: 648 case WDCC_FLUSHCACHE: 649 case WDSF_VERIFY: 650 case WDSF_SEEK: 651 case SET_FEATURES: 652 case WDCC_SETMULTI: 653 case WDCC_IDLE: 654 devState = Command_Execution; 655 action = ACT_CMD_COMPLETE; 656 break; 657 658 // Supported PIO data-in commands 659 case WDCC_IDENTIFY: 660 cmdBytes = cmdBytesLeft = sizeof(struct ataparams); 661 devState = Prepare_Data_In; 662 action = ACT_DATA_READY; 663 break; 664 665 case WDCC_READMULTI: 666 case WDCC_READ: 667 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 668 panic("Attempt to perform CHS access, only supports LBA\n"); 669 670 if (cmdReg.sec_count == 0) 671 cmdBytes = cmdBytesLeft = (256 * SectorSize); 672 else 673 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 674 675 curSector = getLBABase(); 676 677 /** @todo make this a scheduled event to simulate disk delay */ 678 devState = Prepare_Data_In; 679 action = ACT_DATA_READY; 680 break; 681 682 // Supported PIO data-out commands 683 case WDCC_WRITEMULTI: 684 case WDCC_WRITE: 685 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 686 panic("Attempt to perform CHS access, only supports LBA\n"); 687 688 if (cmdReg.sec_count == 0) 689 cmdBytes = cmdBytesLeft = (256 * SectorSize); 690 else 691 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 692 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft); 693 curSector = getLBABase(); 694 695 devState = Prepare_Data_Out; 696 action = ACT_DATA_READY; 697 break; 698 699 // Supported DMA commands 700 case WDCC_WRITEDMA: 701 dmaRead = true; // a write to the disk is a DMA read from memory 702 case WDCC_READDMA: 703 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 704 panic("Attempt to perform CHS access, only supports LBA\n"); 705 706 if (cmdReg.sec_count == 0) 707 cmdBytes = cmdBytesLeft = (256 * SectorSize); 708 else 709 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 710 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft); 711 712 curSector = getLBABase(); 713 714 devState = Prepare_Data_Dma; 715 action = ACT_DMA_READY; 716 break; 717 718 default: 719 panic("Unsupported ATA command: %#x\n", cmdReg.command); 720 } 721 722 if (action != ACT_NONE) { 723 // set the BSY bit 724 status |= STATUS_BSY_BIT; 725 // clear the DRQ bit 726 status &= ~STATUS_DRQ_BIT; 727 // clear the DF bit 728 status &= ~STATUS_DF_BIT; 729 730 updateState(action); 731 } 732} 733 734//// 735// Handle setting and clearing interrupts 736//// 737 738void 739IdeDisk::intrPost() 740{ 741 DPRINTF(IdeDisk, "Posting Interrupt\n"); 742 if (intrPending) 743 panic("Attempt to post an interrupt with one pending\n"); 744 745 intrPending = true; 746 747 // talk to controller to set interrupt 748 if (ctrl) { 749 ctrl->intrPost(); 750 } 751} 752 753void 754IdeDisk::intrClear() 755{ 756 DPRINTF(IdeDisk, "Clearing Interrupt\n"); 757 if (!intrPending) 758 panic("Attempt to clear a non-pending interrupt\n"); 759 760 intrPending = false; 761 762 // talk to controller to clear interrupt 763 if (ctrl) 764 ctrl->intrClear(); 765} 766 767//// 768// Manage the device internal state machine 769//// 770 771void 772IdeDisk::updateState(DevAction_t action) 773{ 774 switch (devState) { 775 case Device_Srst: 776 if (action == ACT_SRST_SET) { 777 // set the BSY bit 778 status |= STATUS_BSY_BIT; 779 } else if (action == ACT_SRST_CLEAR) { 780 // clear the BSY bit 781 status &= ~STATUS_BSY_BIT; 782 783 // reset the device state 784 reset(devID); 785 } 786 break; 787 788 case Device_Idle_S: 789 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 790 devState = Device_Idle_NS; 791 } else if (action == ACT_CMD_WRITE) { 792 startCommand(); 793 } 794 795 break; 796 797 case Device_Idle_SI: 798 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 799 devState = Device_Idle_NS; 800 intrClear(); 801 } else if (action == ACT_STAT_READ || isIENSet()) { 802 devState = Device_Idle_S; 803 intrClear(); 804 } else if (action == ACT_CMD_WRITE) { 805 intrClear(); 806 startCommand(); 807 } 808 809 break; 810 811 case Device_Idle_NS: 812 if (action == ACT_SELECT_WRITE && isDEVSelect()) { 813 if (!isIENSet() && intrPending) { 814 devState = Device_Idle_SI; 815 intrPost(); 816 } 817 if (isIENSet() || !intrPending) { 818 devState = Device_Idle_S; 819 } 820 } 821 break; 822 823 case Command_Execution: 824 if (action == ACT_CMD_COMPLETE) { 825 // clear the BSY bit 826 setComplete(); 827 828 if (!isIENSet()) { 829 devState = Device_Idle_SI; 830 intrPost(); 831 } else { 832 devState = Device_Idle_S; 833 } 834 } 835 break; 836 837 case Prepare_Data_In: 838 if (action == ACT_CMD_ERROR) { 839 // clear the BSY bit 840 setComplete(); 841 842 if (!isIENSet()) { 843 devState = Device_Idle_SI; 844 intrPost(); 845 } else { 846 devState = Device_Idle_S; 847 } 848 } else if (action == ACT_DATA_READY) { 849 // clear the BSY bit 850 status &= ~STATUS_BSY_BIT; 851 // set the DRQ bit 852 status |= STATUS_DRQ_BIT; 853 854 // copy the data into the data buffer 855 if (cmdReg.command == WDCC_IDENTIFY) { 856 // Reset the drqBytes for this block 857 drqBytesLeft = sizeof(struct ataparams); 858 859 memcpy((void *)dataBuffer, (void *)&driveID, 860 sizeof(struct ataparams)); 861 } else { 862 // Reset the drqBytes for this block 863 drqBytesLeft = SectorSize; 864 865 readDisk(curSector++, dataBuffer); 866 } 867 868 // put the first two bytes into the data register 869 memcpy((void *)&cmdReg.data, (void *)dataBuffer, 870 sizeof(uint16_t)); 871 872 if (!isIENSet()) { 873 devState = Data_Ready_INTRQ_In; 874 intrPost(); 875 } else { 876 devState = Transfer_Data_In; 877 } 878 } 879 break; 880 881 case Data_Ready_INTRQ_In: 882 if (action == ACT_STAT_READ) { 883 devState = Transfer_Data_In; 884 intrClear(); 885 } 886 break; 887 888 case Transfer_Data_In: 889 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 890 if (action == ACT_DATA_READ_BYTE) { 891 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 892 } else { 893 drqBytesLeft -= 2; 894 cmdBytesLeft -= 2; 895 896 // copy next short into data registers 897 if (drqBytesLeft) 898 memcpy((void *)&cmdReg.data, 899 (void *)&dataBuffer[SectorSize - drqBytesLeft], 900 sizeof(uint16_t)); 901 } 902 903 if (drqBytesLeft == 0) { 904 if (cmdBytesLeft == 0) { 905 // Clear the BSY bit 906 setComplete(); 907 devState = Device_Idle_S; 908 } else { 909 devState = Prepare_Data_In; 910 // set the BSY_BIT 911 status |= STATUS_BSY_BIT; 912 // clear the DRQ_BIT 913 status &= ~STATUS_DRQ_BIT; 914 915 /** @todo change this to a scheduled event to simulate 916 disk delay */ 917 updateState(ACT_DATA_READY); 918 } 919 } 920 } 921 break; 922 923 case Prepare_Data_Out: 924 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 925 // clear the BSY bit 926 setComplete(); 927 928 if (!isIENSet()) { 929 devState = Device_Idle_SI; 930 intrPost(); 931 } else { 932 devState = Device_Idle_S; 933 } 934 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { 935 // clear the BSY bit 936 status &= ~STATUS_BSY_BIT; 937 // set the DRQ bit 938 status |= STATUS_DRQ_BIT; 939 940 // clear the data buffer to get it ready for writes 941 memset(dataBuffer, 0, MAX_DMA_SIZE); 942 943 // reset the drqBytes for this block 944 drqBytesLeft = SectorSize; 945 946 if (cmdBytesLeft == cmdBytes || isIENSet()) { 947 devState = Transfer_Data_Out; 948 } else { 949 devState = Data_Ready_INTRQ_Out; 950 intrPost(); 951 } 952 } 953 break; 954 955 case Data_Ready_INTRQ_Out: 956 if (action == ACT_STAT_READ) { 957 devState = Transfer_Data_Out; 958 intrClear(); 959 } 960 break; 961 962 case Transfer_Data_Out: 963 if (action == ACT_DATA_WRITE_BYTE || 964 action == ACT_DATA_WRITE_SHORT) { 965 966 if (action == ACT_DATA_READ_BYTE) { 967 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 968 } else { 969 // copy the latest short into the data buffer 970 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 971 (void *)&cmdReg.data, 972 sizeof(uint16_t)); 973 974 drqBytesLeft -= 2; 975 cmdBytesLeft -= 2; 976 } 977 978 if (drqBytesLeft == 0) { 979 // copy the block to the disk 980 writeDisk(curSector++, dataBuffer); 981 982 // set the BSY bit 983 status |= STATUS_BSY_BIT; 984 // set the seek bit 985 status |= STATUS_SEEK_BIT; 986 // clear the DRQ bit 987 status &= ~STATUS_DRQ_BIT; 988 989 devState = Prepare_Data_Out; 990 991 /** @todo change this to a scheduled event to simulate 992 disk delay */ 993 updateState(ACT_DATA_READY); 994 } 995 } 996 break; 997 998 case Prepare_Data_Dma: 999 if (action == ACT_CMD_ERROR) { 1000 // clear the BSY bit 1001 setComplete(); 1002 1003 if (!isIENSet()) { 1004 devState = Device_Idle_SI; 1005 intrPost(); 1006 } else { 1007 devState = Device_Idle_S; 1008 } 1009 } else if (action == ACT_DMA_READY) { 1010 // clear the BSY bit 1011 status &= ~STATUS_BSY_BIT; 1012 // set the DRQ bit 1013 status |= STATUS_DRQ_BIT; 1014 1015 devState = Transfer_Data_Dma; 1016 1017 if (dmaState != Dma_Idle) 1018 panic("Inconsistent DMA state, should be Dma_Idle\n"); 1019 1020 dmaState = Dma_Start; 1021 // wait for the write to the DMA start bit 1022 } 1023 break; 1024 1025 case Transfer_Data_Dma: 1026 if (action == ACT_CMD_ERROR) { 1027 dmaAborted = true; 1028 devState = Device_Dma_Abort; 1029 } else if (action == ACT_DMA_DONE) { 1030 // clear the BSY bit 1031 setComplete(); 1032 // set the seek bit 1033 status |= STATUS_SEEK_BIT; 1034 // clear the controller state for DMA transfer 1035 ctrl->setDmaComplete(this); 1036 1037 if (!isIENSet()) { 1038 devState = Device_Idle_SI; 1039 intrPost(); 1040 } else { 1041 devState = Device_Idle_S; 1042 } 1043 } 1044 break; 1045 1046 case Device_Dma_Abort: 1047 if (action == ACT_CMD_ERROR) { 1048 setComplete(); 1049 status |= STATUS_SEEK_BIT; 1050 ctrl->setDmaComplete(this); 1051 dmaAborted = false; 1052 dmaState = Dma_Idle; 1053 1054 if (!isIENSet()) { 1055 devState = Device_Idle_SI; 1056 intrPost(); 1057 } else { 1058 devState = Device_Idle_S; 1059 } 1060 } else { 1061 DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n"); 1062 } 1063 break; 1064 1065 default: 1066 panic("Unknown IDE device state: %#x\n", devState); 1067 } 1068} 1069 1070void 1071IdeDisk::serialize(CheckpointOut &cp) const 1072{ 1073 // Check all outstanding events to see if they are scheduled 1074 // these are all mutually exclusive 1075 Tick reschedule = 0; 1076 Events_t event = None; 1077 1078 int eventCount = 0; 1079 1080 if (dmaTransferEvent.scheduled()) { 1081 reschedule = dmaTransferEvent.when(); 1082 event = Transfer; 1083 eventCount++; 1084 } 1085 if (dmaReadWaitEvent.scheduled()) { 1086 reschedule = dmaReadWaitEvent.when(); 1087 event = ReadWait; 1088 eventCount++; 1089 } 1090 if (dmaWriteWaitEvent.scheduled()) { 1091 reschedule = dmaWriteWaitEvent.when(); 1092 event = WriteWait; 1093 eventCount++; 1094 } 1095 if (dmaPrdReadEvent.scheduled()) { 1096 reschedule = dmaPrdReadEvent.when(); 1097 event = PrdRead; 1098 eventCount++; 1099 } 1100 if (dmaReadEvent.scheduled()) { 1101 reschedule = dmaReadEvent.when(); 1102 event = DmaRead; 1103 eventCount++; 1104 } 1105 if (dmaWriteEvent.scheduled()) { 1106 reschedule = dmaWriteEvent.when(); 1107 event = DmaWrite; 1108 eventCount++; 1109 } 1110 1111 assert(eventCount <= 1); 1112 1113 SERIALIZE_SCALAR(reschedule); 1114 SERIALIZE_ENUM(event); 1115 1116 // Serialize device registers 1117 SERIALIZE_SCALAR(cmdReg.data); 1118 SERIALIZE_SCALAR(cmdReg.sec_count); 1119 SERIALIZE_SCALAR(cmdReg.sec_num); 1120 SERIALIZE_SCALAR(cmdReg.cyl_low); 1121 SERIALIZE_SCALAR(cmdReg.cyl_high); 1122 SERIALIZE_SCALAR(cmdReg.drive); 1123 SERIALIZE_SCALAR(cmdReg.command); 1124 SERIALIZE_SCALAR(status); 1125 SERIALIZE_SCALAR(nIENBit); 1126 SERIALIZE_SCALAR(devID); 1127 1128 // Serialize the PRD related information 1129 SERIALIZE_SCALAR(curPrd.entry.baseAddr); 1130 SERIALIZE_SCALAR(curPrd.entry.byteCount); 1131 SERIALIZE_SCALAR(curPrd.entry.endOfTable); 1132 SERIALIZE_SCALAR(curPrdAddr); 1133 1134 /** @todo need to serialized chunk generator stuff!! */ 1135 // Serialize current transfer related information 1136 SERIALIZE_SCALAR(cmdBytesLeft); 1137 SERIALIZE_SCALAR(cmdBytes); 1138 SERIALIZE_SCALAR(drqBytesLeft); 1139 SERIALIZE_SCALAR(curSector); 1140 SERIALIZE_SCALAR(dmaRead); 1141 SERIALIZE_SCALAR(intrPending); 1142 SERIALIZE_SCALAR(dmaAborted); 1143 SERIALIZE_ENUM(devState); 1144 SERIALIZE_ENUM(dmaState); 1145 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1146} 1147 1148void 1149IdeDisk::unserialize(CheckpointIn &cp) 1150{ 1151 // Reschedule events that were outstanding 1152 // these are all mutually exclusive 1153 Tick reschedule = 0; 1154 Events_t event = None; 1155 1156 UNSERIALIZE_SCALAR(reschedule); 1157 UNSERIALIZE_ENUM(event); 1158 1159 switch (event) { 1160 case None : break; 1161 case Transfer : schedule(dmaTransferEvent, reschedule); break; 1162 case ReadWait : schedule(dmaReadWaitEvent, reschedule); break; 1163 case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break; 1164 case PrdRead : schedule(dmaPrdReadEvent, reschedule); break; 1165 case DmaRead : schedule(dmaReadEvent, reschedule); break; 1166 case DmaWrite : schedule(dmaWriteEvent, reschedule); break; 1167 } 1168 1169 // Unserialize device registers 1170 UNSERIALIZE_SCALAR(cmdReg.data); 1171 UNSERIALIZE_SCALAR(cmdReg.sec_count); 1172 UNSERIALIZE_SCALAR(cmdReg.sec_num); 1173 UNSERIALIZE_SCALAR(cmdReg.cyl_low); 1174 UNSERIALIZE_SCALAR(cmdReg.cyl_high); 1175 UNSERIALIZE_SCALAR(cmdReg.drive); 1176 UNSERIALIZE_SCALAR(cmdReg.command); 1177 UNSERIALIZE_SCALAR(status); 1178 UNSERIALIZE_SCALAR(nIENBit); 1179 UNSERIALIZE_SCALAR(devID); 1180 1181 // Unserialize the PRD related information 1182 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); 1183 UNSERIALIZE_SCALAR(curPrd.entry.byteCount); 1184 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); 1185 UNSERIALIZE_SCALAR(curPrdAddr); 1186 1187 /** @todo need to serialized chunk generator stuff!! */ 1188 // Unserialize current transfer related information 1189 UNSERIALIZE_SCALAR(cmdBytes); 1190 UNSERIALIZE_SCALAR(cmdBytesLeft); 1191 UNSERIALIZE_SCALAR(drqBytesLeft); 1192 UNSERIALIZE_SCALAR(curSector); 1193 UNSERIALIZE_SCALAR(dmaRead); 1194 UNSERIALIZE_SCALAR(intrPending); 1195 UNSERIALIZE_SCALAR(dmaAborted); 1196 UNSERIALIZE_ENUM(devState); 1197 UNSERIALIZE_ENUM(dmaState); 1198 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1199} 1200 1201IdeDisk * 1202IdeDiskParams::create() 1203{ 1204 return new IdeDisk(this); 1205} 1206