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