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 "dev/disk_image.hh"
46 #include "dev/ide_ctrl.hh"
47 #include "dev/ide_disk.hh"
48 #include "sim/core.hh"
49 #include "sim/sim_object.hh"
52 using namespace TheISA
;
54 IdeDisk::IdeDisk(const Params
*p
)
55 : SimObject(p
), ctrl(NULL
), image(p
->image
), diskDelay(p
->delay
),
56 dmaTransferEvent(this), dmaReadCG(NULL
), dmaReadWaitEvent(this),
57 dmaWriteCG(NULL
), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
58 dmaReadEvent(this), dmaWriteEvent(this)
60 // Reset the device state
63 // fill out the drive ID structure
64 memset(&driveID
, 0, sizeof(struct ataparams
));
66 // Calculate LBA and C/H/S values
71 uint32_t lba_size
= image
->size();
72 if (lba_size
>= 16383*16*63) {
82 if ((lba_size
/ sectors
) >= 16)
85 heads
= (lba_size
/ sectors
);
87 cylinders
= lba_size
/ (heads
* sectors
);
90 // Setup the model name
91 strncpy((char *)driveID
.atap_model
, "5MI EDD si k",
92 sizeof(driveID
.atap_model
));
93 // Set the maximum multisector transfer size
94 driveID
.atap_multi
= MAX_MULTSECT
;
95 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
96 driveID
.atap_capabilities1
= 0x7;
97 // UDMA support, EIDE support
98 driveID
.atap_extensions
= 0x6;
99 // Setup default C/H/S settings
100 driveID
.atap_cylinders
= cylinders
;
101 driveID
.atap_sectors
= sectors
;
102 driveID
.atap_heads
= heads
;
103 // Setup the current multisector transfer size
104 driveID
.atap_curmulti
= MAX_MULTSECT
;
105 driveID
.atap_curmulti_valid
= 0x1;
106 // Number of sectors on disk
107 driveID
.atap_capacity
= lba_size
;
108 // Multiword DMA mode 2 and below supported
109 driveID
.atap_dmamode_supp
= 0x4;
110 // Set PIO mode 4 and 3 supported
111 driveID
.atap_piomode_supp
= 0x3;
112 // Set DMA mode 4 and below supported
113 driveID
.atap_udmamode_supp
= 0x1f;
114 // Statically set hardware config word
115 driveID
.atap_hwreset_res
= 0x4001;
117 //arbitrary for now...
118 driveID
.atap_ata_major
= WDC_VER_ATA7
;
123 // destroy the data buffer
124 delete [] dataBuffer
;
128 IdeDisk::reset(int id
)
130 // initialize the data buffer and shadow registers
131 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
133 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
134 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
135 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
145 // set the device state to idle
149 devState
= Device_Idle_S
;
151 } else if (id
== DEV1
) {
152 devState
= Device_Idle_NS
;
155 panic("Invalid device ID: %#x\n", id
);
158 // set the device ready bit
159 status
= STATUS_DRDY_BIT
;
161 /* The error register must be set to 0x1 on start-up to
162 indicate that no diagnostic error was detected */
171 IdeDisk::isDEVSelect()
173 return ctrl
->isDiskSelected(this);
177 IdeDisk::pciToDma(Addr pciAddr
)
180 return ctrl
->plat
->pciToDma(pciAddr
);
182 panic("Access to unset controller!\n");
186 // Device registers read/write
190 IdeDisk::read(const Addr
&offset
, IdeRegType reg_type
, uint8_t *data
)
192 DevAction_t action
= ACT_NONE
;
197 // Data transfers occur two bytes at a time
199 *(uint16_t*)data
= cmdReg
.data
;
200 action
= ACT_DATA_READ_SHORT
;
203 *data
= cmdReg
.error
;
206 *data
= cmdReg
.sec_count
;
209 *data
= cmdReg
.sec_num
;
212 *data
= cmdReg
.cyl_low
;
215 *data
= cmdReg
.cyl_high
;
218 *data
= cmdReg
.drive
;
222 action
= ACT_STAT_READ
;
225 panic("Invalid IDE command register offset: %#x\n", offset
);
229 if (offset
== ALTSTAT_OFFSET
)
232 panic("Invalid IDE control register offset: %#x\n", offset
);
235 panic("Unknown register block!\n");
237 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
,
240 if (action
!= ACT_NONE
)
245 IdeDisk::write(const Addr
&offset
, IdeRegType reg_type
, const uint8_t *data
)
247 DevAction_t action
= ACT_NONE
;
253 cmdReg
.data
= *(uint16_t*)data
;
254 action
= ACT_DATA_WRITE_SHORT
;
256 case FEATURES_OFFSET
:
259 cmdReg
.sec_count
= *data
;
262 cmdReg
.sec_num
= *data
;
265 cmdReg
.cyl_low
= *data
;
268 cmdReg
.cyl_high
= *data
;
271 cmdReg
.drive
= *data
;
272 action
= ACT_SELECT_WRITE
;
275 cmdReg
.command
= *data
;
276 action
= ACT_CMD_WRITE
;
279 panic("Invalid IDE command register offset: %#x\n", offset
);
283 if (offset
== CONTROL_OFFSET
) {
284 if (*data
& CONTROL_RST_BIT
) {
285 // force the device into the reset state
286 devState
= Device_Srst
;
287 action
= ACT_SRST_SET
;
288 } else if (devState
== Device_Srst
&& !(*data
& CONTROL_RST_BIT
))
289 action
= ACT_SRST_CLEAR
;
291 nIENBit
= (*data
& CONTROL_IEN_BIT
) ? true : false;
294 panic("Invalid IDE control register offset: %#x\n", offset
);
297 panic("Unknown register block!\n");
300 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
302 if (action
!= ACT_NONE
)
307 // Perform DMA transactions
311 IdeDisk::doDmaTransfer()
313 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
314 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
317 if (ctrl
->dmaPending() || ctrl
->getState() != SimObject::Running
) {
318 schedule(dmaTransferEvent
, curTick
+ DMA_BACKOFF_PERIOD
);
321 ctrl
->dmaRead(curPrdAddr
, sizeof(PrdEntry_t
), &dmaPrdReadEvent
,
322 (uint8_t*)&curPrd
.entry
);
326 IdeDisk::dmaPrdReadDone()
329 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
330 curPrd
.getBaseAddr(), pciToDma(curPrd
.getBaseAddr()),
331 curPrd
.getByteCount(), (cmdBytesLeft
/SectorSize
),
332 curPrd
.getEOT(), curSector
);
334 // the prd pointer has already been translated, so just do an increment
335 curPrdAddr
= curPrdAddr
+ sizeof(PrdEntry_t
);
344 IdeDisk::doDmaDataRead()
346 /** @todo we need to figure out what the delay actually will be */
347 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
349 DPRINTF(IdeDisk
, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
350 diskDelay
, totalDiskDelay
);
352 schedule(dmaReadWaitEvent
, curTick
+ totalDiskDelay
);
358 using namespace Stats
;
360 .name(name() + ".dma_read_full_pages")
361 .desc("Number of full page size DMA reads (not PRD).")
364 .name(name() + ".dma_read_bytes")
365 .desc("Number of bytes transfered via DMA reads (not PRD).")
368 .name(name() + ".dma_read_txs")
369 .desc("Number of DMA read transactions (not PRD).")
373 .name(name() + ".dma_write_full_pages")
374 .desc("Number of full page size DMA writes.")
377 .name(name() + ".dma_write_bytes")
378 .desc("Number of bytes transfered via DMA writes.")
381 .name(name() + ".dma_write_txs")
382 .desc("Number of DMA write transactions.")
391 // clear out the data buffer
392 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
393 dmaReadCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
394 curPrd
.getByteCount(), TheISA::PageBytes
);
397 if (ctrl
->dmaPending() || ctrl
->getState() != SimObject::Running
) {
398 schedule(dmaReadWaitEvent
, curTick
+ DMA_BACKOFF_PERIOD
);
400 } else if (!dmaReadCG
->done()) {
401 assert(dmaReadCG
->complete() < MAX_DMA_SIZE
);
402 ctrl
->dmaRead(pciToDma(dmaReadCG
->addr()), dmaReadCG
->size(),
403 &dmaReadWaitEvent
, dataBuffer
+ dmaReadCG
->complete());
404 dmaReadBytes
+= dmaReadCG
->size();
406 if (dmaReadCG
->size() == TheISA::PageBytes
)
410 assert(dmaReadCG
->done());
418 IdeDisk::dmaReadDone()
421 uint32_t bytesWritten
= 0;
424 // write the data to the disk image
425 for (bytesWritten
= 0; bytesWritten
< curPrd
.getByteCount();
426 bytesWritten
+= SectorSize
) {
428 cmdBytesLeft
-= SectorSize
;
429 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
433 if (curPrd
.getEOT()) {
434 assert(cmdBytesLeft
== 0);
436 updateState(ACT_DMA_DONE
);
443 IdeDisk::doDmaDataWrite()
445 /** @todo we need to figure out what the delay actually will be */
446 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
447 uint32_t bytesRead
= 0;
449 DPRINTF(IdeDisk
, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
450 diskDelay
, totalDiskDelay
);
452 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
453 assert(cmdBytesLeft
<= MAX_DMA_SIZE
);
454 while (bytesRead
< curPrd
.getByteCount()) {
455 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
456 bytesRead
+= SectorSize
;
457 cmdBytesLeft
-= SectorSize
;
460 schedule(dmaWriteWaitEvent
, curTick
+ totalDiskDelay
);
464 IdeDisk::doDmaWrite()
468 // clear out the data buffer
469 dmaWriteCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
470 curPrd
.getByteCount(), TheISA::PageBytes
);
472 if (ctrl
->dmaPending() || ctrl
->getState() != SimObject::Running
) {
473 schedule(dmaWriteWaitEvent
, curTick
+ DMA_BACKOFF_PERIOD
);
475 } else if (!dmaWriteCG
->done()) {
476 assert(dmaWriteCG
->complete() < MAX_DMA_SIZE
);
477 ctrl
->dmaWrite(pciToDma(dmaWriteCG
->addr()), dmaWriteCG
->size(),
478 &dmaWriteWaitEvent
, dataBuffer
+ dmaWriteCG
->complete());
479 dmaWriteBytes
+= dmaWriteCG
->size();
481 if (dmaWriteCG
->size() == TheISA::PageBytes
)
485 assert(dmaWriteCG
->done());
493 IdeDisk::dmaWriteDone()
496 if (curPrd
.getEOT()) {
497 assert(cmdBytesLeft
== 0);
499 updateState(ACT_DMA_DONE
);
506 // Disk utility routines
510 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
512 uint32_t bytesRead
= image
->read(data
, sector
);
514 if (bytesRead
!= SectorSize
)
515 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
516 name(), bytesRead
, SectorSize
, errno
);
520 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
522 uint32_t bytesWritten
= image
->write(data
, sector
);
524 if (bytesWritten
!= SectorSize
)
525 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
526 name(), bytesWritten
, SectorSize
, errno
);
530 // Setup and handle commands
534 IdeDisk::startDma(const uint32_t &prdTableBase
)
536 if (dmaState
!= Dma_Start
)
537 panic("Inconsistent DMA state, should be in Dma_Start!\n");
539 if (devState
!= Transfer_Data_Dma
)
540 panic("Inconsistent device state for DMA start!\n");
542 // PRD base address is given by bits 31:2
543 curPrdAddr
= pciToDma((Addr
)(prdTableBase
& ~ULL(0x3)));
545 dmaState
= Dma_Transfer
;
547 // schedule dma transfer (doDmaTransfer)
548 schedule(dmaTransferEvent
, curTick
+ 1);
554 if (dmaState
== Dma_Idle
)
555 panic("Inconsistent DMA state, should be Start or Transfer!");
557 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
558 panic("Inconsistent device state, should be Transfer or Prepare!\n");
560 updateState(ACT_CMD_ERROR
);
564 IdeDisk::startCommand()
566 DevAction_t action
= ACT_NONE
;
571 switch (cmdReg
.command
) {
572 // Supported non-data commands
573 case WDSF_READ_NATIVE_MAX
:
574 size
= image
->size() - 1;
575 cmdReg
.sec_num
= (size
& 0xff);
576 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
577 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
578 cmdReg
.head
= ((size
& 0xf000000) >> 24);
580 devState
= Command_Execution
;
581 action
= ACT_CMD_COMPLETE
;
586 case WDCC_STANDBY_IMMED
:
587 case WDCC_FLUSHCACHE
:
592 devState
= Command_Execution
;
593 action
= ACT_CMD_COMPLETE
;
596 // Supported PIO data-in commands
598 cmdBytes
= cmdBytesLeft
= sizeof(struct ataparams
);
599 devState
= Prepare_Data_In
;
600 action
= ACT_DATA_READY
;
605 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
606 panic("Attempt to perform CHS access, only supports LBA\n");
608 if (cmdReg
.sec_count
== 0)
609 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
611 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
613 curSector
= getLBABase();
615 /** @todo make this a scheduled event to simulate disk delay */
616 devState
= Prepare_Data_In
;
617 action
= ACT_DATA_READY
;
620 // Supported PIO data-out commands
621 case WDCC_WRITEMULTI
:
623 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
624 panic("Attempt to perform CHS access, only supports LBA\n");
626 if (cmdReg
.sec_count
== 0)
627 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
629 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
631 curSector
= getLBABase();
633 devState
= Prepare_Data_Out
;
634 action
= ACT_DATA_READY
;
637 // Supported DMA commands
639 dmaRead
= true; // a write to the disk is a DMA read from memory
641 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
642 panic("Attempt to perform CHS access, only supports LBA\n");
644 if (cmdReg
.sec_count
== 0)
645 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
647 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
649 curSector
= getLBABase();
651 devState
= Prepare_Data_Dma
;
652 action
= ACT_DMA_READY
;
656 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
659 if (action
!= ACT_NONE
) {
661 status
|= STATUS_BSY_BIT
;
663 status
&= ~STATUS_DRQ_BIT
;
665 status
&= ~STATUS_DF_BIT
;
672 // Handle setting and clearing interrupts
678 DPRINTF(IdeDisk
, "Posting Interrupt\n");
680 panic("Attempt to post an interrupt with one pending\n");
684 // talk to controller to set interrupt
686 ctrl
->bmi_regs
.bmis0
|= IDEINTS
;
694 DPRINTF(IdeDisk
, "Clearing Interrupt\n");
696 panic("Attempt to clear a non-pending interrupt\n");
700 // talk to controller to clear interrupt
706 // Manage the device internal state machine
710 IdeDisk::updateState(DevAction_t action
)
714 if (action
== ACT_SRST_SET
) {
716 status
|= STATUS_BSY_BIT
;
717 } else if (action
== ACT_SRST_CLEAR
) {
719 status
&= ~STATUS_BSY_BIT
;
721 // reset the device state
727 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
728 devState
= Device_Idle_NS
;
729 } else if (action
== ACT_CMD_WRITE
) {
736 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
737 devState
= Device_Idle_NS
;
739 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
740 devState
= Device_Idle_S
;
742 } else if (action
== ACT_CMD_WRITE
) {
750 if (action
== ACT_SELECT_WRITE
&& isDEVSelect()) {
751 if (!isIENSet() && intrPending
) {
752 devState
= Device_Idle_SI
;
755 if (isIENSet() || !intrPending
) {
756 devState
= Device_Idle_S
;
761 case Command_Execution
:
762 if (action
== ACT_CMD_COMPLETE
) {
767 devState
= Device_Idle_SI
;
770 devState
= Device_Idle_S
;
775 case Prepare_Data_In
:
776 if (action
== ACT_CMD_ERROR
) {
781 devState
= Device_Idle_SI
;
784 devState
= Device_Idle_S
;
786 } else if (action
== ACT_DATA_READY
) {
788 status
&= ~STATUS_BSY_BIT
;
790 status
|= STATUS_DRQ_BIT
;
792 // copy the data into the data buffer
793 if (cmdReg
.command
== WDCC_IDENTIFY
) {
794 // Reset the drqBytes for this block
795 drqBytesLeft
= sizeof(struct ataparams
);
797 memcpy((void *)dataBuffer
, (void *)&driveID
,
798 sizeof(struct ataparams
));
800 // Reset the drqBytes for this block
801 drqBytesLeft
= SectorSize
;
803 readDisk(curSector
++, dataBuffer
);
806 // put the first two bytes into the data register
807 memcpy((void *)&cmdReg
.data
, (void *)dataBuffer
,
811 devState
= Data_Ready_INTRQ_In
;
814 devState
= Transfer_Data_In
;
819 case Data_Ready_INTRQ_In
:
820 if (action
== ACT_STAT_READ
) {
821 devState
= Transfer_Data_In
;
826 case Transfer_Data_In
:
827 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
828 if (action
== ACT_DATA_READ_BYTE
) {
829 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
834 // copy next short into data registers
836 memcpy((void *)&cmdReg
.data
,
837 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
841 if (drqBytesLeft
== 0) {
842 if (cmdBytesLeft
== 0) {
845 devState
= Device_Idle_S
;
847 devState
= Prepare_Data_In
;
849 status
|= STATUS_BSY_BIT
;
851 status
&= ~STATUS_DRQ_BIT
;
853 /** @todo change this to a scheduled event to simulate
855 updateState(ACT_DATA_READY
);
861 case Prepare_Data_Out
:
862 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
867 devState
= Device_Idle_SI
;
870 devState
= Device_Idle_S
;
872 } else if (action
== ACT_DATA_READY
&& cmdBytesLeft
!= 0) {
874 status
&= ~STATUS_BSY_BIT
;
876 status
|= STATUS_DRQ_BIT
;
878 // clear the data buffer to get it ready for writes
879 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
881 // reset the drqBytes for this block
882 drqBytesLeft
= SectorSize
;
884 if (cmdBytesLeft
== cmdBytes
|| isIENSet()) {
885 devState
= Transfer_Data_Out
;
887 devState
= Data_Ready_INTRQ_Out
;
893 case Data_Ready_INTRQ_Out
:
894 if (action
== ACT_STAT_READ
) {
895 devState
= Transfer_Data_Out
;
900 case Transfer_Data_Out
:
901 if (action
== ACT_DATA_WRITE_BYTE
||
902 action
== ACT_DATA_WRITE_SHORT
) {
904 if (action
== ACT_DATA_READ_BYTE
) {
905 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
907 // copy the latest short into the data buffer
908 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
909 (void *)&cmdReg
.data
,
916 if (drqBytesLeft
== 0) {
917 // copy the block to the disk
918 writeDisk(curSector
++, dataBuffer
);
921 status
|= STATUS_BSY_BIT
;
923 status
|= STATUS_SEEK_BIT
;
925 status
&= ~STATUS_DRQ_BIT
;
927 devState
= Prepare_Data_Out
;
929 /** @todo change this to a scheduled event to simulate
931 updateState(ACT_DATA_READY
);
936 case Prepare_Data_Dma
:
937 if (action
== ACT_CMD_ERROR
) {
942 devState
= Device_Idle_SI
;
945 devState
= Device_Idle_S
;
947 } else if (action
== ACT_DMA_READY
) {
949 status
&= ~STATUS_BSY_BIT
;
951 status
|= STATUS_DRQ_BIT
;
953 devState
= Transfer_Data_Dma
;
955 if (dmaState
!= Dma_Idle
)
956 panic("Inconsistent DMA state, should be Dma_Idle\n");
958 dmaState
= Dma_Start
;
959 // wait for the write to the DMA start bit
963 case Transfer_Data_Dma
:
964 if (action
== ACT_CMD_ERROR
|| action
== ACT_DMA_DONE
) {
968 status
|= STATUS_SEEK_BIT
;
969 // clear the controller state for DMA transfer
970 ctrl
->setDmaComplete(this);
973 devState
= Device_Idle_SI
;
976 devState
= Device_Idle_S
;
982 panic("Unknown IDE device state: %#x\n", devState
);
987 IdeDisk::serialize(ostream
&os
)
989 // Check all outstanding events to see if they are scheduled
990 // these are all mutually exclusive
992 Events_t event
= None
;
996 if (dmaTransferEvent
.scheduled()) {
997 reschedule
= dmaTransferEvent
.when();
1001 if (dmaReadWaitEvent
.scheduled()) {
1002 reschedule
= dmaReadWaitEvent
.when();
1006 if (dmaWriteWaitEvent
.scheduled()) {
1007 reschedule
= dmaWriteWaitEvent
.when();
1011 if (dmaPrdReadEvent
.scheduled()) {
1012 reschedule
= dmaPrdReadEvent
.when();
1016 if (dmaReadEvent
.scheduled()) {
1017 reschedule
= dmaReadEvent
.when();
1021 if (dmaWriteEvent
.scheduled()) {
1022 reschedule
= dmaWriteEvent
.when();
1027 assert(eventCount
<= 1);
1029 SERIALIZE_SCALAR(reschedule
);
1030 SERIALIZE_ENUM(event
);
1032 // Serialize device registers
1033 SERIALIZE_SCALAR(cmdReg
.data
);
1034 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1035 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1036 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1037 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1038 SERIALIZE_SCALAR(cmdReg
.drive
);
1039 SERIALIZE_SCALAR(cmdReg
.command
);
1040 SERIALIZE_SCALAR(status
);
1041 SERIALIZE_SCALAR(nIENBit
);
1042 SERIALIZE_SCALAR(devID
);
1044 // Serialize the PRD related information
1045 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1046 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1047 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1048 SERIALIZE_SCALAR(curPrdAddr
);
1050 /** @todo need to serialized chunk generator stuff!! */
1051 // Serialize current transfer related information
1052 SERIALIZE_SCALAR(cmdBytesLeft
);
1053 SERIALIZE_SCALAR(cmdBytes
);
1054 SERIALIZE_SCALAR(drqBytesLeft
);
1055 SERIALIZE_SCALAR(curSector
);
1056 SERIALIZE_SCALAR(dmaRead
);
1057 SERIALIZE_SCALAR(intrPending
);
1058 SERIALIZE_ENUM(devState
);
1059 SERIALIZE_ENUM(dmaState
);
1060 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1064 IdeDisk::unserialize(Checkpoint
*cp
, const string
§ion
)
1066 // Reschedule events that were outstanding
1067 // these are all mutually exclusive
1068 Tick reschedule
= 0;
1069 Events_t event
= None
;
1071 UNSERIALIZE_SCALAR(reschedule
);
1072 UNSERIALIZE_ENUM(event
);
1076 case Transfer
: schedule(dmaTransferEvent
, reschedule
); break;
1077 case ReadWait
: schedule(dmaReadWaitEvent
, reschedule
); break;
1078 case WriteWait
: schedule(dmaWriteWaitEvent
, reschedule
); break;
1079 case PrdRead
: schedule(dmaPrdReadEvent
, reschedule
); break;
1080 case DmaRead
: schedule(dmaReadEvent
, reschedule
); break;
1081 case DmaWrite
: schedule(dmaWriteEvent
, reschedule
); break;
1084 // Unserialize device registers
1085 UNSERIALIZE_SCALAR(cmdReg
.data
);
1086 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1087 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1088 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1089 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1090 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1091 UNSERIALIZE_SCALAR(cmdReg
.command
);
1092 UNSERIALIZE_SCALAR(status
);
1093 UNSERIALIZE_SCALAR(nIENBit
);
1094 UNSERIALIZE_SCALAR(devID
);
1096 // Unserialize the PRD related information
1097 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1098 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1099 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1100 UNSERIALIZE_SCALAR(curPrdAddr
);
1102 /** @todo need to serialized chunk generator stuff!! */
1103 // Unserialize current transfer related information
1104 UNSERIALIZE_SCALAR(cmdBytes
);
1105 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1106 UNSERIALIZE_SCALAR(drqBytesLeft
);
1107 UNSERIALIZE_SCALAR(curSector
);
1108 UNSERIALIZE_SCALAR(dmaRead
);
1109 UNSERIALIZE_SCALAR(intrPending
);
1110 UNSERIALIZE_ENUM(devState
);
1111 UNSERIALIZE_ENUM(dmaState
);
1112 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1116 IdeDiskParams::create()
1118 return new IdeDisk(this);