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