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