ide_disk.cc revision 2627
12391SN/A/*
22391SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
32391SN/A * All rights reserved.
42391SN/A *
52391SN/A * Redistribution and use in source and binary forms, with or without
62391SN/A * modification, are permitted provided that the following conditions are
72391SN/A * met: redistributions of source code must retain the above copyright
82391SN/A * notice, this list of conditions and the following disclaimer;
92391SN/A * redistributions in binary form must reproduce the above copyright
102391SN/A * notice, this list of conditions and the following disclaimer in the
112391SN/A * documentation and/or other materials provided with the distribution;
122391SN/A * neither the name of the copyright holders nor the names of its
132391SN/A * contributors may be used to endorse or promote products derived from
142391SN/A * this software without specific prior written permission.
152391SN/A *
162391SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252391SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262391SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
292391SN/A/** @file
302391SN/A * Device model implementation for an IDE disk
312391SN/A */
322391SN/A
332391SN/A#include <cerrno>
342391SN/A#include <cstring>
352391SN/A#include <deque>
362391SN/A#include <string>
372391SN/A
382391SN/A#include "base/chunk_generator.hh"
392391SN/A#include "base/cprintf.hh" // csprintf
402391SN/A#include "base/trace.hh"
412391SN/A#include "dev/disk_image.hh"
422391SN/A#include "dev/ide_disk.hh"
432391SN/A#include "dev/ide_ctrl.hh"
442592SN/A#include "dev/tsunami.hh"
452394SN/A#include "dev/tsunami_pchip.hh"
462391SN/A#include "sim/builder.hh"
472391SN/A#include "sim/sim_object.hh"
482415SN/A#include "sim/root.hh"
492423SN/A#include "arch/isa_traits.hh"
502391SN/A
512394SN/Ausing namespace std;
522391SN/Ausing namespace TheISA;
532423SN/A
542391SN/AIdeDisk::IdeDisk(const string &name, DiskImage *img,
552630SN/A                 int id, Tick delay)
562415SN/A    : SimObject(name), ctrl(NULL), image(img), diskDelay(delay),
572415SN/A      dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
582415SN/A      dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
592415SN/A      dmaReadEvent(this), dmaWriteEvent(this)
602415SN/A{
612415SN/A    // Reset the device state
622415SN/A    reset(id);
632415SN/A
642415SN/A    // fill out the drive ID structure
652415SN/A    memset(&driveID, 0, sizeof(struct ataparams));
662415SN/A
672415SN/A    // Calculate LBA and C/H/S values
682415SN/A    uint16_t cylinders;
692415SN/A    uint8_t heads;
702415SN/A    uint8_t sectors;
712415SN/A
722415SN/A    uint32_t lba_size = image->size();
732415SN/A    if (lba_size >= 16383*16*63) {
742565SN/A        cylinders = 16383;
752565SN/A        heads = 16;
762391SN/A        sectors = 63;
772391SN/A    } else {
782391SN/A        if (lba_size >= 63)
792391SN/A            sectors = 63;
802391SN/A        else
812391SN/A            sectors = lba_size;
822391SN/A
832391SN/A        if ((lba_size / sectors) >= 16)
842391SN/A            heads = 16;
852391SN/A        else
862391SN/A            heads = (lba_size / sectors);
872391SN/A
882391SN/A        cylinders = lba_size / (heads * sectors);
892391SN/A    }
902391SN/A
912391SN/A    // Setup the model name
922391SN/A    strncpy((char *)driveID.atap_model, "5MI EDD si k",
932391SN/A            sizeof(driveID.atap_model));
942391SN/A    // Set the maximum multisector transfer size
952541SN/A    driveID.atap_multi = MAX_MULTSECT;
962541SN/A    // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
972541SN/A    driveID.atap_capabilities1 = 0x7;
982541SN/A    // UDMA support, EIDE support
992541SN/A    driveID.atap_extensions = 0x6;
1002541SN/A    // Setup default C/H/S settings
1012541SN/A    driveID.atap_cylinders = cylinders;
1022541SN/A    driveID.atap_sectors = sectors;
1032391SN/A    driveID.atap_heads = heads;
1042391SN/A    // Setup the current multisector transfer size
1052391SN/A    driveID.atap_curmulti = MAX_MULTSECT;
1062391SN/A    driveID.atap_curmulti_valid = 0x1;
1072416SN/A    // Number of sectors on disk
1082391SN/A    driveID.atap_capacity = lba_size;
1092391SN/A    // Multiword DMA mode 2 and below supported
1102391SN/A    driveID.atap_dmamode_supp = 0x400;
1112391SN/A    // Set PIO mode 4 and 3 supported
1122391SN/A    driveID.atap_piomode_supp = 0x3;
1132391SN/A    // Set DMA mode 4 and below supported
1142391SN/A    driveID.atap_udmamode_supp = 0x1f;
1152391SN/A    // Statically set hardware config word
1162391SN/A    driveID.atap_hwreset_res = 0x4001;
1172391SN/A
1182391SN/A    //arbitrary for now...
1192391SN/A    driveID.atap_ata_major = WDC_VER_ATA7;
1202408SN/A}
1212408SN/A
1222408SN/AIdeDisk::~IdeDisk()
1232409SN/A{
1242409SN/A    // destroy the data buffer
1252408SN/A    delete [] dataBuffer;
1262408SN/A}
1272413SN/A
1282630SN/Avoid
1292413SN/AIdeDisk::reset(int id)
1302413SN/A{
1312415SN/A    // initialize the data buffer and shadow registers
1322639Sstever@eecs.umich.edu    dataBuffer = new uint8_t[MAX_DMA_SIZE];
1332641Sstever@eecs.umich.edu
1342416SN/A    memset(dataBuffer, 0, MAX_DMA_SIZE);
1352415SN/A    memset(&cmdReg, 0, sizeof(CommandReg_t));
1362415SN/A    memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
1372413SN/A
1382413SN/A    curPrdAddr = 0;
1392413SN/A    curSector = 0;
1402413SN/A    cmdBytes = 0;
1412630SN/A    cmdBytesLeft = 0;
1422413SN/A    drqBytesLeft = 0;
1432413SN/A    dmaRead = false;
1442662Sstever@eecs.umich.edu    intrPending = false;
1452413SN/A
1462413SN/A    // set the device state to idle
1472413SN/A    dmaState = Dma_Idle;
1482630SN/A
1492413SN/A    if (id == DEV0) {
1502641Sstever@eecs.umich.edu        devState = Device_Idle_S;
1512414SN/A        devID = DEV0;
1522630SN/A    } else if (id == DEV1) {
1532641Sstever@eecs.umich.edu        devState = Device_Idle_NS;
1542641Sstever@eecs.umich.edu        devID = DEV1;
1552641Sstever@eecs.umich.edu    } else {
1562641Sstever@eecs.umich.edu        panic("Invalid device ID: %#x\n", id);
1572418SN/A    }
1582641Sstever@eecs.umich.edu
1592641Sstever@eecs.umich.edu    // set the device ready bit
1602641Sstever@eecs.umich.edu    status = STATUS_DRDY_BIT;
1612641Sstever@eecs.umich.edu
1622631SN/A    /* The error register must be set to 0x1 on start-up to
1632631SN/A       indicate that no diagnostic error was detected */
1642631SN/A    cmdReg.error = 0x1;
1652631SN/A}
1662631SN/A
1672418SN/A////
1682413SN/A// Utility functions
1692413SN/A////
1702413SN/A
1712420SN/Abool
1722641Sstever@eecs.umich.eduIdeDisk::isDEVSelect()
1732413SN/A{
1742413SN/A    return ctrl->isDiskSelected(this);
1752413SN/A}
1762738Sstever@eecs.umich.edu
1772413SN/AAddr
1782738Sstever@eecs.umich.eduIdeDisk::pciToDma(Addr pciAddr)
1792499SN/A{
1802499SN/A    if (ctrl)
1812640Sstever@eecs.umich.edu        return ctrl->plat->pciToDma(pciAddr);
1822499SN/A    else
1832519SN/A        panic("Access to unset controller!\n");
1842519SN/A}
1852640Sstever@eecs.umich.edu
1862462SN/A////
1872462SN/A// Device registers read/write
1882462SN/A////
1892413SN/A
1902413SN/Avoid
1912413SN/AIdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data)
1922413SN/A{
1932413SN/A    DevAction_t action = ACT_NONE;
1942413SN/A
1952413SN/A    switch (reg_type) {
1962640Sstever@eecs.umich.edu      case COMMAND_BLOCK:
1972640Sstever@eecs.umich.edu        switch (offset) {
1982640Sstever@eecs.umich.edu          // Data transfers occur two bytes at a time
1992413SN/A          case DATA_OFFSET:
2002413SN/A            *(uint16_t*)data = cmdReg.data;
2012413SN/A            action = ACT_DATA_READ_SHORT;
2022413SN/A            break;
2032413SN/A          case ERROR_OFFSET:
2042413SN/A            *data = cmdReg.error;
2052413SN/A            break;
2062413SN/A          case NSECTOR_OFFSET:
2072413SN/A            *data = cmdReg.sec_count;
2082522SN/A            break;
2092522SN/A          case SECTOR_OFFSET:
2102413SN/A            *data = cmdReg.sec_num;
2112522SN/A            break;
2122497SN/A          case LCYL_OFFSET:
2132497SN/A            *data = cmdReg.cyl_low;
2142497SN/A            break;
2152522SN/A          case HCYL_OFFSET:
2162497SN/A            *data = cmdReg.cyl_high;
2172522SN/A            break;
2182522SN/A          case DRIVE_OFFSET:
2192522SN/A            *data = cmdReg.drive;
2202413SN/A            break;
2212413SN/A          case STATUS_OFFSET:
2222415SN/A            *data = status;
2232415SN/A            action = ACT_STAT_READ;
2242415SN/A            break;
2252415SN/A          default:
2262415SN/A            panic("Invalid IDE command register offset: %#x\n", offset);
2272413SN/A        }
2282413SN/A        break;
2292630SN/A      case CONTROL_BLOCK:
2302413SN/A        if (offset == ALTSTAT_OFFSET)
2312416SN/A            *data = status;
2322413SN/A        else
2332413SN/A            panic("Invalid IDE control register offset: %#x\n", offset);
2342413SN/A        break;
2352630SN/A      default:
2362413SN/A        panic("Unknown register block!\n");
2372413SN/A    }
2382413SN/A    DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset,
2392413SN/A            (uint32_t)*data);
2402413SN/A
2412630SN/A    if (action != ACT_NONE)
2422413SN/A        updateState(action);
2432413SN/A}
2442413SN/A
2452413SN/Avoid
2462413SN/AIdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data)
2472413SN/A{
2482391SN/A    DevAction_t action = ACT_NONE;
2492391SN/A
2502391SN/A    switch (reg_type) {
2512391SN/A      case COMMAND_BLOCK:
2522391SN/A        switch (offset) {
2532391SN/A          case DATA_OFFSET:
2542391SN/A            cmdReg.data = *(uint16_t*)data;
2552391SN/A            action = ACT_DATA_WRITE_SHORT;
2562391SN/A            break;
2572391SN/A          case FEATURES_OFFSET:
2582391SN/A            break;
2592391SN/A          case NSECTOR_OFFSET:
2602391SN/A            cmdReg.sec_count = *data;
2612391SN/A            break;
2622391SN/A          case SECTOR_OFFSET:
2632391SN/A            cmdReg.sec_num = *data;
2642391SN/A            break;
2652391SN/A          case LCYL_OFFSET:
2662391SN/A            cmdReg.cyl_low = *data;
2672391SN/A            break;
2682391SN/A          case HCYL_OFFSET:
2692391SN/A            cmdReg.cyl_high = *data;
2702391SN/A            break;
2712391SN/A          case DRIVE_OFFSET:
2722391SN/A            cmdReg.drive = *data;
2732391SN/A            action = ACT_SELECT_WRITE;
2742391SN/A            break;
2752391SN/A          case COMMAND_OFFSET:
2762391SN/A            cmdReg.command = *data;
2772391SN/A            action = ACT_CMD_WRITE;
2782391SN/A            break;
2792391SN/A          default:
2802391SN/A            panic("Invalid IDE command register offset: %#x\n", offset);
2812391SN/A        }
2822391SN/A        break;
2832391SN/A      case CONTROL_BLOCK:
2842391SN/A        if (offset == CONTROL_OFFSET) {
2852391SN/A            if (*data & CONTROL_RST_BIT) {
2862391SN/A                // force the device into the reset state
2872391SN/A                devState = Device_Srst;
2882391SN/A                action = ACT_SRST_SET;
2892391SN/A            } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT))
2902391SN/A                action = ACT_SRST_CLEAR;
2912391SN/A
2922391SN/A            nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
2932391SN/A        }
2942391SN/A        else
2952391SN/A            panic("Invalid IDE control register offset: %#x\n", offset);
2962391SN/A        break;
2972391SN/A      default:
2982391SN/A        panic("Unknown register block!\n");
2992391SN/A    }
3002391SN/A
3012391SN/A    DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
3022391SN/A            (uint32_t)*data);
3032391SN/A    if (action != ACT_NONE)
3042391SN/A        updateState(action);
3052391SN/A}
3062391SN/A
3072391SN/A////
3082391SN/A// Perform DMA transactions
3092391SN/A////
3102391SN/A
3112391SN/Avoid
3122391SN/AIdeDisk::doDmaTransfer()
3132391SN/A{
3142391SN/A    if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
3152391SN/A        panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
3162391SN/A              dmaState, devState);
3172391SN/A
3182391SN/A    if (ctrl->dmaPending()) {
3192391SN/A        dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
3202391SN/A        return;
3212391SN/A    } else
3222391SN/A        ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
3232391SN/A                (uint8_t*)&curPrd.entry);
3242391SN/A}
3252391SN/A
3262391SN/Avoid
3272391SN/AIdeDisk::dmaPrdReadDone()
3282391SN/A{
3292391SN/A    DPRINTF(IdeDisk,
3302391SN/A            "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
3312391SN/A            curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
3322391SN/A            curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
3332391SN/A            curPrd.getEOT(), curSector);
3342391SN/A
3352391SN/A    // the prd pointer has already been translated, so just do an increment
3362391SN/A    curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
3372391SN/A
3382391SN/A    if (dmaRead)
3392391SN/A        doDmaDataRead();
3402391SN/A    else
3412391SN/A        doDmaDataWrite();
3422391SN/A}
3432391SN/A
3442391SN/Avoid
3452391SN/AIdeDisk::doDmaDataRead()
3462391SN/A{
3472391SN/A    /** @todo we need to figure out what the delay actually will be */
3482391SN/A    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
3492391SN/A
3502391SN/A    DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
3512391SN/A            diskDelay, totalDiskDelay);
3522391SN/A
3532391SN/A    dmaReadWaitEvent.schedule(curTick + totalDiskDelay);
3542391SN/A}
3552413SN/A
3562391SN/Avoid
3572391SN/AIdeDisk::regStats()
3582391SN/A{
3592391SN/A    using namespace Stats;
3602565SN/A    dmaReadFullPages
3612391SN/A        .name(name() + ".dma_read_full_pages")
3622391SN/A        .desc("Number of full page size DMA reads (not PRD).")
3632391SN/A        ;
3642391SN/A    dmaReadBytes
3652391SN/A        .name(name() + ".dma_read_bytes")
3662391SN/A        .desc("Number of bytes transfered via DMA reads (not PRD).")
3672565SN/A        ;
3682565SN/A    dmaReadTxs
3692391SN/A        .name(name() + ".dma_read_txs")
3702391SN/A        .desc("Number of DMA read transactions (not PRD).")
3712391SN/A        ;
3722391SN/A
3732391SN/A    dmaWriteFullPages
3742391SN/A        .name(name() + ".dma_write_full_pages")
3752565SN/A        .desc("Number of full page size DMA writes.")
3762391SN/A        ;
3772391SN/A    dmaWriteBytes
3782391SN/A        .name(name() + ".dma_write_bytes")
379        .desc("Number of bytes transfered via DMA writes.")
380        ;
381    dmaWriteTxs
382        .name(name() + ".dma_write_txs")
383        .desc("Number of DMA write transactions.")
384        ;
385}
386
387void
388IdeDisk::doDmaRead()
389{
390
391    if (!dmaReadCG) {
392        // clear out the data buffer
393        memset(dataBuffer, 0, MAX_DMA_SIZE);
394        dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
395                curPrd.getByteCount(), TheISA::PageBytes);
396
397    }
398    if (ctrl->dmaPending()) {
399        panic("shouldn't be reentant??");
400        dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
401        return;
402    } else if (!dmaReadCG->done()) {
403        assert(dmaReadCG->complete() < MAX_DMA_SIZE);
404        ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
405                &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
406        dmaReadBytes += dmaReadCG->size();
407        dmaReadTxs++;
408        if (dmaReadCG->size() == TheISA::PageBytes)
409            dmaReadFullPages++;
410        dmaReadCG->next();
411    } else {
412        assert(dmaReadCG->done());
413        delete dmaReadCG;
414        dmaReadCG = NULL;
415        dmaReadDone();
416    }
417}
418
419void
420IdeDisk::dmaReadDone()
421{
422
423    uint32_t bytesWritten = 0;
424
425
426    // write the data to the disk image
427    for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
428         bytesWritten += SectorSize) {
429
430        cmdBytesLeft -= SectorSize;
431        writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
432    }
433
434    // check for the EOT
435    if (curPrd.getEOT()) {
436        assert(cmdBytesLeft == 0);
437        dmaState = Dma_Idle;
438        updateState(ACT_DMA_DONE);
439    } else {
440        doDmaTransfer();
441    }
442}
443
444void
445IdeDisk::doDmaDataWrite()
446{
447    /** @todo we need to figure out what the delay actually will be */
448    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
449    uint32_t bytesRead = 0;
450
451    DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
452            diskDelay, totalDiskDelay);
453
454    memset(dataBuffer, 0, MAX_DMA_SIZE);
455    assert(cmdBytesLeft <= MAX_DMA_SIZE);
456    while (bytesRead < curPrd.getByteCount()) {
457        readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
458        bytesRead += SectorSize;
459        cmdBytesLeft -= SectorSize;
460    }
461
462    dmaWriteWaitEvent.schedule(curTick + totalDiskDelay);
463}
464
465void
466IdeDisk::doDmaWrite()
467{
468
469    if (!dmaWriteCG) {
470        // clear out the data buffer
471        dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
472                curPrd.getByteCount(), TheISA::PageBytes);
473    }
474    if (ctrl->dmaPending()) {
475        panic("shouldn't be reentant??");
476        dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
477        return;
478    } else if (!dmaWriteCG->done()) {
479        assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
480        ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
481                &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
482        dmaWriteBytes += dmaWriteCG->size();
483        dmaWriteTxs++;
484        if (dmaWriteCG->size() == TheISA::PageBytes)
485            dmaWriteFullPages++;
486        dmaWriteCG->next();
487    } else {
488        assert(dmaWriteCG->done());
489        delete dmaWriteCG;
490        dmaWriteCG = NULL;
491        dmaWriteDone();
492    }
493}
494
495void
496IdeDisk::dmaWriteDone()
497{
498    // check for the EOT
499    if (curPrd.getEOT()) {
500        assert(cmdBytesLeft == 0);
501        dmaState = Dma_Idle;
502        updateState(ACT_DMA_DONE);
503    } else {
504        doDmaTransfer();
505    }
506}
507
508////
509// Disk utility routines
510///
511
512void
513IdeDisk::readDisk(uint32_t sector, uint8_t *data)
514{
515    uint32_t bytesRead = image->read(data, sector);
516
517    if (bytesRead != SectorSize)
518        panic("Can't read from %s. Only %d of %d read. errno=%d\n",
519              name(), bytesRead, SectorSize, errno);
520}
521
522void
523IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
524{
525    uint32_t bytesWritten = image->write(data, sector);
526
527    if (bytesWritten != SectorSize)
528        panic("Can't write to %s. Only %d of %d written. errno=%d\n",
529              name(), bytesWritten, SectorSize, errno);
530}
531
532////
533// Setup and handle commands
534////
535
536void
537IdeDisk::startDma(const uint32_t &prdTableBase)
538{
539    if (dmaState != Dma_Start)
540        panic("Inconsistent DMA state, should be in Dma_Start!\n");
541
542    if (devState != Transfer_Data_Dma)
543        panic("Inconsistent device state for DMA start!\n");
544
545    // PRD base address is given by bits 31:2
546    curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
547
548    dmaState = Dma_Transfer;
549
550    // schedule dma transfer (doDmaTransfer)
551    dmaTransferEvent.schedule(curTick + 1);
552}
553
554void
555IdeDisk::abortDma()
556{
557    if (dmaState == Dma_Idle)
558        panic("Inconsistent DMA state, should be Start or Transfer!");
559
560    if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
561        panic("Inconsistent device state, should be Transfer or Prepare!\n");
562
563    updateState(ACT_CMD_ERROR);
564}
565
566void
567IdeDisk::startCommand()
568{
569    DevAction_t action = ACT_NONE;
570    uint32_t size = 0;
571    dmaRead = false;
572
573    // Decode commands
574    switch (cmdReg.command) {
575        // Supported non-data commands
576      case WDSF_READ_NATIVE_MAX:
577        size = image->size() - 1;
578        cmdReg.sec_num = (size & 0xff);
579        cmdReg.cyl_low = ((size & 0xff00) >> 8);
580        cmdReg.cyl_high = ((size & 0xff0000) >> 16);
581        cmdReg.head = ((size & 0xf000000) >> 24);
582
583        devState = Command_Execution;
584        action = ACT_CMD_COMPLETE;
585        break;
586
587      case WDCC_RECAL:
588      case WDCC_IDP:
589      case WDCC_STANDBY_IMMED:
590      case WDCC_FLUSHCACHE:
591      case WDSF_VERIFY:
592      case WDSF_SEEK:
593      case SET_FEATURES:
594      case WDCC_SETMULTI:
595        devState = Command_Execution;
596        action = ACT_CMD_COMPLETE;
597        break;
598
599        // Supported PIO data-in commands
600      case WDCC_IDENTIFY:
601        cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
602        devState = Prepare_Data_In;
603        action = ACT_DATA_READY;
604        break;
605
606      case WDCC_READMULTI:
607      case WDCC_READ:
608        if (!(cmdReg.drive & DRIVE_LBA_BIT))
609            panic("Attempt to perform CHS access, only supports LBA\n");
610
611        if (cmdReg.sec_count == 0)
612            cmdBytes = cmdBytesLeft = (256 * SectorSize);
613        else
614            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
615
616        curSector = getLBABase();
617
618        /** @todo make this a scheduled event to simulate disk delay */
619        devState = Prepare_Data_In;
620        action = ACT_DATA_READY;
621        break;
622
623        // Supported PIO data-out commands
624      case WDCC_WRITEMULTI:
625      case WDCC_WRITE:
626        if (!(cmdReg.drive & DRIVE_LBA_BIT))
627            panic("Attempt to perform CHS access, only supports LBA\n");
628
629        if (cmdReg.sec_count == 0)
630            cmdBytes = cmdBytesLeft = (256 * SectorSize);
631        else
632            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
633
634        curSector = getLBABase();
635
636        devState = Prepare_Data_Out;
637        action = ACT_DATA_READY;
638        break;
639
640        // Supported DMA commands
641      case WDCC_WRITEDMA:
642        dmaRead = true;  // a write to the disk is a DMA read from memory
643      case WDCC_READDMA:
644        if (!(cmdReg.drive & DRIVE_LBA_BIT))
645            panic("Attempt to perform CHS access, only supports LBA\n");
646
647        if (cmdReg.sec_count == 0)
648            cmdBytes = cmdBytesLeft = (256 * SectorSize);
649        else
650            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
651
652        curSector = getLBABase();
653
654        devState = Prepare_Data_Dma;
655        action = ACT_DMA_READY;
656        break;
657
658      default:
659        panic("Unsupported ATA command: %#x\n", cmdReg.command);
660    }
661
662    if (action != ACT_NONE) {
663        // set the BSY bit
664        status |= STATUS_BSY_BIT;
665        // clear the DRQ bit
666        status &= ~STATUS_DRQ_BIT;
667        // clear the DF bit
668        status &= ~STATUS_DF_BIT;
669
670        updateState(action);
671    }
672}
673
674////
675// Handle setting and clearing interrupts
676////
677
678void
679IdeDisk::intrPost()
680{
681    DPRINTF(IdeDisk, "Posting Interrupt\n");
682    if (intrPending)
683        panic("Attempt to post an interrupt with one pending\n");
684
685    intrPending = true;
686
687    // talk to controller to set interrupt
688    if (ctrl) {
689        ctrl->bmi_regs.bmis0 |= IDEINTS;
690        ctrl->intrPost();
691    }
692}
693
694void
695IdeDisk::intrClear()
696{
697    DPRINTF(IdeDisk, "Clearing Interrupt\n");
698    if (!intrPending)
699        panic("Attempt to clear a non-pending interrupt\n");
700
701    intrPending = false;
702
703    // talk to controller to clear interrupt
704    if (ctrl)
705        ctrl->intrClear();
706}
707
708////
709// Manage the device internal state machine
710////
711
712void
713IdeDisk::updateState(DevAction_t action)
714{
715    switch (devState) {
716      case Device_Srst:
717        if (action == ACT_SRST_SET) {
718            // set the BSY bit
719            status |= STATUS_BSY_BIT;
720        } else if (action == ACT_SRST_CLEAR) {
721            // clear the BSY bit
722            status &= ~STATUS_BSY_BIT;
723
724            // reset the device state
725            reset(devID);
726        }
727        break;
728
729      case Device_Idle_S:
730        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
731            devState = Device_Idle_NS;
732        } else if (action == ACT_CMD_WRITE) {
733            startCommand();
734        }
735
736        break;
737
738      case Device_Idle_SI:
739        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
740            devState = Device_Idle_NS;
741            intrClear();
742        } else if (action == ACT_STAT_READ || isIENSet()) {
743            devState = Device_Idle_S;
744            intrClear();
745        } else if (action == ACT_CMD_WRITE) {
746            intrClear();
747            startCommand();
748        }
749
750        break;
751
752      case Device_Idle_NS:
753        if (action == ACT_SELECT_WRITE && isDEVSelect()) {
754            if (!isIENSet() && intrPending) {
755                devState = Device_Idle_SI;
756                intrPost();
757            }
758            if (isIENSet() || !intrPending) {
759                devState = Device_Idle_S;
760            }
761        }
762        break;
763
764      case Command_Execution:
765        if (action == ACT_CMD_COMPLETE) {
766            // clear the BSY bit
767            setComplete();
768
769            if (!isIENSet()) {
770                devState = Device_Idle_SI;
771                intrPost();
772            } else {
773                devState = Device_Idle_S;
774            }
775        }
776        break;
777
778      case Prepare_Data_In:
779        if (action == ACT_CMD_ERROR) {
780            // clear the BSY bit
781            setComplete();
782
783            if (!isIENSet()) {
784                devState = Device_Idle_SI;
785                intrPost();
786            } else {
787                devState = Device_Idle_S;
788            }
789        } else if (action == ACT_DATA_READY) {
790            // clear the BSY bit
791            status &= ~STATUS_BSY_BIT;
792            // set the DRQ bit
793            status |= STATUS_DRQ_BIT;
794
795            // copy the data into the data buffer
796            if (cmdReg.command == WDCC_IDENTIFY) {
797                // Reset the drqBytes for this block
798                drqBytesLeft = sizeof(struct ataparams);
799
800                memcpy((void *)dataBuffer, (void *)&driveID,
801                       sizeof(struct ataparams));
802            } else {
803                // Reset the drqBytes for this block
804                drqBytesLeft = SectorSize;
805
806                readDisk(curSector++, dataBuffer);
807            }
808
809            // put the first two bytes into the data register
810            memcpy((void *)&cmdReg.data, (void *)dataBuffer,
811                   sizeof(uint16_t));
812
813            if (!isIENSet()) {
814                devState = Data_Ready_INTRQ_In;
815                intrPost();
816            } else {
817                devState = Transfer_Data_In;
818            }
819        }
820        break;
821
822      case Data_Ready_INTRQ_In:
823        if (action == ACT_STAT_READ) {
824            devState = Transfer_Data_In;
825            intrClear();
826        }
827        break;
828
829      case Transfer_Data_In:
830        if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
831            if (action == ACT_DATA_READ_BYTE) {
832                panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
833            } else {
834                drqBytesLeft -= 2;
835                cmdBytesLeft -= 2;
836
837                // copy next short into data registers
838                if (drqBytesLeft)
839                    memcpy((void *)&cmdReg.data,
840                           (void *)&dataBuffer[SectorSize - drqBytesLeft],
841                           sizeof(uint16_t));
842            }
843
844            if (drqBytesLeft == 0) {
845                if (cmdBytesLeft == 0) {
846                    // Clear the BSY bit
847                    setComplete();
848                    devState = Device_Idle_S;
849                } else {
850                    devState = Prepare_Data_In;
851                    // set the BSY_BIT
852                    status |= STATUS_BSY_BIT;
853                    // clear the DRQ_BIT
854                    status &= ~STATUS_DRQ_BIT;
855
856                    /** @todo change this to a scheduled event to simulate
857                        disk delay */
858                    updateState(ACT_DATA_READY);
859                }
860            }
861        }
862        break;
863
864      case Prepare_Data_Out:
865        if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
866            // clear the BSY bit
867            setComplete();
868
869            if (!isIENSet()) {
870                devState = Device_Idle_SI;
871                intrPost();
872            } else {
873                devState = Device_Idle_S;
874            }
875        } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
876            // clear the BSY bit
877            status &= ~STATUS_BSY_BIT;
878            // set the DRQ bit
879            status |= STATUS_DRQ_BIT;
880
881            // clear the data buffer to get it ready for writes
882            memset(dataBuffer, 0, MAX_DMA_SIZE);
883
884            // reset the drqBytes for this block
885            drqBytesLeft = SectorSize;
886
887            if (cmdBytesLeft == cmdBytes || isIENSet()) {
888                devState = Transfer_Data_Out;
889            } else {
890                devState = Data_Ready_INTRQ_Out;
891                intrPost();
892            }
893        }
894        break;
895
896      case Data_Ready_INTRQ_Out:
897        if (action == ACT_STAT_READ) {
898            devState = Transfer_Data_Out;
899            intrClear();
900        }
901        break;
902
903      case Transfer_Data_Out:
904        if (action == ACT_DATA_WRITE_BYTE ||
905            action == ACT_DATA_WRITE_SHORT) {
906
907            if (action == ACT_DATA_READ_BYTE) {
908                panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
909            } else {
910                // copy the latest short into the data buffer
911                memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
912                       (void *)&cmdReg.data,
913                       sizeof(uint16_t));
914
915                drqBytesLeft -= 2;
916                cmdBytesLeft -= 2;
917            }
918
919            if (drqBytesLeft == 0) {
920                // copy the block to the disk
921                writeDisk(curSector++, dataBuffer);
922
923                // set the BSY bit
924                status |= STATUS_BSY_BIT;
925                // set the seek bit
926                status |= STATUS_SEEK_BIT;
927                // clear the DRQ bit
928                status &= ~STATUS_DRQ_BIT;
929
930                devState = Prepare_Data_Out;
931
932                /** @todo change this to a scheduled event to simulate
933                    disk delay */
934                updateState(ACT_DATA_READY);
935            }
936        }
937        break;
938
939      case Prepare_Data_Dma:
940        if (action == ACT_CMD_ERROR) {
941            // clear the BSY bit
942            setComplete();
943
944            if (!isIENSet()) {
945                devState = Device_Idle_SI;
946                intrPost();
947            } else {
948                devState = Device_Idle_S;
949            }
950        } else if (action == ACT_DMA_READY) {
951            // clear the BSY bit
952            status &= ~STATUS_BSY_BIT;
953            // set the DRQ bit
954            status |= STATUS_DRQ_BIT;
955
956            devState = Transfer_Data_Dma;
957
958            if (dmaState != Dma_Idle)
959                panic("Inconsistent DMA state, should be Dma_Idle\n");
960
961            dmaState = Dma_Start;
962            // wait for the write to the DMA start bit
963        }
964        break;
965
966      case Transfer_Data_Dma:
967        if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) {
968            // clear the BSY bit
969            setComplete();
970            // set the seek bit
971            status |= STATUS_SEEK_BIT;
972            // clear the controller state for DMA transfer
973            ctrl->setDmaComplete(this);
974
975            if (!isIENSet()) {
976                devState = Device_Idle_SI;
977                intrPost();
978            } else {
979                devState = Device_Idle_S;
980            }
981        }
982        break;
983
984      default:
985        panic("Unknown IDE device state: %#x\n", devState);
986    }
987}
988
989void
990IdeDisk::serialize(ostream &os)
991{
992    // Check all outstanding events to see if they are scheduled
993    // these are all mutually exclusive
994    Tick reschedule = 0;
995    Events_t event = None;
996
997    int eventCount = 0;
998
999    if (dmaTransferEvent.scheduled()) {
1000        reschedule = dmaTransferEvent.when();
1001        event = Transfer;
1002        eventCount++;
1003    }
1004    if (dmaReadWaitEvent.scheduled()) {
1005        reschedule = dmaReadWaitEvent.when();
1006        event = ReadWait;
1007        eventCount++;
1008    }
1009    if (dmaWriteWaitEvent.scheduled()) {
1010        reschedule = dmaWriteWaitEvent.when();
1011        event = WriteWait;
1012        eventCount++;
1013    }
1014    if (dmaPrdReadEvent.scheduled()) {
1015        reschedule = dmaPrdReadEvent.when();
1016        event = PrdRead;
1017        eventCount++;
1018    }
1019    if (dmaReadEvent.scheduled()) {
1020        reschedule = dmaReadEvent.when();
1021        event = DmaRead;
1022        eventCount++;
1023    }
1024    if (dmaWriteEvent.scheduled()) {
1025        reschedule = dmaWriteEvent.when();
1026        event = DmaWrite;
1027        eventCount++;
1028    }
1029
1030    assert(eventCount <= 1);
1031
1032    SERIALIZE_SCALAR(reschedule);
1033    SERIALIZE_ENUM(event);
1034
1035    // Serialize device registers
1036    SERIALIZE_SCALAR(cmdReg.data);
1037    SERIALIZE_SCALAR(cmdReg.sec_count);
1038    SERIALIZE_SCALAR(cmdReg.sec_num);
1039    SERIALIZE_SCALAR(cmdReg.cyl_low);
1040    SERIALIZE_SCALAR(cmdReg.cyl_high);
1041    SERIALIZE_SCALAR(cmdReg.drive);
1042    SERIALIZE_SCALAR(cmdReg.command);
1043    SERIALIZE_SCALAR(status);
1044    SERIALIZE_SCALAR(nIENBit);
1045    SERIALIZE_SCALAR(devID);
1046
1047    // Serialize the PRD related information
1048    SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1049    SERIALIZE_SCALAR(curPrd.entry.byteCount);
1050    SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1051    SERIALIZE_SCALAR(curPrdAddr);
1052
1053    /** @todo need to serialized chunk generator stuff!! */
1054    // Serialize current transfer related information
1055    SERIALIZE_SCALAR(cmdBytesLeft);
1056    SERIALIZE_SCALAR(cmdBytes);
1057    SERIALIZE_SCALAR(drqBytesLeft);
1058    SERIALIZE_SCALAR(curSector);
1059    SERIALIZE_SCALAR(dmaRead);
1060    SERIALIZE_SCALAR(intrPending);
1061    SERIALIZE_ENUM(devState);
1062    SERIALIZE_ENUM(dmaState);
1063    SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1064}
1065
1066void
1067IdeDisk::unserialize(Checkpoint *cp, const string &section)
1068{
1069    // Reschedule events that were outstanding
1070    // these are all mutually exclusive
1071    Tick reschedule = 0;
1072    Events_t event = None;
1073
1074    UNSERIALIZE_SCALAR(reschedule);
1075    UNSERIALIZE_ENUM(event);
1076
1077    switch (event) {
1078      case None : break;
1079      case Transfer : dmaTransferEvent.schedule(reschedule); break;
1080      case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
1081      case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
1082      case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
1083      case DmaRead : dmaReadEvent.schedule(reschedule); break;
1084      case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
1085    }
1086
1087    // Unserialize device registers
1088    UNSERIALIZE_SCALAR(cmdReg.data);
1089    UNSERIALIZE_SCALAR(cmdReg.sec_count);
1090    UNSERIALIZE_SCALAR(cmdReg.sec_num);
1091    UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1092    UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1093    UNSERIALIZE_SCALAR(cmdReg.drive);
1094    UNSERIALIZE_SCALAR(cmdReg.command);
1095    UNSERIALIZE_SCALAR(status);
1096    UNSERIALIZE_SCALAR(nIENBit);
1097    UNSERIALIZE_SCALAR(devID);
1098
1099    // Unserialize the PRD related information
1100    UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1101    UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1102    UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1103    UNSERIALIZE_SCALAR(curPrdAddr);
1104
1105    /** @todo need to serialized chunk generator stuff!! */
1106    // Unserialize current transfer related information
1107    UNSERIALIZE_SCALAR(cmdBytes);
1108    UNSERIALIZE_SCALAR(cmdBytesLeft);
1109    UNSERIALIZE_SCALAR(drqBytesLeft);
1110    UNSERIALIZE_SCALAR(curSector);
1111    UNSERIALIZE_SCALAR(dmaRead);
1112    UNSERIALIZE_SCALAR(intrPending);
1113    UNSERIALIZE_ENUM(devState);
1114    UNSERIALIZE_ENUM(dmaState);
1115    UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1116}
1117
1118#ifndef DOXYGEN_SHOULD_SKIP_THIS
1119
1120enum DriveID { master, slave };
1121static const char *DriveID_strings[] = { "master", "slave" };
1122BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
1123
1124    SimObjectParam<DiskImage *> image;
1125    SimpleEnumParam<DriveID> driveID;
1126    Param<int> delay;
1127
1128END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
1129
1130BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
1131
1132    INIT_PARAM(image, "Disk image"),
1133    INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings),
1134    INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1)
1135
1136END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
1137
1138
1139CREATE_SIM_OBJECT(IdeDisk)
1140{
1141    return new IdeDisk(getInstanceName(), image, driveID, delay);
1142}
1143
1144REGISTER_SIM_OBJECT("IdeDisk", IdeDisk)
1145
1146#endif //DOXYGEN_SHOULD_SKIP_THIS
1147