2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
28 * Authors: Andrew Schultz
33 * Device model implementation for an IDE disk
41 #include "arch/isa_traits.hh"
42 #include "base/chunk_generator.hh"
43 #include "base/cprintf.hh" // csprintf
44 #include "base/trace.hh"
45 #include "config/the_isa.hh"
46 #include "dev/disk_image.hh"
47 #include "dev/ide_ctrl.hh"
48 #include "dev/ide_disk.hh"
49 #include "sim/core.hh"
50 #include "sim/sim_object.hh"
53 using namespace TheISA
;
55 IdeDisk::IdeDisk(const Params
*p
)
56 : SimObject(p
), ctrl(NULL
), image(p
->image
), diskDelay(p
->delay
),
57 dmaTransferEvent(this), dmaReadCG(NULL
), dmaReadWaitEvent(this),
58 dmaWriteCG(NULL
), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
59 dmaReadEvent(this), dmaWriteEvent(this)
61 // Reset the device state
64 // fill out the drive ID structure
65 memset(&driveID
, 0, sizeof(struct ataparams
));
67 // Calculate LBA and C/H/S values
72 uint32_t lba_size
= image
->size();
73 if (lba_size
>= 16383*16*63) {
83 if ((lba_size
/ sectors
) >= 16)
86 heads
= (lba_size
/ sectors
);
88 cylinders
= lba_size
/ (heads
* sectors
);
91 // Setup the model name
92 strncpy((char *)driveID
.atap_model
, "5MI EDD si k",
93 sizeof(driveID
.atap_model
));
94 // Set the maximum multisector transfer size
95 driveID
.atap_multi
= MAX_MULTSECT
;
96 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
97 driveID
.atap_capabilities1
= 0x7;
98 // UDMA support, EIDE support
99 driveID
.atap_extensions
= 0x6;
100 // Setup default C/H/S settings
101 driveID
.atap_cylinders
= cylinders
;
102 driveID
.atap_sectors
= sectors
;
103 driveID
.atap_heads
= heads
;
104 // Setup the current multisector transfer size
105 driveID
.atap_curmulti
= MAX_MULTSECT
;
106 driveID
.atap_curmulti_valid
= 0x1;
107 // Number of sectors on disk
108 driveID
.atap_capacity
= lba_size
;
109 // Multiword DMA mode 2 and below supported
110 driveID
.atap_dmamode_supp
= 0x4;
111 // Set PIO mode 4 and 3 supported
112 driveID
.atap_piomode_supp
= 0x3;
113 // Set DMA mode 4 and below supported
114 driveID
.atap_udmamode_supp
= 0x1f;
115 // Statically set hardware config word
116 driveID
.atap_hwreset_res
= 0x4001;
118 //arbitrary for now...
119 driveID
.atap_ata_major
= WDC_VER_ATA7
;
124 // destroy the data buffer
125 delete [] dataBuffer
;
129 IdeDisk::reset(int id
)
131 // initialize the data buffer and shadow registers
132 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
134 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
135 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
136 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
146 // set the device state to idle
150 devState
= Device_Idle_S
;
152 } else if (id
== DEV1
) {
153 devState
= Device_Idle_NS
;
156 panic("Invalid device ID: %#x\n", id
);
159 // set the device ready bit
160 status
= STATUS_DRDY_BIT
;
162 /* The error register must be set to 0x1 on start-up to
163 indicate that no diagnostic error was detected */
172 IdeDisk::isDEVSelect()
174 return ctrl
->isDiskSelected(this);
178 IdeDisk::pciToDma(Addr pciAddr
)
181 return ctrl
->pciToDma(pciAddr
);
183 panic("Access to unset controller!\n");
187 // Device registers read/write
191 IdeDisk::readCommand(const Addr offset
, int size
, uint8_t *data
)
193 if (offset
== DATA_OFFSET
) {
194 if (size
== sizeof(uint16_t)) {
195 *(uint16_t *)data
= cmdReg
.data
;
196 } else if (size
== sizeof(uint32_t)) {
197 *(uint16_t *)data
= cmdReg
.data
;
198 updateState(ACT_DATA_READ_SHORT
);
199 *((uint16_t *)data
+ 1) = cmdReg
.data
;
201 panic("Data read of unsupported size %d.\n", size
);
203 updateState(ACT_DATA_READ_SHORT
);
206 assert(size
== sizeof(uint8_t));
209 *data
= cmdReg
.error
;
212 *data
= cmdReg
.sec_count
;
215 *data
= cmdReg
.sec_num
;
218 *data
= cmdReg
.cyl_low
;
221 *data
= cmdReg
.cyl_high
;
224 *data
= cmdReg
.drive
;
228 updateState(ACT_STAT_READ
);
231 panic("Invalid IDE command register offset: %#x\n", offset
);
233 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
237 IdeDisk::readControl(const Addr offset
, int size
, uint8_t *data
)
239 assert(size
== sizeof(uint8_t));
241 if (offset
!= ALTSTAT_OFFSET
)
242 panic("Invalid IDE control register offset: %#x\n", offset
);
243 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
247 IdeDisk::writeCommand(const Addr offset
, int size
, const uint8_t *data
)
249 if (offset
== DATA_OFFSET
) {
250 if (size
== sizeof(uint16_t)) {
251 cmdReg
.data
= *(const uint16_t *)data
;
252 } else if (size
== sizeof(uint32_t)) {
253 cmdReg
.data
= *(const uint16_t *)data
;
254 updateState(ACT_DATA_WRITE_SHORT
);
255 cmdReg
.data
= *((const uint16_t *)data
+ 1);
257 panic("Data write of unsupported size %d.\n", size
);
259 updateState(ACT_DATA_WRITE_SHORT
);
263 assert(size
== sizeof(uint8_t));
265 case FEATURES_OFFSET
:
268 cmdReg
.sec_count
= *data
;
271 cmdReg
.sec_num
= *data
;
274 cmdReg
.cyl_low
= *data
;
277 cmdReg
.cyl_high
= *data
;
280 cmdReg
.drive
= *data
;
281 updateState(ACT_SELECT_WRITE
);
284 cmdReg
.command
= *data
;
285 updateState(ACT_CMD_WRITE
);
288 panic("Invalid IDE command register offset: %#x\n", offset
);
290 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
295 IdeDisk::writeControl(const Addr offset
, int size
, const uint8_t *data
)
297 if (offset
!= CONTROL_OFFSET
)
298 panic("Invalid IDE control register offset: %#x\n", offset
);
300 if (*data
& CONTROL_RST_BIT
) {
301 // force the device into the reset state
302 devState
= Device_Srst
;
303 updateState(ACT_SRST_SET
);
304 } else if (devState
== Device_Srst
&& !(*data
& CONTROL_RST_BIT
)) {
305 updateState(ACT_SRST_CLEAR
);
308 nIENBit
= *data
& CONTROL_IEN_BIT
;
310 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
315 // Perform DMA transactions
319 IdeDisk::doDmaTransfer()
321 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
322 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
325 if (ctrl
->dmaPending() || ctrl
->getState() != SimObject::Running
) {
326 schedule(dmaTransferEvent
, curTick() + DMA_BACKOFF_PERIOD
);
329 ctrl
->dmaRead(curPrdAddr
, sizeof(PrdEntry_t
), &dmaPrdReadEvent
,
330 (uint8_t*)&curPrd
.entry
);
334 IdeDisk::dmaPrdReadDone()
337 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
338 curPrd
.getBaseAddr(), pciToDma(curPrd
.getBaseAddr()),
339 curPrd
.getByteCount(), (cmdBytesLeft
/SectorSize
),
340 curPrd
.getEOT(), curSector
);
342 // the prd pointer has already been translated, so just do an increment
343 curPrdAddr
= curPrdAddr
+ sizeof(PrdEntry_t
);
352 IdeDisk::doDmaDataRead()
354 /** @todo we need to figure out what the delay actually will be */
355 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
357 DPRINTF(IdeDisk
, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
358 diskDelay
, totalDiskDelay
);
360 schedule(dmaReadWaitEvent
, curTick() + totalDiskDelay
);
366 using namespace Stats
;
368 .name(name() + ".dma_read_full_pages")
369 .desc("Number of full page size DMA reads (not PRD).")
372 .name(name() + ".dma_read_bytes")
373 .desc("Number of bytes transfered via DMA reads (not PRD).")
376 .name(name() + ".dma_read_txs")
377 .desc("Number of DMA read transactions (not PRD).")
381 .name(name() + ".dma_write_full_pages")
382 .desc("Number of full page size DMA writes.")
385 .name(name() + ".dma_write_bytes")
386 .desc("Number of bytes transfered via DMA writes.")
389 .name(name() + ".dma_write_txs")
390 .desc("Number of DMA write transactions.")
399 // clear out the data buffer
400 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
401 dmaReadCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
402 curPrd
.getByteCount(), TheISA::PageBytes
);
405 if (ctrl
->dmaPending() || ctrl
->getState() != SimObject::Running
) {
406 schedule(dmaReadWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
408 } else if (!dmaReadCG
->done()) {
409 assert(dmaReadCG
->complete() < MAX_DMA_SIZE
);
410 ctrl
->dmaRead(pciToDma(dmaReadCG
->addr()), dmaReadCG
->size(),
411 &dmaReadWaitEvent
, dataBuffer
+ dmaReadCG
->complete());
412 dmaReadBytes
+= dmaReadCG
->size();
414 if (dmaReadCG
->size() == TheISA::PageBytes
)
418 assert(dmaReadCG
->done());
426 IdeDisk::dmaReadDone()
429 uint32_t bytesWritten
= 0;
432 // write the data to the disk image
433 for (bytesWritten
= 0; bytesWritten
< curPrd
.getByteCount();
434 bytesWritten
+= SectorSize
) {
436 cmdBytesLeft
-= SectorSize
;
437 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
441 if (curPrd
.getEOT()) {
442 assert(cmdBytesLeft
== 0);
444 updateState(ACT_DMA_DONE
);
451 IdeDisk::doDmaDataWrite()
453 /** @todo we need to figure out what the delay actually will be */
454 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
455 uint32_t bytesRead
= 0;
457 DPRINTF(IdeDisk
, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
458 diskDelay
, totalDiskDelay
);
460 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
461 assert(cmdBytesLeft
<= MAX_DMA_SIZE
);
462 while (bytesRead
< curPrd
.getByteCount()) {
463 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
464 bytesRead
+= SectorSize
;
465 cmdBytesLeft
-= SectorSize
;
468 schedule(dmaWriteWaitEvent
, curTick() + totalDiskDelay
);
472 IdeDisk::doDmaWrite()
476 // clear out the data buffer
477 dmaWriteCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
478 curPrd
.getByteCount(), TheISA::PageBytes
);
480 if (ctrl
->dmaPending() || ctrl
->getState() != SimObject::Running
) {
481 schedule(dmaWriteWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
483 } else if (!dmaWriteCG
->done()) {
484 assert(dmaWriteCG
->complete() < MAX_DMA_SIZE
);
485 ctrl
->dmaWrite(pciToDma(dmaWriteCG
->addr()), dmaWriteCG
->size(),
486 &dmaWriteWaitEvent
, dataBuffer
+ dmaWriteCG
->complete());
487 dmaWriteBytes
+= dmaWriteCG
->size();
489 if (dmaWriteCG
->size() == TheISA::PageBytes
)
493 assert(dmaWriteCG
->done());
501 IdeDisk::dmaWriteDone()
504 if (curPrd
.getEOT()) {
505 assert(cmdBytesLeft
== 0);
507 updateState(ACT_DMA_DONE
);
514 // Disk utility routines
518 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
520 uint32_t bytesRead
= image
->read(data
, sector
);
522 if (bytesRead
!= SectorSize
)
523 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
524 name(), bytesRead
, SectorSize
, errno
);
528 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
530 uint32_t bytesWritten
= image
->write(data
, sector
);
532 if (bytesWritten
!= SectorSize
)
533 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
534 name(), bytesWritten
, SectorSize
, errno
);
538 // Setup and handle commands
542 IdeDisk::startDma(const uint32_t &prdTableBase
)
544 if (dmaState
!= Dma_Start
)
545 panic("Inconsistent DMA state, should be in Dma_Start!\n");
547 if (devState
!= Transfer_Data_Dma
)
548 panic("Inconsistent device state for DMA start!\n");
550 // PRD base address is given by bits 31:2
551 curPrdAddr
= pciToDma((Addr
)(prdTableBase
& ~ULL(0x3)));
553 dmaState
= Dma_Transfer
;
555 // schedule dma transfer (doDmaTransfer)
556 schedule(dmaTransferEvent
, curTick() + 1);
562 if (dmaState
== Dma_Idle
)
563 panic("Inconsistent DMA state, should be Start or Transfer!");
565 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
566 panic("Inconsistent device state, should be Transfer or Prepare!\n");
568 updateState(ACT_CMD_ERROR
);
572 IdeDisk::startCommand()
574 DevAction_t action
= ACT_NONE
;
579 switch (cmdReg
.command
) {
580 // Supported non-data commands
581 case WDSF_READ_NATIVE_MAX
:
582 size
= image
->size() - 1;
583 cmdReg
.sec_num
= (size
& 0xff);
584 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
585 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
586 cmdReg
.head
= ((size
& 0xf000000) >> 24);
588 devState
= Command_Execution
;
589 action
= ACT_CMD_COMPLETE
;
594 case WDCC_STANDBY_IMMED
:
595 case WDCC_FLUSHCACHE
:
600 devState
= Command_Execution
;
601 action
= ACT_CMD_COMPLETE
;
604 // Supported PIO data-in commands
606 cmdBytes
= cmdBytesLeft
= sizeof(struct ataparams
);
607 devState
= Prepare_Data_In
;
608 action
= ACT_DATA_READY
;
613 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
614 panic("Attempt to perform CHS access, only supports LBA\n");
616 if (cmdReg
.sec_count
== 0)
617 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
619 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
621 curSector
= getLBABase();
623 /** @todo make this a scheduled event to simulate disk delay */
624 devState
= Prepare_Data_In
;
625 action
= ACT_DATA_READY
;
628 // Supported PIO data-out commands
629 case WDCC_WRITEMULTI
:
631 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
632 panic("Attempt to perform CHS access, only supports LBA\n");
634 if (cmdReg
.sec_count
== 0)
635 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
637 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
639 curSector
= getLBABase();
641 devState
= Prepare_Data_Out
;
642 action
= ACT_DATA_READY
;
645 // Supported DMA commands
647 dmaRead
= true; // a write to the disk is a DMA read from memory
649 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
650 panic("Attempt to perform CHS access, only supports LBA\n");
652 if (cmdReg
.sec_count
== 0)
653 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
655 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
657 curSector
= getLBABase();
659 devState
= Prepare_Data_Dma
;
660 action
= ACT_DMA_READY
;
664 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
667 if (action
!= ACT_NONE
) {
669 status
|= STATUS_BSY_BIT
;
671 status
&= ~STATUS_DRQ_BIT
;
673 status
&= ~STATUS_DF_BIT
;
680 // Handle setting and clearing interrupts
686 DPRINTF(IdeDisk
, "Posting Interrupt\n");
688 panic("Attempt to post an interrupt with one pending\n");
692 // talk to controller to set interrupt
701 DPRINTF(IdeDisk
, "Clearing Interrupt\n");
703 panic("Attempt to clear a non-pending interrupt\n");
707 // talk to controller to clear interrupt
713 // Manage the device internal state machine
717 IdeDisk::updateState(DevAction_t action
)
721 if (action
== ACT_SRST_SET
) {
723 status
|= STATUS_BSY_BIT
;
724 } else if (action
== ACT_SRST_CLEAR
) {
726 status
&= ~STATUS_BSY_BIT
;
728 // reset the device state
734 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
735 devState
= Device_Idle_NS
;
736 } else if (action
== ACT_CMD_WRITE
) {
743 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
744 devState
= Device_Idle_NS
;
746 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
747 devState
= Device_Idle_S
;
749 } else if (action
== ACT_CMD_WRITE
) {
757 if (action
== ACT_SELECT_WRITE
&& isDEVSelect()) {
758 if (!isIENSet() && intrPending
) {
759 devState
= Device_Idle_SI
;
762 if (isIENSet() || !intrPending
) {
763 devState
= Device_Idle_S
;
768 case Command_Execution
:
769 if (action
== ACT_CMD_COMPLETE
) {
774 devState
= Device_Idle_SI
;
777 devState
= Device_Idle_S
;
782 case Prepare_Data_In
:
783 if (action
== ACT_CMD_ERROR
) {
788 devState
= Device_Idle_SI
;
791 devState
= Device_Idle_S
;
793 } else if (action
== ACT_DATA_READY
) {
795 status
&= ~STATUS_BSY_BIT
;
797 status
|= STATUS_DRQ_BIT
;
799 // copy the data into the data buffer
800 if (cmdReg
.command
== WDCC_IDENTIFY
) {
801 // Reset the drqBytes for this block
802 drqBytesLeft
= sizeof(struct ataparams
);
804 memcpy((void *)dataBuffer
, (void *)&driveID
,
805 sizeof(struct ataparams
));
807 // Reset the drqBytes for this block
808 drqBytesLeft
= SectorSize
;
810 readDisk(curSector
++, dataBuffer
);
813 // put the first two bytes into the data register
814 memcpy((void *)&cmdReg
.data
, (void *)dataBuffer
,
818 devState
= Data_Ready_INTRQ_In
;
821 devState
= Transfer_Data_In
;
826 case Data_Ready_INTRQ_In
:
827 if (action
== ACT_STAT_READ
) {
828 devState
= Transfer_Data_In
;
833 case Transfer_Data_In
:
834 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
835 if (action
== ACT_DATA_READ_BYTE
) {
836 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
841 // copy next short into data registers
843 memcpy((void *)&cmdReg
.data
,
844 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
848 if (drqBytesLeft
== 0) {
849 if (cmdBytesLeft
== 0) {
852 devState
= Device_Idle_S
;
854 devState
= Prepare_Data_In
;
856 status
|= STATUS_BSY_BIT
;
858 status
&= ~STATUS_DRQ_BIT
;
860 /** @todo change this to a scheduled event to simulate
862 updateState(ACT_DATA_READY
);
868 case Prepare_Data_Out
:
869 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
874 devState
= Device_Idle_SI
;
877 devState
= Device_Idle_S
;
879 } else if (action
== ACT_DATA_READY
&& cmdBytesLeft
!= 0) {
881 status
&= ~STATUS_BSY_BIT
;
883 status
|= STATUS_DRQ_BIT
;
885 // clear the data buffer to get it ready for writes
886 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
888 // reset the drqBytes for this block
889 drqBytesLeft
= SectorSize
;
891 if (cmdBytesLeft
== cmdBytes
|| isIENSet()) {
892 devState
= Transfer_Data_Out
;
894 devState
= Data_Ready_INTRQ_Out
;
900 case Data_Ready_INTRQ_Out
:
901 if (action
== ACT_STAT_READ
) {
902 devState
= Transfer_Data_Out
;
907 case Transfer_Data_Out
:
908 if (action
== ACT_DATA_WRITE_BYTE
||
909 action
== ACT_DATA_WRITE_SHORT
) {
911 if (action
== ACT_DATA_READ_BYTE
) {
912 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
914 // copy the latest short into the data buffer
915 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
916 (void *)&cmdReg
.data
,
923 if (drqBytesLeft
== 0) {
924 // copy the block to the disk
925 writeDisk(curSector
++, dataBuffer
);
928 status
|= STATUS_BSY_BIT
;
930 status
|= STATUS_SEEK_BIT
;
932 status
&= ~STATUS_DRQ_BIT
;
934 devState
= Prepare_Data_Out
;
936 /** @todo change this to a scheduled event to simulate
938 updateState(ACT_DATA_READY
);
943 case Prepare_Data_Dma
:
944 if (action
== ACT_CMD_ERROR
) {
949 devState
= Device_Idle_SI
;
952 devState
= Device_Idle_S
;
954 } else if (action
== ACT_DMA_READY
) {
956 status
&= ~STATUS_BSY_BIT
;
958 status
|= STATUS_DRQ_BIT
;
960 devState
= Transfer_Data_Dma
;
962 if (dmaState
!= Dma_Idle
)
963 panic("Inconsistent DMA state, should be Dma_Idle\n");
965 dmaState
= Dma_Start
;
966 // wait for the write to the DMA start bit
970 case Transfer_Data_Dma
:
971 if (action
== ACT_CMD_ERROR
|| action
== ACT_DMA_DONE
) {
975 status
|= STATUS_SEEK_BIT
;
976 // clear the controller state for DMA transfer
977 ctrl
->setDmaComplete(this);
980 devState
= Device_Idle_SI
;
983 devState
= Device_Idle_S
;
989 panic("Unknown IDE device state: %#x\n", devState
);
994 IdeDisk::serialize(ostream
&os
)
996 // Check all outstanding events to see if they are scheduled
997 // these are all mutually exclusive
999 Events_t event
= None
;
1003 if (dmaTransferEvent
.scheduled()) {
1004 reschedule
= dmaTransferEvent
.when();
1008 if (dmaReadWaitEvent
.scheduled()) {
1009 reschedule
= dmaReadWaitEvent
.when();
1013 if (dmaWriteWaitEvent
.scheduled()) {
1014 reschedule
= dmaWriteWaitEvent
.when();
1018 if (dmaPrdReadEvent
.scheduled()) {
1019 reschedule
= dmaPrdReadEvent
.when();
1023 if (dmaReadEvent
.scheduled()) {
1024 reschedule
= dmaReadEvent
.when();
1028 if (dmaWriteEvent
.scheduled()) {
1029 reschedule
= dmaWriteEvent
.when();
1034 assert(eventCount
<= 1);
1036 SERIALIZE_SCALAR(reschedule
);
1037 SERIALIZE_ENUM(event
);
1039 // Serialize device registers
1040 SERIALIZE_SCALAR(cmdReg
.data
);
1041 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1042 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1043 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1044 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1045 SERIALIZE_SCALAR(cmdReg
.drive
);
1046 SERIALIZE_SCALAR(cmdReg
.command
);
1047 SERIALIZE_SCALAR(status
);
1048 SERIALIZE_SCALAR(nIENBit
);
1049 SERIALIZE_SCALAR(devID
);
1051 // Serialize the PRD related information
1052 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1053 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1054 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1055 SERIALIZE_SCALAR(curPrdAddr
);
1057 /** @todo need to serialized chunk generator stuff!! */
1058 // Serialize current transfer related information
1059 SERIALIZE_SCALAR(cmdBytesLeft
);
1060 SERIALIZE_SCALAR(cmdBytes
);
1061 SERIALIZE_SCALAR(drqBytesLeft
);
1062 SERIALIZE_SCALAR(curSector
);
1063 SERIALIZE_SCALAR(dmaRead
);
1064 SERIALIZE_SCALAR(intrPending
);
1065 SERIALIZE_ENUM(devState
);
1066 SERIALIZE_ENUM(dmaState
);
1067 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1071 IdeDisk::unserialize(Checkpoint
*cp
, const string
§ion
)
1073 // Reschedule events that were outstanding
1074 // these are all mutually exclusive
1075 Tick reschedule
= 0;
1076 Events_t event
= None
;
1078 UNSERIALIZE_SCALAR(reschedule
);
1079 UNSERIALIZE_ENUM(event
);
1083 case Transfer
: schedule(dmaTransferEvent
, reschedule
); break;
1084 case ReadWait
: schedule(dmaReadWaitEvent
, reschedule
); break;
1085 case WriteWait
: schedule(dmaWriteWaitEvent
, reschedule
); break;
1086 case PrdRead
: schedule(dmaPrdReadEvent
, reschedule
); break;
1087 case DmaRead
: schedule(dmaReadEvent
, reschedule
); break;
1088 case DmaWrite
: schedule(dmaWriteEvent
, reschedule
); break;
1091 // Unserialize device registers
1092 UNSERIALIZE_SCALAR(cmdReg
.data
);
1093 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1094 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1095 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1096 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1097 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1098 UNSERIALIZE_SCALAR(cmdReg
.command
);
1099 UNSERIALIZE_SCALAR(status
);
1100 UNSERIALIZE_SCALAR(nIENBit
);
1101 UNSERIALIZE_SCALAR(devID
);
1103 // Unserialize the PRD related information
1104 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1105 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1106 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1107 UNSERIALIZE_SCALAR(curPrdAddr
);
1109 /** @todo need to serialized chunk generator stuff!! */
1110 // Unserialize current transfer related information
1111 UNSERIALIZE_SCALAR(cmdBytes
);
1112 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1113 UNSERIALIZE_SCALAR(drqBytesLeft
);
1114 UNSERIALIZE_SCALAR(curSector
);
1115 UNSERIALIZE_SCALAR(dmaRead
);
1116 UNSERIALIZE_SCALAR(intrPending
);
1117 UNSERIALIZE_ENUM(devState
);
1118 UNSERIALIZE_ENUM(dmaState
);
1119 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1123 IdeDiskParams::create()
1125 return new IdeDisk(this);