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 M5_FALLTHROUGH; 709 case WDCC_READDMA: 710 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 711 panic("Attempt to perform CHS access, only supports LBA\n"); 712 713 if (cmdReg.sec_count == 0) 714 cmdBytes = cmdBytesLeft = (256 * SectorSize); 715 else 716 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 717 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft); 718 719 curSector = getLBABase(); 720 721 devState = Prepare_Data_Dma; 722 action = ACT_DMA_READY; 723 break; 724 725 default: 726 panic("Unsupported ATA command: %#x\n", cmdReg.command); 727 } 728 729 if (action != ACT_NONE) { 730 // set the BSY bit 731 status |= STATUS_BSY_BIT; 732 // clear the DRQ bit 733 status &= ~STATUS_DRQ_BIT; 734 // clear the DF bit 735 status &= ~STATUS_DF_BIT; 736 737 updateState(action); 738 } 739} 740 741//// 742// Handle setting and clearing interrupts 743//// 744 745void 746IdeDisk::intrPost() 747{ 748 DPRINTF(IdeDisk, "Posting Interrupt\n"); 749 if (intrPending) 750 panic("Attempt to post an interrupt with one pending\n"); 751 752 intrPending = true; 753 754 // talk to controller to set interrupt 755 if (ctrl) { 756 ctrl->intrPost(); 757 } 758} 759 760void 761IdeDisk::intrClear() 762{ 763 DPRINTF(IdeDisk, "Clearing Interrupt\n"); 764 if (!intrPending) 765 panic("Attempt to clear a non-pending interrupt\n"); 766 767 intrPending = false; 768 769 // talk to controller to clear interrupt 770 if (ctrl) 771 ctrl->intrClear(); 772} 773 774//// 775// Manage the device internal state machine 776//// 777 778void 779IdeDisk::updateState(DevAction_t action) 780{ 781 switch (devState) { 782 case Device_Srst: 783 if (action == ACT_SRST_SET) { 784 // set the BSY bit 785 status |= STATUS_BSY_BIT; 786 } else if (action == ACT_SRST_CLEAR) { 787 // clear the BSY bit 788 status &= ~STATUS_BSY_BIT; 789 790 // reset the device state 791 reset(devID); 792 } 793 break; 794 795 case Device_Idle_S: 796 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 797 devState = Device_Idle_NS; 798 } else if (action == ACT_CMD_WRITE) { 799 startCommand(); 800 } 801 802 break; 803 804 case Device_Idle_SI: 805 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 806 devState = Device_Idle_NS; 807 intrClear(); 808 } else if (action == ACT_STAT_READ || isIENSet()) { 809 devState = Device_Idle_S; 810 intrClear(); 811 } else if (action == ACT_CMD_WRITE) { 812 intrClear(); 813 startCommand(); 814 } 815 816 break; 817 818 case Device_Idle_NS: 819 if (action == ACT_SELECT_WRITE && isDEVSelect()) { 820 if (!isIENSet() && intrPending) { 821 devState = Device_Idle_SI; 822 intrPost(); 823 } 824 if (isIENSet() || !intrPending) { 825 devState = Device_Idle_S; 826 } 827 } 828 break; 829 830 case Command_Execution: 831 if (action == ACT_CMD_COMPLETE) { 832 // clear the BSY bit 833 setComplete(); 834 835 if (!isIENSet()) { 836 devState = Device_Idle_SI; 837 intrPost(); 838 } else { 839 devState = Device_Idle_S; 840 } 841 } 842 break; 843 844 case Prepare_Data_In: 845 if (action == ACT_CMD_ERROR) { 846 // clear the BSY bit 847 setComplete(); 848 849 if (!isIENSet()) { 850 devState = Device_Idle_SI; 851 intrPost(); 852 } else { 853 devState = Device_Idle_S; 854 } 855 } else if (action == ACT_DATA_READY) { 856 // clear the BSY bit 857 status &= ~STATUS_BSY_BIT; 858 // set the DRQ bit 859 status |= STATUS_DRQ_BIT; 860 861 // copy the data into the data buffer 862 if (cmdReg.command == WDCC_IDENTIFY || 863 cmdReg.command == ATAPI_IDENTIFY_DEVICE) { 864 // Reset the drqBytes for this block 865 drqBytesLeft = sizeof(struct ataparams); 866 867 memcpy((void *)dataBuffer, (void *)&driveID, 868 sizeof(struct ataparams)); 869 } else { 870 // Reset the drqBytes for this block 871 drqBytesLeft = SectorSize; 872 873 readDisk(curSector++, dataBuffer); 874 } 875 876 // put the first two bytes into the data register 877 memcpy((void *)&cmdReg.data, (void *)dataBuffer, 878 sizeof(uint16_t)); 879 880 if (!isIENSet()) { 881 devState = Data_Ready_INTRQ_In; 882 intrPost(); 883 } else { 884 devState = Transfer_Data_In; 885 } 886 } 887 break; 888 889 case Data_Ready_INTRQ_In: 890 if (action == ACT_STAT_READ) { 891 devState = Transfer_Data_In; 892 intrClear(); 893 } 894 break; 895 896 case Transfer_Data_In: 897 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 898 if (action == ACT_DATA_READ_BYTE) { 899 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 900 } else { 901 drqBytesLeft -= 2; 902 cmdBytesLeft -= 2; 903 904 // copy next short into data registers 905 if (drqBytesLeft) 906 memcpy((void *)&cmdReg.data, 907 (void *)&dataBuffer[SectorSize - drqBytesLeft], 908 sizeof(uint16_t)); 909 } 910 911 if (drqBytesLeft == 0) { 912 if (cmdBytesLeft == 0) { 913 // Clear the BSY bit 914 setComplete(); 915 devState = Device_Idle_S; 916 } else { 917 devState = Prepare_Data_In; 918 // set the BSY_BIT 919 status |= STATUS_BSY_BIT; 920 // clear the DRQ_BIT 921 status &= ~STATUS_DRQ_BIT; 922 923 /** @todo change this to a scheduled event to simulate 924 disk delay */ 925 updateState(ACT_DATA_READY); 926 } 927 } 928 } 929 break; 930 931 case Prepare_Data_Out: 932 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 933 // clear the BSY bit 934 setComplete(); 935 936 if (!isIENSet()) { 937 devState = Device_Idle_SI; 938 intrPost(); 939 } else { 940 devState = Device_Idle_S; 941 } 942 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { 943 // clear the BSY bit 944 status &= ~STATUS_BSY_BIT; 945 // set the DRQ bit 946 status |= STATUS_DRQ_BIT; 947 948 // clear the data buffer to get it ready for writes 949 memset(dataBuffer, 0, MAX_DMA_SIZE); 950 951 // reset the drqBytes for this block 952 drqBytesLeft = SectorSize; 953 954 if (cmdBytesLeft == cmdBytes || isIENSet()) { 955 devState = Transfer_Data_Out; 956 } else { 957 devState = Data_Ready_INTRQ_Out; 958 intrPost(); 959 } 960 } 961 break; 962 963 case Data_Ready_INTRQ_Out: 964 if (action == ACT_STAT_READ) { 965 devState = Transfer_Data_Out; 966 intrClear(); 967 } 968 break; 969 970 case Transfer_Data_Out: 971 if (action == ACT_DATA_WRITE_BYTE || 972 action == ACT_DATA_WRITE_SHORT) { 973 974 if (action == ACT_DATA_READ_BYTE) { 975 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 976 } else { 977 // copy the latest short into the data buffer 978 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 979 (void *)&cmdReg.data, 980 sizeof(uint16_t)); 981 982 drqBytesLeft -= 2; 983 cmdBytesLeft -= 2; 984 } 985 986 if (drqBytesLeft == 0) { 987 // copy the block to the disk 988 writeDisk(curSector++, dataBuffer); 989 990 // set the BSY bit 991 status |= STATUS_BSY_BIT; 992 // set the seek bit 993 status |= STATUS_SEEK_BIT; 994 // clear the DRQ bit 995 status &= ~STATUS_DRQ_BIT; 996 997 devState = Prepare_Data_Out; 998 999 /** @todo change this to a scheduled event to simulate 1000 disk delay */ 1001 updateState(ACT_DATA_READY); 1002 } 1003 } 1004 break; 1005 1006 case Prepare_Data_Dma: 1007 if (action == ACT_CMD_ERROR) { 1008 // clear the BSY bit 1009 setComplete(); 1010 1011 if (!isIENSet()) { 1012 devState = Device_Idle_SI; 1013 intrPost(); 1014 } else { 1015 devState = Device_Idle_S; 1016 } 1017 } else if (action == ACT_DMA_READY) { 1018 // clear the BSY bit 1019 status &= ~STATUS_BSY_BIT; 1020 // set the DRQ bit 1021 status |= STATUS_DRQ_BIT; 1022 1023 devState = Transfer_Data_Dma; 1024 1025 if (dmaState != Dma_Idle) 1026 panic("Inconsistent DMA state, should be Dma_Idle\n"); 1027 1028 dmaState = Dma_Start; 1029 // wait for the write to the DMA start bit 1030 } 1031 break; 1032 1033 case Transfer_Data_Dma: 1034 if (action == ACT_CMD_ERROR) { 1035 dmaAborted = true; 1036 devState = Device_Dma_Abort; 1037 } else if (action == ACT_DMA_DONE) { 1038 // clear the BSY bit 1039 setComplete(); 1040 // set the seek bit 1041 status |= STATUS_SEEK_BIT; 1042 // clear the controller state for DMA transfer 1043 ctrl->setDmaComplete(this); 1044 1045 if (!isIENSet()) { 1046 devState = Device_Idle_SI; 1047 intrPost(); 1048 } else { 1049 devState = Device_Idle_S; 1050 } 1051 } 1052 break; 1053 1054 case Device_Dma_Abort: 1055 if (action == ACT_CMD_ERROR) { 1056 setComplete(); 1057 status |= STATUS_SEEK_BIT; 1058 ctrl->setDmaComplete(this); 1059 dmaAborted = false; 1060 dmaState = Dma_Idle; 1061 1062 if (!isIENSet()) { 1063 devState = Device_Idle_SI; 1064 intrPost(); 1065 } else { 1066 devState = Device_Idle_S; 1067 } 1068 } else { 1069 DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n"); 1070 } 1071 break; 1072 1073 default: 1074 panic("Unknown IDE device state: %#x\n", devState); 1075 } 1076} 1077 1078void 1079IdeDisk::serialize(CheckpointOut &cp) const 1080{ 1081 // Check all outstanding events to see if they are scheduled 1082 // these are all mutually exclusive 1083 Tick reschedule = 0; 1084 Events_t event = None; 1085 1086 int eventCount = 0; 1087 1088 if (dmaTransferEvent.scheduled()) { 1089 reschedule = dmaTransferEvent.when(); 1090 event = Transfer; 1091 eventCount++; 1092 } 1093 if (dmaReadWaitEvent.scheduled()) { 1094 reschedule = dmaReadWaitEvent.when(); 1095 event = ReadWait; 1096 eventCount++; 1097 } 1098 if (dmaWriteWaitEvent.scheduled()) { 1099 reschedule = dmaWriteWaitEvent.when(); 1100 event = WriteWait; 1101 eventCount++; 1102 } 1103 if (dmaPrdReadEvent.scheduled()) { 1104 reschedule = dmaPrdReadEvent.when(); 1105 event = PrdRead; 1106 eventCount++; 1107 } 1108 if (dmaReadEvent.scheduled()) { 1109 reschedule = dmaReadEvent.when(); 1110 event = DmaRead; 1111 eventCount++; 1112 } 1113 if (dmaWriteEvent.scheduled()) { 1114 reschedule = dmaWriteEvent.when(); 1115 event = DmaWrite; 1116 eventCount++; 1117 } 1118 1119 assert(eventCount <= 1); 1120 1121 SERIALIZE_SCALAR(reschedule); 1122 SERIALIZE_ENUM(event); 1123 1124 // Serialize device registers 1125 SERIALIZE_SCALAR(cmdReg.data); 1126 SERIALIZE_SCALAR(cmdReg.sec_count); 1127 SERIALIZE_SCALAR(cmdReg.sec_num); 1128 SERIALIZE_SCALAR(cmdReg.cyl_low); 1129 SERIALIZE_SCALAR(cmdReg.cyl_high); 1130 SERIALIZE_SCALAR(cmdReg.drive); 1131 SERIALIZE_SCALAR(cmdReg.command); 1132 SERIALIZE_SCALAR(status); 1133 SERIALIZE_SCALAR(nIENBit); 1134 SERIALIZE_SCALAR(devID); 1135 1136 // Serialize the PRD related information 1137 SERIALIZE_SCALAR(curPrd.entry.baseAddr); 1138 SERIALIZE_SCALAR(curPrd.entry.byteCount); 1139 SERIALIZE_SCALAR(curPrd.entry.endOfTable); 1140 SERIALIZE_SCALAR(curPrdAddr); 1141 1142 /** @todo need to serialized chunk generator stuff!! */ 1143 // Serialize current transfer related information 1144 SERIALIZE_SCALAR(cmdBytesLeft); 1145 SERIALIZE_SCALAR(cmdBytes); 1146 SERIALIZE_SCALAR(drqBytesLeft); 1147 SERIALIZE_SCALAR(curSector); 1148 SERIALIZE_SCALAR(dmaRead); 1149 SERIALIZE_SCALAR(intrPending); 1150 SERIALIZE_SCALAR(dmaAborted); 1151 SERIALIZE_ENUM(devState); 1152 SERIALIZE_ENUM(dmaState); 1153 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1154} 1155 1156void 1157IdeDisk::unserialize(CheckpointIn &cp) 1158{ 1159 // Reschedule events that were outstanding 1160 // these are all mutually exclusive 1161 Tick reschedule = 0; 1162 Events_t event = None; 1163 1164 UNSERIALIZE_SCALAR(reschedule); 1165 UNSERIALIZE_ENUM(event); 1166 1167 switch (event) { 1168 case None : break; 1169 case Transfer : schedule(dmaTransferEvent, reschedule); break; 1170 case ReadWait : schedule(dmaReadWaitEvent, reschedule); break; 1171 case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break; 1172 case PrdRead : schedule(dmaPrdReadEvent, reschedule); break; 1173 case DmaRead : schedule(dmaReadEvent, reschedule); break; 1174 case DmaWrite : schedule(dmaWriteEvent, reschedule); break; 1175 } 1176 1177 // Unserialize device registers 1178 UNSERIALIZE_SCALAR(cmdReg.data); 1179 UNSERIALIZE_SCALAR(cmdReg.sec_count); 1180 UNSERIALIZE_SCALAR(cmdReg.sec_num); 1181 UNSERIALIZE_SCALAR(cmdReg.cyl_low); 1182 UNSERIALIZE_SCALAR(cmdReg.cyl_high); 1183 UNSERIALIZE_SCALAR(cmdReg.drive); 1184 UNSERIALIZE_SCALAR(cmdReg.command); 1185 UNSERIALIZE_SCALAR(status); 1186 UNSERIALIZE_SCALAR(nIENBit); 1187 UNSERIALIZE_SCALAR(devID); 1188 1189 // Unserialize the PRD related information 1190 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); 1191 UNSERIALIZE_SCALAR(curPrd.entry.byteCount); 1192 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); 1193 UNSERIALIZE_SCALAR(curPrdAddr); 1194 1195 /** @todo need to serialized chunk generator stuff!! */ 1196 // Unserialize current transfer related information 1197 UNSERIALIZE_SCALAR(cmdBytes); 1198 UNSERIALIZE_SCALAR(cmdBytesLeft); 1199 UNSERIALIZE_SCALAR(drqBytesLeft); 1200 UNSERIALIZE_SCALAR(curSector); 1201 UNSERIALIZE_SCALAR(dmaRead); 1202 UNSERIALIZE_SCALAR(intrPending); 1203 UNSERIALIZE_SCALAR(dmaAborted); 1204 UNSERIALIZE_ENUM(devState); 1205 UNSERIALIZE_ENUM(dmaState); 1206 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1207} 1208 1209IdeDisk * 1210IdeDiskParams::create() 1211{ 1212 return new IdeDisk(this); 1213} 1214