2 * Copyright (c) 2003 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.
30 * Device model implementation for an IDE disk
38 #include "base/cprintf.hh" // csprintf
39 #include "base/trace.hh"
40 #include "dev/disk_image.hh"
41 #include "dev/ide_disk.hh"
42 #include "dev/ide_ctrl.hh"
43 #include "dev/tsunami.hh"
44 #include "dev/tsunami_pchip.hh"
45 #include "mem/functional_mem/physical_memory.hh"
46 #include "mem/bus/bus.hh"
47 #include "mem/bus/dma_interface.hh"
48 #include "mem/bus/pio_interface.hh"
49 #include "mem/bus/pio_interface_impl.hh"
50 #include "sim/builder.hh"
51 #include "sim/sim_object.hh"
52 #include "sim/universe.hh"
56 IdeDisk::IdeDisk(const string
&name
, DiskImage
*img
, PhysicalMemory
*phys
,
58 : SimObject(name
), ctrl(NULL
), image(img
), physmem(phys
), dmaTransferEvent(this),
59 dmaReadWaitEvent(this), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
60 dmaReadEvent(this), dmaWriteEvent(this)
62 diskDelay
= (delay
* ticksPerSecond
/ 1000) / image
->size();
64 // initialize the data buffer and shadow registers
65 dataBuffer
= new uint8_t[MAX_DMA_SIZE
];
67 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
68 memset(&cmdReg
, 0, sizeof(CommandReg_t
));
69 memset(&curPrd
.entry
, 0, sizeof(PrdEntry_t
));
79 // fill out the drive ID structure
80 memset(&driveID
, 0, sizeof(struct hd_driveid
));
82 // Calculate LBA and C/H/S values
87 uint32_t lba_size
= image
->size();
88 if (lba_size
>= 16383*16*63) {
98 if ((lba_size
/ sectors
) >= 16)
101 heads
= (lba_size
/ sectors
);
103 cylinders
= lba_size
/ (heads
* sectors
);
106 // Setup the model name
107 sprintf((char *)driveID
.model
, "5MI EDD si k");
108 // Set the maximum multisector transfer size
109 driveID
.max_multsect
= MAX_MULTSECT
;
110 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
111 driveID
.capability
= 0x7;
112 // UDMA support, EIDE support
113 driveID
.field_valid
= 0x6;
114 // Setup default C/H/S settings
115 driveID
.cyls
= cylinders
;
116 driveID
.sectors
= sectors
;
117 driveID
.heads
= heads
;
118 // Setup the current multisector transfer size
119 driveID
.multsect
= MAX_MULTSECT
;
120 driveID
.multsect_valid
= 0x1;
121 // Number of sectors on disk
122 driveID
.lba_capacity
= lba_size
;
123 // Multiword DMA mode 2 and below supported
124 driveID
.dma_mword
= 0x400;
125 // Set PIO mode 4 and 3 supported
126 driveID
.eide_pio_modes
= 0x3;
127 // Set DMA mode 4 and below supported
128 driveID
.dma_ultra
= 0x10;
129 // Statically set hardware config word
130 driveID
.hw_config
= 0x4001;
132 // set the device state to idle
136 devState
= Device_Idle_S
;
138 } else if (id
== DEV1
) {
139 devState
= Device_Idle_NS
;
142 panic("Invalid device ID: %#x\n", id
);
145 // set the device ready bit
146 cmdReg
.status
|= STATUS_DRDY_BIT
;
151 // destroy the data buffer
152 delete [] dataBuffer
;
156 // Device registers read/write
160 IdeDisk::read(const Addr
&offset
, bool byte
, bool cmdBlk
, uint8_t *data
)
162 DevAction_t action
= ACT_NONE
;
165 if (offset
< 0 || offset
> sizeof(CommandReg_t
))
166 panic("Invalid disk command register offset: %#x\n", offset
);
168 if (!byte
&& offset
!= DATA_OFFSET
)
169 panic("Invalid 16-bit read, only allowed on data reg\n");
172 *(uint16_t *)data
= *(uint16_t *)&cmdReg
.data0
;
174 *data
= ((uint8_t *)&cmdReg
)[offset
];
176 // determine if an action needs to be taken on the state machine
177 if (offset
== STATUS_OFFSET
) {
178 action
= ACT_STAT_READ
;
179 } else if (offset
== DATA_OFFSET
) {
181 action
= ACT_DATA_READ_BYTE
;
183 action
= ACT_DATA_READ_SHORT
;
187 if (offset
!= ALTSTAT_OFFSET
)
188 panic("Invalid disk control register offset: %#x\n", offset
);
191 panic("Invalid 16-bit read from control block\n");
193 *data
= ((uint8_t *)&cmdReg
)[STATUS_OFFSET
];
196 if (action
!= ACT_NONE
)
201 IdeDisk::write(const Addr
&offset
, bool byte
, bool cmdBlk
, const uint8_t *data
)
203 DevAction_t action
= ACT_NONE
;
206 if (offset
< 0 || offset
> sizeof(CommandReg_t
))
207 panic("Invalid disk command register offset: %#x\n", offset
);
209 if (!byte
&& offset
!= DATA_OFFSET
)
210 panic("Invalid 16-bit write, only allowed on data reg\n");
213 *((uint16_t *)&cmdReg
.data0
) = *(uint16_t *)data
;
215 ((uint8_t *)&cmdReg
)[offset
] = *data
;
217 // determine if an action needs to be taken on the state machine
218 if (offset
== COMMAND_OFFSET
) {
219 action
= ACT_CMD_WRITE
;
220 } else if (offset
== DATA_OFFSET
) {
222 action
= ACT_DATA_WRITE_BYTE
;
224 action
= ACT_DATA_WRITE_SHORT
;
228 if (offset
!= CONTROL_OFFSET
)
229 panic("Invalid disk control register offset: %#x\n", offset
);
232 panic("Invalid 16-bit write to control block\n");
234 if (*data
& CONTROL_RST_BIT
)
235 panic("Software reset not supported!\n");
237 nIENBit
= (*data
& CONTROL_IEN_BIT
) ? true : false;
240 if (action
!= ACT_NONE
)
245 // Perform DMA transactions
249 IdeDisk::doDmaTransfer()
251 if (dmaState
!= Dma_Transfer
|| devState
!= Transfer_Data_Dma
)
252 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
255 // first read the current PRD
257 if (dmaInterface
->busy()) {
258 // reschedule after waiting period
259 dmaTransferEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
263 dmaInterface
->doDMA(Read
, curPrdAddr
, sizeof(PrdEntry_t
), curTick
,
271 IdeDisk::dmaPrdReadDone()
273 // actually copy the PRD from physical memory
274 memcpy((void *)&curPrd
.entry
,
275 physmem
->dma_addr(curPrdAddr
, sizeof(PrdEntry_t
)),
278 curPrdAddr
+= sizeof(PrdEntry_t
);
289 Tick totalDiskDelay
= diskDelay
* (curPrd
.getByteCount() / SectorSize
);
292 if (dmaInterface
->busy()) {
293 // reschedule after waiting period
294 dmaReadWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
299 ctrl
->tsunami
->pchip
->translatePciToDma(curPrd
.getBaseAddr());
300 dmaInterface
->doDMA(Read
, dmaAddr
, curPrd
.getByteCount(),
301 curTick
+ totalDiskDelay
, &dmaReadEvent
);
303 // schedule dmaReadEvent with sectorDelay (dmaReadDone)
304 dmaReadEvent
.schedule(curTick
+ totalDiskDelay
);
309 IdeDisk::dmaReadDone()
311 // actually copy the data from memory to data buffer
313 ctrl
->tsunami
->pchip
->translatePciToDma(curPrd
.getBaseAddr());
314 memcpy((void *)dataBuffer
,
315 physmem
->dma_addr(dmaAddr
, curPrd
.getByteCount()),
316 curPrd
.getByteCount());
318 uint32_t bytesWritten
= 0;
320 while (bytesWritten
< curPrd
.getByteCount()) {
321 if (cmdBytesLeft
<= 0)
322 panic("DMA data is larger than # sectors specified\n");
324 writeDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesWritten
));
326 bytesWritten
+= SectorSize
;
327 cmdBytesLeft
-= SectorSize
;
331 if (curPrd
.getEOT()){
332 assert(cmdBytesLeft
== 0);
334 updateState(ACT_DMA_DONE
);
341 IdeDisk::doDmaWrite()
343 Tick totalDiskDelay
= diskDelay
* (curPrd
.getByteCount() / SectorSize
);
346 if (dmaInterface
->busy()) {
347 // reschedule after waiting period
348 dmaWriteWaitEvent
.schedule(curTick
+ DMA_BACKOFF_PERIOD
);
353 ctrl
->tsunami
->pchip
->translatePciToDma(curPrd
.getBaseAddr());
354 dmaInterface
->doDMA(WriteInvalidate
, dmaAddr
,
355 curPrd
.getByteCount(), curTick
+ totalDiskDelay
,
358 // schedule event with disk delay (dmaWriteDone)
359 dmaWriteEvent
.schedule(curTick
+ totalDiskDelay
);
364 IdeDisk::dmaWriteDone()
366 uint32_t bytesRead
= 0;
368 // clear out the data buffer
369 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
371 while (bytesRead
< curPrd
.getByteCount()) {
372 if (cmdBytesLeft
<= 0)
373 panic("DMA requested data is larger than # sectors specified\n");
375 readDisk(curSector
++, (uint8_t *)(dataBuffer
+ bytesRead
));
377 bytesRead
+= SectorSize
;
378 cmdBytesLeft
-= SectorSize
;
381 // copy the data to memory
383 ctrl
->tsunami
->pchip
->translatePciToDma(curPrd
.getBaseAddr());
384 memcpy(physmem
->dma_addr(dmaAddr
, curPrd
.getByteCount()),
385 (void *)dataBuffer
, curPrd
.getByteCount());
388 if (curPrd
.getEOT()) {
389 assert(cmdBytesLeft
== 0);
391 updateState(ACT_DMA_DONE
);
398 // Disk utility routines
402 IdeDisk::readDisk(uint32_t sector
, uint8_t *data
)
404 uint32_t bytesRead
= image
->read(data
, sector
);
406 if (bytesRead
!= SectorSize
)
407 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
408 name(), bytesRead
, SectorSize
, errno
);
412 IdeDisk::writeDisk(uint32_t sector
, uint8_t *data
)
414 uint32_t bytesWritten
= image
->write(data
, sector
);
416 if (bytesWritten
!= SectorSize
)
417 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
418 name(), bytesWritten
, SectorSize
, errno
);
422 // Setup and handle commands
426 IdeDisk::startDma(const uint32_t &prdTableBase
)
428 if (dmaState
!= Dma_Start
)
429 panic("Inconsistent DMA state, should be in Dma_Start!\n");
431 if (devState
!= Transfer_Data_Dma
)
432 panic("Inconsistent device state for DMA start!\n");
434 curPrdAddr
= ctrl
->tsunami
->pchip
->translatePciToDma(prdTableBase
);
436 dmaState
= Dma_Transfer
;
438 // schedule dma transfer (doDmaTransfer)
439 dmaTransferEvent
.schedule(curTick
+ 1);
445 if (dmaState
== Dma_Idle
)
446 panic("Inconsistent DMA state, should be in Dma_Start or Dma_Transfer!\n");
448 if (devState
!= Transfer_Data_Dma
&& devState
!= Prepare_Data_Dma
)
449 panic("Inconsistent device state, should be in Transfer or Prepare!\n");
451 updateState(ACT_CMD_ERROR
);
455 IdeDisk::startCommand()
457 DevAction_t action
= ACT_NONE
;
461 // copy the command to the shadow
462 curCommand
= cmdReg
.command
;
465 switch (cmdReg
.command
) {
466 // Supported non-data commands
467 case WIN_READ_NATIVE_MAX
:
468 size
= image
->size() - 1;
469 cmdReg
.sec_num
= (size
& 0xff);
470 cmdReg
.cyl_low
= ((size
& 0xff00) >> 8);
471 cmdReg
.cyl_high
= ((size
& 0xff0000) >> 16);
472 cmdReg
.head
= ((size
& 0xf000000) >> 24);
474 devState
= Command_Execution
;
475 action
= ACT_CMD_COMPLETE
;
480 case WIN_FLUSH_CACHE
:
483 case WIN_SETFEATURES
:
485 devState
= Command_Execution
;
486 action
= ACT_CMD_COMPLETE
;
489 // Supported PIO data-in commands
491 cmdBytesLeft
= drqBytesLeft
= sizeof(struct hd_driveid
);
492 devState
= Prepare_Data_In
;
493 action
= ACT_DATA_READY
;
498 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
499 panic("Attempt to perform CHS access, only supports LBA\n");
501 if (cmdReg
.sec_count
== 0)
502 cmdBytesLeft
= (256 * SectorSize
);
504 cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
506 drqBytesLeft
= SectorSize
;
507 curSector
= getLBABase();
509 devState
= Prepare_Data_In
;
510 action
= ACT_DATA_READY
;
513 // Supported PIO data-out commands
516 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
517 panic("Attempt to perform CHS access, only supports LBA\n");
519 if (cmdReg
.sec_count
== 0)
520 cmdBytesLeft
= (256 * SectorSize
);
522 cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
524 drqBytesLeft
= SectorSize
;
525 curSector
= getLBABase();
527 devState
= Prepare_Data_Out
;
528 action
= ACT_DATA_READY
;
531 // Supported DMA commands
533 dmaRead
= true; // a write to the disk is a DMA read from memory
535 if (!(cmdReg
.drive
& DRIVE_LBA_BIT
))
536 panic("Attempt to perform CHS access, only supports LBA\n");
538 if (cmdReg
.sec_count
== 0)
539 cmdBytesLeft
= (256 * SectorSize
);
541 cmdBytesLeft
= (cmdReg
.sec_count
* SectorSize
);
543 drqBytesLeft
= SectorSize
;
544 curSector
= getLBABase();
546 devState
= Prepare_Data_Dma
;
547 action
= ACT_DMA_READY
;
551 panic("Unsupported ATA command: %#x\n", cmdReg
.command
);
554 if (action
!= ACT_NONE
) {
556 cmdReg
.status
|= STATUS_BSY_BIT
;
558 cmdReg
.status
&= ~STATUS_DRQ_BIT
;
565 // Handle setting and clearing interrupts
572 panic("Attempt to post an interrupt with one pending\n");
576 // talk to controller to set interrupt
585 panic("Attempt to clear a non-pending interrupt\n");
589 // talk to controller to clear interrupt
595 // Manage the device internal state machine
599 IdeDisk::updateState(DevAction_t action
)
604 devState
= Device_Idle_NS
;
605 else if (action
== ACT_CMD_WRITE
)
611 if (!isDEVSelect()) {
612 devState
= Device_Idle_NS
;
614 } else if (action
== ACT_STAT_READ
|| isIENSet()) {
615 devState
= Device_Idle_S
;
617 } else if (action
== ACT_CMD_WRITE
) {
626 if (!isIENSet() && intrPending
) {
627 devState
= Device_Idle_SI
;
630 if (isIENSet() || !intrPending
) {
631 devState
= Device_Idle_S
;
636 case Command_Execution
:
637 if (action
== ACT_CMD_COMPLETE
) {
642 devState
= Device_Idle_SI
;
645 devState
= Device_Idle_S
;
650 case Prepare_Data_In
:
651 if (action
== ACT_CMD_ERROR
) {
656 devState
= Device_Idle_SI
;
659 devState
= Device_Idle_S
;
661 } else if (action
== ACT_DATA_READY
) {
663 cmdReg
.status
&= ~STATUS_BSY_BIT
;
665 cmdReg
.status
|= STATUS_DRQ_BIT
;
667 // put the first two bytes into the data register
668 memcpy((void *)&cmdReg
.data0
, (void *)dataBuffer
, sizeof(uint16_t));
669 // copy the data into the data buffer
670 if (curCommand
== WIN_IDENTIFY
)
671 memcpy((void *)dataBuffer
, (void *)&driveID
,
672 sizeof(struct hd_driveid
));
674 readDisk(curSector
++, dataBuffer
);
677 devState
= Data_Ready_INTRQ_In
;
680 devState
= Transfer_Data_In
;
685 case Data_Ready_INTRQ_In
:
686 if (action
== ACT_STAT_READ
) {
687 devState
= Transfer_Data_In
;
692 case Transfer_Data_In
:
693 if (action
== ACT_DATA_READ_BYTE
|| action
== ACT_DATA_READ_SHORT
) {
694 if (action
== ACT_DATA_READ_BYTE
) {
695 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
700 // copy next short into data registers
701 memcpy((void *)&cmdReg
.data0
,
702 (void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
706 if (drqBytesLeft
== 0) {
707 if (cmdBytesLeft
== 0) {
710 devState
= Device_Idle_S
;
712 devState
= Prepare_Data_In
;
713 cmdReg
.status
|= STATUS_BSY_BIT
;
719 case Prepare_Data_Out
:
720 if (action
== ACT_CMD_ERROR
|| cmdBytesLeft
== 0) {
725 devState
= Device_Idle_SI
;
728 devState
= Device_Idle_S
;
730 } else if (cmdBytesLeft
!= 0) {
732 cmdReg
.status
&= ~STATUS_BSY_BIT
;
734 cmdReg
.status
|= STATUS_DRQ_BIT
;
736 // clear the data buffer to get it ready for writes
737 memset(dataBuffer
, 0, MAX_DMA_SIZE
);
740 devState
= Data_Ready_INTRQ_Out
;
743 devState
= Transfer_Data_Out
;
748 case Data_Ready_INTRQ_Out
:
749 if (action
== ACT_STAT_READ
) {
750 devState
= Transfer_Data_Out
;
755 case Transfer_Data_Out
:
756 if (action
== ACT_DATA_WRITE_BYTE
|| action
== ACT_DATA_WRITE_SHORT
) {
757 if (action
== ACT_DATA_READ_BYTE
) {
758 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
760 // copy the latest short into the data buffer
761 memcpy((void *)&dataBuffer
[SectorSize
- drqBytesLeft
],
762 (void *)&cmdReg
.data0
,
769 if (drqBytesLeft
== 0) {
770 // copy the block to the disk
771 writeDisk(curSector
++, dataBuffer
);
774 cmdReg
.status
|= STATUS_BSY_BIT
;
776 cmdReg
.status
&= ~STATUS_DRQ_BIT
;
778 devState
= Prepare_Data_Out
;
783 case Prepare_Data_Dma
:
784 if (action
== ACT_CMD_ERROR
) {
789 devState
= Device_Idle_SI
;
792 devState
= Device_Idle_S
;
794 } else if (action
== ACT_DMA_READY
) {
796 cmdReg
.status
&= ~STATUS_BSY_BIT
;
798 cmdReg
.status
|= STATUS_DRQ_BIT
;
800 devState
= Transfer_Data_Dma
;
802 if (dmaState
!= Dma_Idle
)
803 panic("Inconsistent DMA state, should be Dma_Idle\n");
805 dmaState
= Dma_Start
;
806 // wait for the write to the DMA start bit
810 case Transfer_Data_Dma
:
811 if (action
== ACT_CMD_ERROR
|| action
== ACT_DMA_DONE
) {
815 cmdReg
.status
|= 0x10;
816 // clear the controller state for DMA transfer
817 ctrl
->setDmaComplete(this);
820 devState
= Device_Idle_SI
;
823 devState
= Device_Idle_S
;
829 panic("Unknown IDE device state: %#x\n", devState
);
834 IdeDisk::serialize(ostream
&os
)
839 IdeDisk::unserialize(Checkpoint
*cp
, const string
§ion
)
843 #ifndef DOXYGEN_SHOULD_SKIP_THIS
845 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
847 SimObjectParam
<DiskImage
*> image
;
848 SimObjectParam
<PhysicalMemory
*> physmem
;
850 Param
<int> disk_delay
;
852 END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk
)
854 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
856 INIT_PARAM(image
, "Disk image"),
857 INIT_PARAM(physmem
, "Physical memory"),
858 INIT_PARAM(driveID
, "Drive ID (0=master 1=slave)"),
859 INIT_PARAM_DFLT(disk_delay
, "Fixed disk delay in milliseconds", 0)
861 END_INIT_SIM_OBJECT_PARAMS(IdeDisk
)
864 CREATE_SIM_OBJECT(IdeDisk
)
866 return new IdeDisk(getInstanceName(), image
, physmem
, driveID
, disk_delay
);
869 REGISTER_SIM_OBJECT("IdeDisk", IdeDisk
)
871 #endif //DOXYGEN_SHOULD_SKIP_THIS