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