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