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]{ doDmaTransfer(); }, name()),
73 dmaReadWaitEvent([this]{ doDmaRead(); }, name()),
75 dmaWriteWaitEvent([this]{ doDmaWrite(); }, name()),
76 dmaPrdReadEvent([this]{ dmaPrdReadDone(); }, name()),
77 dmaReadEvent([this]{ dmaReadDone(); }, name()),
78 dmaWriteEvent([this]{ dmaWriteDone(); }, name())
80 // Reset the device state
83 // fill out the drive ID structure
84 memset(&driveID
, 0, sizeof(struct ataparams
));
86 // Calculate LBA and C/H/S values
91 uint32_t lba_size
= image
->size();
92 if (lba_size
>= 16383*16*63) {
99 else if (lba_size
== 0)
100 panic("Bad IDE image size: 0\n");
104 if ((lba_size
/ sectors
) >= 16)
107 heads
= (lba_size
/ sectors
);
109 cylinders
= lba_size
/ (heads
* sectors
);
112 // Setup the model name
113 strncpy((char *)driveID
.atap_model
, "5MI EDD si k",
114 sizeof(driveID
.atap_model
));
115 // Set the maximum multisector transfer size
116 driveID
.atap_multi
= MAX_MULTSECT
;
117 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
118 driveID
.atap_capabilities1
= 0x7;
119 // UDMA support, EIDE support
120 driveID
.atap_extensions
= 0x6;
121 // Setup default C/H/S settings
122 driveID
.atap_cylinders
= cylinders
;
123 driveID
.atap_sectors
= sectors
;
124 driveID
.atap_heads
= heads
;
125 // Setup the current multisector transfer size
126 driveID
.atap_curmulti
= MAX_MULTSECT
;
127 driveID
.atap_curmulti_valid
= 0x1;
128 // Number of sectors on disk
129 driveID
.atap_capacity
= lba_size
;
130 // Multiword DMA mode 2 and below supported
131 driveID
.atap_dmamode_supp
= 0x4;
132 // Set PIO mode 4 and 3 supported
133 driveID
.atap_piomode_supp
= 0x3;
134 // Set DMA mode 4 and below supported
135 driveID
.atap_udmamode_supp
= 0x1f;
136 // Statically set hardware config word
137 driveID
.atap_hwreset_res
= 0x4001;
139 //arbitrary for now...
140 driveID
.atap_ata_major
= WDC_VER_ATA7
;
145 // destroy the data buffer
146 delete [] dataBuffer
;
150 IdeDisk::reset(int id
)
152 // initialize the data buffer and shadow registers
153 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
155 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
156 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
157 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
168 // set the device state to idle
172 devState
= Device_Idle_S
;
174 } else if (id
== DEV1
) {
175 devState
= Device_Idle_NS
;
178 panic("Invalid device ID: %#x\n", id
);
181 // set the device ready bit
182 status
= STATUS_DRDY_BIT
;
184 /* The error register must be set to 0x1 on start-up to
185 indicate that no diagnostic error was detected */
194 IdeDisk::isDEVSelect()
196 return ctrl
->isDiskSelected(this);
200 IdeDisk::pciToDma(Addr pciAddr
)
203 return ctrl
->pciToDma(pciAddr
);
205 panic("Access to unset controller!\n");
209 // Device registers read/write
213 IdeDisk::readCommand(const Addr offset
, int size
, uint8_t *data
)
215 if (offset
== DATA_OFFSET
) {
216 if (size
== sizeof(uint16_t)) {
217 *(uint16_t *)data
= cmdReg
.data
;
218 } else if (size
== sizeof(uint32_t)) {
219 *(uint16_t *)data
= cmdReg
.data
;
220 updateState(ACT_DATA_READ_SHORT
);
221 *((uint16_t *)data
+ 1) = cmdReg
.data
;
223 panic("Data read of unsupported size %d.\n", size
);
225 updateState(ACT_DATA_READ_SHORT
);
228 assert(size
== sizeof(uint8_t));
231 *data
= cmdReg
.error
;
234 *data
= cmdReg
.sec_count
;
237 *data
= cmdReg
.sec_num
;
240 *data
= cmdReg
.cyl_low
;
243 *data
= cmdReg
.cyl_high
;
246 *data
= cmdReg
.drive
;
250 updateState(ACT_STAT_READ
);
253 panic("Invalid IDE command register offset: %#x\n", offset
);
255 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
259 IdeDisk::readControl(const Addr offset
, int size
, uint8_t *data
)
261 assert(size
== sizeof(uint8_t));
263 if (offset
!= ALTSTAT_OFFSET
)
264 panic("Invalid IDE control register offset: %#x\n", offset
);
265 DPRINTF(IdeDisk
, "Read to disk at offset: %#x data %#x\n", offset
, *data
);
269 IdeDisk::writeCommand(const Addr offset
, int size
, const uint8_t *data
)
271 if (offset
== DATA_OFFSET
) {
272 if (size
== sizeof(uint16_t)) {
273 cmdReg
.data
= *(const uint16_t *)data
;
274 } else if (size
== sizeof(uint32_t)) {
275 cmdReg
.data
= *(const uint16_t *)data
;
276 updateState(ACT_DATA_WRITE_SHORT
);
277 cmdReg
.data
= *((const uint16_t *)data
+ 1);
279 panic("Data write of unsupported size %d.\n", size
);
281 updateState(ACT_DATA_WRITE_SHORT
);
285 assert(size
== sizeof(uint8_t));
287 case FEATURES_OFFSET
:
290 cmdReg
.sec_count
= *data
;
293 cmdReg
.sec_num
= *data
;
296 cmdReg
.cyl_low
= *data
;
299 cmdReg
.cyl_high
= *data
;
302 cmdReg
.drive
= *data
;
303 updateState(ACT_SELECT_WRITE
);
306 cmdReg
.command
= *data
;
307 updateState(ACT_CMD_WRITE
);
310 panic("Invalid IDE command register offset: %#x\n", offset
);
312 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
317 IdeDisk::writeControl(const Addr offset
, int size
, const uint8_t *data
)
319 if (offset
!= CONTROL_OFFSET
)
320 panic("Invalid IDE control register offset: %#x\n", offset
);
322 if (*data
& CONTROL_RST_BIT
) {
323 // force the device into the reset state
324 devState
= Device_Srst
;
325 updateState(ACT_SRST_SET
);
326 } else if (devState
== Device_Srst
&& !(*data
& CONTROL_RST_BIT
)) {
327 updateState(ACT_SRST_CLEAR
);
330 nIENBit
= *data
& CONTROL_IEN_BIT
;
332 DPRINTF(IdeDisk
, "Write to disk at offset: %#x data %#x\n", offset
,
337 // Perform DMA transactions
341 IdeDisk::doDmaTransfer()
344 DPRINTF(IdeDisk
, "DMA Aborted before reading PRD entry\n");
345 updateState(ACT_CMD_ERROR
);
349 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
350 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
353 if (ctrl
->dmaPending() || ctrl
->drainState() != DrainState::Running
) {
354 schedule(dmaTransferEvent
, curTick() + DMA_BACKOFF_PERIOD
);
357 ctrl
->dmaRead(curPrdAddr
, sizeof(PrdEntry_t
), &dmaPrdReadEvent
,
358 (uint8_t*)&curPrd
.entry
);
362 IdeDisk::dmaPrdReadDone()
365 DPRINTF(IdeDisk
, "DMA Aborted while reading PRD entry\n");
366 updateState(ACT_CMD_ERROR
);
371 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
372 curPrd
.getBaseAddr(), pciToDma(curPrd
.getBaseAddr()),
373 curPrd
.getByteCount(), (cmdBytesLeft
/SectorSize
),
374 curPrd
.getEOT(), curSector
);
376 // the prd pointer has already been translated, so just do an increment
377 curPrdAddr
= curPrdAddr
+ sizeof(PrdEntry_t
);
386 IdeDisk::doDmaDataRead()
388 /** @todo we need to figure out what the delay actually will be */
389 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
391 DPRINTF(IdeDisk
, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
392 diskDelay
, totalDiskDelay
);
394 schedule(dmaReadWaitEvent
, curTick() + totalDiskDelay
);
400 SimObject::regStats();
402 using namespace Stats
;
404 .name(name() + ".dma_read_full_pages")
405 .desc("Number of full page size DMA reads (not PRD).")
408 .name(name() + ".dma_read_bytes")
409 .desc("Number of bytes transfered via DMA reads (not PRD).")
412 .name(name() + ".dma_read_txs")
413 .desc("Number of DMA read transactions (not PRD).")
417 .name(name() + ".dma_write_full_pages")
418 .desc("Number of full page size DMA writes.")
421 .name(name() + ".dma_write_bytes")
422 .desc("Number of bytes transfered via DMA writes.")
425 .name(name() + ".dma_write_txs")
426 .desc("Number of DMA write transactions.")
434 DPRINTF(IdeDisk
, "DMA Aborted in middle of Dma Read\n");
438 updateState(ACT_CMD_ERROR
);
443 // clear out the data buffer
444 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
445 dmaReadCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
446 curPrd
.getByteCount(), TheISA::PageBytes
);
449 if (ctrl
->dmaPending() || ctrl
->drainState() != DrainState::Running
) {
450 schedule(dmaReadWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
452 } else if (!dmaReadCG
->done()) {
453 assert(dmaReadCG
->complete() < MAX_DMA_SIZE
);
454 ctrl
->dmaRead(pciToDma(dmaReadCG
->addr()), dmaReadCG
->size(),
455 &dmaReadWaitEvent
, dataBuffer
+ dmaReadCG
->complete());
456 dmaReadBytes
+= dmaReadCG
->size();
458 if (dmaReadCG
->size() == TheISA::PageBytes
)
462 assert(dmaReadCG
->done());
470 IdeDisk::dmaReadDone()
472 uint32_t bytesWritten
= 0;
474 // write the data to the disk image
475 for (bytesWritten
= 0; bytesWritten
< curPrd
.getByteCount();
476 bytesWritten
+= SectorSize
) {
478 cmdBytesLeft
-= SectorSize
;
479 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
483 if (curPrd
.getEOT()) {
484 assert(cmdBytesLeft
== 0);
486 updateState(ACT_DMA_DONE
);
493 IdeDisk::doDmaDataWrite()
495 /** @todo we need to figure out what the delay actually will be */
496 Tick totalDiskDelay
= diskDelay
+ (curPrd
.getByteCount() / SectorSize
);
497 uint32_t bytesRead
= 0;
499 DPRINTF(IdeDisk
, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
500 diskDelay
, totalDiskDelay
);
502 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
503 assert(cmdBytesLeft
<= MAX_DMA_SIZE
);
504 while (bytesRead
< curPrd
.getByteCount()) {
505 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
506 bytesRead
+= SectorSize
;
507 cmdBytesLeft
-= SectorSize
;
509 DPRINTF(IdeDisk
, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
510 bytesRead
, cmdBytesLeft
);
512 schedule(dmaWriteWaitEvent
, curTick() + totalDiskDelay
);
516 IdeDisk::doDmaWrite()
519 DPRINTF(IdeDisk
, "DMA Aborted while doing DMA Write\n");
523 updateState(ACT_CMD_ERROR
);
527 // clear out the data buffer
528 dmaWriteCG
= new ChunkGenerator(curPrd
.getBaseAddr(),
529 curPrd
.getByteCount(), TheISA::PageBytes
);
531 if (ctrl
->dmaPending() || ctrl
->drainState() != DrainState::Running
) {
532 schedule(dmaWriteWaitEvent
, curTick() + DMA_BACKOFF_PERIOD
);
533 DPRINTF(IdeDisk
, "doDmaWrite: rescheduling\n");
535 } else if (!dmaWriteCG
->done()) {
536 assert(dmaWriteCG
->complete() < MAX_DMA_SIZE
);
537 ctrl
->dmaWrite(pciToDma(dmaWriteCG
->addr()), dmaWriteCG
->size(),
538 &dmaWriteWaitEvent
, dataBuffer
+ dmaWriteCG
->complete());
539 DPRINTF(IdeDisk
, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
540 curPrd
.getByteCount(), curPrd
.getEOT());
541 dmaWriteBytes
+= dmaWriteCG
->size();
543 if (dmaWriteCG
->size() == TheISA::PageBytes
)
547 DPRINTF(IdeDisk
, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
548 curPrd
.getByteCount(), curPrd
.getEOT());
549 assert(dmaWriteCG
->done());
557 IdeDisk::dmaWriteDone()
559 DPRINTF(IdeDisk
, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
560 curPrd
.getByteCount(), curPrd
.getEOT(), cmdBytesLeft
);
562 if (curPrd
.getEOT()) {
563 assert(cmdBytesLeft
== 0);
565 updateState(ACT_DMA_DONE
);
572 // Disk utility routines
576 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
578 uint32_t bytesRead
= image
->read(data
, sector
);
580 if (bytesRead
!= SectorSize
)
581 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
582 name(), bytesRead
, SectorSize
, errno
);
586 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
588 uint32_t bytesWritten
= image
->write(data
, sector
);
590 if (bytesWritten
!= SectorSize
)
591 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
592 name(), bytesWritten
, SectorSize
, errno
);
596 // Setup and handle commands
600 IdeDisk::startDma(const uint32_t &prdTableBase
)
602 if (dmaState
!= Dma_Start
)
603 panic("Inconsistent DMA state, should be in Dma_Start!\n");
605 if (devState
!= Transfer_Data_Dma
)
606 panic("Inconsistent device state for DMA start!\n");
608 // PRD base address is given by bits 31:2
609 curPrdAddr
= pciToDma((Addr
)(prdTableBase
& ~ULL(0x3)));
611 dmaState
= Dma_Transfer
;
613 // schedule dma transfer (doDmaTransfer)
614 schedule(dmaTransferEvent
, curTick() + 1);
620 if (dmaState
== Dma_Idle
)
621 panic("Inconsistent DMA state, should be Start or Transfer!");
623 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
624 panic("Inconsistent device state, should be Transfer or Prepare!\n");
626 updateState(ACT_CMD_ERROR
);
630 IdeDisk::startCommand()
632 DevAction_t action
= ACT_NONE
;
637 switch (cmdReg
.command
) {
638 // Supported non-data commands
639 case WDSF_READ_NATIVE_MAX
:
640 size
= (uint32_t)image
->size() - 1;
641 cmdReg
.sec_num
= (size
& 0xff);
642 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
643 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
644 cmdReg
.head
= ((size
& 0xf000000) >> 24);
646 devState
= Command_Execution
;
647 action
= ACT_CMD_COMPLETE
;
652 case WDCC_STANDBY_IMMED
:
653 case WDCC_FLUSHCACHE
:
659 devState
= Command_Execution
;
660 action
= ACT_CMD_COMPLETE
;
663 // Supported PIO data-in commands
665 case ATAPI_IDENTIFY_DEVICE
:
666 cmdBytes
= cmdBytesLeft
= sizeof(struct ataparams
);
667 devState
= Prepare_Data_In
;
668 action
= ACT_DATA_READY
;
673 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
674 panic("Attempt to perform CHS access, only supports LBA\n");
676 if (cmdReg
.sec_count
== 0)
677 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
679 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
681 curSector
= getLBABase();
683 /** @todo make this a scheduled event to simulate disk delay */
684 devState
= Prepare_Data_In
;
685 action
= ACT_DATA_READY
;
688 // Supported PIO data-out commands
689 case WDCC_WRITEMULTI
:
691 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
692 panic("Attempt to perform CHS access, only supports LBA\n");
694 if (cmdReg
.sec_count
== 0)
695 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
697 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
698 DPRINTF(IdeDisk
, "Setting cmdBytesLeft to %d\n", cmdBytesLeft
);
699 curSector
= getLBABase();
701 devState
= Prepare_Data_Out
;
702 action
= ACT_DATA_READY
;
705 // Supported DMA commands
707 dmaRead
= true; // a write to the disk is a DMA read from memory
710 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
711 panic("Attempt to perform CHS access, only supports LBA\n");
713 if (cmdReg
.sec_count
== 0)
714 cmdBytes
= cmdBytesLeft
= (256 * SectorSize
);
716 cmdBytes
= cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
717 DPRINTF(IdeDisk
, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft
);
719 curSector
= getLBABase();
721 devState
= Prepare_Data_Dma
;
722 action
= ACT_DMA_READY
;
726 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
729 if (action
!= ACT_NONE
) {
731 status
|= STATUS_BSY_BIT
;
733 status
&= ~STATUS_DRQ_BIT
;
735 status
&= ~STATUS_DF_BIT
;
742 // Handle setting and clearing interrupts
748 DPRINTF(IdeDisk
, "Posting Interrupt\n");
750 panic("Attempt to post an interrupt with one pending\n");
754 // talk to controller to set interrupt
763 DPRINTF(IdeDisk
, "Clearing Interrupt\n");
765 panic("Attempt to clear a non-pending interrupt\n");
769 // talk to controller to clear interrupt
775 // Manage the device internal state machine
779 IdeDisk::updateState(DevAction_t action
)
783 if (action
== ACT_SRST_SET
) {
785 status
|= STATUS_BSY_BIT
;
786 } else if (action
== ACT_SRST_CLEAR
) {
788 status
&= ~STATUS_BSY_BIT
;
790 // reset the device state
796 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
797 devState
= Device_Idle_NS
;
798 } else if (action
== ACT_CMD_WRITE
) {
805 if (action
== ACT_SELECT_WRITE
&& !isDEVSelect()) {
806 devState
= Device_Idle_NS
;
808 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
809 devState
= Device_Idle_S
;
811 } else if (action
== ACT_CMD_WRITE
) {
819 if (action
== ACT_SELECT_WRITE
&& isDEVSelect()) {
820 if (!isIENSet() && intrPending
) {
821 devState
= Device_Idle_SI
;
824 if (isIENSet() || !intrPending
) {
825 devState
= Device_Idle_S
;
830 case Command_Execution
:
831 if (action
== ACT_CMD_COMPLETE
) {
836 devState
= Device_Idle_SI
;
839 devState
= Device_Idle_S
;
844 case Prepare_Data_In
:
845 if (action
== ACT_CMD_ERROR
) {
850 devState
= Device_Idle_SI
;
853 devState
= Device_Idle_S
;
855 } else if (action
== ACT_DATA_READY
) {
857 status
&= ~STATUS_BSY_BIT
;
859 status
|= STATUS_DRQ_BIT
;
861 // copy the data into the data buffer
862 if (cmdReg
.command
== WDCC_IDENTIFY
||
863 cmdReg
.command
== ATAPI_IDENTIFY_DEVICE
) {
864 // Reset the drqBytes for this block
865 drqBytesLeft
= sizeof(struct ataparams
);
867 memcpy((void *)dataBuffer
, (void *)&driveID
,
868 sizeof(struct ataparams
));
870 // Reset the drqBytes for this block
871 drqBytesLeft
= SectorSize
;
873 readDisk(curSector
++, dataBuffer
);
876 // put the first two bytes into the data register
877 memcpy((void *)&cmdReg
.data
, (void *)dataBuffer
,
881 devState
= Data_Ready_INTRQ_In
;
884 devState
= Transfer_Data_In
;
889 case Data_Ready_INTRQ_In
:
890 if (action
== ACT_STAT_READ
) {
891 devState
= Transfer_Data_In
;
896 case Transfer_Data_In
:
897 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
898 if (action
== ACT_DATA_READ_BYTE
) {
899 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
904 // copy next short into data registers
906 memcpy((void *)&cmdReg
.data
,
907 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
911 if (drqBytesLeft
== 0) {
912 if (cmdBytesLeft
== 0) {
915 devState
= Device_Idle_S
;
917 devState
= Prepare_Data_In
;
919 status
|= STATUS_BSY_BIT
;
921 status
&= ~STATUS_DRQ_BIT
;
923 /** @todo change this to a scheduled event to simulate
925 updateState(ACT_DATA_READY
);
931 case Prepare_Data_Out
:
932 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
937 devState
= Device_Idle_SI
;
940 devState
= Device_Idle_S
;
942 } else if (action
== ACT_DATA_READY
&& cmdBytesLeft
!= 0) {
944 status
&= ~STATUS_BSY_BIT
;
946 status
|= STATUS_DRQ_BIT
;
948 // clear the data buffer to get it ready for writes
949 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
951 // reset the drqBytes for this block
952 drqBytesLeft
= SectorSize
;
954 if (cmdBytesLeft
== cmdBytes
|| isIENSet()) {
955 devState
= Transfer_Data_Out
;
957 devState
= Data_Ready_INTRQ_Out
;
963 case Data_Ready_INTRQ_Out
:
964 if (action
== ACT_STAT_READ
) {
965 devState
= Transfer_Data_Out
;
970 case Transfer_Data_Out
:
971 if (action
== ACT_DATA_WRITE_BYTE
||
972 action
== ACT_DATA_WRITE_SHORT
) {
974 if (action
== ACT_DATA_READ_BYTE
) {
975 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
977 // copy the latest short into the data buffer
978 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
979 (void *)&cmdReg
.data
,
986 if (drqBytesLeft
== 0) {
987 // copy the block to the disk
988 writeDisk(curSector
++, dataBuffer
);
991 status
|= STATUS_BSY_BIT
;
993 status
|= STATUS_SEEK_BIT
;
995 status
&= ~STATUS_DRQ_BIT
;
997 devState
= Prepare_Data_Out
;
999 /** @todo change this to a scheduled event to simulate
1001 updateState(ACT_DATA_READY
);
1006 case Prepare_Data_Dma
:
1007 if (action
== ACT_CMD_ERROR
) {
1008 // clear the BSY bit
1012 devState
= Device_Idle_SI
;
1015 devState
= Device_Idle_S
;
1017 } else if (action
== ACT_DMA_READY
) {
1018 // clear the BSY bit
1019 status
&= ~STATUS_BSY_BIT
;
1021 status
|= STATUS_DRQ_BIT
;
1023 devState
= Transfer_Data_Dma
;
1025 if (dmaState
!= Dma_Idle
)
1026 panic("Inconsistent DMA state, should be Dma_Idle\n");
1028 dmaState
= Dma_Start
;
1029 // wait for the write to the DMA start bit
1033 case Transfer_Data_Dma
:
1034 if (action
== ACT_CMD_ERROR
) {
1036 devState
= Device_Dma_Abort
;
1037 } else if (action
== ACT_DMA_DONE
) {
1038 // clear the BSY bit
1041 status
|= STATUS_SEEK_BIT
;
1042 // clear the controller state for DMA transfer
1043 ctrl
->setDmaComplete(this);
1046 devState
= Device_Idle_SI
;
1049 devState
= Device_Idle_S
;
1054 case Device_Dma_Abort
:
1055 if (action
== ACT_CMD_ERROR
) {
1057 status
|= STATUS_SEEK_BIT
;
1058 ctrl
->setDmaComplete(this);
1060 dmaState
= Dma_Idle
;
1063 devState
= Device_Idle_SI
;
1066 devState
= Device_Idle_S
;
1069 DPRINTF(IdeDisk
, "Disk still busy aborting previous DMA command\n");
1074 panic("Unknown IDE device state: %#x\n", devState
);
1079 IdeDisk::serialize(CheckpointOut
&cp
) const
1081 // Check all outstanding events to see if they are scheduled
1082 // these are all mutually exclusive
1083 Tick reschedule
= 0;
1084 Events_t event
= None
;
1088 if (dmaTransferEvent
.scheduled()) {
1089 reschedule
= dmaTransferEvent
.when();
1093 if (dmaReadWaitEvent
.scheduled()) {
1094 reschedule
= dmaReadWaitEvent
.when();
1098 if (dmaWriteWaitEvent
.scheduled()) {
1099 reschedule
= dmaWriteWaitEvent
.when();
1103 if (dmaPrdReadEvent
.scheduled()) {
1104 reschedule
= dmaPrdReadEvent
.when();
1108 if (dmaReadEvent
.scheduled()) {
1109 reschedule
= dmaReadEvent
.when();
1113 if (dmaWriteEvent
.scheduled()) {
1114 reschedule
= dmaWriteEvent
.when();
1119 assert(eventCount
<= 1);
1121 SERIALIZE_SCALAR(reschedule
);
1122 SERIALIZE_ENUM(event
);
1124 // Serialize device registers
1125 SERIALIZE_SCALAR(cmdReg
.data
);
1126 SERIALIZE_SCALAR(cmdReg
.sec_count
);
1127 SERIALIZE_SCALAR(cmdReg
.sec_num
);
1128 SERIALIZE_SCALAR(cmdReg
.cyl_low
);
1129 SERIALIZE_SCALAR(cmdReg
.cyl_high
);
1130 SERIALIZE_SCALAR(cmdReg
.drive
);
1131 SERIALIZE_SCALAR(cmdReg
.command
);
1132 SERIALIZE_SCALAR(status
);
1133 SERIALIZE_SCALAR(nIENBit
);
1134 SERIALIZE_SCALAR(devID
);
1136 // Serialize the PRD related information
1137 SERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1138 SERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1139 SERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1140 SERIALIZE_SCALAR(curPrdAddr
);
1142 /** @todo need to serialized chunk generator stuff!! */
1143 // Serialize current transfer related information
1144 SERIALIZE_SCALAR(cmdBytesLeft
);
1145 SERIALIZE_SCALAR(cmdBytes
);
1146 SERIALIZE_SCALAR(drqBytesLeft
);
1147 SERIALIZE_SCALAR(curSector
);
1148 SERIALIZE_SCALAR(dmaRead
);
1149 SERIALIZE_SCALAR(intrPending
);
1150 SERIALIZE_SCALAR(dmaAborted
);
1151 SERIALIZE_ENUM(devState
);
1152 SERIALIZE_ENUM(dmaState
);
1153 SERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1157 IdeDisk::unserialize(CheckpointIn
&cp
)
1159 // Reschedule events that were outstanding
1160 // these are all mutually exclusive
1161 Tick reschedule
= 0;
1162 Events_t event
= None
;
1164 UNSERIALIZE_SCALAR(reschedule
);
1165 UNSERIALIZE_ENUM(event
);
1169 case Transfer
: schedule(dmaTransferEvent
, reschedule
); break;
1170 case ReadWait
: schedule(dmaReadWaitEvent
, reschedule
); break;
1171 case WriteWait
: schedule(dmaWriteWaitEvent
, reschedule
); break;
1172 case PrdRead
: schedule(dmaPrdReadEvent
, reschedule
); break;
1173 case DmaRead
: schedule(dmaReadEvent
, reschedule
); break;
1174 case DmaWrite
: schedule(dmaWriteEvent
, reschedule
); break;
1177 // Unserialize device registers
1178 UNSERIALIZE_SCALAR(cmdReg
.data
);
1179 UNSERIALIZE_SCALAR(cmdReg
.sec_count
);
1180 UNSERIALIZE_SCALAR(cmdReg
.sec_num
);
1181 UNSERIALIZE_SCALAR(cmdReg
.cyl_low
);
1182 UNSERIALIZE_SCALAR(cmdReg
.cyl_high
);
1183 UNSERIALIZE_SCALAR(cmdReg
.drive
);
1184 UNSERIALIZE_SCALAR(cmdReg
.command
);
1185 UNSERIALIZE_SCALAR(status
);
1186 UNSERIALIZE_SCALAR(nIENBit
);
1187 UNSERIALIZE_SCALAR(devID
);
1189 // Unserialize the PRD related information
1190 UNSERIALIZE_SCALAR(curPrd
.entry
.baseAddr
);
1191 UNSERIALIZE_SCALAR(curPrd
.entry
.byteCount
);
1192 UNSERIALIZE_SCALAR(curPrd
.entry
.endOfTable
);
1193 UNSERIALIZE_SCALAR(curPrdAddr
);
1195 /** @todo need to serialized chunk generator stuff!! */
1196 // Unserialize current transfer related information
1197 UNSERIALIZE_SCALAR(cmdBytes
);
1198 UNSERIALIZE_SCALAR(cmdBytesLeft
);
1199 UNSERIALIZE_SCALAR(drqBytesLeft
);
1200 UNSERIALIZE_SCALAR(curSector
);
1201 UNSERIALIZE_SCALAR(dmaRead
);
1202 UNSERIALIZE_SCALAR(intrPending
);
1203 UNSERIALIZE_SCALAR(dmaAborted
);
1204 UNSERIALIZE_ENUM(devState
);
1205 UNSERIALIZE_ENUM(dmaState
);
1206 UNSERIALIZE_ARRAY(dataBuffer
, MAX_DMA_SIZE
);
1210 IdeDiskParams::create()
1212 return new IdeDisk(this);