First steps toward getting full system to work with
[gem5.git] / dev / ide_disk.cc
1 /*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
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.
15 *
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.
27 */
28
29 /** @file
30 * Device model implementation for an IDE disk
31 */
32
33 #include <cerrno>
34 #include <cstring>
35 #include <deque>
36 #include <string>
37
38 #include "base/chunk_generator.hh"
39 #include "base/cprintf.hh" // csprintf
40 #include "base/trace.hh"
41 #include "dev/disk_image.hh"
42 #include "dev/ide_disk.hh"
43 #include "dev/ide_ctrl.hh"
44 #include "dev/tsunami.hh"
45 #include "dev/tsunami_pchip.hh"
46 #include "sim/builder.hh"
47 #include "sim/sim_object.hh"
48 #include "sim/root.hh"
49 #include "arch/isa_traits.hh"
50
51 using namespace std;
52 using namespace TheISA;
53
54 IdeDisk::IdeDisk(const string &name, DiskImage *img,
55 int id, Tick delay)
56 : SimObject(name), ctrl(NULL), image(img), diskDelay(delay),
57 dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
58 dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
59 dmaReadEvent(this), dmaWriteEvent(this)
60 {
61 // Reset the device state
62 reset(id);
63
64 // fill out the drive ID structure
65 memset(&driveID, 0, sizeof(struct ataparams));
66
67 // Calculate LBA and C/H/S values
68 uint16_t cylinders;
69 uint8_t heads;
70 uint8_t sectors;
71
72 uint32_t lba_size = image->size();
73 if (lba_size >= 16383*16*63) {
74 cylinders = 16383;
75 heads = 16;
76 sectors = 63;
77 } else {
78 if (lba_size >= 63)
79 sectors = 63;
80 else
81 sectors = lba_size;
82
83 if ((lba_size / sectors) >= 16)
84 heads = 16;
85 else
86 heads = (lba_size / sectors);
87
88 cylinders = lba_size / (heads * sectors);
89 }
90
91 // Setup the model name
92 strncpy((char *)driveID.atap_model, "5MI EDD si k",
93 sizeof(driveID.atap_model));
94 // Set the maximum multisector transfer size
95 driveID.atap_multi = MAX_MULTSECT;
96 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
97 driveID.atap_capabilities1 = 0x7;
98 // UDMA support, EIDE support
99 driveID.atap_extensions = 0x6;
100 // Setup default C/H/S settings
101 driveID.atap_cylinders = cylinders;
102 driveID.atap_sectors = sectors;
103 driveID.atap_heads = heads;
104 // Setup the current multisector transfer size
105 driveID.atap_curmulti = MAX_MULTSECT;
106 driveID.atap_curmulti_valid = 0x1;
107 // Number of sectors on disk
108 driveID.atap_capacity = lba_size;
109 // Multiword DMA mode 2 and below supported
110 driveID.atap_dmamode_supp = 0x400;
111 // Set PIO mode 4 and 3 supported
112 driveID.atap_piomode_supp = 0x3;
113 // Set DMA mode 4 and below supported
114 driveID.atap_udmamode_supp = 0x1f;
115 // Statically set hardware config word
116 driveID.atap_hwreset_res = 0x4001;
117
118 //arbitrary for now...
119 driveID.atap_ata_major = WDC_VER_ATA7;
120 }
121
122 IdeDisk::~IdeDisk()
123 {
124 // destroy the data buffer
125 delete [] dataBuffer;
126 }
127
128 void
129 IdeDisk::reset(int id)
130 {
131 // initialize the data buffer and shadow registers
132 dataBuffer = new uint8_t[MAX_DMA_SIZE];
133
134 memset(dataBuffer, 0, MAX_DMA_SIZE);
135 memset(&cmdReg, 0, sizeof(CommandReg_t));
136 memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
137
138 curPrdAddr = 0;
139 curSector = 0;
140 cmdBytes = 0;
141 cmdBytesLeft = 0;
142 drqBytesLeft = 0;
143 dmaRead = false;
144 intrPending = false;
145
146 // set the device state to idle
147 dmaState = Dma_Idle;
148
149 if (id == DEV0) {
150 devState = Device_Idle_S;
151 devID = DEV0;
152 } else if (id == DEV1) {
153 devState = Device_Idle_NS;
154 devID = DEV1;
155 } else {
156 panic("Invalid device ID: %#x\n", id);
157 }
158
159 // set the device ready bit
160 status = STATUS_DRDY_BIT;
161
162 /* The error register must be set to 0x1 on start-up to
163 indicate that no diagnostic error was detected */
164 cmdReg.error = 0x1;
165 }
166
167 ////
168 // Utility functions
169 ////
170
171 bool
172 IdeDisk::isDEVSelect()
173 {
174 return ctrl->isDiskSelected(this);
175 }
176
177 Addr
178 IdeDisk::pciToDma(Addr pciAddr)
179 {
180 if (ctrl)
181 return ctrl->plat->pciToDma(pciAddr);
182 else
183 panic("Access to unset controller!\n");
184 }
185
186 ////
187 // Device registers read/write
188 ////
189
190 void
191 IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data)
192 {
193 DevAction_t action = ACT_NONE;
194
195 switch (reg_type) {
196 case COMMAND_BLOCK:
197 switch (offset) {
198 // Data transfers occur two bytes at a time
199 case DATA_OFFSET:
200 *(uint16_t*)data = cmdReg.data;
201 action = ACT_DATA_READ_SHORT;
202 break;
203 case ERROR_OFFSET:
204 *data = cmdReg.error;
205 break;
206 case NSECTOR_OFFSET:
207 *data = cmdReg.sec_count;
208 break;
209 case SECTOR_OFFSET:
210 *data = cmdReg.sec_num;
211 break;
212 case LCYL_OFFSET:
213 *data = cmdReg.cyl_low;
214 break;
215 case HCYL_OFFSET:
216 *data = cmdReg.cyl_high;
217 break;
218 case DRIVE_OFFSET:
219 *data = cmdReg.drive;
220 break;
221 case STATUS_OFFSET:
222 *data = status;
223 action = ACT_STAT_READ;
224 break;
225 default:
226 panic("Invalid IDE command register offset: %#x\n", offset);
227 }
228 break;
229 case CONTROL_BLOCK:
230 if (offset == ALTSTAT_OFFSET)
231 *data = status;
232 else
233 panic("Invalid IDE control register offset: %#x\n", offset);
234 break;
235 default:
236 panic("Unknown register block!\n");
237 }
238 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset,
239 (uint32_t)*data);
240
241 if (action != ACT_NONE)
242 updateState(action);
243 }
244
245 void
246 IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data)
247 {
248 DevAction_t action = ACT_NONE;
249
250 switch (reg_type) {
251 case COMMAND_BLOCK:
252 switch (offset) {
253 case DATA_OFFSET:
254 cmdReg.data = *(uint16_t*)data;
255 action = ACT_DATA_WRITE_SHORT;
256 break;
257 case FEATURES_OFFSET:
258 break;
259 case NSECTOR_OFFSET:
260 cmdReg.sec_count = *data;
261 break;
262 case SECTOR_OFFSET:
263 cmdReg.sec_num = *data;
264 break;
265 case LCYL_OFFSET:
266 cmdReg.cyl_low = *data;
267 break;
268 case HCYL_OFFSET:
269 cmdReg.cyl_high = *data;
270 break;
271 case DRIVE_OFFSET:
272 cmdReg.drive = *data;
273 action = ACT_SELECT_WRITE;
274 break;
275 case COMMAND_OFFSET:
276 cmdReg.command = *data;
277 action = ACT_CMD_WRITE;
278 break;
279 default:
280 panic("Invalid IDE command register offset: %#x\n", offset);
281 }
282 break;
283 case CONTROL_BLOCK:
284 if (offset == CONTROL_OFFSET) {
285 if (*data & CONTROL_RST_BIT) {
286 // force the device into the reset state
287 devState = Device_Srst;
288 action = ACT_SRST_SET;
289 } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT))
290 action = ACT_SRST_CLEAR;
291
292 nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
293 }
294 else
295 panic("Invalid IDE control register offset: %#x\n", offset);
296 break;
297 default:
298 panic("Unknown register block!\n");
299 }
300
301 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
302 (uint32_t)*data);
303 if (action != ACT_NONE)
304 updateState(action);
305 }
306
307 ////
308 // Perform DMA transactions
309 ////
310
311 void
312 IdeDisk::doDmaTransfer()
313 {
314 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
315 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
316 dmaState, devState);
317
318 if (ctrl->dmaPending()) {
319 dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
320 return;
321 } else
322 ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
323 (uint8_t*)&curPrd.entry);
324 }
325
326 void
327 IdeDisk::dmaPrdReadDone()
328 {
329 DPRINTF(IdeDisk,
330 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
331 curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
332 curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
333 curPrd.getEOT(), curSector);
334
335 // the prd pointer has already been translated, so just do an increment
336 curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
337
338 if (dmaRead)
339 doDmaDataRead();
340 else
341 doDmaDataWrite();
342 }
343
344 void
345 IdeDisk::doDmaDataRead()
346 {
347 /** @todo we need to figure out what the delay actually will be */
348 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
349
350 DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
351 diskDelay, totalDiskDelay);
352
353 dmaReadWaitEvent.schedule(curTick + totalDiskDelay);
354 }
355
356 void
357 IdeDisk::regStats()
358 {
359 using namespace Stats;
360 dmaReadFullPages
361 .name(name() + ".dma_read_full_pages")
362 .desc("Number of full page size DMA reads (not PRD).")
363 ;
364 dmaReadBytes
365 .name(name() + ".dma_read_bytes")
366 .desc("Number of bytes transfered via DMA reads (not PRD).")
367 ;
368 dmaReadTxs
369 .name(name() + ".dma_read_txs")
370 .desc("Number of DMA read transactions (not PRD).")
371 ;
372
373 dmaWriteFullPages
374 .name(name() + ".dma_write_full_pages")
375 .desc("Number of full page size DMA writes.")
376 ;
377 dmaWriteBytes
378 .name(name() + ".dma_write_bytes")
379 .desc("Number of bytes transfered via DMA writes.")
380 ;
381 dmaWriteTxs
382 .name(name() + ".dma_write_txs")
383 .desc("Number of DMA write transactions.")
384 ;
385 }
386
387 void
388 IdeDisk::doDmaRead()
389 {
390
391 if (!dmaReadCG) {
392 // clear out the data buffer
393 memset(dataBuffer, 0, MAX_DMA_SIZE);
394 dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
395 curPrd.getByteCount(), TheISA::PageBytes);
396
397 }
398 if (ctrl->dmaPending()) {
399 panic("shouldn't be reentant??");
400 dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
401 return;
402 } else if (!dmaReadCG->done()) {
403 assert(dmaReadCG->complete() < MAX_DMA_SIZE);
404 ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
405 &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
406 dmaReadBytes += dmaReadCG->size();
407 dmaReadTxs++;
408 if (dmaReadCG->size() == TheISA::PageBytes)
409 dmaReadFullPages++;
410 dmaReadCG->next();
411 } else {
412 assert(dmaReadCG->done());
413 delete dmaReadCG;
414 dmaReadCG = NULL;
415 dmaReadDone();
416 }
417 }
418
419 void
420 IdeDisk::dmaReadDone()
421 {
422
423 uint32_t bytesWritten = 0;
424
425
426 // write the data to the disk image
427 for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
428 bytesWritten += SectorSize) {
429
430 cmdBytesLeft -= SectorSize;
431 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
432 }
433
434 // check for the EOT
435 if (curPrd.getEOT()) {
436 assert(cmdBytesLeft == 0);
437 dmaState = Dma_Idle;
438 updateState(ACT_DMA_DONE);
439 } else {
440 doDmaTransfer();
441 }
442 }
443
444 void
445 IdeDisk::doDmaDataWrite()
446 {
447 /** @todo we need to figure out what the delay actually will be */
448 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
449 uint32_t bytesRead = 0;
450
451 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
452 diskDelay, totalDiskDelay);
453
454 memset(dataBuffer, 0, MAX_DMA_SIZE);
455 assert(cmdBytesLeft <= MAX_DMA_SIZE);
456 while (bytesRead < curPrd.getByteCount()) {
457 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
458 bytesRead += SectorSize;
459 cmdBytesLeft -= SectorSize;
460 }
461
462 dmaWriteWaitEvent.schedule(curTick + totalDiskDelay);
463 }
464
465 void
466 IdeDisk::doDmaWrite()
467 {
468
469 if (!dmaWriteCG) {
470 // clear out the data buffer
471 dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
472 curPrd.getByteCount(), TheISA::PageBytes);
473 }
474 if (ctrl->dmaPending()) {
475 panic("shouldn't be reentant??");
476 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
477 return;
478 } else if (!dmaWriteCG->done()) {
479 assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
480 ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
481 &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
482 dmaWriteBytes += dmaWriteCG->size();
483 dmaWriteTxs++;
484 if (dmaWriteCG->size() == TheISA::PageBytes)
485 dmaWriteFullPages++;
486 dmaWriteCG->next();
487 } else {
488 assert(dmaWriteCG->done());
489 delete dmaWriteCG;
490 dmaWriteCG = NULL;
491 dmaWriteDone();
492 }
493 }
494
495 void
496 IdeDisk::dmaWriteDone()
497 {
498 // check for the EOT
499 if (curPrd.getEOT()) {
500 assert(cmdBytesLeft == 0);
501 dmaState = Dma_Idle;
502 updateState(ACT_DMA_DONE);
503 } else {
504 doDmaTransfer();
505 }
506 }
507
508 ////
509 // Disk utility routines
510 ///
511
512 void
513 IdeDisk::readDisk(uint32_t sector, uint8_t *data)
514 {
515 uint32_t bytesRead = image->read(data, sector);
516
517 if (bytesRead != SectorSize)
518 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
519 name(), bytesRead, SectorSize, errno);
520 }
521
522 void
523 IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
524 {
525 uint32_t bytesWritten = image->write(data, sector);
526
527 if (bytesWritten != SectorSize)
528 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
529 name(), bytesWritten, SectorSize, errno);
530 }
531
532 ////
533 // Setup and handle commands
534 ////
535
536 void
537 IdeDisk::startDma(const uint32_t &prdTableBase)
538 {
539 if (dmaState != Dma_Start)
540 panic("Inconsistent DMA state, should be in Dma_Start!\n");
541
542 if (devState != Transfer_Data_Dma)
543 panic("Inconsistent device state for DMA start!\n");
544
545 // PRD base address is given by bits 31:2
546 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
547
548 dmaState = Dma_Transfer;
549
550 // schedule dma transfer (doDmaTransfer)
551 dmaTransferEvent.schedule(curTick + 1);
552 }
553
554 void
555 IdeDisk::abortDma()
556 {
557 if (dmaState == Dma_Idle)
558 panic("Inconsistent DMA state, should be Start or Transfer!");
559
560 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
561 panic("Inconsistent device state, should be Transfer or Prepare!\n");
562
563 updateState(ACT_CMD_ERROR);
564 }
565
566 void
567 IdeDisk::startCommand()
568 {
569 DevAction_t action = ACT_NONE;
570 uint32_t size = 0;
571 dmaRead = false;
572
573 // Decode commands
574 switch (cmdReg.command) {
575 // Supported non-data commands
576 case WDSF_READ_NATIVE_MAX:
577 size = image->size() - 1;
578 cmdReg.sec_num = (size & 0xff);
579 cmdReg.cyl_low = ((size & 0xff00) >> 8);
580 cmdReg.cyl_high = ((size & 0xff0000) >> 16);
581 cmdReg.head = ((size & 0xf000000) >> 24);
582
583 devState = Command_Execution;
584 action = ACT_CMD_COMPLETE;
585 break;
586
587 case WDCC_RECAL:
588 case WDCC_IDP:
589 case WDCC_STANDBY_IMMED:
590 case WDCC_FLUSHCACHE:
591 case WDSF_VERIFY:
592 case WDSF_SEEK:
593 case SET_FEATURES:
594 case WDCC_SETMULTI:
595 devState = Command_Execution;
596 action = ACT_CMD_COMPLETE;
597 break;
598
599 // Supported PIO data-in commands
600 case WDCC_IDENTIFY:
601 cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
602 devState = Prepare_Data_In;
603 action = ACT_DATA_READY;
604 break;
605
606 case WDCC_READMULTI:
607 case WDCC_READ:
608 if (!(cmdReg.drive & DRIVE_LBA_BIT))
609 panic("Attempt to perform CHS access, only supports LBA\n");
610
611 if (cmdReg.sec_count == 0)
612 cmdBytes = cmdBytesLeft = (256 * SectorSize);
613 else
614 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
615
616 curSector = getLBABase();
617
618 /** @todo make this a scheduled event to simulate disk delay */
619 devState = Prepare_Data_In;
620 action = ACT_DATA_READY;
621 break;
622
623 // Supported PIO data-out commands
624 case WDCC_WRITEMULTI:
625 case WDCC_WRITE:
626 if (!(cmdReg.drive & DRIVE_LBA_BIT))
627 panic("Attempt to perform CHS access, only supports LBA\n");
628
629 if (cmdReg.sec_count == 0)
630 cmdBytes = cmdBytesLeft = (256 * SectorSize);
631 else
632 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
633
634 curSector = getLBABase();
635
636 devState = Prepare_Data_Out;
637 action = ACT_DATA_READY;
638 break;
639
640 // Supported DMA commands
641 case WDCC_WRITEDMA:
642 dmaRead = true; // a write to the disk is a DMA read from memory
643 case WDCC_READDMA:
644 if (!(cmdReg.drive & DRIVE_LBA_BIT))
645 panic("Attempt to perform CHS access, only supports LBA\n");
646
647 if (cmdReg.sec_count == 0)
648 cmdBytes = cmdBytesLeft = (256 * SectorSize);
649 else
650 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
651
652 curSector = getLBABase();
653
654 devState = Prepare_Data_Dma;
655 action = ACT_DMA_READY;
656 break;
657
658 default:
659 panic("Unsupported ATA command: %#x\n", cmdReg.command);
660 }
661
662 if (action != ACT_NONE) {
663 // set the BSY bit
664 status |= STATUS_BSY_BIT;
665 // clear the DRQ bit
666 status &= ~STATUS_DRQ_BIT;
667 // clear the DF bit
668 status &= ~STATUS_DF_BIT;
669
670 updateState(action);
671 }
672 }
673
674 ////
675 // Handle setting and clearing interrupts
676 ////
677
678 void
679 IdeDisk::intrPost()
680 {
681 DPRINTF(IdeDisk, "Posting Interrupt\n");
682 if (intrPending)
683 panic("Attempt to post an interrupt with one pending\n");
684
685 intrPending = true;
686
687 // talk to controller to set interrupt
688 if (ctrl) {
689 ctrl->bmi_regs.bmis0 |= IDEINTS;
690 ctrl->intrPost();
691 }
692 }
693
694 void
695 IdeDisk::intrClear()
696 {
697 DPRINTF(IdeDisk, "Clearing Interrupt\n");
698 if (!intrPending)
699 panic("Attempt to clear a non-pending interrupt\n");
700
701 intrPending = false;
702
703 // talk to controller to clear interrupt
704 if (ctrl)
705 ctrl->intrClear();
706 }
707
708 ////
709 // Manage the device internal state machine
710 ////
711
712 void
713 IdeDisk::updateState(DevAction_t action)
714 {
715 switch (devState) {
716 case Device_Srst:
717 if (action == ACT_SRST_SET) {
718 // set the BSY bit
719 status |= STATUS_BSY_BIT;
720 } else if (action == ACT_SRST_CLEAR) {
721 // clear the BSY bit
722 status &= ~STATUS_BSY_BIT;
723
724 // reset the device state
725 reset(devID);
726 }
727 break;
728
729 case Device_Idle_S:
730 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
731 devState = Device_Idle_NS;
732 } else if (action == ACT_CMD_WRITE) {
733 startCommand();
734 }
735
736 break;
737
738 case Device_Idle_SI:
739 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
740 devState = Device_Idle_NS;
741 intrClear();
742 } else if (action == ACT_STAT_READ || isIENSet()) {
743 devState = Device_Idle_S;
744 intrClear();
745 } else if (action == ACT_CMD_WRITE) {
746 intrClear();
747 startCommand();
748 }
749
750 break;
751
752 case Device_Idle_NS:
753 if (action == ACT_SELECT_WRITE && isDEVSelect()) {
754 if (!isIENSet() && intrPending) {
755 devState = Device_Idle_SI;
756 intrPost();
757 }
758 if (isIENSet() || !intrPending) {
759 devState = Device_Idle_S;
760 }
761 }
762 break;
763
764 case Command_Execution:
765 if (action == ACT_CMD_COMPLETE) {
766 // clear the BSY bit
767 setComplete();
768
769 if (!isIENSet()) {
770 devState = Device_Idle_SI;
771 intrPost();
772 } else {
773 devState = Device_Idle_S;
774 }
775 }
776 break;
777
778 case Prepare_Data_In:
779 if (action == ACT_CMD_ERROR) {
780 // clear the BSY bit
781 setComplete();
782
783 if (!isIENSet()) {
784 devState = Device_Idle_SI;
785 intrPost();
786 } else {
787 devState = Device_Idle_S;
788 }
789 } else if (action == ACT_DATA_READY) {
790 // clear the BSY bit
791 status &= ~STATUS_BSY_BIT;
792 // set the DRQ bit
793 status |= STATUS_DRQ_BIT;
794
795 // copy the data into the data buffer
796 if (cmdReg.command == WDCC_IDENTIFY) {
797 // Reset the drqBytes for this block
798 drqBytesLeft = sizeof(struct ataparams);
799
800 memcpy((void *)dataBuffer, (void *)&driveID,
801 sizeof(struct ataparams));
802 } else {
803 // Reset the drqBytes for this block
804 drqBytesLeft = SectorSize;
805
806 readDisk(curSector++, dataBuffer);
807 }
808
809 // put the first two bytes into the data register
810 memcpy((void *)&cmdReg.data, (void *)dataBuffer,
811 sizeof(uint16_t));
812
813 if (!isIENSet()) {
814 devState = Data_Ready_INTRQ_In;
815 intrPost();
816 } else {
817 devState = Transfer_Data_In;
818 }
819 }
820 break;
821
822 case Data_Ready_INTRQ_In:
823 if (action == ACT_STAT_READ) {
824 devState = Transfer_Data_In;
825 intrClear();
826 }
827 break;
828
829 case Transfer_Data_In:
830 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
831 if (action == ACT_DATA_READ_BYTE) {
832 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
833 } else {
834 drqBytesLeft -= 2;
835 cmdBytesLeft -= 2;
836
837 // copy next short into data registers
838 if (drqBytesLeft)
839 memcpy((void *)&cmdReg.data,
840 (void *)&dataBuffer[SectorSize - drqBytesLeft],
841 sizeof(uint16_t));
842 }
843
844 if (drqBytesLeft == 0) {
845 if (cmdBytesLeft == 0) {
846 // Clear the BSY bit
847 setComplete();
848 devState = Device_Idle_S;
849 } else {
850 devState = Prepare_Data_In;
851 // set the BSY_BIT
852 status |= STATUS_BSY_BIT;
853 // clear the DRQ_BIT
854 status &= ~STATUS_DRQ_BIT;
855
856 /** @todo change this to a scheduled event to simulate
857 disk delay */
858 updateState(ACT_DATA_READY);
859 }
860 }
861 }
862 break;
863
864 case Prepare_Data_Out:
865 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
866 // clear the BSY bit
867 setComplete();
868
869 if (!isIENSet()) {
870 devState = Device_Idle_SI;
871 intrPost();
872 } else {
873 devState = Device_Idle_S;
874 }
875 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
876 // clear the BSY bit
877 status &= ~STATUS_BSY_BIT;
878 // set the DRQ bit
879 status |= STATUS_DRQ_BIT;
880
881 // clear the data buffer to get it ready for writes
882 memset(dataBuffer, 0, MAX_DMA_SIZE);
883
884 // reset the drqBytes for this block
885 drqBytesLeft = SectorSize;
886
887 if (cmdBytesLeft == cmdBytes || isIENSet()) {
888 devState = Transfer_Data_Out;
889 } else {
890 devState = Data_Ready_INTRQ_Out;
891 intrPost();
892 }
893 }
894 break;
895
896 case Data_Ready_INTRQ_Out:
897 if (action == ACT_STAT_READ) {
898 devState = Transfer_Data_Out;
899 intrClear();
900 }
901 break;
902
903 case Transfer_Data_Out:
904 if (action == ACT_DATA_WRITE_BYTE ||
905 action == ACT_DATA_WRITE_SHORT) {
906
907 if (action == ACT_DATA_READ_BYTE) {
908 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
909 } else {
910 // copy the latest short into the data buffer
911 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
912 (void *)&cmdReg.data,
913 sizeof(uint16_t));
914
915 drqBytesLeft -= 2;
916 cmdBytesLeft -= 2;
917 }
918
919 if (drqBytesLeft == 0) {
920 // copy the block to the disk
921 writeDisk(curSector++, dataBuffer);
922
923 // set the BSY bit
924 status |= STATUS_BSY_BIT;
925 // set the seek bit
926 status |= STATUS_SEEK_BIT;
927 // clear the DRQ bit
928 status &= ~STATUS_DRQ_BIT;
929
930 devState = Prepare_Data_Out;
931
932 /** @todo change this to a scheduled event to simulate
933 disk delay */
934 updateState(ACT_DATA_READY);
935 }
936 }
937 break;
938
939 case Prepare_Data_Dma:
940 if (action == ACT_CMD_ERROR) {
941 // clear the BSY bit
942 setComplete();
943
944 if (!isIENSet()) {
945 devState = Device_Idle_SI;
946 intrPost();
947 } else {
948 devState = Device_Idle_S;
949 }
950 } else if (action == ACT_DMA_READY) {
951 // clear the BSY bit
952 status &= ~STATUS_BSY_BIT;
953 // set the DRQ bit
954 status |= STATUS_DRQ_BIT;
955
956 devState = Transfer_Data_Dma;
957
958 if (dmaState != Dma_Idle)
959 panic("Inconsistent DMA state, should be Dma_Idle\n");
960
961 dmaState = Dma_Start;
962 // wait for the write to the DMA start bit
963 }
964 break;
965
966 case Transfer_Data_Dma:
967 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) {
968 // clear the BSY bit
969 setComplete();
970 // set the seek bit
971 status |= STATUS_SEEK_BIT;
972 // clear the controller state for DMA transfer
973 ctrl->setDmaComplete(this);
974
975 if (!isIENSet()) {
976 devState = Device_Idle_SI;
977 intrPost();
978 } else {
979 devState = Device_Idle_S;
980 }
981 }
982 break;
983
984 default:
985 panic("Unknown IDE device state: %#x\n", devState);
986 }
987 }
988
989 void
990 IdeDisk::serialize(ostream &os)
991 {
992 // Check all outstanding events to see if they are scheduled
993 // these are all mutually exclusive
994 Tick reschedule = 0;
995 Events_t event = None;
996
997 int eventCount = 0;
998
999 if (dmaTransferEvent.scheduled()) {
1000 reschedule = dmaTransferEvent.when();
1001 event = Transfer;
1002 eventCount++;
1003 }
1004 if (dmaReadWaitEvent.scheduled()) {
1005 reschedule = dmaReadWaitEvent.when();
1006 event = ReadWait;
1007 eventCount++;
1008 }
1009 if (dmaWriteWaitEvent.scheduled()) {
1010 reschedule = dmaWriteWaitEvent.when();
1011 event = WriteWait;
1012 eventCount++;
1013 }
1014 if (dmaPrdReadEvent.scheduled()) {
1015 reschedule = dmaPrdReadEvent.when();
1016 event = PrdRead;
1017 eventCount++;
1018 }
1019 if (dmaReadEvent.scheduled()) {
1020 reschedule = dmaReadEvent.when();
1021 event = DmaRead;
1022 eventCount++;
1023 }
1024 if (dmaWriteEvent.scheduled()) {
1025 reschedule = dmaWriteEvent.when();
1026 event = DmaWrite;
1027 eventCount++;
1028 }
1029
1030 assert(eventCount <= 1);
1031
1032 SERIALIZE_SCALAR(reschedule);
1033 SERIALIZE_ENUM(event);
1034
1035 // Serialize device registers
1036 SERIALIZE_SCALAR(cmdReg.data);
1037 SERIALIZE_SCALAR(cmdReg.sec_count);
1038 SERIALIZE_SCALAR(cmdReg.sec_num);
1039 SERIALIZE_SCALAR(cmdReg.cyl_low);
1040 SERIALIZE_SCALAR(cmdReg.cyl_high);
1041 SERIALIZE_SCALAR(cmdReg.drive);
1042 SERIALIZE_SCALAR(cmdReg.command);
1043 SERIALIZE_SCALAR(status);
1044 SERIALIZE_SCALAR(nIENBit);
1045 SERIALIZE_SCALAR(devID);
1046
1047 // Serialize the PRD related information
1048 SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1049 SERIALIZE_SCALAR(curPrd.entry.byteCount);
1050 SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1051 SERIALIZE_SCALAR(curPrdAddr);
1052
1053 /** @todo need to serialized chunk generator stuff!! */
1054 // Serialize current transfer related information
1055 SERIALIZE_SCALAR(cmdBytesLeft);
1056 SERIALIZE_SCALAR(cmdBytes);
1057 SERIALIZE_SCALAR(drqBytesLeft);
1058 SERIALIZE_SCALAR(curSector);
1059 SERIALIZE_SCALAR(dmaRead);
1060 SERIALIZE_SCALAR(intrPending);
1061 SERIALIZE_ENUM(devState);
1062 SERIALIZE_ENUM(dmaState);
1063 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1064 }
1065
1066 void
1067 IdeDisk::unserialize(Checkpoint *cp, const string &section)
1068 {
1069 // Reschedule events that were outstanding
1070 // these are all mutually exclusive
1071 Tick reschedule = 0;
1072 Events_t event = None;
1073
1074 UNSERIALIZE_SCALAR(reschedule);
1075 UNSERIALIZE_ENUM(event);
1076
1077 switch (event) {
1078 case None : break;
1079 case Transfer : dmaTransferEvent.schedule(reschedule); break;
1080 case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
1081 case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
1082 case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
1083 case DmaRead : dmaReadEvent.schedule(reschedule); break;
1084 case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
1085 }
1086
1087 // Unserialize device registers
1088 UNSERIALIZE_SCALAR(cmdReg.data);
1089 UNSERIALIZE_SCALAR(cmdReg.sec_count);
1090 UNSERIALIZE_SCALAR(cmdReg.sec_num);
1091 UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1092 UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1093 UNSERIALIZE_SCALAR(cmdReg.drive);
1094 UNSERIALIZE_SCALAR(cmdReg.command);
1095 UNSERIALIZE_SCALAR(status);
1096 UNSERIALIZE_SCALAR(nIENBit);
1097 UNSERIALIZE_SCALAR(devID);
1098
1099 // Unserialize the PRD related information
1100 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1101 UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1102 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1103 UNSERIALIZE_SCALAR(curPrdAddr);
1104
1105 /** @todo need to serialized chunk generator stuff!! */
1106 // Unserialize current transfer related information
1107 UNSERIALIZE_SCALAR(cmdBytes);
1108 UNSERIALIZE_SCALAR(cmdBytesLeft);
1109 UNSERIALIZE_SCALAR(drqBytesLeft);
1110 UNSERIALIZE_SCALAR(curSector);
1111 UNSERIALIZE_SCALAR(dmaRead);
1112 UNSERIALIZE_SCALAR(intrPending);
1113 UNSERIALIZE_ENUM(devState);
1114 UNSERIALIZE_ENUM(dmaState);
1115 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1116 }
1117
1118 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1119
1120 enum DriveID { master, slave };
1121 static const char *DriveID_strings[] = { "master", "slave" };
1122 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
1123
1124 SimObjectParam<DiskImage *> image;
1125 SimpleEnumParam<DriveID> driveID;
1126 Param<int> delay;
1127
1128 END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
1129
1130 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
1131
1132 INIT_PARAM(image, "Disk image"),
1133 INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings),
1134 INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1)
1135
1136 END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
1137
1138
1139 CREATE_SIM_OBJECT(IdeDisk)
1140 {
1141 return new IdeDisk(getInstanceName(), image, driveID, delay);
1142 }
1143
1144 REGISTER_SIM_OBJECT("IdeDisk", IdeDisk)
1145
1146 #endif //DOXYGEN_SHOULD_SKIP_THIS