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