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