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 "debug/IdeDisk.hh"
47 #include "dev/disk_image.hh"
48 #include "dev/ide_ctrl.hh"
49 #include "dev/ide_disk.hh"
50 #include "sim/core.hh"
51 #include "sim/sim_object.hh"
54 using namespace TheISA
;
56 IdeDisk::IdeDisk(const Params
*p
)
57 : SimObject(p
), ctrl(NULL
), image(p
->image
), diskDelay(p
->delay
),
58 dmaTransferEvent(this), dmaReadCG(NULL
), dmaReadWaitEvent(this),
59 dmaWriteCG(NULL
), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
60 dmaReadEvent(this), dmaWriteEvent(this)
62 // Reset the device state
65 // fill out the drive ID structure
66 memset(&driveID
, 0, sizeof(struct ataparams
));
68 // Calculate LBA and C/H/S values
73 uint32_t lba_size
= image
->size();
74 if (lba_size
>= 16383*16*63) {
84 if ((lba_size
/ sectors
) >= 16)
87 heads
= (lba_size
/ sectors
);
89 cylinders
= lba_size
/ (heads
* sectors
);
92 // Setup the model name
93 strncpy((char *)driveID
.atap_model
, "5MI EDD si k",
94 sizeof(driveID
.atap_model
));
95 // Set the maximum multisector transfer size
96 driveID
.atap_multi
= MAX_MULTSECT
;
97 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
98 driveID
.atap_capabilities1
= 0x7;
99 // UDMA support, EIDE support
100 driveID
.atap_extensions
= 0x6;
101 // Setup default C/H/S settings
102 driveID
.atap_cylinders
= cylinders
;
103 driveID
.atap_sectors
= sectors
;
104 driveID
.atap_heads
= heads
;
105 // Setup the current multisector transfer size
106 driveID
.atap_curmulti
= MAX_MULTSECT
;
107 driveID
.atap_curmulti_valid
= 0x1;
108 // Number of sectors on disk
109 driveID
.atap_capacity
= lba_size
;
110 // Multiword DMA mode 2 and below supported
111 driveID
.atap_dmamode_supp
= 0x4;
112 // Set PIO mode 4 and 3 supported
113 driveID
.atap_piomode_supp
= 0x3;
114 // Set DMA mode 4 and below supported
115 driveID
.atap_udmamode_supp
= 0x1f;
116 // Statically set hardware config word
117 driveID
.atap_hwreset_res
= 0x4001;
119 //arbitrary for now...
120 driveID
.atap_ata_major
= WDC_VER_ATA7
;
125 // destroy the data buffer
126 delete [] dataBuffer
;
130 IdeDisk::reset(int id
)
132 // initialize the data buffer and shadow registers
133 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
135 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
136 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
137 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
147 // set the device state to idle
151 devState
= Device_Idle_S
;
153 } else if (id
== DEV1
) {
154 devState
= Device_Idle_NS
;
157 panic("Invalid device ID: %#x\n", id
);
160 // set the device ready bit
161 status
= STATUS_DRDY_BIT
;
163 /* The error register must be set to 0x1 on start-up to
164 indicate that no diagnostic error was detected */
173 IdeDisk::isDEVSelect()
175 return ctrl
->isDiskSelected(this);
179 IdeDisk::pciToDma(Addr pciAddr
)
182 return ctrl
->pciToDma(pciAddr
);
184 panic("Access to unset controller!\n");
188 // Device registers read/write
192 IdeDisk::readCommand(const Addr offset
, int size
, uint8_t *data
)
194 if (offset
== DATA_OFFSET
) {
195 if (size
== sizeof(uint16_t)) {
196 *(uint16_t *)data
= cmdReg
.data
;
197 } else if (size
== sizeof(uint32_t)) {
198 *(uint16_t *)data
= cmdReg
.data
;
199 updateState(ACT_DATA_READ_SHORT
);
200 *((uint16_t *)data
+ 1) = cmdReg
.data
;
202 panic("Data read of unsupported size %d.\n", size
);
204 updateState(ACT_DATA_READ_SHORT
);
207 assert(size
== sizeof(uint8_t));
210 *data
= cmdReg
.error
;
213 *data
= cmdReg
.sec_count
;
216 *data
= cmdReg
.sec_num
;
219 *data
= cmdReg
.cyl_low
;
222 *data
= cmdReg
.cyl_high
;
225 *data
= cmdReg
.drive
;
229 updateState(ACT_STAT_READ
);
232 panic("Invalid IDE command register offset: %#x\n", offset
);
234 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
238 IdeDisk::readControl(const Addr offset
, int size
, uint8_t *data
)
240 assert(size
== sizeof(uint8_t));
242 if (offset
!= ALTSTAT_OFFSET
)
243 panic("Invalid IDE control register offset: %#x\n", offset
);
244 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
248 IdeDisk::writeCommand(const Addr offset
, int size
, const uint8_t *data
)
250 if (offset
== DATA_OFFSET
) {
251 if (size
== sizeof(uint16_t)) {
252 cmdReg
.data
= *(const uint16_t *)data
;
253 } else if (size
== sizeof(uint32_t)) {
254 cmdReg
.data
= *(const uint16_t *)data
;
255 updateState(ACT_DATA_WRITE_SHORT
);
256 cmdReg
.data
= *((const uint16_t *)data
+ 1);
258 panic("Data write of unsupported size %d.\n", size
);
260 updateState(ACT_DATA_WRITE_SHORT
);
264 assert(size
== sizeof(uint8_t));
266 case FEATURES_OFFSET
:
269 cmdReg
.sec_count
= *data
;
272 cmdReg
.sec_num
= *data
;
275 cmdReg
.cyl_low
= *data
;
278 cmdReg
.cyl_high
= *data
;
281 cmdReg
.drive
= *data
;
282 updateState(ACT_SELECT_WRITE
);
285 cmdReg
.command
= *data
;
286 updateState(ACT_CMD_WRITE
);
289 panic("Invalid IDE command register offset: %#x\n", offset
);
291 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
296 IdeDisk::writeControl(const Addr offset
, int size
, const uint8_t *data
)
298 if (offset
!= CONTROL_OFFSET
)
299 panic("Invalid IDE control register offset: %#x\n", offset
);
301 if (*data
& CONTROL_RST_BIT
) {
302 // force the device into the reset state
303 devState
= Device_Srst
;
304 updateState(ACT_SRST_SET
);
305 } else if (devState
== Device_Srst
&& !(*data
& CONTROL_RST_BIT
)) {
306 updateState(ACT_SRST_CLEAR
);
309 nIENBit
= *data
& CONTROL_IEN_BIT
;
311 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
316 // Perform DMA transactions
320 IdeDisk::doDmaTransfer()
322 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
323 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
326 if (ctrl
->dmaPending() || ctrl
->getDrainState() != Drainable::Running
) {
327 schedule(dmaTransferEvent
, curTick() + DMA_BACKOFF_PERIOD
);
330 ctrl
->dmaRead(curPrdAddr
, sizeof(PrdEntry_t
), &dmaPrdReadEvent
,
331 (uint8_t*)&curPrd
.entry
);
335 IdeDisk::dmaPrdReadDone()
339 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
340 curPrd
.getBaseAddr(), pciToDma(curPrd
.getBaseAddr()),
341 curPrd
.getByteCount(), (cmdBytesLeft
/SectorSize
),
342 curPrd
.getEOT(), curSector
);
344 // the prd pointer has already been translated, so just do an increment
345 curPrdAddr
= curPrdAddr
+ sizeof(PrdEntry_t
);
354 IdeDisk::doDmaDataRead()
356 /** @todo we need to figure out what the delay actually will be */
357 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
359 DPRINTF(IdeDisk
, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
360 diskDelay
, totalDiskDelay
);
362 schedule(dmaReadWaitEvent
, curTick() + totalDiskDelay
);
368 using namespace Stats
;
370 .name(name() + ".dma_read_full_pages")
371 .desc("Number of full page size DMA reads (not PRD).")
374 .name(name() + ".dma_read_bytes")
375 .desc("Number of bytes transfered via DMA reads (not PRD).")
378 .name(name() + ".dma_read_txs")
379 .desc("Number of DMA read transactions (not PRD).")
383 .name(name() + ".dma_write_full_pages")
384 .desc("Number of full page size DMA writes.")
387 .name(name() + ".dma_write_bytes")
388 .desc("Number of bytes transfered via DMA writes.")
391 .name(name() + ".dma_write_txs")
392 .desc("Number of DMA write transactions.")
401 // clear out the data buffer
402 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
403 dmaReadCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
404 curPrd
.getByteCount(), TheISA::PageBytes
);
407 if (ctrl
->dmaPending() || ctrl
->getDrainState() != Drainable::Running
) {
408 schedule(dmaReadWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
410 } else if (!dmaReadCG
->done()) {
411 assert(dmaReadCG
->complete() < MAX_DMA_SIZE
);
412 ctrl
->dmaRead(pciToDma(dmaReadCG
->addr()), dmaReadCG
->size(),
413 &dmaReadWaitEvent
, dataBuffer
+ dmaReadCG
->complete());
414 dmaReadBytes
+= dmaReadCG
->size();
416 if (dmaReadCG
->size() == TheISA::PageBytes
)
420 assert(dmaReadCG
->done());
428 IdeDisk::dmaReadDone()
431 uint32_t bytesWritten
= 0;
434 // write the data to the disk image
435 for (bytesWritten
= 0; bytesWritten
< curPrd
.getByteCount();
436 bytesWritten
+= SectorSize
) {
438 cmdBytesLeft
-= SectorSize
;
439 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
443 if (curPrd
.getEOT()) {
444 assert(cmdBytesLeft
== 0);
446 updateState(ACT_DMA_DONE
);
453 IdeDisk::doDmaDataWrite()
455 /** @todo we need to figure out what the delay actually will be */
456 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
457 uint32_t bytesRead
= 0;
459 DPRINTF(IdeDisk
, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
460 diskDelay
, totalDiskDelay
);
462 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
463 assert(cmdBytesLeft
<= MAX_DMA_SIZE
);
464 while (bytesRead
< curPrd
.getByteCount()) {
465 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
466 bytesRead
+= SectorSize
;
467 cmdBytesLeft
-= SectorSize
;
469 DPRINTF(IdeDisk
, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
470 bytesRead
, cmdBytesLeft
);
472 schedule(dmaWriteWaitEvent
, curTick() + totalDiskDelay
);
476 IdeDisk::doDmaWrite()
478 DPRINTF(IdeDisk
, "doDmaWrite: rescheduling\n");
480 // clear out the data buffer
481 dmaWriteCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
482 curPrd
.getByteCount(), TheISA::PageBytes
);
484 if (ctrl
->dmaPending() || ctrl
->getDrainState() != Drainable::Running
) {
485 schedule(dmaWriteWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
486 DPRINTF(IdeDisk
, "doDmaWrite: rescheduling\n");
488 } else if (!dmaWriteCG
->done()) {
489 assert(dmaWriteCG
->complete() < MAX_DMA_SIZE
);
490 ctrl
->dmaWrite(pciToDma(dmaWriteCG
->addr()), dmaWriteCG
->size(),
491 &dmaWriteWaitEvent
, dataBuffer
+ dmaWriteCG
->complete());
492 DPRINTF(IdeDisk
, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
493 curPrd
.getByteCount(), curPrd
.getEOT());
494 dmaWriteBytes
+= dmaWriteCG
->size();
496 if (dmaWriteCG
->size() == TheISA::PageBytes
)
500 DPRINTF(IdeDisk
, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
501 curPrd
.getByteCount(), curPrd
.getEOT());
502 assert(dmaWriteCG
->done());
510 IdeDisk::dmaWriteDone()
512 DPRINTF(IdeDisk
, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
513 curPrd
.getByteCount(), curPrd
.getEOT(), cmdBytesLeft
);
515 if (curPrd
.getEOT()) {
516 assert(cmdBytesLeft
== 0);
518 updateState(ACT_DMA_DONE
);
525 // Disk utility routines
529 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
531 uint32_t bytesRead
= image
->read(data
, sector
);
533 if (bytesRead
!= SectorSize
)
534 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
535 name(), bytesRead
, SectorSize
, errno
);
539 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
541 uint32_t bytesWritten
= image
->write(data
, sector
);
543 if (bytesWritten
!= SectorSize
)
544 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
545 name(), bytesWritten
, SectorSize
, errno
);
549 // Setup and handle commands
553 IdeDisk::startDma(const uint32_t &prdTableBase
)
555 if (dmaState
!= Dma_Start
)
556 panic("Inconsistent DMA state, should be in Dma_Start!\n");
558 if (devState
!= Transfer_Data_Dma
)
559 panic("Inconsistent device state for DMA start!\n");
561 // PRD base address is given by bits 31:2
562 curPrdAddr
= pciToDma((Addr
)(prdTableBase
& ~ULL(0x3)));
564 dmaState
= Dma_Transfer
;
566 // schedule dma transfer (doDmaTransfer)
567 schedule(dmaTransferEvent
, curTick() + 1);
573 if (dmaState
== Dma_Idle
)
574 panic("Inconsistent DMA state, should be Start or Transfer!");
576 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
577 panic("Inconsistent device state, should be Transfer or Prepare!\n");
579 updateState(ACT_CMD_ERROR
);
583 IdeDisk::startCommand()
585 DevAction_t action
= ACT_NONE
;
590 switch (cmdReg
.command
) {
591 // Supported non-data commands
592 case WDSF_READ_NATIVE_MAX
:
593 size
= (uint32_t)image
->size() - 1;
594 cmdReg
.sec_num
= (size
& 0xff);
595 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
596 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
597 cmdReg
.head
= ((size
& 0xf000000) >> 24);
599 devState
= Command_Execution
;
600 action
= ACT_CMD_COMPLETE
;
605 case WDCC_STANDBY_IMMED
:
606 case WDCC_FLUSHCACHE
:
611 devState
= Command_Execution
;
612 action
= ACT_CMD_COMPLETE
;
615 // Supported PIO data-in commands
617 cmdBytes
= cmdBytesLeft
= sizeof(struct ataparams
);
618 devState
= Prepare_Data_In
;
619 action
= ACT_DATA_READY
;
624 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
625 panic("Attempt to perform CHS access, only supports LBA\n");
627 if (cmdReg
.sec_count
== 0)
628 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
630 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
632 curSector
= getLBABase();
634 /** @todo make this a scheduled event to simulate disk delay */
635 devState
= Prepare_Data_In
;
636 action
= ACT_DATA_READY
;
639 // Supported PIO data-out commands
640 case WDCC_WRITEMULTI
:
642 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
643 panic("Attempt to perform CHS access, only supports LBA\n");
645 if (cmdReg
.sec_count
== 0)
646 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
648 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
649 DPRINTF(IdeDisk
, "Setting cmdBytesLeft to %d\n", cmdBytesLeft
);
650 curSector
= getLBABase();
652 devState
= Prepare_Data_Out
;
653 action
= ACT_DATA_READY
;
656 // Supported DMA commands
658 dmaRead
= true; // a write to the disk is a DMA read from memory
660 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
661 panic("Attempt to perform CHS access, only supports LBA\n");
663 if (cmdReg
.sec_count
== 0)
664 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
666 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
667 DPRINTF(IdeDisk
, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft
);
669 curSector
= getLBABase();
671 devState
= Prepare_Data_Dma
;
672 action
= ACT_DMA_READY
;
676 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
679 if (action
!= ACT_NONE
) {
681 status
|= STATUS_BSY_BIT
;
683 status
&= ~STATUS_DRQ_BIT
;
685 status
&= ~STATUS_DF_BIT
;
692 // Handle setting and clearing interrupts
698 DPRINTF(IdeDisk
, "Posting Interrupt\n");
700 panic("Attempt to post an interrupt with one pending\n");
704 // talk to controller to set interrupt
713 DPRINTF(IdeDisk
, "Clearing Interrupt\n");
715 panic("Attempt to clear a non-pending interrupt\n");
719 // talk to controller to clear interrupt
725 // Manage the device internal state machine
729 IdeDisk::updateState(DevAction_t action
)
733 if (action
== ACT_SRST_SET
) {
735 status
|= STATUS_BSY_BIT
;
736 } else if (action
== ACT_SRST_CLEAR
) {
738 status
&= ~STATUS_BSY_BIT
;
740 // reset the device state
746 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
747 devState
= Device_Idle_NS
;
748 } else if (action
== ACT_CMD_WRITE
) {
755 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
756 devState
= Device_Idle_NS
;
758 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
759 devState
= Device_Idle_S
;
761 } else if (action
== ACT_CMD_WRITE
) {
769 if (action
== ACT_SELECT_WRITE
&& isDEVSelect()) {
770 if (!isIENSet() && intrPending
) {
771 devState
= Device_Idle_SI
;
774 if (isIENSet() || !intrPending
) {
775 devState
= Device_Idle_S
;
780 case Command_Execution
:
781 if (action
== ACT_CMD_COMPLETE
) {
786 devState
= Device_Idle_SI
;
789 devState
= Device_Idle_S
;
794 case Prepare_Data_In
:
795 if (action
== ACT_CMD_ERROR
) {
800 devState
= Device_Idle_SI
;
803 devState
= Device_Idle_S
;
805 } else if (action
== ACT_DATA_READY
) {
807 status
&= ~STATUS_BSY_BIT
;
809 status
|= STATUS_DRQ_BIT
;
811 // copy the data into the data buffer
812 if (cmdReg
.command
== WDCC_IDENTIFY
) {
813 // Reset the drqBytes for this block
814 drqBytesLeft
= sizeof(struct ataparams
);
816 memcpy((void *)dataBuffer
, (void *)&driveID
,
817 sizeof(struct ataparams
));
819 // Reset the drqBytes for this block
820 drqBytesLeft
= SectorSize
;
822 readDisk(curSector
++, dataBuffer
);
825 // put the first two bytes into the data register
826 memcpy((void *)&cmdReg
.data
, (void *)dataBuffer
,
830 devState
= Data_Ready_INTRQ_In
;
833 devState
= Transfer_Data_In
;
838 case Data_Ready_INTRQ_In
:
839 if (action
== ACT_STAT_READ
) {
840 devState
= Transfer_Data_In
;
845 case Transfer_Data_In
:
846 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
847 if (action
== ACT_DATA_READ_BYTE
) {
848 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
853 // copy next short into data registers
855 memcpy((void *)&cmdReg
.data
,
856 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
860 if (drqBytesLeft
== 0) {
861 if (cmdBytesLeft
== 0) {
864 devState
= Device_Idle_S
;
866 devState
= Prepare_Data_In
;
868 status
|= STATUS_BSY_BIT
;
870 status
&= ~STATUS_DRQ_BIT
;
872 /** @todo change this to a scheduled event to simulate
874 updateState(ACT_DATA_READY
);
880 case Prepare_Data_Out
:
881 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
886 devState
= Device_Idle_SI
;
889 devState
= Device_Idle_S
;
891 } else if (action
== ACT_DATA_READY
&& cmdBytesLeft
!= 0) {
893 status
&= ~STATUS_BSY_BIT
;
895 status
|= STATUS_DRQ_BIT
;
897 // clear the data buffer to get it ready for writes
898 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
900 // reset the drqBytes for this block
901 drqBytesLeft
= SectorSize
;
903 if (cmdBytesLeft
== cmdBytes
|| isIENSet()) {
904 devState
= Transfer_Data_Out
;
906 devState
= Data_Ready_INTRQ_Out
;
912 case Data_Ready_INTRQ_Out
:
913 if (action
== ACT_STAT_READ
) {
914 devState
= Transfer_Data_Out
;
919 case Transfer_Data_Out
:
920 if (action
== ACT_DATA_WRITE_BYTE
||
921 action
== ACT_DATA_WRITE_SHORT
) {
923 if (action
== ACT_DATA_READ_BYTE
) {
924 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
926 // copy the latest short into the data buffer
927 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
928 (void *)&cmdReg
.data
,
935 if (drqBytesLeft
== 0) {
936 // copy the block to the disk
937 writeDisk(curSector
++, dataBuffer
);
940 status
|= STATUS_BSY_BIT
;
942 status
|= STATUS_SEEK_BIT
;
944 status
&= ~STATUS_DRQ_BIT
;
946 devState
= Prepare_Data_Out
;
948 /** @todo change this to a scheduled event to simulate
950 updateState(ACT_DATA_READY
);
955 case Prepare_Data_Dma
:
956 if (action
== ACT_CMD_ERROR
) {
961 devState
= Device_Idle_SI
;
964 devState
= Device_Idle_S
;
966 } else if (action
== ACT_DMA_READY
) {
968 status
&= ~STATUS_BSY_BIT
;
970 status
|= STATUS_DRQ_BIT
;
972 devState
= Transfer_Data_Dma
;
974 if (dmaState
!= Dma_Idle
)
975 panic("Inconsistent DMA state, should be Dma_Idle\n");
977 dmaState
= Dma_Start
;
978 // wait for the write to the DMA start bit
982 case Transfer_Data_Dma
:
983 if (action
== ACT_CMD_ERROR
|| action
== ACT_DMA_DONE
) {
987 status
|= STATUS_SEEK_BIT
;
988 // clear the controller state for DMA transfer
989 ctrl
->setDmaComplete(this);
992 devState
= Device_Idle_SI
;
995 devState
= Device_Idle_S
;
1001 panic("Unknown IDE device state: %#x\n", devState
);
1006 IdeDisk::serialize(ostream
&os
)
1008 // Check all outstanding events to see if they are scheduled
1009 // these are all mutually exclusive
1010 Tick reschedule
= 0;
1011 Events_t event
= None
;
1015 if (dmaTransferEvent
.scheduled()) {
1016 reschedule
= dmaTransferEvent
.when();
1020 if (dmaReadWaitEvent
.scheduled()) {
1021 reschedule
= dmaReadWaitEvent
.when();
1025 if (dmaWriteWaitEvent
.scheduled()) {
1026 reschedule
= dmaWriteWaitEvent
.when();
1030 if (dmaPrdReadEvent
.scheduled()) {
1031 reschedule
= dmaPrdReadEvent
.when();
1035 if (dmaReadEvent
.scheduled()) {
1036 reschedule
= dmaReadEvent
.when();
1040 if (dmaWriteEvent
.scheduled()) {
1041 reschedule
= dmaWriteEvent
.when();
1046 assert(eventCount
<= 1);
1048 SERIALIZE_SCALAR(reschedule
);
1049 SERIALIZE_ENUM(event
);
1051 // Serialize device registers
1052 SERIALIZE_SCALAR(cmdReg
.data
);
1053 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1054 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1055 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1056 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1057 SERIALIZE_SCALAR(cmdReg
.drive
);
1058 SERIALIZE_SCALAR(cmdReg
.command
);
1059 SERIALIZE_SCALAR(status
);
1060 SERIALIZE_SCALAR(nIENBit
);
1061 SERIALIZE_SCALAR(devID
);
1063 // Serialize the PRD related information
1064 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1065 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1066 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1067 SERIALIZE_SCALAR(curPrdAddr
);
1069 /** @todo need to serialized chunk generator stuff!! */
1070 // Serialize current transfer related information
1071 SERIALIZE_SCALAR(cmdBytesLeft
);
1072 SERIALIZE_SCALAR(cmdBytes
);
1073 SERIALIZE_SCALAR(drqBytesLeft
);
1074 SERIALIZE_SCALAR(curSector
);
1075 SERIALIZE_SCALAR(dmaRead
);
1076 SERIALIZE_SCALAR(intrPending
);
1077 SERIALIZE_ENUM(devState
);
1078 SERIALIZE_ENUM(dmaState
);
1079 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1083 IdeDisk::unserialize(Checkpoint
*cp
, const string
§ion
)
1085 // Reschedule events that were outstanding
1086 // these are all mutually exclusive
1087 Tick reschedule
= 0;
1088 Events_t event
= None
;
1090 UNSERIALIZE_SCALAR(reschedule
);
1091 UNSERIALIZE_ENUM(event
);
1095 case Transfer
: schedule(dmaTransferEvent
, reschedule
); break;
1096 case ReadWait
: schedule(dmaReadWaitEvent
, reschedule
); break;
1097 case WriteWait
: schedule(dmaWriteWaitEvent
, reschedule
); break;
1098 case PrdRead
: schedule(dmaPrdReadEvent
, reschedule
); break;
1099 case DmaRead
: schedule(dmaReadEvent
, reschedule
); break;
1100 case DmaWrite
: schedule(dmaWriteEvent
, reschedule
); break;
1103 // Unserialize device registers
1104 UNSERIALIZE_SCALAR(cmdReg
.data
);
1105 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1106 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1107 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1108 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1109 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1110 UNSERIALIZE_SCALAR(cmdReg
.command
);
1111 UNSERIALIZE_SCALAR(status
);
1112 UNSERIALIZE_SCALAR(nIENBit
);
1113 UNSERIALIZE_SCALAR(devID
);
1115 // Unserialize the PRD related information
1116 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1117 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1118 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1119 UNSERIALIZE_SCALAR(curPrdAddr
);
1121 /** @todo need to serialized chunk generator stuff!! */
1122 // Unserialize current transfer related information
1123 UNSERIALIZE_SCALAR(cmdBytes
);
1124 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1125 UNSERIALIZE_SCALAR(drqBytesLeft
);
1126 UNSERIALIZE_SCALAR(curSector
);
1127 UNSERIALIZE_SCALAR(dmaRead
);
1128 UNSERIALIZE_SCALAR(intrPending
);
1129 UNSERIALIZE_ENUM(devState
);
1130 UNSERIALIZE_ENUM(dmaState
);
1131 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1135 IdeDiskParams::create()
1137 return new IdeDisk(this);