2 * Copyright (c) 2013 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 * Authors: Andrew Schultz
45 * Device model implementation for an IDE disk
53 #include "arch/isa_traits.hh"
54 #include "base/chunk_generator.hh"
55 #include "base/cprintf.hh" // csprintf
56 #include "base/trace.hh"
57 #include "config/the_isa.hh"
58 #include "debug/IdeDisk.hh"
59 #include "dev/disk_image.hh"
60 #include "dev/ide_ctrl.hh"
61 #include "dev/ide_disk.hh"
62 #include "sim/core.hh"
63 #include "sim/sim_object.hh"
66 using namespace TheISA
;
68 IdeDisk::IdeDisk(const Params
*p
)
69 : SimObject(p
), ctrl(NULL
), image(p
->image
), diskDelay(p
->delay
),
70 dmaTransferEvent(this), dmaReadCG(NULL
), dmaReadWaitEvent(this),
71 dmaWriteCG(NULL
), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
72 dmaReadEvent(this), dmaWriteEvent(this)
74 // Reset the device state
77 // fill out the drive ID structure
78 memset(&driveID
, 0, sizeof(struct ataparams
));
80 // Calculate LBA and C/H/S values
85 uint32_t lba_size
= image
->size();
86 if (lba_size
>= 16383*16*63) {
96 if ((lba_size
/ sectors
) >= 16)
99 heads
= (lba_size
/ sectors
);
101 cylinders
= lba_size
/ (heads
* sectors
);
104 // Setup the model name
105 strncpy((char *)driveID
.atap_model
, "5MI EDD si k",
106 sizeof(driveID
.atap_model
));
107 // Set the maximum multisector transfer size
108 driveID
.atap_multi
= MAX_MULTSECT
;
109 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
110 driveID
.atap_capabilities1
= 0x7;
111 // UDMA support, EIDE support
112 driveID
.atap_extensions
= 0x6;
113 // Setup default C/H/S settings
114 driveID
.atap_cylinders
= cylinders
;
115 driveID
.atap_sectors
= sectors
;
116 driveID
.atap_heads
= heads
;
117 // Setup the current multisector transfer size
118 driveID
.atap_curmulti
= MAX_MULTSECT
;
119 driveID
.atap_curmulti_valid
= 0x1;
120 // Number of sectors on disk
121 driveID
.atap_capacity
= lba_size
;
122 // Multiword DMA mode 2 and below supported
123 driveID
.atap_dmamode_supp
= 0x4;
124 // Set PIO mode 4 and 3 supported
125 driveID
.atap_piomode_supp
= 0x3;
126 // Set DMA mode 4 and below supported
127 driveID
.atap_udmamode_supp
= 0x1f;
128 // Statically set hardware config word
129 driveID
.atap_hwreset_res
= 0x4001;
131 //arbitrary for now...
132 driveID
.atap_ata_major
= WDC_VER_ATA7
;
137 // destroy the data buffer
138 delete [] dataBuffer
;
142 IdeDisk::reset(int id
)
144 // initialize the data buffer and shadow registers
145 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
147 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
148 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
149 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
160 // set the device state to idle
164 devState
= Device_Idle_S
;
166 } else if (id
== DEV1
) {
167 devState
= Device_Idle_NS
;
170 panic("Invalid device ID: %#x\n", id
);
173 // set the device ready bit
174 status
= STATUS_DRDY_BIT
;
176 /* The error register must be set to 0x1 on start-up to
177 indicate that no diagnostic error was detected */
186 IdeDisk::isDEVSelect()
188 return ctrl
->isDiskSelected(this);
192 IdeDisk::pciToDma(Addr pciAddr
)
195 return ctrl
->pciToDma(pciAddr
);
197 panic("Access to unset controller!\n");
201 // Device registers read/write
205 IdeDisk::readCommand(const Addr offset
, int size
, uint8_t *data
)
207 if (offset
== DATA_OFFSET
) {
208 if (size
== sizeof(uint16_t)) {
209 *(uint16_t *)data
= cmdReg
.data
;
210 } else if (size
== sizeof(uint32_t)) {
211 *(uint16_t *)data
= cmdReg
.data
;
212 updateState(ACT_DATA_READ_SHORT
);
213 *((uint16_t *)data
+ 1) = cmdReg
.data
;
215 panic("Data read of unsupported size %d.\n", size
);
217 updateState(ACT_DATA_READ_SHORT
);
220 assert(size
== sizeof(uint8_t));
223 *data
= cmdReg
.error
;
226 *data
= cmdReg
.sec_count
;
229 *data
= cmdReg
.sec_num
;
232 *data
= cmdReg
.cyl_low
;
235 *data
= cmdReg
.cyl_high
;
238 *data
= cmdReg
.drive
;
242 updateState(ACT_STAT_READ
);
245 panic("Invalid IDE command register offset: %#x\n", offset
);
247 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
251 IdeDisk::readControl(const Addr offset
, int size
, uint8_t *data
)
253 assert(size
== sizeof(uint8_t));
255 if (offset
!= ALTSTAT_OFFSET
)
256 panic("Invalid IDE control register offset: %#x\n", offset
);
257 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
261 IdeDisk::writeCommand(const Addr offset
, int size
, const uint8_t *data
)
263 if (offset
== DATA_OFFSET
) {
264 if (size
== sizeof(uint16_t)) {
265 cmdReg
.data
= *(const uint16_t *)data
;
266 } else if (size
== sizeof(uint32_t)) {
267 cmdReg
.data
= *(const uint16_t *)data
;
268 updateState(ACT_DATA_WRITE_SHORT
);
269 cmdReg
.data
= *((const uint16_t *)data
+ 1);
271 panic("Data write of unsupported size %d.\n", size
);
273 updateState(ACT_DATA_WRITE_SHORT
);
277 assert(size
== sizeof(uint8_t));
279 case FEATURES_OFFSET
:
282 cmdReg
.sec_count
= *data
;
285 cmdReg
.sec_num
= *data
;
288 cmdReg
.cyl_low
= *data
;
291 cmdReg
.cyl_high
= *data
;
294 cmdReg
.drive
= *data
;
295 updateState(ACT_SELECT_WRITE
);
298 cmdReg
.command
= *data
;
299 updateState(ACT_CMD_WRITE
);
302 panic("Invalid IDE command register offset: %#x\n", offset
);
304 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
309 IdeDisk::writeControl(const Addr offset
, int size
, const uint8_t *data
)
311 if (offset
!= CONTROL_OFFSET
)
312 panic("Invalid IDE control register offset: %#x\n", offset
);
314 if (*data
& CONTROL_RST_BIT
) {
315 // force the device into the reset state
316 devState
= Device_Srst
;
317 updateState(ACT_SRST_SET
);
318 } else if (devState
== Device_Srst
&& !(*data
& CONTROL_RST_BIT
)) {
319 updateState(ACT_SRST_CLEAR
);
322 nIENBit
= *data
& CONTROL_IEN_BIT
;
324 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
329 // Perform DMA transactions
333 IdeDisk::doDmaTransfer()
336 DPRINTF(IdeDisk
, "DMA Aborted before reading PRD entry\n");
337 updateState(ACT_CMD_ERROR
);
341 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
342 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
345 if (ctrl
->dmaPending() || ctrl
->getDrainState() != Drainable::Running
) {
346 schedule(dmaTransferEvent
, curTick() + DMA_BACKOFF_PERIOD
);
349 ctrl
->dmaRead(curPrdAddr
, sizeof(PrdEntry_t
), &dmaPrdReadEvent
,
350 (uint8_t*)&curPrd
.entry
);
354 IdeDisk::dmaPrdReadDone()
357 DPRINTF(IdeDisk
, "DMA Aborted while reading PRD entry\n");
358 updateState(ACT_CMD_ERROR
);
363 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
364 curPrd
.getBaseAddr(), pciToDma(curPrd
.getBaseAddr()),
365 curPrd
.getByteCount(), (cmdBytesLeft
/SectorSize
),
366 curPrd
.getEOT(), curSector
);
368 // the prd pointer has already been translated, so just do an increment
369 curPrdAddr
= curPrdAddr
+ sizeof(PrdEntry_t
);
378 IdeDisk::doDmaDataRead()
380 /** @todo we need to figure out what the delay actually will be */
381 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
383 DPRINTF(IdeDisk
, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
384 diskDelay
, totalDiskDelay
);
386 schedule(dmaReadWaitEvent
, curTick() + totalDiskDelay
);
392 using namespace Stats
;
394 .name(name() + ".dma_read_full_pages")
395 .desc("Number of full page size DMA reads (not PRD).")
398 .name(name() + ".dma_read_bytes")
399 .desc("Number of bytes transfered via DMA reads (not PRD).")
402 .name(name() + ".dma_read_txs")
403 .desc("Number of DMA read transactions (not PRD).")
407 .name(name() + ".dma_write_full_pages")
408 .desc("Number of full page size DMA writes.")
411 .name(name() + ".dma_write_bytes")
412 .desc("Number of bytes transfered via DMA writes.")
415 .name(name() + ".dma_write_txs")
416 .desc("Number of DMA write transactions.")
424 DPRINTF(IdeDisk
, "DMA Aborted in middle of Dma Read\n");
428 updateState(ACT_CMD_ERROR
);
433 // clear out the data buffer
434 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
435 dmaReadCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
436 curPrd
.getByteCount(), TheISA::PageBytes
);
439 if (ctrl
->dmaPending() || ctrl
->getDrainState() != Drainable::Running
) {
440 schedule(dmaReadWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
442 } else if (!dmaReadCG
->done()) {
443 assert(dmaReadCG
->complete() < MAX_DMA_SIZE
);
444 ctrl
->dmaRead(pciToDma(dmaReadCG
->addr()), dmaReadCG
->size(),
445 &dmaReadWaitEvent
, dataBuffer
+ dmaReadCG
->complete());
446 dmaReadBytes
+= dmaReadCG
->size();
448 if (dmaReadCG
->size() == TheISA::PageBytes
)
452 assert(dmaReadCG
->done());
460 IdeDisk::dmaReadDone()
462 uint32_t bytesWritten
= 0;
464 // write the data to the disk image
465 for (bytesWritten
= 0; bytesWritten
< curPrd
.getByteCount();
466 bytesWritten
+= SectorSize
) {
468 cmdBytesLeft
-= SectorSize
;
469 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
473 if (curPrd
.getEOT()) {
474 assert(cmdBytesLeft
== 0);
476 updateState(ACT_DMA_DONE
);
483 IdeDisk::doDmaDataWrite()
485 /** @todo we need to figure out what the delay actually will be */
486 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
487 uint32_t bytesRead
= 0;
489 DPRINTF(IdeDisk
, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
490 diskDelay
, totalDiskDelay
);
492 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
493 assert(cmdBytesLeft
<= MAX_DMA_SIZE
);
494 while (bytesRead
< curPrd
.getByteCount()) {
495 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
496 bytesRead
+= SectorSize
;
497 cmdBytesLeft
-= SectorSize
;
499 DPRINTF(IdeDisk
, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
500 bytesRead
, cmdBytesLeft
);
502 schedule(dmaWriteWaitEvent
, curTick() + totalDiskDelay
);
506 IdeDisk::doDmaWrite()
509 DPRINTF(IdeDisk
, "DMA Aborted while doing DMA Write\n");
513 updateState(ACT_CMD_ERROR
);
517 // clear out the data buffer
518 dmaWriteCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
519 curPrd
.getByteCount(), TheISA::PageBytes
);
521 if (ctrl
->dmaPending() || ctrl
->getDrainState() != Drainable::Running
) {
522 schedule(dmaWriteWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
523 DPRINTF(IdeDisk
, "doDmaWrite: rescheduling\n");
525 } else if (!dmaWriteCG
->done()) {
526 assert(dmaWriteCG
->complete() < MAX_DMA_SIZE
);
527 ctrl
->dmaWrite(pciToDma(dmaWriteCG
->addr()), dmaWriteCG
->size(),
528 &dmaWriteWaitEvent
, dataBuffer
+ dmaWriteCG
->complete());
529 DPRINTF(IdeDisk
, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
530 curPrd
.getByteCount(), curPrd
.getEOT());
531 dmaWriteBytes
+= dmaWriteCG
->size();
533 if (dmaWriteCG
->size() == TheISA::PageBytes
)
537 DPRINTF(IdeDisk
, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
538 curPrd
.getByteCount(), curPrd
.getEOT());
539 assert(dmaWriteCG
->done());
547 IdeDisk::dmaWriteDone()
549 DPRINTF(IdeDisk
, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
550 curPrd
.getByteCount(), curPrd
.getEOT(), cmdBytesLeft
);
552 if (curPrd
.getEOT()) {
553 assert(cmdBytesLeft
== 0);
555 updateState(ACT_DMA_DONE
);
562 // Disk utility routines
566 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
568 uint32_t bytesRead
= image
->read(data
, sector
);
570 if (bytesRead
!= SectorSize
)
571 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
572 name(), bytesRead
, SectorSize
, errno
);
576 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
578 uint32_t bytesWritten
= image
->write(data
, sector
);
580 if (bytesWritten
!= SectorSize
)
581 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
582 name(), bytesWritten
, SectorSize
, errno
);
586 // Setup and handle commands
590 IdeDisk::startDma(const uint32_t &prdTableBase
)
592 if (dmaState
!= Dma_Start
)
593 panic("Inconsistent DMA state, should be in Dma_Start!\n");
595 if (devState
!= Transfer_Data_Dma
)
596 panic("Inconsistent device state for DMA start!\n");
598 // PRD base address is given by bits 31:2
599 curPrdAddr
= pciToDma((Addr
)(prdTableBase
& ~ULL(0x3)));
601 dmaState
= Dma_Transfer
;
603 // schedule dma transfer (doDmaTransfer)
604 schedule(dmaTransferEvent
, curTick() + 1);
610 if (dmaState
== Dma_Idle
)
611 panic("Inconsistent DMA state, should be Start or Transfer!");
613 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
614 panic("Inconsistent device state, should be Transfer or Prepare!\n");
616 updateState(ACT_CMD_ERROR
);
620 IdeDisk::startCommand()
622 DevAction_t action
= ACT_NONE
;
627 switch (cmdReg
.command
) {
628 // Supported non-data commands
629 case WDSF_READ_NATIVE_MAX
:
630 size
= (uint32_t)image
->size() - 1;
631 cmdReg
.sec_num
= (size
& 0xff);
632 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
633 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
634 cmdReg
.head
= ((size
& 0xf000000) >> 24);
636 devState
= Command_Execution
;
637 action
= ACT_CMD_COMPLETE
;
642 case WDCC_STANDBY_IMMED
:
643 case WDCC_FLUSHCACHE
:
649 devState
= Command_Execution
;
650 action
= ACT_CMD_COMPLETE
;
653 // Supported PIO data-in commands
655 cmdBytes
= cmdBytesLeft
= sizeof(struct ataparams
);
656 devState
= Prepare_Data_In
;
657 action
= ACT_DATA_READY
;
662 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
663 panic("Attempt to perform CHS access, only supports LBA\n");
665 if (cmdReg
.sec_count
== 0)
666 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
668 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
670 curSector
= getLBABase();
672 /** @todo make this a scheduled event to simulate disk delay */
673 devState
= Prepare_Data_In
;
674 action
= ACT_DATA_READY
;
677 // Supported PIO data-out commands
678 case WDCC_WRITEMULTI
:
680 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
681 panic("Attempt to perform CHS access, only supports LBA\n");
683 if (cmdReg
.sec_count
== 0)
684 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
686 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
687 DPRINTF(IdeDisk
, "Setting cmdBytesLeft to %d\n", cmdBytesLeft
);
688 curSector
= getLBABase();
690 devState
= Prepare_Data_Out
;
691 action
= ACT_DATA_READY
;
694 // Supported DMA commands
696 dmaRead
= true; // a write to the disk is a DMA read from memory
698 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
699 panic("Attempt to perform CHS access, only supports LBA\n");
701 if (cmdReg
.sec_count
== 0)
702 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
704 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
705 DPRINTF(IdeDisk
, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft
);
707 curSector
= getLBABase();
709 devState
= Prepare_Data_Dma
;
710 action
= ACT_DMA_READY
;
714 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
717 if (action
!= ACT_NONE
) {
719 status
|= STATUS_BSY_BIT
;
721 status
&= ~STATUS_DRQ_BIT
;
723 status
&= ~STATUS_DF_BIT
;
730 // Handle setting and clearing interrupts
736 DPRINTF(IdeDisk
, "Posting Interrupt\n");
738 panic("Attempt to post an interrupt with one pending\n");
742 // talk to controller to set interrupt
751 DPRINTF(IdeDisk
, "Clearing Interrupt\n");
753 panic("Attempt to clear a non-pending interrupt\n");
757 // talk to controller to clear interrupt
763 // Manage the device internal state machine
767 IdeDisk::updateState(DevAction_t action
)
771 if (action
== ACT_SRST_SET
) {
773 status
|= STATUS_BSY_BIT
;
774 } else if (action
== ACT_SRST_CLEAR
) {
776 status
&= ~STATUS_BSY_BIT
;
778 // reset the device state
784 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
785 devState
= Device_Idle_NS
;
786 } else if (action
== ACT_CMD_WRITE
) {
793 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
794 devState
= Device_Idle_NS
;
796 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
797 devState
= Device_Idle_S
;
799 } else if (action
== ACT_CMD_WRITE
) {
807 if (action
== ACT_SELECT_WRITE
&& isDEVSelect()) {
808 if (!isIENSet() && intrPending
) {
809 devState
= Device_Idle_SI
;
812 if (isIENSet() || !intrPending
) {
813 devState
= Device_Idle_S
;
818 case Command_Execution
:
819 if (action
== ACT_CMD_COMPLETE
) {
824 devState
= Device_Idle_SI
;
827 devState
= Device_Idle_S
;
832 case Prepare_Data_In
:
833 if (action
== ACT_CMD_ERROR
) {
838 devState
= Device_Idle_SI
;
841 devState
= Device_Idle_S
;
843 } else if (action
== ACT_DATA_READY
) {
845 status
&= ~STATUS_BSY_BIT
;
847 status
|= STATUS_DRQ_BIT
;
849 // copy the data into the data buffer
850 if (cmdReg
.command
== WDCC_IDENTIFY
) {
851 // Reset the drqBytes for this block
852 drqBytesLeft
= sizeof(struct ataparams
);
854 memcpy((void *)dataBuffer
, (void *)&driveID
,
855 sizeof(struct ataparams
));
857 // Reset the drqBytes for this block
858 drqBytesLeft
= SectorSize
;
860 readDisk(curSector
++, dataBuffer
);
863 // put the first two bytes into the data register
864 memcpy((void *)&cmdReg
.data
, (void *)dataBuffer
,
868 devState
= Data_Ready_INTRQ_In
;
871 devState
= Transfer_Data_In
;
876 case Data_Ready_INTRQ_In
:
877 if (action
== ACT_STAT_READ
) {
878 devState
= Transfer_Data_In
;
883 case Transfer_Data_In
:
884 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
885 if (action
== ACT_DATA_READ_BYTE
) {
886 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
891 // copy next short into data registers
893 memcpy((void *)&cmdReg
.data
,
894 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
898 if (drqBytesLeft
== 0) {
899 if (cmdBytesLeft
== 0) {
902 devState
= Device_Idle_S
;
904 devState
= Prepare_Data_In
;
906 status
|= STATUS_BSY_BIT
;
908 status
&= ~STATUS_DRQ_BIT
;
910 /** @todo change this to a scheduled event to simulate
912 updateState(ACT_DATA_READY
);
918 case Prepare_Data_Out
:
919 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
924 devState
= Device_Idle_SI
;
927 devState
= Device_Idle_S
;
929 } else if (action
== ACT_DATA_READY
&& cmdBytesLeft
!= 0) {
931 status
&= ~STATUS_BSY_BIT
;
933 status
|= STATUS_DRQ_BIT
;
935 // clear the data buffer to get it ready for writes
936 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
938 // reset the drqBytes for this block
939 drqBytesLeft
= SectorSize
;
941 if (cmdBytesLeft
== cmdBytes
|| isIENSet()) {
942 devState
= Transfer_Data_Out
;
944 devState
= Data_Ready_INTRQ_Out
;
950 case Data_Ready_INTRQ_Out
:
951 if (action
== ACT_STAT_READ
) {
952 devState
= Transfer_Data_Out
;
957 case Transfer_Data_Out
:
958 if (action
== ACT_DATA_WRITE_BYTE
||
959 action
== ACT_DATA_WRITE_SHORT
) {
961 if (action
== ACT_DATA_READ_BYTE
) {
962 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
964 // copy the latest short into the data buffer
965 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
966 (void *)&cmdReg
.data
,
973 if (drqBytesLeft
== 0) {
974 // copy the block to the disk
975 writeDisk(curSector
++, dataBuffer
);
978 status
|= STATUS_BSY_BIT
;
980 status
|= STATUS_SEEK_BIT
;
982 status
&= ~STATUS_DRQ_BIT
;
984 devState
= Prepare_Data_Out
;
986 /** @todo change this to a scheduled event to simulate
988 updateState(ACT_DATA_READY
);
993 case Prepare_Data_Dma
:
994 if (action
== ACT_CMD_ERROR
) {
999 devState
= Device_Idle_SI
;
1002 devState
= Device_Idle_S
;
1004 } else if (action
== ACT_DMA_READY
) {
1005 // clear the BSY bit
1006 status
&= ~STATUS_BSY_BIT
;
1008 status
|= STATUS_DRQ_BIT
;
1010 devState
= Transfer_Data_Dma
;
1012 if (dmaState
!= Dma_Idle
)
1013 panic("Inconsistent DMA state, should be Dma_Idle\n");
1015 dmaState
= Dma_Start
;
1016 // wait for the write to the DMA start bit
1020 case Transfer_Data_Dma
:
1021 if (action
== ACT_CMD_ERROR
) {
1023 devState
= Device_Dma_Abort
;
1024 } else if (action
== ACT_DMA_DONE
) {
1025 // clear the BSY bit
1028 status
|= STATUS_SEEK_BIT
;
1029 // clear the controller state for DMA transfer
1030 ctrl
->setDmaComplete(this);
1033 devState
= Device_Idle_SI
;
1036 devState
= Device_Idle_S
;
1041 case Device_Dma_Abort
:
1042 if (action
== ACT_CMD_ERROR
) {
1044 status
|= STATUS_SEEK_BIT
;
1045 ctrl
->setDmaComplete(this);
1047 dmaState
= Dma_Idle
;
1050 devState
= Device_Idle_SI
;
1053 devState
= Device_Idle_S
;
1056 DPRINTF(IdeDisk
, "Disk still busy aborting previous DMA command\n");
1061 panic("Unknown IDE device state: %#x\n", devState
);
1066 IdeDisk::serialize(ostream
&os
)
1068 // Check all outstanding events to see if they are scheduled
1069 // these are all mutually exclusive
1070 Tick reschedule
= 0;
1071 Events_t event
= None
;
1075 if (dmaTransferEvent
.scheduled()) {
1076 reschedule
= dmaTransferEvent
.when();
1080 if (dmaReadWaitEvent
.scheduled()) {
1081 reschedule
= dmaReadWaitEvent
.when();
1085 if (dmaWriteWaitEvent
.scheduled()) {
1086 reschedule
= dmaWriteWaitEvent
.when();
1090 if (dmaPrdReadEvent
.scheduled()) {
1091 reschedule
= dmaPrdReadEvent
.when();
1095 if (dmaReadEvent
.scheduled()) {
1096 reschedule
= dmaReadEvent
.when();
1100 if (dmaWriteEvent
.scheduled()) {
1101 reschedule
= dmaWriteEvent
.when();
1106 assert(eventCount
<= 1);
1108 SERIALIZE_SCALAR(reschedule
);
1109 SERIALIZE_ENUM(event
);
1111 // Serialize device registers
1112 SERIALIZE_SCALAR(cmdReg
.data
);
1113 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1114 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1115 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1116 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1117 SERIALIZE_SCALAR(cmdReg
.drive
);
1118 SERIALIZE_SCALAR(cmdReg
.command
);
1119 SERIALIZE_SCALAR(status
);
1120 SERIALIZE_SCALAR(nIENBit
);
1121 SERIALIZE_SCALAR(devID
);
1123 // Serialize the PRD related information
1124 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1125 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1126 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1127 SERIALIZE_SCALAR(curPrdAddr
);
1129 /** @todo need to serialized chunk generator stuff!! */
1130 // Serialize current transfer related information
1131 SERIALIZE_SCALAR(cmdBytesLeft
);
1132 SERIALIZE_SCALAR(cmdBytes
);
1133 SERIALIZE_SCALAR(drqBytesLeft
);
1134 SERIALIZE_SCALAR(curSector
);
1135 SERIALIZE_SCALAR(dmaRead
);
1136 SERIALIZE_SCALAR(intrPending
);
1137 SERIALIZE_SCALAR(dmaAborted
);
1138 SERIALIZE_ENUM(devState
);
1139 SERIALIZE_ENUM(dmaState
);
1140 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1144 IdeDisk::unserialize(Checkpoint
*cp
, const string
§ion
)
1146 // Reschedule events that were outstanding
1147 // these are all mutually exclusive
1148 Tick reschedule
= 0;
1149 Events_t event
= None
;
1151 UNSERIALIZE_SCALAR(reschedule
);
1152 UNSERIALIZE_ENUM(event
);
1156 case Transfer
: schedule(dmaTransferEvent
, reschedule
); break;
1157 case ReadWait
: schedule(dmaReadWaitEvent
, reschedule
); break;
1158 case WriteWait
: schedule(dmaWriteWaitEvent
, reschedule
); break;
1159 case PrdRead
: schedule(dmaPrdReadEvent
, reschedule
); break;
1160 case DmaRead
: schedule(dmaReadEvent
, reschedule
); break;
1161 case DmaWrite
: schedule(dmaWriteEvent
, reschedule
); break;
1164 // Unserialize device registers
1165 UNSERIALIZE_SCALAR(cmdReg
.data
);
1166 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1167 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1168 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1169 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1170 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1171 UNSERIALIZE_SCALAR(cmdReg
.command
);
1172 UNSERIALIZE_SCALAR(status
);
1173 UNSERIALIZE_SCALAR(nIENBit
);
1174 UNSERIALIZE_SCALAR(devID
);
1176 // Unserialize the PRD related information
1177 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1178 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1179 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1180 UNSERIALIZE_SCALAR(curPrdAddr
);
1182 /** @todo need to serialized chunk generator stuff!! */
1183 // Unserialize current transfer related information
1184 UNSERIALIZE_SCALAR(cmdBytes
);
1185 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1186 UNSERIALIZE_SCALAR(drqBytesLeft
);
1187 UNSERIALIZE_SCALAR(curSector
);
1188 UNSERIALIZE_SCALAR(dmaRead
);
1189 UNSERIALIZE_SCALAR(intrPending
);
1190 UNSERIALIZE_SCALAR(dmaAborted
);
1191 UNSERIALIZE_ENUM(devState
);
1192 UNSERIALIZE_ENUM(dmaState
);
1193 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1197 IdeDiskParams::create()
1199 return new IdeDisk(this);