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
48 #include "dev/storage/ide_disk.hh"
55 #include "arch/isa_traits.hh"
56 #include "base/chunk_generator.hh"
57 #include "base/cprintf.hh" // csprintf
58 #include "base/trace.hh"
59 #include "config/the_isa.hh"
60 #include "debug/IdeDisk.hh"
61 #include "dev/storage/disk_image.hh"
62 #include "dev/storage/ide_ctrl.hh"
63 #include "sim/core.hh"
64 #include "sim/sim_object.hh"
67 using namespace TheISA
;
69 IdeDisk::IdeDisk(const Params
*p
)
70 : SimObject(p
), ctrl(NULL
), image(p
->image
), diskDelay(p
->delay
),
71 dmaTransferEvent(this), dmaReadCG(NULL
), dmaReadWaitEvent(this),
72 dmaWriteCG(NULL
), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
73 dmaReadEvent(this), dmaWriteEvent(this)
75 // Reset the device state
78 // fill out the drive ID structure
79 memset(&driveID
, 0, sizeof(struct ataparams
));
81 // Calculate LBA and C/H/S values
86 uint32_t lba_size
= image
->size();
87 if (lba_size
>= 16383*16*63) {
94 else if (lba_size
== 0)
95 panic("Bad IDE image size: 0\n");
99 if ((lba_size
/ sectors
) >= 16)
102 heads
= (lba_size
/ sectors
);
104 cylinders
= lba_size
/ (heads
* sectors
);
107 // Setup the model name
108 strncpy((char *)driveID
.atap_model
, "5MI EDD si k",
109 sizeof(driveID
.atap_model
));
110 // Set the maximum multisector transfer size
111 driveID
.atap_multi
= MAX_MULTSECT
;
112 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
113 driveID
.atap_capabilities1
= 0x7;
114 // UDMA support, EIDE support
115 driveID
.atap_extensions
= 0x6;
116 // Setup default C/H/S settings
117 driveID
.atap_cylinders
= cylinders
;
118 driveID
.atap_sectors
= sectors
;
119 driveID
.atap_heads
= heads
;
120 // Setup the current multisector transfer size
121 driveID
.atap_curmulti
= MAX_MULTSECT
;
122 driveID
.atap_curmulti_valid
= 0x1;
123 // Number of sectors on disk
124 driveID
.atap_capacity
= lba_size
;
125 // Multiword DMA mode 2 and below supported
126 driveID
.atap_dmamode_supp
= 0x4;
127 // Set PIO mode 4 and 3 supported
128 driveID
.atap_piomode_supp
= 0x3;
129 // Set DMA mode 4 and below supported
130 driveID
.atap_udmamode_supp
= 0x1f;
131 // Statically set hardware config word
132 driveID
.atap_hwreset_res
= 0x4001;
134 //arbitrary for now...
135 driveID
.atap_ata_major
= WDC_VER_ATA7
;
140 // destroy the data buffer
141 delete [] dataBuffer
;
145 IdeDisk::reset(int id
)
147 // initialize the data buffer and shadow registers
148 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
150 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
151 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
152 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
163 // set the device state to idle
167 devState
= Device_Idle_S
;
169 } else if (id
== DEV1
) {
170 devState
= Device_Idle_NS
;
173 panic("Invalid device ID: %#x\n", id
);
176 // set the device ready bit
177 status
= STATUS_DRDY_BIT
;
179 /* The error register must be set to 0x1 on start-up to
180 indicate that no diagnostic error was detected */
189 IdeDisk::isDEVSelect()
191 return ctrl
->isDiskSelected(this);
195 IdeDisk::pciToDma(Addr pciAddr
)
198 return ctrl
->pciToDma(pciAddr
);
200 panic("Access to unset controller!\n");
204 // Device registers read/write
208 IdeDisk::readCommand(const Addr offset
, int size
, uint8_t *data
)
210 if (offset
== DATA_OFFSET
) {
211 if (size
== sizeof(uint16_t)) {
212 *(uint16_t *)data
= cmdReg
.data
;
213 } else if (size
== sizeof(uint32_t)) {
214 *(uint16_t *)data
= cmdReg
.data
;
215 updateState(ACT_DATA_READ_SHORT
);
216 *((uint16_t *)data
+ 1) = cmdReg
.data
;
218 panic("Data read of unsupported size %d.\n", size
);
220 updateState(ACT_DATA_READ_SHORT
);
223 assert(size
== sizeof(uint8_t));
226 *data
= cmdReg
.error
;
229 *data
= cmdReg
.sec_count
;
232 *data
= cmdReg
.sec_num
;
235 *data
= cmdReg
.cyl_low
;
238 *data
= cmdReg
.cyl_high
;
241 *data
= cmdReg
.drive
;
245 updateState(ACT_STAT_READ
);
248 panic("Invalid IDE command register offset: %#x\n", offset
);
250 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
254 IdeDisk::readControl(const Addr offset
, int size
, uint8_t *data
)
256 assert(size
== sizeof(uint8_t));
258 if (offset
!= ALTSTAT_OFFSET
)
259 panic("Invalid IDE control register offset: %#x\n", offset
);
260 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
264 IdeDisk::writeCommand(const Addr offset
, int size
, const uint8_t *data
)
266 if (offset
== DATA_OFFSET
) {
267 if (size
== sizeof(uint16_t)) {
268 cmdReg
.data
= *(const uint16_t *)data
;
269 } else if (size
== sizeof(uint32_t)) {
270 cmdReg
.data
= *(const uint16_t *)data
;
271 updateState(ACT_DATA_WRITE_SHORT
);
272 cmdReg
.data
= *((const uint16_t *)data
+ 1);
274 panic("Data write of unsupported size %d.\n", size
);
276 updateState(ACT_DATA_WRITE_SHORT
);
280 assert(size
== sizeof(uint8_t));
282 case FEATURES_OFFSET
:
285 cmdReg
.sec_count
= *data
;
288 cmdReg
.sec_num
= *data
;
291 cmdReg
.cyl_low
= *data
;
294 cmdReg
.cyl_high
= *data
;
297 cmdReg
.drive
= *data
;
298 updateState(ACT_SELECT_WRITE
);
301 cmdReg
.command
= *data
;
302 updateState(ACT_CMD_WRITE
);
305 panic("Invalid IDE command register offset: %#x\n", offset
);
307 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
312 IdeDisk::writeControl(const Addr offset
, int size
, const uint8_t *data
)
314 if (offset
!= CONTROL_OFFSET
)
315 panic("Invalid IDE control register offset: %#x\n", offset
);
317 if (*data
& CONTROL_RST_BIT
) {
318 // force the device into the reset state
319 devState
= Device_Srst
;
320 updateState(ACT_SRST_SET
);
321 } else if (devState
== Device_Srst
&& !(*data
& CONTROL_RST_BIT
)) {
322 updateState(ACT_SRST_CLEAR
);
325 nIENBit
= *data
& CONTROL_IEN_BIT
;
327 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
332 // Perform DMA transactions
336 IdeDisk::doDmaTransfer()
339 DPRINTF(IdeDisk
, "DMA Aborted before reading PRD entry\n");
340 updateState(ACT_CMD_ERROR
);
344 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
345 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
348 if (ctrl
->dmaPending() || ctrl
->drainState() != DrainState::Running
) {
349 schedule(dmaTransferEvent
, curTick() + DMA_BACKOFF_PERIOD
);
352 ctrl
->dmaRead(curPrdAddr
, sizeof(PrdEntry_t
), &dmaPrdReadEvent
,
353 (uint8_t*)&curPrd
.entry
);
357 IdeDisk::dmaPrdReadDone()
360 DPRINTF(IdeDisk
, "DMA Aborted while reading PRD entry\n");
361 updateState(ACT_CMD_ERROR
);
366 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
367 curPrd
.getBaseAddr(), pciToDma(curPrd
.getBaseAddr()),
368 curPrd
.getByteCount(), (cmdBytesLeft
/SectorSize
),
369 curPrd
.getEOT(), curSector
);
371 // the prd pointer has already been translated, so just do an increment
372 curPrdAddr
= curPrdAddr
+ sizeof(PrdEntry_t
);
381 IdeDisk::doDmaDataRead()
383 /** @todo we need to figure out what the delay actually will be */
384 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
386 DPRINTF(IdeDisk
, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
387 diskDelay
, totalDiskDelay
);
389 schedule(dmaReadWaitEvent
, curTick() + totalDiskDelay
);
395 SimObject::regStats();
397 using namespace Stats
;
399 .name(name() + ".dma_read_full_pages")
400 .desc("Number of full page size DMA reads (not PRD).")
403 .name(name() + ".dma_read_bytes")
404 .desc("Number of bytes transfered via DMA reads (not PRD).")
407 .name(name() + ".dma_read_txs")
408 .desc("Number of DMA read transactions (not PRD).")
412 .name(name() + ".dma_write_full_pages")
413 .desc("Number of full page size DMA writes.")
416 .name(name() + ".dma_write_bytes")
417 .desc("Number of bytes transfered via DMA writes.")
420 .name(name() + ".dma_write_txs")
421 .desc("Number of DMA write transactions.")
429 DPRINTF(IdeDisk
, "DMA Aborted in middle of Dma Read\n");
433 updateState(ACT_CMD_ERROR
);
438 // clear out the data buffer
439 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
440 dmaReadCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
441 curPrd
.getByteCount(), TheISA::PageBytes
);
444 if (ctrl
->dmaPending() || ctrl
->drainState() != DrainState::Running
) {
445 schedule(dmaReadWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
447 } else if (!dmaReadCG
->done()) {
448 assert(dmaReadCG
->complete() < MAX_DMA_SIZE
);
449 ctrl
->dmaRead(pciToDma(dmaReadCG
->addr()), dmaReadCG
->size(),
450 &dmaReadWaitEvent
, dataBuffer
+ dmaReadCG
->complete());
451 dmaReadBytes
+= dmaReadCG
->size();
453 if (dmaReadCG
->size() == TheISA::PageBytes
)
457 assert(dmaReadCG
->done());
465 IdeDisk::dmaReadDone()
467 uint32_t bytesWritten
= 0;
469 // write the data to the disk image
470 for (bytesWritten
= 0; bytesWritten
< curPrd
.getByteCount();
471 bytesWritten
+= SectorSize
) {
473 cmdBytesLeft
-= SectorSize
;
474 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
478 if (curPrd
.getEOT()) {
479 assert(cmdBytesLeft
== 0);
481 updateState(ACT_DMA_DONE
);
488 IdeDisk::doDmaDataWrite()
490 /** @todo we need to figure out what the delay actually will be */
491 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
492 uint32_t bytesRead
= 0;
494 DPRINTF(IdeDisk
, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
495 diskDelay
, totalDiskDelay
);
497 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
498 assert(cmdBytesLeft
<= MAX_DMA_SIZE
);
499 while (bytesRead
< curPrd
.getByteCount()) {
500 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
501 bytesRead
+= SectorSize
;
502 cmdBytesLeft
-= SectorSize
;
504 DPRINTF(IdeDisk
, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
505 bytesRead
, cmdBytesLeft
);
507 schedule(dmaWriteWaitEvent
, curTick() + totalDiskDelay
);
511 IdeDisk::doDmaWrite()
514 DPRINTF(IdeDisk
, "DMA Aborted while doing DMA Write\n");
518 updateState(ACT_CMD_ERROR
);
522 // clear out the data buffer
523 dmaWriteCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
524 curPrd
.getByteCount(), TheISA::PageBytes
);
526 if (ctrl
->dmaPending() || ctrl
->drainState() != DrainState::Running
) {
527 schedule(dmaWriteWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
528 DPRINTF(IdeDisk
, "doDmaWrite: rescheduling\n");
530 } else if (!dmaWriteCG
->done()) {
531 assert(dmaWriteCG
->complete() < MAX_DMA_SIZE
);
532 ctrl
->dmaWrite(pciToDma(dmaWriteCG
->addr()), dmaWriteCG
->size(),
533 &dmaWriteWaitEvent
, dataBuffer
+ dmaWriteCG
->complete());
534 DPRINTF(IdeDisk
, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
535 curPrd
.getByteCount(), curPrd
.getEOT());
536 dmaWriteBytes
+= dmaWriteCG
->size();
538 if (dmaWriteCG
->size() == TheISA::PageBytes
)
542 DPRINTF(IdeDisk
, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
543 curPrd
.getByteCount(), curPrd
.getEOT());
544 assert(dmaWriteCG
->done());
552 IdeDisk::dmaWriteDone()
554 DPRINTF(IdeDisk
, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
555 curPrd
.getByteCount(), curPrd
.getEOT(), cmdBytesLeft
);
557 if (curPrd
.getEOT()) {
558 assert(cmdBytesLeft
== 0);
560 updateState(ACT_DMA_DONE
);
567 // Disk utility routines
571 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
573 uint32_t bytesRead
= image
->read(data
, sector
);
575 if (bytesRead
!= SectorSize
)
576 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
577 name(), bytesRead
, SectorSize
, errno
);
581 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
583 uint32_t bytesWritten
= image
->write(data
, sector
);
585 if (bytesWritten
!= SectorSize
)
586 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
587 name(), bytesWritten
, SectorSize
, errno
);
591 // Setup and handle commands
595 IdeDisk::startDma(const uint32_t &prdTableBase
)
597 if (dmaState
!= Dma_Start
)
598 panic("Inconsistent DMA state, should be in Dma_Start!\n");
600 if (devState
!= Transfer_Data_Dma
)
601 panic("Inconsistent device state for DMA start!\n");
603 // PRD base address is given by bits 31:2
604 curPrdAddr
= pciToDma((Addr
)(prdTableBase
& ~ULL(0x3)));
606 dmaState
= Dma_Transfer
;
608 // schedule dma transfer (doDmaTransfer)
609 schedule(dmaTransferEvent
, curTick() + 1);
615 if (dmaState
== Dma_Idle
)
616 panic("Inconsistent DMA state, should be Start or Transfer!");
618 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
619 panic("Inconsistent device state, should be Transfer or Prepare!\n");
621 updateState(ACT_CMD_ERROR
);
625 IdeDisk::startCommand()
627 DevAction_t action
= ACT_NONE
;
632 switch (cmdReg
.command
) {
633 // Supported non-data commands
634 case WDSF_READ_NATIVE_MAX
:
635 size
= (uint32_t)image
->size() - 1;
636 cmdReg
.sec_num
= (size
& 0xff);
637 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
638 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
639 cmdReg
.head
= ((size
& 0xf000000) >> 24);
641 devState
= Command_Execution
;
642 action
= ACT_CMD_COMPLETE
;
647 case WDCC_STANDBY_IMMED
:
648 case WDCC_FLUSHCACHE
:
654 devState
= Command_Execution
;
655 action
= ACT_CMD_COMPLETE
;
658 // Supported PIO data-in commands
660 case ATAPI_IDENTIFY_DEVICE
:
661 cmdBytes
= cmdBytesLeft
= sizeof(struct ataparams
);
662 devState
= Prepare_Data_In
;
663 action
= ACT_DATA_READY
;
668 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
669 panic("Attempt to perform CHS access, only supports LBA\n");
671 if (cmdReg
.sec_count
== 0)
672 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
674 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
676 curSector
= getLBABase();
678 /** @todo make this a scheduled event to simulate disk delay */
679 devState
= Prepare_Data_In
;
680 action
= ACT_DATA_READY
;
683 // Supported PIO data-out commands
684 case WDCC_WRITEMULTI
:
686 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
687 panic("Attempt to perform CHS access, only supports LBA\n");
689 if (cmdReg
.sec_count
== 0)
690 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
692 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
693 DPRINTF(IdeDisk
, "Setting cmdBytesLeft to %d\n", cmdBytesLeft
);
694 curSector
= getLBABase();
696 devState
= Prepare_Data_Out
;
697 action
= ACT_DATA_READY
;
700 // Supported DMA commands
702 dmaRead
= true; // a write to the disk is a DMA read from memory
704 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
705 panic("Attempt to perform CHS access, only supports LBA\n");
707 if (cmdReg
.sec_count
== 0)
708 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
710 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
711 DPRINTF(IdeDisk
, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft
);
713 curSector
= getLBABase();
715 devState
= Prepare_Data_Dma
;
716 action
= ACT_DMA_READY
;
720 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
723 if (action
!= ACT_NONE
) {
725 status
|= STATUS_BSY_BIT
;
727 status
&= ~STATUS_DRQ_BIT
;
729 status
&= ~STATUS_DF_BIT
;
736 // Handle setting and clearing interrupts
742 DPRINTF(IdeDisk
, "Posting Interrupt\n");
744 panic("Attempt to post an interrupt with one pending\n");
748 // talk to controller to set interrupt
757 DPRINTF(IdeDisk
, "Clearing Interrupt\n");
759 panic("Attempt to clear a non-pending interrupt\n");
763 // talk to controller to clear interrupt
769 // Manage the device internal state machine
773 IdeDisk::updateState(DevAction_t action
)
777 if (action
== ACT_SRST_SET
) {
779 status
|= STATUS_BSY_BIT
;
780 } else if (action
== ACT_SRST_CLEAR
) {
782 status
&= ~STATUS_BSY_BIT
;
784 // reset the device state
790 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
791 devState
= Device_Idle_NS
;
792 } else if (action
== ACT_CMD_WRITE
) {
799 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
800 devState
= Device_Idle_NS
;
802 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
803 devState
= Device_Idle_S
;
805 } else if (action
== ACT_CMD_WRITE
) {
813 if (action
== ACT_SELECT_WRITE
&& isDEVSelect()) {
814 if (!isIENSet() && intrPending
) {
815 devState
= Device_Idle_SI
;
818 if (isIENSet() || !intrPending
) {
819 devState
= Device_Idle_S
;
824 case Command_Execution
:
825 if (action
== ACT_CMD_COMPLETE
) {
830 devState
= Device_Idle_SI
;
833 devState
= Device_Idle_S
;
838 case Prepare_Data_In
:
839 if (action
== ACT_CMD_ERROR
) {
844 devState
= Device_Idle_SI
;
847 devState
= Device_Idle_S
;
849 } else if (action
== ACT_DATA_READY
) {
851 status
&= ~STATUS_BSY_BIT
;
853 status
|= STATUS_DRQ_BIT
;
855 // copy the data into the data buffer
856 if (cmdReg
.command
== WDCC_IDENTIFY
||
857 cmdReg
.command
== ATAPI_IDENTIFY_DEVICE
) {
858 // Reset the drqBytes for this block
859 drqBytesLeft
= sizeof(struct ataparams
);
861 memcpy((void *)dataBuffer
, (void *)&driveID
,
862 sizeof(struct ataparams
));
864 // Reset the drqBytes for this block
865 drqBytesLeft
= SectorSize
;
867 readDisk(curSector
++, dataBuffer
);
870 // put the first two bytes into the data register
871 memcpy((void *)&cmdReg
.data
, (void *)dataBuffer
,
875 devState
= Data_Ready_INTRQ_In
;
878 devState
= Transfer_Data_In
;
883 case Data_Ready_INTRQ_In
:
884 if (action
== ACT_STAT_READ
) {
885 devState
= Transfer_Data_In
;
890 case Transfer_Data_In
:
891 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
892 if (action
== ACT_DATA_READ_BYTE
) {
893 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
898 // copy next short into data registers
900 memcpy((void *)&cmdReg
.data
,
901 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
905 if (drqBytesLeft
== 0) {
906 if (cmdBytesLeft
== 0) {
909 devState
= Device_Idle_S
;
911 devState
= Prepare_Data_In
;
913 status
|= STATUS_BSY_BIT
;
915 status
&= ~STATUS_DRQ_BIT
;
917 /** @todo change this to a scheduled event to simulate
919 updateState(ACT_DATA_READY
);
925 case Prepare_Data_Out
:
926 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
931 devState
= Device_Idle_SI
;
934 devState
= Device_Idle_S
;
936 } else if (action
== ACT_DATA_READY
&& cmdBytesLeft
!= 0) {
938 status
&= ~STATUS_BSY_BIT
;
940 status
|= STATUS_DRQ_BIT
;
942 // clear the data buffer to get it ready for writes
943 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
945 // reset the drqBytes for this block
946 drqBytesLeft
= SectorSize
;
948 if (cmdBytesLeft
== cmdBytes
|| isIENSet()) {
949 devState
= Transfer_Data_Out
;
951 devState
= Data_Ready_INTRQ_Out
;
957 case Data_Ready_INTRQ_Out
:
958 if (action
== ACT_STAT_READ
) {
959 devState
= Transfer_Data_Out
;
964 case Transfer_Data_Out
:
965 if (action
== ACT_DATA_WRITE_BYTE
||
966 action
== ACT_DATA_WRITE_SHORT
) {
968 if (action
== ACT_DATA_READ_BYTE
) {
969 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
971 // copy the latest short into the data buffer
972 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
973 (void *)&cmdReg
.data
,
980 if (drqBytesLeft
== 0) {
981 // copy the block to the disk
982 writeDisk(curSector
++, dataBuffer
);
985 status
|= STATUS_BSY_BIT
;
987 status
|= STATUS_SEEK_BIT
;
989 status
&= ~STATUS_DRQ_BIT
;
991 devState
= Prepare_Data_Out
;
993 /** @todo change this to a scheduled event to simulate
995 updateState(ACT_DATA_READY
);
1000 case Prepare_Data_Dma
:
1001 if (action
== ACT_CMD_ERROR
) {
1002 // clear the BSY bit
1006 devState
= Device_Idle_SI
;
1009 devState
= Device_Idle_S
;
1011 } else if (action
== ACT_DMA_READY
) {
1012 // clear the BSY bit
1013 status
&= ~STATUS_BSY_BIT
;
1015 status
|= STATUS_DRQ_BIT
;
1017 devState
= Transfer_Data_Dma
;
1019 if (dmaState
!= Dma_Idle
)
1020 panic("Inconsistent DMA state, should be Dma_Idle\n");
1022 dmaState
= Dma_Start
;
1023 // wait for the write to the DMA start bit
1027 case Transfer_Data_Dma
:
1028 if (action
== ACT_CMD_ERROR
) {
1030 devState
= Device_Dma_Abort
;
1031 } else if (action
== ACT_DMA_DONE
) {
1032 // clear the BSY bit
1035 status
|= STATUS_SEEK_BIT
;
1036 // clear the controller state for DMA transfer
1037 ctrl
->setDmaComplete(this);
1040 devState
= Device_Idle_SI
;
1043 devState
= Device_Idle_S
;
1048 case Device_Dma_Abort
:
1049 if (action
== ACT_CMD_ERROR
) {
1051 status
|= STATUS_SEEK_BIT
;
1052 ctrl
->setDmaComplete(this);
1054 dmaState
= Dma_Idle
;
1057 devState
= Device_Idle_SI
;
1060 devState
= Device_Idle_S
;
1063 DPRINTF(IdeDisk
, "Disk still busy aborting previous DMA command\n");
1068 panic("Unknown IDE device state: %#x\n", devState
);
1073 IdeDisk::serialize(CheckpointOut
&cp
) const
1075 // Check all outstanding events to see if they are scheduled
1076 // these are all mutually exclusive
1077 Tick reschedule
= 0;
1078 Events_t event
= None
;
1082 if (dmaTransferEvent
.scheduled()) {
1083 reschedule
= dmaTransferEvent
.when();
1087 if (dmaReadWaitEvent
.scheduled()) {
1088 reschedule
= dmaReadWaitEvent
.when();
1092 if (dmaWriteWaitEvent
.scheduled()) {
1093 reschedule
= dmaWriteWaitEvent
.when();
1097 if (dmaPrdReadEvent
.scheduled()) {
1098 reschedule
= dmaPrdReadEvent
.when();
1102 if (dmaReadEvent
.scheduled()) {
1103 reschedule
= dmaReadEvent
.when();
1107 if (dmaWriteEvent
.scheduled()) {
1108 reschedule
= dmaWriteEvent
.when();
1113 assert(eventCount
<= 1);
1115 SERIALIZE_SCALAR(reschedule
);
1116 SERIALIZE_ENUM(event
);
1118 // Serialize device registers
1119 SERIALIZE_SCALAR(cmdReg
.data
);
1120 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1121 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1122 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1123 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1124 SERIALIZE_SCALAR(cmdReg
.drive
);
1125 SERIALIZE_SCALAR(cmdReg
.command
);
1126 SERIALIZE_SCALAR(status
);
1127 SERIALIZE_SCALAR(nIENBit
);
1128 SERIALIZE_SCALAR(devID
);
1130 // Serialize the PRD related information
1131 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1132 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1133 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1134 SERIALIZE_SCALAR(curPrdAddr
);
1136 /** @todo need to serialized chunk generator stuff!! */
1137 // Serialize current transfer related information
1138 SERIALIZE_SCALAR(cmdBytesLeft
);
1139 SERIALIZE_SCALAR(cmdBytes
);
1140 SERIALIZE_SCALAR(drqBytesLeft
);
1141 SERIALIZE_SCALAR(curSector
);
1142 SERIALIZE_SCALAR(dmaRead
);
1143 SERIALIZE_SCALAR(intrPending
);
1144 SERIALIZE_SCALAR(dmaAborted
);
1145 SERIALIZE_ENUM(devState
);
1146 SERIALIZE_ENUM(dmaState
);
1147 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1151 IdeDisk::unserialize(CheckpointIn
&cp
)
1153 // Reschedule events that were outstanding
1154 // these are all mutually exclusive
1155 Tick reschedule
= 0;
1156 Events_t event
= None
;
1158 UNSERIALIZE_SCALAR(reschedule
);
1159 UNSERIALIZE_ENUM(event
);
1163 case Transfer
: schedule(dmaTransferEvent
, reschedule
); break;
1164 case ReadWait
: schedule(dmaReadWaitEvent
, reschedule
); break;
1165 case WriteWait
: schedule(dmaWriteWaitEvent
, reschedule
); break;
1166 case PrdRead
: schedule(dmaPrdReadEvent
, reschedule
); break;
1167 case DmaRead
: schedule(dmaReadEvent
, reschedule
); break;
1168 case DmaWrite
: schedule(dmaWriteEvent
, reschedule
); break;
1171 // Unserialize device registers
1172 UNSERIALIZE_SCALAR(cmdReg
.data
);
1173 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1174 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1175 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1176 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1177 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1178 UNSERIALIZE_SCALAR(cmdReg
.command
);
1179 UNSERIALIZE_SCALAR(status
);
1180 UNSERIALIZE_SCALAR(nIENBit
);
1181 UNSERIALIZE_SCALAR(devID
);
1183 // Unserialize the PRD related information
1184 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1185 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1186 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1187 UNSERIALIZE_SCALAR(curPrdAddr
);
1189 /** @todo need to serialized chunk generator stuff!! */
1190 // Unserialize current transfer related information
1191 UNSERIALIZE_SCALAR(cmdBytes
);
1192 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1193 UNSERIALIZE_SCALAR(drqBytesLeft
);
1194 UNSERIALIZE_SCALAR(curSector
);
1195 UNSERIALIZE_SCALAR(dmaRead
);
1196 UNSERIALIZE_SCALAR(intrPending
);
1197 UNSERIALIZE_SCALAR(dmaAborted
);
1198 UNSERIALIZE_ENUM(devState
);
1199 UNSERIALIZE_ENUM(dmaState
);
1200 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1204 IdeDiskParams::create()
1206 return new IdeDisk(this);