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