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