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