ide_disk.cc revision 861
1/* 2 * Copyright (c) 2003 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/** @file 30 * Device model implementation for an IDE disk 31 */ 32 33#include <cerrno> 34#include <cstring> 35#include <deque> 36#include <string> 37 38#include "arch/alpha/pmap.h" 39#include "base/cprintf.hh" // csprintf 40#include "base/trace.hh" 41#include "dev/disk_image.hh" 42#include "dev/ide_disk.hh" 43#include "dev/ide_ctrl.hh" 44#include "dev/tsunami.hh" 45#include "dev/tsunami_pchip.hh" 46#include "mem/functional_mem/physical_memory.hh" 47#include "mem/bus/bus.hh" 48#include "mem/bus/dma_interface.hh" 49#include "mem/bus/pio_interface.hh" 50#include "mem/bus/pio_interface_impl.hh" 51#include "sim/builder.hh" 52#include "sim/sim_object.hh" 53#include "sim/universe.hh" 54 55using namespace std; 56 57IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, 58 int id, int delay) 59 : SimObject(name), ctrl(NULL), image(img), physmem(phys), 60 dmaTransferEvent(this), dmaReadWaitEvent(this), 61 dmaWriteWaitEvent(this), dmaPrdReadEvent(this), 62 dmaReadEvent(this), dmaWriteEvent(this) 63{ 64 diskDelay = (delay * ticksPerSecond / 100000); 65 66 // initialize the data buffer and shadow registers 67 dataBuffer = new uint8_t[MAX_DMA_SIZE]; 68 69 memset(dataBuffer, 0, MAX_DMA_SIZE); 70 memset(&cmdReg, 0, sizeof(CommandReg_t)); 71 memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 72 73 curPrdAddr = 0; 74 curSector = 0; 75 curCommand = 0; 76 cmdBytesLeft = 0; 77 drqBytesLeft = 0; 78 dmaRead = false; 79 intrPending = false; 80 81 // fill out the drive ID structure 82 memset(&driveID, 0, sizeof(struct hd_driveid)); 83 84 // Calculate LBA and C/H/S values 85 uint16_t cylinders; 86 uint8_t heads; 87 uint8_t sectors; 88 89 uint32_t lba_size = image->size(); 90 if (lba_size >= 16383*16*63) { 91 cylinders = 16383; 92 heads = 16; 93 sectors = 63; 94 } else { 95 if (lba_size >= 63) 96 sectors = 63; 97 else 98 sectors = lba_size; 99 100 if ((lba_size / sectors) >= 16) 101 heads = 16; 102 else 103 heads = (lba_size / sectors); 104 105 cylinders = lba_size / (heads * sectors); 106 } 107 108 // Setup the model name 109 sprintf((char *)driveID.model, "5MI EDD si k"); 110 // Set the maximum multisector transfer size 111 driveID.max_multsect = MAX_MULTSECT; 112 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 113 driveID.capability = 0x7; 114 // UDMA support, EIDE support 115 driveID.field_valid = 0x6; 116 // Setup default C/H/S settings 117 driveID.cyls = cylinders; 118 driveID.sectors = sectors; 119 driveID.heads = heads; 120 // Setup the current multisector transfer size 121 driveID.multsect = MAX_MULTSECT; 122 driveID.multsect_valid = 0x1; 123 // Number of sectors on disk 124 driveID.lba_capacity = lba_size; 125 // Multiword DMA mode 2 and below supported 126 driveID.dma_mword = 0x400; 127 // Set PIO mode 4 and 3 supported 128 driveID.eide_pio_modes = 0x3; 129 // Set DMA mode 4 and below supported 130 driveID.dma_ultra = 0x10; 131 // Statically set hardware config word 132 driveID.hw_config = 0x4001; 133 134 // set the device state to idle 135 dmaState = Dma_Idle; 136 137 if (id == DEV0) { 138 devState = Device_Idle_S; 139 devID = DEV0; 140 } else if (id == DEV1) { 141 devState = Device_Idle_NS; 142 devID = DEV1; 143 } else { 144 panic("Invalid device ID: %#x\n", id); 145 } 146 147 // set the device ready bit 148 cmdReg.status |= STATUS_DRDY_BIT; 149} 150 151IdeDisk::~IdeDisk() 152{ 153 // destroy the data buffer 154 delete [] dataBuffer; 155} 156 157Addr 158IdeDisk::pciToDma(Addr &pciAddr) 159{ 160 if (ctrl) 161 return ctrl->tsunami->pchip->translatePciToDma(pciAddr); 162 else 163 panic("Access to unset controller!\n"); 164} 165 166//// 167// Device registers read/write 168//// 169 170void 171IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data) 172{ 173 DevAction_t action = ACT_NONE; 174 175 if (cmdBlk) { 176 if (offset < 0 || offset > sizeof(CommandReg_t)) 177 panic("Invalid disk command register offset: %#x\n", offset); 178 179 if (!byte && offset != DATA_OFFSET) 180 panic("Invalid 16-bit read, only allowed on data reg\n"); 181 182 if (!byte) 183 *(uint16_t *)data = *(uint16_t *)&cmdReg.data0; 184 else 185 *data = ((uint8_t *)&cmdReg)[offset]; 186 187 // determine if an action needs to be taken on the state machine 188 if (offset == STATUS_OFFSET) { 189 action = ACT_STAT_READ; 190 } else if (offset == DATA_OFFSET) { 191 if (byte) 192 action = ACT_DATA_READ_BYTE; 193 else 194 action = ACT_DATA_READ_SHORT; 195 } 196 197 } else { 198 if (offset != ALTSTAT_OFFSET) 199 panic("Invalid disk control register offset: %#x\n", offset); 200 201 if (!byte) 202 panic("Invalid 16-bit read from control block\n"); 203 204 *data = ((uint8_t *)&cmdReg)[STATUS_OFFSET]; 205 } 206 207 if (action != ACT_NONE) 208 updateState(action); 209} 210 211void 212IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data) 213{ 214 DevAction_t action = ACT_NONE; 215 216 if (cmdBlk) { 217 if (offset < 0 || offset > sizeof(CommandReg_t)) 218 panic("Invalid disk command register offset: %#x\n", offset); 219 220 if (!byte && offset != DATA_OFFSET) 221 panic("Invalid 16-bit write, only allowed on data reg\n"); 222 223 if (!byte) 224 *((uint16_t *)&cmdReg.data0) = *(uint16_t *)data; 225 else 226 ((uint8_t *)&cmdReg)[offset] = *data; 227 228 // determine if an action needs to be taken on the state machine 229 if (offset == COMMAND_OFFSET) { 230 action = ACT_CMD_WRITE; 231 } else if (offset == DATA_OFFSET) { 232 if (byte) 233 action = ACT_DATA_WRITE_BYTE; 234 else 235 action = ACT_DATA_WRITE_SHORT; 236 } 237 238 } else { 239 if (offset != CONTROL_OFFSET) 240 panic("Invalid disk control register offset: %#x\n", offset); 241 242 if (!byte) 243 panic("Invalid 16-bit write to control block\n"); 244 245 if (*data & CONTROL_RST_BIT) 246 panic("Software reset not supported!\n"); 247 248 nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; 249 } 250 251 if (action != ACT_NONE) 252 updateState(action); 253} 254 255//// 256// Perform DMA transactions 257//// 258 259void 260IdeDisk::doDmaTransfer() 261{ 262 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 263 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 264 dmaState, devState); 265 266 // first read the current PRD 267 if (dmaInterface) { 268 if (dmaInterface->busy()) { 269 // reschedule after waiting period 270 dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 271 return; 272 } 273 274 dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick, 275 &dmaPrdReadEvent); 276 } else { 277 dmaPrdReadDone(); 278 } 279} 280 281void 282IdeDisk::dmaPrdReadDone() 283{ 284 // actually copy the PRD from physical memory 285 memcpy((void *)&curPrd.entry, 286 physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)), 287 sizeof(PrdEntry_t)); 288 289 curPrdAddr += sizeof(PrdEntry_t); 290 291 if (dmaRead) 292 doDmaRead(); 293 else 294 doDmaWrite(); 295} 296 297void 298IdeDisk::doDmaRead() 299{ 300 Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize); 301 302 if (dmaInterface) { 303 if (dmaInterface->busy()) { 304 // reschedule after waiting period 305 dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 306 return; 307 } 308 309 Addr dmaAddr = 310 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr()); 311 dmaInterface->doDMA(Read, dmaAddr, curPrd.getByteCount(), 312 curTick + totalDiskDelay, &dmaReadEvent); 313 } else { 314 // schedule dmaReadEvent with sectorDelay (dmaReadDone) 315 dmaReadEvent.schedule(curTick + totalDiskDelay); 316 } 317} 318 319void 320IdeDisk::dmaReadDone() 321{ 322 323 Addr curAddr = 0, dmaAddr = 0; 324 uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0; 325 326 // set initial address 327 curAddr = curPrd.getBaseAddr(); 328 329 // clear out the data buffer 330 memset(dataBuffer, 0, MAX_DMA_SIZE); 331 332 // read the data from memory via DMA into a data buffer 333 while (bytesWritten < curPrd.getByteCount()) { 334 if (cmdBytesLeft <= 0) 335 panic("DMA data is larger than # of sectors specified\n"); 336 337 dmaAddr = pciToDma(curAddr); 338 339 // calculate how many bytes are in the current page 340 bytesLeft = curPrd.getByteCount() - bytesWritten; 341 bytesInPage = (bytesLeft > ALPHA_PGBYTES) ? ALPHA_PGBYTES : bytesLeft; 342 // check to make sure we don't cross a page boundary 343 if ((curAddr + bytesInPage) > 344 (alpha_trunc_page(curAddr) + ALPHA_PGBYTES)) 345 346 bytesInPage = alpha_round_page(curAddr) - curAddr; 347 348 // copy the data from memory into the data buffer 349 /** @todo Use real DMA with interfaces here */ 350 memcpy((void *)(dataBuffer + bytesWritten), 351 physmem->dma_addr(dmaAddr, bytesInPage), 352 bytesInPage); 353 354 curAddr += bytesInPage; 355 bytesWritten += bytesInPage; 356 cmdBytesLeft -= bytesInPage; 357 } 358 359 // write the data to the disk image 360 for (bytesWritten = 0; 361 bytesWritten < curPrd.getByteCount(); 362 bytesWritten += SectorSize) 363 364 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 365 366#if 0 367 // actually copy the data from memory to data buffer 368 Addr dmaAddr = 369 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr()); 370 memcpy((void *)dataBuffer, 371 physmem->dma_addr(dmaAddr, curPrd.getByteCount()), 372 curPrd.getByteCount()); 373 374 uint32_t bytesWritten = 0; 375 376 while (bytesWritten < curPrd.getByteCount()) { 377 if (cmdBytesLeft <= 0) 378 panic("DMA data is larger than # sectors specified\n"); 379 380 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 381 382 bytesWritten += SectorSize; 383 cmdBytesLeft -= SectorSize; 384 } 385#endif 386 387 // check for the EOT 388 if (curPrd.getEOT()){ 389 assert(cmdBytesLeft == 0); 390 dmaState = Dma_Idle; 391 updateState(ACT_DMA_DONE); 392 } else { 393 doDmaTransfer(); 394 } 395} 396 397void 398IdeDisk::doDmaWrite() 399{ 400 Tick totalDiskDelay = diskDelay * (curPrd.getByteCount() / SectorSize); 401 402 if (dmaInterface) { 403 if (dmaInterface->busy()) { 404 // reschedule after waiting period 405 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 406 return; 407 } 408 409 Addr dmaAddr = 410 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr()); 411 dmaInterface->doDMA(WriteInvalidate, dmaAddr, 412 curPrd.getByteCount(), curTick + totalDiskDelay, 413 &dmaWriteEvent); 414 } else { 415 // schedule event with disk delay (dmaWriteDone) 416 dmaWriteEvent.schedule(curTick + totalDiskDelay); 417 } 418} 419 420void 421IdeDisk::dmaWriteDone() 422{ 423 Addr curAddr = 0, pageAddr = 0, dmaAddr = 0; 424 uint32_t bytesRead = 0, bytesInPage = 0; 425 426 // setup the initial page and DMA address 427 curAddr = curPrd.getBaseAddr(); 428 pageAddr = alpha_trunc_page(curAddr); 429 dmaAddr = pciToDma(curAddr); 430 431 // clear out the data buffer 432 memset(dataBuffer, 0, MAX_DMA_SIZE); 433 434 while (bytesRead < curPrd.getByteCount()) { 435 // see if we have crossed into a new page 436 if (pageAddr != alpha_trunc_page(curAddr)) { 437 // write the data to memory 438 /** @todo Do real DMA using interfaces here */ 439 memcpy(physmem->dma_addr(dmaAddr, bytesInPage), 440 (void *)(dataBuffer + (bytesRead - bytesInPage)), 441 bytesInPage); 442 443 // update the DMA address and page address 444 pageAddr = alpha_trunc_page(curAddr); 445 dmaAddr = pciToDma(curAddr); 446 447 bytesInPage = 0; 448 } 449 450 if (cmdBytesLeft <= 0) 451 panic("DMA requested data is larger than # sectors specified\n"); 452 453 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 454 455 curAddr += SectorSize; 456 bytesRead += SectorSize; 457 bytesInPage += SectorSize; 458 cmdBytesLeft -= SectorSize; 459 } 460 461 // write the last page worth read to memory 462 /** @todo Do real DMA using interfaces here */ 463 if (bytesInPage != 0) { 464 memcpy(physmem->dma_addr(dmaAddr, bytesInPage), 465 (void *)(dataBuffer + (bytesRead - bytesInPage)), 466 bytesInPage); 467 } 468 469#if 0 470 Addr dmaAddr = ctrl->tsunami->pchip-> 471 translatePciToDma(curPrd.getBaseAddr()); 472 473 memcpy(physmem->dma_addr(dmaAddr, curPrd.getByteCount()), 474 (void *)dataBuffer, curPrd.getByteCount()); 475#endif 476 477 // check for the EOT 478 if (curPrd.getEOT()) { 479 assert(cmdBytesLeft == 0); 480 dmaState = Dma_Idle; 481 updateState(ACT_DMA_DONE); 482 } else { 483 doDmaTransfer(); 484 } 485} 486 487//// 488// Disk utility routines 489/// 490 491void 492IdeDisk::readDisk(uint32_t sector, uint8_t *data) 493{ 494 uint32_t bytesRead = image->read(data, sector); 495 496 if (bytesRead != SectorSize) 497 panic("Can't read from %s. Only %d of %d read. errno=%d\n", 498 name(), bytesRead, SectorSize, errno); 499} 500 501void 502IdeDisk::writeDisk(uint32_t sector, uint8_t *data) 503{ 504 uint32_t bytesWritten = image->write(data, sector); 505 506 if (bytesWritten != SectorSize) 507 panic("Can't write to %s. Only %d of %d written. errno=%d\n", 508 name(), bytesWritten, SectorSize, errno); 509} 510 511//// 512// Setup and handle commands 513//// 514 515void 516IdeDisk::startDma(const uint32_t &prdTableBase) 517{ 518 if (dmaState != Dma_Start) 519 panic("Inconsistent DMA state, should be in Dma_Start!\n"); 520 521 if (devState != Transfer_Data_Dma) 522 panic("Inconsistent device state for DMA start!\n"); 523 524 curPrdAddr = ctrl->tsunami->pchip->translatePciToDma(prdTableBase); 525 526 dmaState = Dma_Transfer; 527 528 // schedule dma transfer (doDmaTransfer) 529 dmaTransferEvent.schedule(curTick + 1); 530} 531 532void 533IdeDisk::abortDma() 534{ 535 if (dmaState == Dma_Idle) 536 panic("Inconsistent DMA state, should be in Dma_Start or Dma_Transfer!\n"); 537 538 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 539 panic("Inconsistent device state, should be in Transfer or Prepare!\n"); 540 541 updateState(ACT_CMD_ERROR); 542} 543 544void 545IdeDisk::startCommand() 546{ 547 DevAction_t action = ACT_NONE; 548 uint32_t size = 0; 549 dmaRead = false; 550 551 // copy the command to the shadow 552 curCommand = cmdReg.command; 553 554 // Decode commands 555 switch (cmdReg.command) { 556 // Supported non-data commands 557 case WIN_READ_NATIVE_MAX: 558 size = image->size() - 1; 559 cmdReg.sec_num = (size & 0xff); 560 cmdReg.cyl_low = ((size & 0xff00) >> 8); 561 cmdReg.cyl_high = ((size & 0xff0000) >> 16); 562 cmdReg.head = ((size & 0xf000000) >> 24); 563 564 devState = Command_Execution; 565 action = ACT_CMD_COMPLETE; 566 break; 567 568 case WIN_RECAL: 569 case WIN_SPECIFY: 570 case WIN_FLUSH_CACHE: 571 case WIN_VERIFY: 572 case WIN_SEEK: 573 case WIN_SETFEATURES: 574 case WIN_SETMULT: 575 devState = Command_Execution; 576 action = ACT_CMD_COMPLETE; 577 break; 578 579 // Supported PIO data-in commands 580 case WIN_IDENTIFY: 581 cmdBytesLeft = drqBytesLeft = sizeof(struct hd_driveid); 582 devState = Prepare_Data_In; 583 action = ACT_DATA_READY; 584 break; 585 586 case WIN_MULTREAD: 587 case WIN_READ: 588 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 589 panic("Attempt to perform CHS access, only supports LBA\n"); 590 591 if (cmdReg.sec_count == 0) 592 cmdBytesLeft = (256 * SectorSize); 593 else 594 cmdBytesLeft = (cmdReg.sec_count * SectorSize); 595 596 drqBytesLeft = SectorSize; 597 curSector = getLBABase(); 598 599 devState = Prepare_Data_In; 600 action = ACT_DATA_READY; 601 break; 602 603 // Supported PIO data-out commands 604 case WIN_MULTWRITE: 605 case WIN_WRITE: 606 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 607 panic("Attempt to perform CHS access, only supports LBA\n"); 608 609 if (cmdReg.sec_count == 0) 610 cmdBytesLeft = (256 * SectorSize); 611 else 612 cmdBytesLeft = (cmdReg.sec_count * SectorSize); 613 614 drqBytesLeft = SectorSize; 615 curSector = getLBABase(); 616 617 devState = Prepare_Data_Out; 618 action = ACT_DATA_READY; 619 break; 620 621 // Supported DMA commands 622 case WIN_WRITEDMA: 623 dmaRead = true; // a write to the disk is a DMA read from memory 624 case WIN_READDMA: 625 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 626 panic("Attempt to perform CHS access, only supports LBA\n"); 627 628 if (cmdReg.sec_count == 0) 629 cmdBytesLeft = (256 * SectorSize); 630 else 631 cmdBytesLeft = (cmdReg.sec_count * SectorSize); 632 633 drqBytesLeft = SectorSize; 634 curSector = getLBABase(); 635 636 devState = Prepare_Data_Dma; 637 action = ACT_DMA_READY; 638 break; 639 640 default: 641 panic("Unsupported ATA command: %#x\n", cmdReg.command); 642 } 643 644 if (action != ACT_NONE) { 645 // set the BSY bit 646 cmdReg.status |= STATUS_BSY_BIT; 647 // clear the DRQ bit 648 cmdReg.status &= ~STATUS_DRQ_BIT; 649 650 updateState(action); 651 } 652} 653 654//// 655// Handle setting and clearing interrupts 656//// 657 658void 659IdeDisk::intrPost() 660{ 661 if (intrPending) 662 panic("Attempt to post an interrupt with one pending\n"); 663 664 intrPending = true; 665 666 // talk to controller to set interrupt 667 if (ctrl) 668 ctrl->intrPost(); 669} 670 671void 672IdeDisk::intrClear() 673{ 674 if (!intrPending) 675 panic("Attempt to clear a non-pending interrupt\n"); 676 677 intrPending = false; 678 679 // talk to controller to clear interrupt 680 if (ctrl) 681 ctrl->intrClear(); 682} 683 684//// 685// Manage the device internal state machine 686//// 687 688void 689IdeDisk::updateState(DevAction_t action) 690{ 691 switch (devState) { 692 case Device_Idle_S: 693 if (!isDEVSelect()) 694 devState = Device_Idle_NS; 695 else if (action == ACT_CMD_WRITE) 696 startCommand(); 697 698 break; 699 700 case Device_Idle_SI: 701 if (!isDEVSelect()) { 702 devState = Device_Idle_NS; 703 intrClear(); 704 } else if (action == ACT_STAT_READ || isIENSet()) { 705 devState = Device_Idle_S; 706 intrClear(); 707 } else if (action == ACT_CMD_WRITE) { 708 intrClear(); 709 startCommand(); 710 } 711 712 break; 713 714 case Device_Idle_NS: 715 if (isDEVSelect()) { 716 if (!isIENSet() && intrPending) { 717 devState = Device_Idle_SI; 718 intrPost(); 719 } 720 if (isIENSet() || !intrPending) { 721 devState = Device_Idle_S; 722 } 723 } 724 break; 725 726 case Command_Execution: 727 if (action == ACT_CMD_COMPLETE) { 728 // clear the BSY bit 729 setComplete(); 730 731 if (!isIENSet()) { 732 devState = Device_Idle_SI; 733 intrPost(); 734 } else { 735 devState = Device_Idle_S; 736 } 737 } 738 break; 739 740 case Prepare_Data_In: 741 if (action == ACT_CMD_ERROR) { 742 // clear the BSY bit 743 setComplete(); 744 745 if (!isIENSet()) { 746 devState = Device_Idle_SI; 747 intrPost(); 748 } else { 749 devState = Device_Idle_S; 750 } 751 } else if (action == ACT_DATA_READY) { 752 // clear the BSY bit 753 cmdReg.status &= ~STATUS_BSY_BIT; 754 // set the DRQ bit 755 cmdReg.status |= STATUS_DRQ_BIT; 756 757 // put the first two bytes into the data register 758 memcpy((void *)&cmdReg.data0, (void *)dataBuffer, 759 sizeof(uint16_t)); 760 761 // copy the data into the data buffer 762 if (curCommand == WIN_IDENTIFY) 763 memcpy((void *)dataBuffer, (void *)&driveID, 764 sizeof(struct hd_driveid)); 765 else 766 readDisk(curSector++, dataBuffer); 767 768 if (!isIENSet()) { 769 devState = Data_Ready_INTRQ_In; 770 intrPost(); 771 } else { 772 devState = Transfer_Data_In; 773 } 774 } 775 break; 776 777 case Data_Ready_INTRQ_In: 778 if (action == ACT_STAT_READ) { 779 devState = Transfer_Data_In; 780 intrClear(); 781 } 782 break; 783 784 case Transfer_Data_In: 785 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 786 if (action == ACT_DATA_READ_BYTE) { 787 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 788 } else { 789 drqBytesLeft -= 2; 790 cmdBytesLeft -= 2; 791 792 // copy next short into data registers 793 memcpy((void *)&cmdReg.data0, 794 (void *)&dataBuffer[SectorSize - drqBytesLeft], 795 sizeof(uint16_t)); 796 } 797 798 if (drqBytesLeft == 0) { 799 if (cmdBytesLeft == 0) { 800 // Clear the BSY bit 801 setComplete(); 802 devState = Device_Idle_S; 803 } else { 804 devState = Prepare_Data_In; 805 cmdReg.status |= STATUS_BSY_BIT; 806 } 807 } 808 } 809 break; 810 811 case Prepare_Data_Out: 812 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 813 // clear the BSY bit 814 setComplete(); 815 816 if (!isIENSet()) { 817 devState = Device_Idle_SI; 818 intrPost(); 819 } else { 820 devState = Device_Idle_S; 821 } 822 } else if (cmdBytesLeft != 0) { 823 // clear the BSY bit 824 cmdReg.status &= ~STATUS_BSY_BIT; 825 // set the DRQ bit 826 cmdReg.status |= STATUS_DRQ_BIT; 827 828 // clear the data buffer to get it ready for writes 829 memset(dataBuffer, 0, MAX_DMA_SIZE); 830 831 if (!isIENSet()) { 832 devState = Data_Ready_INTRQ_Out; 833 intrPost(); 834 } else { 835 devState = Transfer_Data_Out; 836 } 837 } 838 break; 839 840 case Data_Ready_INTRQ_Out: 841 if (action == ACT_STAT_READ) { 842 devState = Transfer_Data_Out; 843 intrClear(); 844 } 845 break; 846 847 case Transfer_Data_Out: 848 if (action == ACT_DATA_WRITE_BYTE || 849 action == ACT_DATA_WRITE_SHORT) { 850 851 if (action == ACT_DATA_READ_BYTE) { 852 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 853 } else { 854 // copy the latest short into the data buffer 855 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 856 (void *)&cmdReg.data0, 857 sizeof(uint16_t)); 858 859 drqBytesLeft -= 2; 860 cmdBytesLeft -= 2; 861 } 862 863 if (drqBytesLeft == 0) { 864 // copy the block to the disk 865 writeDisk(curSector++, dataBuffer); 866 867 // set the BSY bit 868 cmdReg.status |= STATUS_BSY_BIT; 869 // clear the DRQ bit 870 cmdReg.status &= ~STATUS_DRQ_BIT; 871 872 devState = Prepare_Data_Out; 873 } 874 } 875 break; 876 877 case Prepare_Data_Dma: 878 if (action == ACT_CMD_ERROR) { 879 // clear the BSY bit 880 setComplete(); 881 882 if (!isIENSet()) { 883 devState = Device_Idle_SI; 884 intrPost(); 885 } else { 886 devState = Device_Idle_S; 887 } 888 } else if (action == ACT_DMA_READY) { 889 // clear the BSY bit 890 cmdReg.status &= ~STATUS_BSY_BIT; 891 // set the DRQ bit 892 cmdReg.status |= STATUS_DRQ_BIT; 893 894 devState = Transfer_Data_Dma; 895 896 if (dmaState != Dma_Idle) 897 panic("Inconsistent DMA state, should be Dma_Idle\n"); 898 899 dmaState = Dma_Start; 900 // wait for the write to the DMA start bit 901 } 902 break; 903 904 case Transfer_Data_Dma: 905 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { 906 // clear the BSY bit 907 setComplete(); 908 // set the seek bit 909 cmdReg.status |= 0x10; 910 // clear the controller state for DMA transfer 911 ctrl->setDmaComplete(this); 912 913 if (!isIENSet()) { 914 devState = Device_Idle_SI; 915 intrPost(); 916 } else { 917 devState = Device_Idle_S; 918 } 919 } 920 break; 921 922 default: 923 panic("Unknown IDE device state: %#x\n", devState); 924 } 925} 926 927void 928IdeDisk::serialize(ostream &os) 929{ 930} 931 932void 933IdeDisk::unserialize(Checkpoint *cp, const string §ion) 934{ 935} 936 937#ifndef DOXYGEN_SHOULD_SKIP_THIS 938 939BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 940 941 SimObjectParam<DiskImage *> image; 942 SimObjectParam<PhysicalMemory *> physmem; 943 Param<int> driveID; 944 Param<int> disk_delay; 945 946END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 947 948BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) 949 950 INIT_PARAM(image, "Disk image"), 951 INIT_PARAM(physmem, "Physical memory"), 952 INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"), 953 INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in milliseconds", 0) 954 955END_INIT_SIM_OBJECT_PARAMS(IdeDisk) 956 957 958CREATE_SIM_OBJECT(IdeDisk) 959{ 960 return new IdeDisk(getInstanceName(), image, physmem, driveID, 961 disk_delay); 962} 963 964REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) 965 966#endif //DOXYGEN_SHOULD_SKIP_THIS 967