ide_disk.cc revision 11101
1/*
2 * Copyright (c) 2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Andrew Schultz
41 *          Ali Saidi
42 */
43
44/** @file
45 * Device model implementation for an IDE disk
46 */
47
48#include <cerrno>
49#include <cstring>
50#include <deque>
51#include <string>
52
53#include "arch/isa_traits.hh"
54#include "base/chunk_generator.hh"
55#include "base/cprintf.hh" // csprintf
56#include "base/trace.hh"
57#include "config/the_isa.hh"
58#include "debug/IdeDisk.hh"
59#include "dev/disk_image.hh"
60#include "dev/ide_ctrl.hh"
61#include "dev/ide_disk.hh"
62#include "sim/core.hh"
63#include "sim/sim_object.hh"
64
65using namespace std;
66using namespace TheISA;
67
68IdeDisk::IdeDisk(const Params *p)
69    : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),
70      dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
71      dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
72      dmaReadEvent(this), dmaWriteEvent(this)
73{
74    // Reset the device state
75    reset(p->driveID);
76
77    // fill out the drive ID structure
78    memset(&driveID, 0, sizeof(struct ataparams));
79
80    // Calculate LBA and C/H/S values
81    uint16_t cylinders;
82    uint8_t heads;
83    uint8_t sectors;
84
85    uint32_t lba_size = image->size();
86    if (lba_size >= 16383*16*63) {
87        cylinders = 16383;
88        heads = 16;
89        sectors = 63;
90    } else {
91        if (lba_size >= 63)
92            sectors = 63;
93        else if (lba_size == 0)
94            panic("Bad IDE image size: 0\n");
95        else
96            sectors = lba_size;
97
98        if ((lba_size / sectors) >= 16)
99            heads = 16;
100        else
101            heads = (lba_size / sectors);
102
103        cylinders = lba_size / (heads * sectors);
104    }
105
106    // Setup the model name
107    strncpy((char *)driveID.atap_model, "5MI EDD si k",
108            sizeof(driveID.atap_model));
109    // Set the maximum multisector transfer size
110    driveID.atap_multi = MAX_MULTSECT;
111    // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
112    driveID.atap_capabilities1 = 0x7;
113    // UDMA support, EIDE support
114    driveID.atap_extensions = 0x6;
115    // Setup default C/H/S settings
116    driveID.atap_cylinders = cylinders;
117    driveID.atap_sectors = sectors;
118    driveID.atap_heads = heads;
119    // Setup the current multisector transfer size
120    driveID.atap_curmulti = MAX_MULTSECT;
121    driveID.atap_curmulti_valid = 0x1;
122    // Number of sectors on disk
123    driveID.atap_capacity = lba_size;
124    // Multiword DMA mode 2 and below supported
125    driveID.atap_dmamode_supp = 0x4;
126    // Set PIO mode 4 and 3 supported
127    driveID.atap_piomode_supp = 0x3;
128    // Set DMA mode 4 and below supported
129    driveID.atap_udmamode_supp = 0x1f;
130    // Statically set hardware config word
131    driveID.atap_hwreset_res = 0x4001;
132
133    //arbitrary for now...
134    driveID.atap_ata_major = WDC_VER_ATA7;
135}
136
137IdeDisk::~IdeDisk()
138{
139    // destroy the data buffer
140    delete [] dataBuffer;
141}
142
143void
144IdeDisk::reset(int id)
145{
146    // initialize the data buffer and shadow registers
147    dataBuffer = new uint8_t[MAX_DMA_SIZE];
148
149    memset(dataBuffer, 0, MAX_DMA_SIZE);
150    memset(&cmdReg, 0, sizeof(CommandReg_t));
151    memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
152
153    curPrdAddr = 0;
154    curSector = 0;
155    cmdBytes = 0;
156    cmdBytesLeft = 0;
157    drqBytesLeft = 0;
158    dmaRead = false;
159    intrPending = false;
160    dmaAborted = false;
161
162    // set the device state to idle
163    dmaState = Dma_Idle;
164
165    if (id == DEV0) {
166        devState = Device_Idle_S;
167        devID = DEV0;
168    } else if (id == DEV1) {
169        devState = Device_Idle_NS;
170        devID = DEV1;
171    } else {
172        panic("Invalid device ID: %#x\n", id);
173    }
174
175    // set the device ready bit
176    status = STATUS_DRDY_BIT;
177
178    /* The error register must be set to 0x1 on start-up to
179       indicate that no diagnostic error was detected */
180    cmdReg.error = 0x1;
181}
182
183////
184// Utility functions
185////
186
187bool
188IdeDisk::isDEVSelect()
189{
190    return ctrl->isDiskSelected(this);
191}
192
193Addr
194IdeDisk::pciToDma(Addr pciAddr)
195{
196    if (ctrl)
197        return ctrl->pciToDma(pciAddr);
198    else
199        panic("Access to unset controller!\n");
200}
201
202////
203// Device registers read/write
204////
205
206void
207IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
208{
209    if (offset == DATA_OFFSET) {
210        if (size == sizeof(uint16_t)) {
211            *(uint16_t *)data = cmdReg.data;
212        } else if (size == sizeof(uint32_t)) {
213            *(uint16_t *)data = cmdReg.data;
214            updateState(ACT_DATA_READ_SHORT);
215            *((uint16_t *)data + 1) = cmdReg.data;
216        } else {
217            panic("Data read of unsupported size %d.\n", size);
218        }
219        updateState(ACT_DATA_READ_SHORT);
220        return;
221    }
222    assert(size == sizeof(uint8_t));
223    switch (offset) {
224      case ERROR_OFFSET:
225        *data = cmdReg.error;
226        break;
227      case NSECTOR_OFFSET:
228        *data = cmdReg.sec_count;
229        break;
230      case SECTOR_OFFSET:
231        *data = cmdReg.sec_num;
232        break;
233      case LCYL_OFFSET:
234        *data = cmdReg.cyl_low;
235        break;
236      case HCYL_OFFSET:
237        *data = cmdReg.cyl_high;
238        break;
239      case DRIVE_OFFSET:
240        *data = cmdReg.drive;
241        break;
242      case STATUS_OFFSET:
243        *data = status;
244        updateState(ACT_STAT_READ);
245        break;
246      default:
247        panic("Invalid IDE command register offset: %#x\n", offset);
248    }
249    DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
250}
251
252void
253IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
254{
255    assert(size == sizeof(uint8_t));
256    *data = status;
257    if (offset != ALTSTAT_OFFSET)
258        panic("Invalid IDE control register offset: %#x\n", offset);
259    DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
260}
261
262void
263IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
264{
265    if (offset == DATA_OFFSET) {
266        if (size == sizeof(uint16_t)) {
267            cmdReg.data = *(const uint16_t *)data;
268        } else if (size == sizeof(uint32_t)) {
269            cmdReg.data = *(const uint16_t *)data;
270            updateState(ACT_DATA_WRITE_SHORT);
271            cmdReg.data = *((const uint16_t *)data + 1);
272        } else {
273            panic("Data write of unsupported size %d.\n", size);
274        }
275        updateState(ACT_DATA_WRITE_SHORT);
276        return;
277    }
278
279    assert(size == sizeof(uint8_t));
280    switch (offset) {
281      case FEATURES_OFFSET:
282        break;
283      case NSECTOR_OFFSET:
284        cmdReg.sec_count = *data;
285        break;
286      case SECTOR_OFFSET:
287        cmdReg.sec_num = *data;
288        break;
289      case LCYL_OFFSET:
290        cmdReg.cyl_low = *data;
291        break;
292      case HCYL_OFFSET:
293        cmdReg.cyl_high = *data;
294        break;
295      case DRIVE_OFFSET:
296        cmdReg.drive = *data;
297        updateState(ACT_SELECT_WRITE);
298        break;
299      case COMMAND_OFFSET:
300        cmdReg.command = *data;
301        updateState(ACT_CMD_WRITE);
302        break;
303      default:
304        panic("Invalid IDE command register offset: %#x\n", offset);
305    }
306    DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
307            (uint32_t)*data);
308}
309
310void
311IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
312{
313    if (offset != CONTROL_OFFSET)
314        panic("Invalid IDE control register offset: %#x\n", offset);
315
316    if (*data & CONTROL_RST_BIT) {
317        // force the device into the reset state
318        devState = Device_Srst;
319        updateState(ACT_SRST_SET);
320    } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
321        updateState(ACT_SRST_CLEAR);
322    }
323
324    nIENBit = *data & CONTROL_IEN_BIT;
325
326    DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
327            (uint32_t)*data);
328}
329
330////
331// Perform DMA transactions
332////
333
334void
335IdeDisk::doDmaTransfer()
336{
337    if (dmaAborted) {
338        DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
339        updateState(ACT_CMD_ERROR);
340        return;
341    }
342
343    if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
344        panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
345              dmaState, devState);
346
347    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
348        schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
349        return;
350    } else
351        ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
352                (uint8_t*)&curPrd.entry);
353}
354
355void
356IdeDisk::dmaPrdReadDone()
357{
358    if (dmaAborted) {
359        DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
360        updateState(ACT_CMD_ERROR);
361        return;
362    }
363
364    DPRINTF(IdeDisk,
365            "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
366            curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
367            curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
368            curPrd.getEOT(), curSector);
369
370    // the prd pointer has already been translated, so just do an increment
371    curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
372
373    if (dmaRead)
374        doDmaDataRead();
375    else
376        doDmaDataWrite();
377}
378
379void
380IdeDisk::doDmaDataRead()
381{
382    /** @todo we need to figure out what the delay actually will be */
383    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
384
385    DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
386            diskDelay, totalDiskDelay);
387
388    schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
389}
390
391void
392IdeDisk::regStats()
393{
394    using namespace Stats;
395    dmaReadFullPages
396        .name(name() + ".dma_read_full_pages")
397        .desc("Number of full page size DMA reads (not PRD).")
398        ;
399    dmaReadBytes
400        .name(name() + ".dma_read_bytes")
401        .desc("Number of bytes transfered via DMA reads (not PRD).")
402        ;
403    dmaReadTxs
404        .name(name() + ".dma_read_txs")
405        .desc("Number of DMA read transactions (not PRD).")
406        ;
407
408    dmaWriteFullPages
409        .name(name() + ".dma_write_full_pages")
410        .desc("Number of full page size DMA writes.")
411        ;
412    dmaWriteBytes
413        .name(name() + ".dma_write_bytes")
414        .desc("Number of bytes transfered via DMA writes.")
415        ;
416    dmaWriteTxs
417        .name(name() + ".dma_write_txs")
418        .desc("Number of DMA write transactions.")
419        ;
420}
421
422void
423IdeDisk::doDmaRead()
424{
425    if (dmaAborted) {
426        DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
427        if (dmaReadCG)
428            delete dmaReadCG;
429        dmaReadCG = NULL;
430        updateState(ACT_CMD_ERROR);
431        return;
432    }
433
434    if (!dmaReadCG) {
435        // clear out the data buffer
436        memset(dataBuffer, 0, MAX_DMA_SIZE);
437        dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
438                curPrd.getByteCount(), TheISA::PageBytes);
439
440    }
441    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
442        schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
443        return;
444    } else if (!dmaReadCG->done()) {
445        assert(dmaReadCG->complete() < MAX_DMA_SIZE);
446        ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
447                &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
448        dmaReadBytes += dmaReadCG->size();
449        dmaReadTxs++;
450        if (dmaReadCG->size() == TheISA::PageBytes)
451            dmaReadFullPages++;
452        dmaReadCG->next();
453    } else {
454        assert(dmaReadCG->done());
455        delete dmaReadCG;
456        dmaReadCG = NULL;
457        dmaReadDone();
458    }
459}
460
461void
462IdeDisk::dmaReadDone()
463{
464    uint32_t bytesWritten = 0;
465
466    // write the data to the disk image
467    for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
468         bytesWritten += SectorSize) {
469
470        cmdBytesLeft -= SectorSize;
471        writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
472    }
473
474    // check for the EOT
475    if (curPrd.getEOT()) {
476        assert(cmdBytesLeft == 0);
477        dmaState = Dma_Idle;
478        updateState(ACT_DMA_DONE);
479    } else {
480        doDmaTransfer();
481    }
482}
483
484void
485IdeDisk::doDmaDataWrite()
486{
487    /** @todo we need to figure out what the delay actually will be */
488    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
489    uint32_t bytesRead = 0;
490
491    DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
492            diskDelay, totalDiskDelay);
493
494    memset(dataBuffer, 0, MAX_DMA_SIZE);
495    assert(cmdBytesLeft <= MAX_DMA_SIZE);
496    while (bytesRead < curPrd.getByteCount()) {
497        readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
498        bytesRead += SectorSize;
499        cmdBytesLeft -= SectorSize;
500    }
501    DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
502            bytesRead, cmdBytesLeft);
503
504    schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
505}
506
507void
508IdeDisk::doDmaWrite()
509{
510    if (dmaAborted) {
511        DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
512        if (dmaWriteCG)
513            delete dmaWriteCG;
514        dmaWriteCG = NULL;
515        updateState(ACT_CMD_ERROR);
516        return;
517    }
518    if (!dmaWriteCG) {
519        // clear out the data buffer
520        dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
521                curPrd.getByteCount(), TheISA::PageBytes);
522    }
523    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
524        schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
525        DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
526        return;
527    } else if (!dmaWriteCG->done()) {
528        assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
529        ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
530                &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
531        DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
532                curPrd.getByteCount(), curPrd.getEOT());
533        dmaWriteBytes += dmaWriteCG->size();
534        dmaWriteTxs++;
535        if (dmaWriteCG->size() == TheISA::PageBytes)
536            dmaWriteFullPages++;
537        dmaWriteCG->next();
538    } else {
539        DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
540                curPrd.getByteCount(), curPrd.getEOT());
541        assert(dmaWriteCG->done());
542        delete dmaWriteCG;
543        dmaWriteCG = NULL;
544        dmaWriteDone();
545    }
546}
547
548void
549IdeDisk::dmaWriteDone()
550{
551    DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
552                curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft);
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    schedule(dmaTransferEvent, 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 WDSF_READ_NATIVE_MAX:
632        size = (uint32_t)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 WDCC_RECAL:
643      case WDCC_IDP:
644      case WDCC_STANDBY_IMMED:
645      case WDCC_FLUSHCACHE:
646      case WDSF_VERIFY:
647      case WDSF_SEEK:
648      case SET_FEATURES:
649      case WDCC_SETMULTI:
650      case WDCC_IDLE:
651        devState = Command_Execution;
652        action = ACT_CMD_COMPLETE;
653        break;
654
655        // Supported PIO data-in commands
656      case WDCC_IDENTIFY:
657        cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
658        devState = Prepare_Data_In;
659        action = ACT_DATA_READY;
660        break;
661
662      case WDCC_READMULTI:
663      case WDCC_READ:
664        if (!(cmdReg.drive & DRIVE_LBA_BIT))
665            panic("Attempt to perform CHS access, only supports LBA\n");
666
667        if (cmdReg.sec_count == 0)
668            cmdBytes = cmdBytesLeft = (256 * SectorSize);
669        else
670            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
671
672        curSector = getLBABase();
673
674        /** @todo make this a scheduled event to simulate disk delay */
675        devState = Prepare_Data_In;
676        action = ACT_DATA_READY;
677        break;
678
679        // Supported PIO data-out commands
680      case WDCC_WRITEMULTI:
681      case WDCC_WRITE:
682        if (!(cmdReg.drive & DRIVE_LBA_BIT))
683            panic("Attempt to perform CHS access, only supports LBA\n");
684
685        if (cmdReg.sec_count == 0)
686            cmdBytes = cmdBytesLeft = (256 * SectorSize);
687        else
688            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
689        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
690        curSector = getLBABase();
691
692        devState = Prepare_Data_Out;
693        action = ACT_DATA_READY;
694        break;
695
696        // Supported DMA commands
697      case WDCC_WRITEDMA:
698        dmaRead = true;  // a write to the disk is a DMA read from memory
699      case WDCC_READDMA:
700        if (!(cmdReg.drive & DRIVE_LBA_BIT))
701            panic("Attempt to perform CHS access, only supports LBA\n");
702
703        if (cmdReg.sec_count == 0)
704            cmdBytes = cmdBytesLeft = (256 * SectorSize);
705        else
706            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
707        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
708
709        curSector = getLBABase();
710
711        devState = Prepare_Data_Dma;
712        action = ACT_DMA_READY;
713        break;
714
715      default:
716        panic("Unsupported ATA command: %#x\n", cmdReg.command);
717    }
718
719    if (action != ACT_NONE) {
720        // set the BSY bit
721        status |= STATUS_BSY_BIT;
722        // clear the DRQ bit
723        status &= ~STATUS_DRQ_BIT;
724        // clear the DF bit
725        status &= ~STATUS_DF_BIT;
726
727        updateState(action);
728    }
729}
730
731////
732// Handle setting and clearing interrupts
733////
734
735void
736IdeDisk::intrPost()
737{
738    DPRINTF(IdeDisk, "Posting Interrupt\n");
739    if (intrPending)
740        panic("Attempt to post an interrupt with one pending\n");
741
742    intrPending = true;
743
744    // talk to controller to set interrupt
745    if (ctrl) {
746        ctrl->intrPost();
747    }
748}
749
750void
751IdeDisk::intrClear()
752{
753    DPRINTF(IdeDisk, "Clearing Interrupt\n");
754    if (!intrPending)
755        panic("Attempt to clear a non-pending interrupt\n");
756
757    intrPending = false;
758
759    // talk to controller to clear interrupt
760    if (ctrl)
761        ctrl->intrClear();
762}
763
764////
765// Manage the device internal state machine
766////
767
768void
769IdeDisk::updateState(DevAction_t action)
770{
771    switch (devState) {
772      case Device_Srst:
773        if (action == ACT_SRST_SET) {
774            // set the BSY bit
775            status |= STATUS_BSY_BIT;
776        } else if (action == ACT_SRST_CLEAR) {
777            // clear the BSY bit
778            status &= ~STATUS_BSY_BIT;
779
780            // reset the device state
781            reset(devID);
782        }
783        break;
784
785      case Device_Idle_S:
786        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
787            devState = Device_Idle_NS;
788        } else if (action == ACT_CMD_WRITE) {
789            startCommand();
790        }
791
792        break;
793
794      case Device_Idle_SI:
795        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
796            devState = Device_Idle_NS;
797            intrClear();
798        } else if (action == ACT_STAT_READ || isIENSet()) {
799            devState = Device_Idle_S;
800            intrClear();
801        } else if (action == ACT_CMD_WRITE) {
802            intrClear();
803            startCommand();
804        }
805
806        break;
807
808      case Device_Idle_NS:
809        if (action == ACT_SELECT_WRITE && isDEVSelect()) {
810            if (!isIENSet() && intrPending) {
811                devState = Device_Idle_SI;
812                intrPost();
813            }
814            if (isIENSet() || !intrPending) {
815                devState = Device_Idle_S;
816            }
817        }
818        break;
819
820      case Command_Execution:
821        if (action == ACT_CMD_COMPLETE) {
822            // clear the BSY bit
823            setComplete();
824
825            if (!isIENSet()) {
826                devState = Device_Idle_SI;
827                intrPost();
828            } else {
829                devState = Device_Idle_S;
830            }
831        }
832        break;
833
834      case Prepare_Data_In:
835        if (action == ACT_CMD_ERROR) {
836            // clear the BSY bit
837            setComplete();
838
839            if (!isIENSet()) {
840                devState = Device_Idle_SI;
841                intrPost();
842            } else {
843                devState = Device_Idle_S;
844            }
845        } else if (action == ACT_DATA_READY) {
846            // clear the BSY bit
847            status &= ~STATUS_BSY_BIT;
848            // set the DRQ bit
849            status |= STATUS_DRQ_BIT;
850
851            // copy the data into the data buffer
852            if (cmdReg.command == WDCC_IDENTIFY) {
853                // Reset the drqBytes for this block
854                drqBytesLeft = sizeof(struct ataparams);
855
856                memcpy((void *)dataBuffer, (void *)&driveID,
857                       sizeof(struct ataparams));
858            } else {
859                // Reset the drqBytes for this block
860                drqBytesLeft = SectorSize;
861
862                readDisk(curSector++, dataBuffer);
863            }
864
865            // put the first two bytes into the data register
866            memcpy((void *)&cmdReg.data, (void *)dataBuffer,
867                   sizeof(uint16_t));
868
869            if (!isIENSet()) {
870                devState = Data_Ready_INTRQ_In;
871                intrPost();
872            } else {
873                devState = Transfer_Data_In;
874            }
875        }
876        break;
877
878      case Data_Ready_INTRQ_In:
879        if (action == ACT_STAT_READ) {
880            devState = Transfer_Data_In;
881            intrClear();
882        }
883        break;
884
885      case Transfer_Data_In:
886        if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
887            if (action == ACT_DATA_READ_BYTE) {
888                panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
889            } else {
890                drqBytesLeft -= 2;
891                cmdBytesLeft -= 2;
892
893                // copy next short into data registers
894                if (drqBytesLeft)
895                    memcpy((void *)&cmdReg.data,
896                           (void *)&dataBuffer[SectorSize - drqBytesLeft],
897                           sizeof(uint16_t));
898            }
899
900            if (drqBytesLeft == 0) {
901                if (cmdBytesLeft == 0) {
902                    // Clear the BSY bit
903                    setComplete();
904                    devState = Device_Idle_S;
905                } else {
906                    devState = Prepare_Data_In;
907                    // set the BSY_BIT
908                    status |= STATUS_BSY_BIT;
909                    // clear the DRQ_BIT
910                    status &= ~STATUS_DRQ_BIT;
911
912                    /** @todo change this to a scheduled event to simulate
913                        disk delay */
914                    updateState(ACT_DATA_READY);
915                }
916            }
917        }
918        break;
919
920      case Prepare_Data_Out:
921        if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
922            // clear the BSY bit
923            setComplete();
924
925            if (!isIENSet()) {
926                devState = Device_Idle_SI;
927                intrPost();
928            } else {
929                devState = Device_Idle_S;
930            }
931        } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
932            // clear the BSY bit
933            status &= ~STATUS_BSY_BIT;
934            // set the DRQ bit
935            status |= STATUS_DRQ_BIT;
936
937            // clear the data buffer to get it ready for writes
938            memset(dataBuffer, 0, MAX_DMA_SIZE);
939
940            // reset the drqBytes for this block
941            drqBytesLeft = SectorSize;
942
943            if (cmdBytesLeft == cmdBytes || isIENSet()) {
944                devState = Transfer_Data_Out;
945            } else {
946                devState = Data_Ready_INTRQ_Out;
947                intrPost();
948            }
949        }
950        break;
951
952      case Data_Ready_INTRQ_Out:
953        if (action == ACT_STAT_READ) {
954            devState = Transfer_Data_Out;
955            intrClear();
956        }
957        break;
958
959      case Transfer_Data_Out:
960        if (action == ACT_DATA_WRITE_BYTE ||
961            action == ACT_DATA_WRITE_SHORT) {
962
963            if (action == ACT_DATA_READ_BYTE) {
964                panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
965            } else {
966                // copy the latest short into the data buffer
967                memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
968                       (void *)&cmdReg.data,
969                       sizeof(uint16_t));
970
971                drqBytesLeft -= 2;
972                cmdBytesLeft -= 2;
973            }
974
975            if (drqBytesLeft == 0) {
976                // copy the block to the disk
977                writeDisk(curSector++, dataBuffer);
978
979                // set the BSY bit
980                status |= STATUS_BSY_BIT;
981                // set the seek bit
982                status |= STATUS_SEEK_BIT;
983                // clear the DRQ bit
984                status &= ~STATUS_DRQ_BIT;
985
986                devState = Prepare_Data_Out;
987
988                /** @todo change this to a scheduled event to simulate
989                    disk delay */
990                updateState(ACT_DATA_READY);
991            }
992        }
993        break;
994
995      case Prepare_Data_Dma:
996        if (action == ACT_CMD_ERROR) {
997            // clear the BSY bit
998            setComplete();
999
1000            if (!isIENSet()) {
1001                devState = Device_Idle_SI;
1002                intrPost();
1003            } else {
1004                devState = Device_Idle_S;
1005            }
1006        } else if (action == ACT_DMA_READY) {
1007            // clear the BSY bit
1008            status &= ~STATUS_BSY_BIT;
1009            // set the DRQ bit
1010            status |= STATUS_DRQ_BIT;
1011
1012            devState = Transfer_Data_Dma;
1013
1014            if (dmaState != Dma_Idle)
1015                panic("Inconsistent DMA state, should be Dma_Idle\n");
1016
1017            dmaState = Dma_Start;
1018            // wait for the write to the DMA start bit
1019        }
1020        break;
1021
1022      case Transfer_Data_Dma:
1023        if (action == ACT_CMD_ERROR) {
1024            dmaAborted = true;
1025            devState = Device_Dma_Abort;
1026        } else if (action == ACT_DMA_DONE) {
1027            // clear the BSY bit
1028            setComplete();
1029            // set the seek bit
1030            status |= STATUS_SEEK_BIT;
1031            // clear the controller state for DMA transfer
1032            ctrl->setDmaComplete(this);
1033
1034            if (!isIENSet()) {
1035                devState = Device_Idle_SI;
1036                intrPost();
1037            } else {
1038                devState = Device_Idle_S;
1039            }
1040        }
1041        break;
1042
1043      case Device_Dma_Abort:
1044        if (action == ACT_CMD_ERROR) {
1045            setComplete();
1046            status |= STATUS_SEEK_BIT;
1047            ctrl->setDmaComplete(this);
1048            dmaAborted = false;
1049            dmaState = Dma_Idle;
1050
1051            if (!isIENSet()) {
1052                devState = Device_Idle_SI;
1053                intrPost();
1054            } else {
1055                devState = Device_Idle_S;
1056            }
1057        } else {
1058            DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1059        }
1060        break;
1061
1062      default:
1063        panic("Unknown IDE device state: %#x\n", devState);
1064    }
1065}
1066
1067void
1068IdeDisk::serialize(CheckpointOut &cp) const
1069{
1070    // Check all outstanding events to see if they are scheduled
1071    // these are all mutually exclusive
1072    Tick reschedule = 0;
1073    Events_t event = None;
1074
1075    int eventCount = 0;
1076
1077    if (dmaTransferEvent.scheduled()) {
1078        reschedule = dmaTransferEvent.when();
1079        event = Transfer;
1080        eventCount++;
1081    }
1082    if (dmaReadWaitEvent.scheduled()) {
1083        reschedule = dmaReadWaitEvent.when();
1084        event = ReadWait;
1085        eventCount++;
1086    }
1087    if (dmaWriteWaitEvent.scheduled()) {
1088        reschedule = dmaWriteWaitEvent.when();
1089        event = WriteWait;
1090        eventCount++;
1091    }
1092    if (dmaPrdReadEvent.scheduled()) {
1093        reschedule = dmaPrdReadEvent.when();
1094        event = PrdRead;
1095        eventCount++;
1096    }
1097    if (dmaReadEvent.scheduled()) {
1098        reschedule = dmaReadEvent.when();
1099        event = DmaRead;
1100        eventCount++;
1101    }
1102    if (dmaWriteEvent.scheduled()) {
1103        reschedule = dmaWriteEvent.when();
1104        event = DmaWrite;
1105        eventCount++;
1106    }
1107
1108    assert(eventCount <= 1);
1109
1110    SERIALIZE_SCALAR(reschedule);
1111    SERIALIZE_ENUM(event);
1112
1113    // Serialize device registers
1114    SERIALIZE_SCALAR(cmdReg.data);
1115    SERIALIZE_SCALAR(cmdReg.sec_count);
1116    SERIALIZE_SCALAR(cmdReg.sec_num);
1117    SERIALIZE_SCALAR(cmdReg.cyl_low);
1118    SERIALIZE_SCALAR(cmdReg.cyl_high);
1119    SERIALIZE_SCALAR(cmdReg.drive);
1120    SERIALIZE_SCALAR(cmdReg.command);
1121    SERIALIZE_SCALAR(status);
1122    SERIALIZE_SCALAR(nIENBit);
1123    SERIALIZE_SCALAR(devID);
1124
1125    // Serialize the PRD related information
1126    SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1127    SERIALIZE_SCALAR(curPrd.entry.byteCount);
1128    SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1129    SERIALIZE_SCALAR(curPrdAddr);
1130
1131    /** @todo need to serialized chunk generator stuff!! */
1132    // Serialize current transfer related information
1133    SERIALIZE_SCALAR(cmdBytesLeft);
1134    SERIALIZE_SCALAR(cmdBytes);
1135    SERIALIZE_SCALAR(drqBytesLeft);
1136    SERIALIZE_SCALAR(curSector);
1137    SERIALIZE_SCALAR(dmaRead);
1138    SERIALIZE_SCALAR(intrPending);
1139    SERIALIZE_SCALAR(dmaAborted);
1140    SERIALIZE_ENUM(devState);
1141    SERIALIZE_ENUM(dmaState);
1142    SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1143}
1144
1145void
1146IdeDisk::unserialize(CheckpointIn &cp)
1147{
1148    // Reschedule events that were outstanding
1149    // these are all mutually exclusive
1150    Tick reschedule = 0;
1151    Events_t event = None;
1152
1153    UNSERIALIZE_SCALAR(reschedule);
1154    UNSERIALIZE_ENUM(event);
1155
1156    switch (event) {
1157      case None : break;
1158      case Transfer : schedule(dmaTransferEvent, reschedule); break;
1159      case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
1160      case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
1161      case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
1162      case DmaRead : schedule(dmaReadEvent, reschedule); break;
1163      case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1164    }
1165
1166    // Unserialize device registers
1167    UNSERIALIZE_SCALAR(cmdReg.data);
1168    UNSERIALIZE_SCALAR(cmdReg.sec_count);
1169    UNSERIALIZE_SCALAR(cmdReg.sec_num);
1170    UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1171    UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1172    UNSERIALIZE_SCALAR(cmdReg.drive);
1173    UNSERIALIZE_SCALAR(cmdReg.command);
1174    UNSERIALIZE_SCALAR(status);
1175    UNSERIALIZE_SCALAR(nIENBit);
1176    UNSERIALIZE_SCALAR(devID);
1177
1178    // Unserialize the PRD related information
1179    UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1180    UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1181    UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1182    UNSERIALIZE_SCALAR(curPrdAddr);
1183
1184    /** @todo need to serialized chunk generator stuff!! */
1185    // Unserialize current transfer related information
1186    UNSERIALIZE_SCALAR(cmdBytes);
1187    UNSERIALIZE_SCALAR(cmdBytesLeft);
1188    UNSERIALIZE_SCALAR(drqBytesLeft);
1189    UNSERIALIZE_SCALAR(curSector);
1190    UNSERIALIZE_SCALAR(dmaRead);
1191    UNSERIALIZE_SCALAR(intrPending);
1192    UNSERIALIZE_SCALAR(dmaAborted);
1193    UNSERIALIZE_ENUM(devState);
1194    UNSERIALIZE_ENUM(dmaState);
1195    UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1196}
1197
1198IdeDisk *
1199IdeDiskParams::create()
1200{
1201    return new IdeDisk(this);
1202}
1203