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