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