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