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