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