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