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