ide_disk.cc revision 10913
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
94            sectors = lba_size;
95
96        if ((lba_size / sectors) >= 16)
97            heads = 16;
98        else
99            heads = (lba_size / sectors);
100
101        cylinders = lba_size / (heads * sectors);
102    }
103
104    // Setup the model name
105    strncpy((char *)driveID.atap_model, "5MI EDD si k",
106            sizeof(driveID.atap_model));
107    // Set the maximum multisector transfer size
108    driveID.atap_multi = MAX_MULTSECT;
109    // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
110    driveID.atap_capabilities1 = 0x7;
111    // UDMA support, EIDE support
112    driveID.atap_extensions = 0x6;
113    // Setup default C/H/S settings
114    driveID.atap_cylinders = cylinders;
115    driveID.atap_sectors = sectors;
116    driveID.atap_heads = heads;
117    // Setup the current multisector transfer size
118    driveID.atap_curmulti = MAX_MULTSECT;
119    driveID.atap_curmulti_valid = 0x1;
120    // Number of sectors on disk
121    driveID.atap_capacity = lba_size;
122    // Multiword DMA mode 2 and below supported
123    driveID.atap_dmamode_supp = 0x4;
124    // Set PIO mode 4 and 3 supported
125    driveID.atap_piomode_supp = 0x3;
126    // Set DMA mode 4 and below supported
127    driveID.atap_udmamode_supp = 0x1f;
128    // Statically set hardware config word
129    driveID.atap_hwreset_res = 0x4001;
130
131    //arbitrary for now...
132    driveID.atap_ata_major = WDC_VER_ATA7;
133}
134
135IdeDisk::~IdeDisk()
136{
137    // destroy the data buffer
138    delete [] dataBuffer;
139}
140
141void
142IdeDisk::reset(int id)
143{
144    // initialize the data buffer and shadow registers
145    dataBuffer = new uint8_t[MAX_DMA_SIZE];
146
147    memset(dataBuffer, 0, MAX_DMA_SIZE);
148    memset(&cmdReg, 0, sizeof(CommandReg_t));
149    memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
150
151    curPrdAddr = 0;
152    curSector = 0;
153    cmdBytes = 0;
154    cmdBytesLeft = 0;
155    drqBytesLeft = 0;
156    dmaRead = false;
157    intrPending = false;
158    dmaAborted = false;
159
160    // set the device state to idle
161    dmaState = Dma_Idle;
162
163    if (id == DEV0) {
164        devState = Device_Idle_S;
165        devID = DEV0;
166    } else if (id == DEV1) {
167        devState = Device_Idle_NS;
168        devID = DEV1;
169    } else {
170        panic("Invalid device ID: %#x\n", id);
171    }
172
173    // set the device ready bit
174    status = STATUS_DRDY_BIT;
175
176    /* The error register must be set to 0x1 on start-up to
177       indicate that no diagnostic error was detected */
178    cmdReg.error = 0x1;
179}
180
181////
182// Utility functions
183////
184
185bool
186IdeDisk::isDEVSelect()
187{
188    return ctrl->isDiskSelected(this);
189}
190
191Addr
192IdeDisk::pciToDma(Addr pciAddr)
193{
194    if (ctrl)
195        return ctrl->pciToDma(pciAddr);
196    else
197        panic("Access to unset controller!\n");
198}
199
200////
201// Device registers read/write
202////
203
204void
205IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
206{
207    if (offset == DATA_OFFSET) {
208        if (size == sizeof(uint16_t)) {
209            *(uint16_t *)data = cmdReg.data;
210        } else if (size == sizeof(uint32_t)) {
211            *(uint16_t *)data = cmdReg.data;
212            updateState(ACT_DATA_READ_SHORT);
213            *((uint16_t *)data + 1) = cmdReg.data;
214        } else {
215            panic("Data read of unsupported size %d.\n", size);
216        }
217        updateState(ACT_DATA_READ_SHORT);
218        return;
219    }
220    assert(size == sizeof(uint8_t));
221    switch (offset) {
222      case ERROR_OFFSET:
223        *data = cmdReg.error;
224        break;
225      case NSECTOR_OFFSET:
226        *data = cmdReg.sec_count;
227        break;
228      case SECTOR_OFFSET:
229        *data = cmdReg.sec_num;
230        break;
231      case LCYL_OFFSET:
232        *data = cmdReg.cyl_low;
233        break;
234      case HCYL_OFFSET:
235        *data = cmdReg.cyl_high;
236        break;
237      case DRIVE_OFFSET:
238        *data = cmdReg.drive;
239        break;
240      case STATUS_OFFSET:
241        *data = status;
242        updateState(ACT_STAT_READ);
243        break;
244      default:
245        panic("Invalid IDE command register offset: %#x\n", offset);
246    }
247    DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
248}
249
250void
251IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
252{
253    assert(size == sizeof(uint8_t));
254    *data = status;
255    if (offset != ALTSTAT_OFFSET)
256        panic("Invalid IDE control register offset: %#x\n", offset);
257    DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
258}
259
260void
261IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
262{
263    if (offset == DATA_OFFSET) {
264        if (size == sizeof(uint16_t)) {
265            cmdReg.data = *(const uint16_t *)data;
266        } else if (size == sizeof(uint32_t)) {
267            cmdReg.data = *(const uint16_t *)data;
268            updateState(ACT_DATA_WRITE_SHORT);
269            cmdReg.data = *((const uint16_t *)data + 1);
270        } else {
271            panic("Data write of unsupported size %d.\n", size);
272        }
273        updateState(ACT_DATA_WRITE_SHORT);
274        return;
275    }
276
277    assert(size == sizeof(uint8_t));
278    switch (offset) {
279      case FEATURES_OFFSET:
280        break;
281      case NSECTOR_OFFSET:
282        cmdReg.sec_count = *data;
283        break;
284      case SECTOR_OFFSET:
285        cmdReg.sec_num = *data;
286        break;
287      case LCYL_OFFSET:
288        cmdReg.cyl_low = *data;
289        break;
290      case HCYL_OFFSET:
291        cmdReg.cyl_high = *data;
292        break;
293      case DRIVE_OFFSET:
294        cmdReg.drive = *data;
295        updateState(ACT_SELECT_WRITE);
296        break;
297      case COMMAND_OFFSET:
298        cmdReg.command = *data;
299        updateState(ACT_CMD_WRITE);
300        break;
301      default:
302        panic("Invalid IDE command register offset: %#x\n", offset);
303    }
304    DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
305            (uint32_t)*data);
306}
307
308void
309IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
310{
311    if (offset != CONTROL_OFFSET)
312        panic("Invalid IDE control register offset: %#x\n", offset);
313
314    if (*data & CONTROL_RST_BIT) {
315        // force the device into the reset state
316        devState = Device_Srst;
317        updateState(ACT_SRST_SET);
318    } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
319        updateState(ACT_SRST_CLEAR);
320    }
321
322    nIENBit = *data & CONTROL_IEN_BIT;
323
324    DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
325            (uint32_t)*data);
326}
327
328////
329// Perform DMA transactions
330////
331
332void
333IdeDisk::doDmaTransfer()
334{
335    if (dmaAborted) {
336        DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
337        updateState(ACT_CMD_ERROR);
338        return;
339    }
340
341    if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
342        panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
343              dmaState, devState);
344
345    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
346        schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
347        return;
348    } else
349        ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
350                (uint8_t*)&curPrd.entry);
351}
352
353void
354IdeDisk::dmaPrdReadDone()
355{
356    if (dmaAborted) {
357        DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
358        updateState(ACT_CMD_ERROR);
359        return;
360    }
361
362    DPRINTF(IdeDisk,
363            "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
364            curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
365            curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
366            curPrd.getEOT(), curSector);
367
368    // the prd pointer has already been translated, so just do an increment
369    curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
370
371    if (dmaRead)
372        doDmaDataRead();
373    else
374        doDmaDataWrite();
375}
376
377void
378IdeDisk::doDmaDataRead()
379{
380    /** @todo we need to figure out what the delay actually will be */
381    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
382
383    DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
384            diskDelay, totalDiskDelay);
385
386    schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
387}
388
389void
390IdeDisk::regStats()
391{
392    using namespace Stats;
393    dmaReadFullPages
394        .name(name() + ".dma_read_full_pages")
395        .desc("Number of full page size DMA reads (not PRD).")
396        ;
397    dmaReadBytes
398        .name(name() + ".dma_read_bytes")
399        .desc("Number of bytes transfered via DMA reads (not PRD).")
400        ;
401    dmaReadTxs
402        .name(name() + ".dma_read_txs")
403        .desc("Number of DMA read transactions (not PRD).")
404        ;
405
406    dmaWriteFullPages
407        .name(name() + ".dma_write_full_pages")
408        .desc("Number of full page size DMA writes.")
409        ;
410    dmaWriteBytes
411        .name(name() + ".dma_write_bytes")
412        .desc("Number of bytes transfered via DMA writes.")
413        ;
414    dmaWriteTxs
415        .name(name() + ".dma_write_txs")
416        .desc("Number of DMA write transactions.")
417        ;
418}
419
420void
421IdeDisk::doDmaRead()
422{
423    if (dmaAborted) {
424        DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
425        if (dmaReadCG)
426            delete dmaReadCG;
427        dmaReadCG = NULL;
428        updateState(ACT_CMD_ERROR);
429        return;
430    }
431
432    if (!dmaReadCG) {
433        // clear out the data buffer
434        memset(dataBuffer, 0, MAX_DMA_SIZE);
435        dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
436                curPrd.getByteCount(), TheISA::PageBytes);
437
438    }
439    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
440        schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
441        return;
442    } else if (!dmaReadCG->done()) {
443        assert(dmaReadCG->complete() < MAX_DMA_SIZE);
444        ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
445                &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
446        dmaReadBytes += dmaReadCG->size();
447        dmaReadTxs++;
448        if (dmaReadCG->size() == TheISA::PageBytes)
449            dmaReadFullPages++;
450        dmaReadCG->next();
451    } else {
452        assert(dmaReadCG->done());
453        delete dmaReadCG;
454        dmaReadCG = NULL;
455        dmaReadDone();
456    }
457}
458
459void
460IdeDisk::dmaReadDone()
461{
462    uint32_t bytesWritten = 0;
463
464    // write the data to the disk image
465    for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
466         bytesWritten += SectorSize) {
467
468        cmdBytesLeft -= SectorSize;
469        writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
470    }
471
472    // check for the EOT
473    if (curPrd.getEOT()) {
474        assert(cmdBytesLeft == 0);
475        dmaState = Dma_Idle;
476        updateState(ACT_DMA_DONE);
477    } else {
478        doDmaTransfer();
479    }
480}
481
482void
483IdeDisk::doDmaDataWrite()
484{
485    /** @todo we need to figure out what the delay actually will be */
486    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
487    uint32_t bytesRead = 0;
488
489    DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
490            diskDelay, totalDiskDelay);
491
492    memset(dataBuffer, 0, MAX_DMA_SIZE);
493    assert(cmdBytesLeft <= MAX_DMA_SIZE);
494    while (bytesRead < curPrd.getByteCount()) {
495        readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
496        bytesRead += SectorSize;
497        cmdBytesLeft -= SectorSize;
498    }
499    DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
500            bytesRead, cmdBytesLeft);
501
502    schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
503}
504
505void
506IdeDisk::doDmaWrite()
507{
508    if (dmaAborted) {
509        DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
510        if (dmaWriteCG)
511            delete dmaWriteCG;
512        dmaWriteCG = NULL;
513        updateState(ACT_CMD_ERROR);
514        return;
515    }
516    if (!dmaWriteCG) {
517        // clear out the data buffer
518        dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
519                curPrd.getByteCount(), TheISA::PageBytes);
520    }
521    if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
522        schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
523        DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
524        return;
525    } else if (!dmaWriteCG->done()) {
526        assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
527        ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
528                &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
529        DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
530                curPrd.getByteCount(), curPrd.getEOT());
531        dmaWriteBytes += dmaWriteCG->size();
532        dmaWriteTxs++;
533        if (dmaWriteCG->size() == TheISA::PageBytes)
534            dmaWriteFullPages++;
535        dmaWriteCG->next();
536    } else {
537        DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
538                curPrd.getByteCount(), curPrd.getEOT());
539        assert(dmaWriteCG->done());
540        delete dmaWriteCG;
541        dmaWriteCG = NULL;
542        dmaWriteDone();
543    }
544}
545
546void
547IdeDisk::dmaWriteDone()
548{
549    DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
550                curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft);
551    // check for the EOT
552    if (curPrd.getEOT()) {
553        assert(cmdBytesLeft == 0);
554        dmaState = Dma_Idle;
555        updateState(ACT_DMA_DONE);
556    } else {
557        doDmaTransfer();
558    }
559}
560
561////
562// Disk utility routines
563///
564
565void
566IdeDisk::readDisk(uint32_t sector, uint8_t *data)
567{
568    uint32_t bytesRead = image->read(data, sector);
569
570    if (bytesRead != SectorSize)
571        panic("Can't read from %s. Only %d of %d read. errno=%d\n",
572              name(), bytesRead, SectorSize, errno);
573}
574
575void
576IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
577{
578    uint32_t bytesWritten = image->write(data, sector);
579
580    if (bytesWritten != SectorSize)
581        panic("Can't write to %s. Only %d of %d written. errno=%d\n",
582              name(), bytesWritten, SectorSize, errno);
583}
584
585////
586// Setup and handle commands
587////
588
589void
590IdeDisk::startDma(const uint32_t &prdTableBase)
591{
592    if (dmaState != Dma_Start)
593        panic("Inconsistent DMA state, should be in Dma_Start!\n");
594
595    if (devState != Transfer_Data_Dma)
596        panic("Inconsistent device state for DMA start!\n");
597
598    // PRD base address is given by bits 31:2
599    curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
600
601    dmaState = Dma_Transfer;
602
603    // schedule dma transfer (doDmaTransfer)
604    schedule(dmaTransferEvent, curTick() + 1);
605}
606
607void
608IdeDisk::abortDma()
609{
610    if (dmaState == Dma_Idle)
611        panic("Inconsistent DMA state, should be Start or Transfer!");
612
613    if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
614        panic("Inconsistent device state, should be Transfer or Prepare!\n");
615
616    updateState(ACT_CMD_ERROR);
617}
618
619void
620IdeDisk::startCommand()
621{
622    DevAction_t action = ACT_NONE;
623    uint32_t size = 0;
624    dmaRead = false;
625
626    // Decode commands
627    switch (cmdReg.command) {
628        // Supported non-data commands
629      case WDSF_READ_NATIVE_MAX:
630        size = (uint32_t)image->size() - 1;
631        cmdReg.sec_num = (size & 0xff);
632        cmdReg.cyl_low = ((size & 0xff00) >> 8);
633        cmdReg.cyl_high = ((size & 0xff0000) >> 16);
634        cmdReg.head = ((size & 0xf000000) >> 24);
635
636        devState = Command_Execution;
637        action = ACT_CMD_COMPLETE;
638        break;
639
640      case WDCC_RECAL:
641      case WDCC_IDP:
642      case WDCC_STANDBY_IMMED:
643      case WDCC_FLUSHCACHE:
644      case WDSF_VERIFY:
645      case WDSF_SEEK:
646      case SET_FEATURES:
647      case WDCC_SETMULTI:
648      case WDCC_IDLE:
649        devState = Command_Execution;
650        action = ACT_CMD_COMPLETE;
651        break;
652
653        // Supported PIO data-in commands
654      case WDCC_IDENTIFY:
655        cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
656        devState = Prepare_Data_In;
657        action = ACT_DATA_READY;
658        break;
659
660      case WDCC_READMULTI:
661      case WDCC_READ:
662        if (!(cmdReg.drive & DRIVE_LBA_BIT))
663            panic("Attempt to perform CHS access, only supports LBA\n");
664
665        if (cmdReg.sec_count == 0)
666            cmdBytes = cmdBytesLeft = (256 * SectorSize);
667        else
668            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
669
670        curSector = getLBABase();
671
672        /** @todo make this a scheduled event to simulate disk delay */
673        devState = Prepare_Data_In;
674        action = ACT_DATA_READY;
675        break;
676
677        // Supported PIO data-out commands
678      case WDCC_WRITEMULTI:
679      case WDCC_WRITE:
680        if (!(cmdReg.drive & DRIVE_LBA_BIT))
681            panic("Attempt to perform CHS access, only supports LBA\n");
682
683        if (cmdReg.sec_count == 0)
684            cmdBytes = cmdBytesLeft = (256 * SectorSize);
685        else
686            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
687        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
688        curSector = getLBABase();
689
690        devState = Prepare_Data_Out;
691        action = ACT_DATA_READY;
692        break;
693
694        // Supported DMA commands
695      case WDCC_WRITEDMA:
696        dmaRead = true;  // a write to the disk is a DMA read from memory
697      case WDCC_READDMA:
698        if (!(cmdReg.drive & DRIVE_LBA_BIT))
699            panic("Attempt to perform CHS access, only supports LBA\n");
700
701        if (cmdReg.sec_count == 0)
702            cmdBytes = cmdBytesLeft = (256 * SectorSize);
703        else
704            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
705        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
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}
747
748void
749IdeDisk::intrClear()
750{
751    DPRINTF(IdeDisk, "Clearing Interrupt\n");
752    if (!intrPending)
753        panic("Attempt to clear a non-pending interrupt\n");
754
755    intrPending = false;
756
757    // talk to controller to clear interrupt
758    if (ctrl)
759        ctrl->intrClear();
760}
761
762////
763// Manage the device internal state machine
764////
765
766void
767IdeDisk::updateState(DevAction_t action)
768{
769    switch (devState) {
770      case Device_Srst:
771        if (action == ACT_SRST_SET) {
772            // set the BSY bit
773            status |= STATUS_BSY_BIT;
774        } else if (action == ACT_SRST_CLEAR) {
775            // clear the BSY bit
776            status &= ~STATUS_BSY_BIT;
777
778            // reset the device state
779            reset(devID);
780        }
781        break;
782
783      case Device_Idle_S:
784        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
785            devState = Device_Idle_NS;
786        } else if (action == ACT_CMD_WRITE) {
787            startCommand();
788        }
789
790        break;
791
792      case Device_Idle_SI:
793        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
794            devState = Device_Idle_NS;
795            intrClear();
796        } else if (action == ACT_STAT_READ || isIENSet()) {
797            devState = Device_Idle_S;
798            intrClear();
799        } else if (action == ACT_CMD_WRITE) {
800            intrClear();
801            startCommand();
802        }
803
804        break;
805
806      case Device_Idle_NS:
807        if (action == ACT_SELECT_WRITE && isDEVSelect()) {
808            if (!isIENSet() && intrPending) {
809                devState = Device_Idle_SI;
810                intrPost();
811            }
812            if (isIENSet() || !intrPending) {
813                devState = Device_Idle_S;
814            }
815        }
816        break;
817
818      case Command_Execution:
819        if (action == ACT_CMD_COMPLETE) {
820            // clear the BSY bit
821            setComplete();
822
823            if (!isIENSet()) {
824                devState = Device_Idle_SI;
825                intrPost();
826            } else {
827                devState = Device_Idle_S;
828            }
829        }
830        break;
831
832      case Prepare_Data_In:
833        if (action == ACT_CMD_ERROR) {
834            // clear the BSY bit
835            setComplete();
836
837            if (!isIENSet()) {
838                devState = Device_Idle_SI;
839                intrPost();
840            } else {
841                devState = Device_Idle_S;
842            }
843        } else if (action == ACT_DATA_READY) {
844            // clear the BSY bit
845            status &= ~STATUS_BSY_BIT;
846            // set the DRQ bit
847            status |= STATUS_DRQ_BIT;
848
849            // copy the data into the data buffer
850            if (cmdReg.command == WDCC_IDENTIFY) {
851                // Reset the drqBytes for this block
852                drqBytesLeft = sizeof(struct ataparams);
853
854                memcpy((void *)dataBuffer, (void *)&driveID,
855                       sizeof(struct ataparams));
856            } else {
857                // Reset the drqBytes for this block
858                drqBytesLeft = SectorSize;
859
860                readDisk(curSector++, dataBuffer);
861            }
862
863            // put the first two bytes into the data register
864            memcpy((void *)&cmdReg.data, (void *)dataBuffer,
865                   sizeof(uint16_t));
866
867            if (!isIENSet()) {
868                devState = Data_Ready_INTRQ_In;
869                intrPost();
870            } else {
871                devState = Transfer_Data_In;
872            }
873        }
874        break;
875
876      case Data_Ready_INTRQ_In:
877        if (action == ACT_STAT_READ) {
878            devState = Transfer_Data_In;
879            intrClear();
880        }
881        break;
882
883      case Transfer_Data_In:
884        if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
885            if (action == ACT_DATA_READ_BYTE) {
886                panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
887            } else {
888                drqBytesLeft -= 2;
889                cmdBytesLeft -= 2;
890
891                // copy next short into data registers
892                if (drqBytesLeft)
893                    memcpy((void *)&cmdReg.data,
894                           (void *)&dataBuffer[SectorSize - drqBytesLeft],
895                           sizeof(uint16_t));
896            }
897
898            if (drqBytesLeft == 0) {
899                if (cmdBytesLeft == 0) {
900                    // Clear the BSY bit
901                    setComplete();
902                    devState = Device_Idle_S;
903                } else {
904                    devState = Prepare_Data_In;
905                    // set the BSY_BIT
906                    status |= STATUS_BSY_BIT;
907                    // clear the DRQ_BIT
908                    status &= ~STATUS_DRQ_BIT;
909
910                    /** @todo change this to a scheduled event to simulate
911                        disk delay */
912                    updateState(ACT_DATA_READY);
913                }
914            }
915        }
916        break;
917
918      case Prepare_Data_Out:
919        if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
920            // clear the BSY bit
921            setComplete();
922
923            if (!isIENSet()) {
924                devState = Device_Idle_SI;
925                intrPost();
926            } else {
927                devState = Device_Idle_S;
928            }
929        } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
930            // clear the BSY bit
931            status &= ~STATUS_BSY_BIT;
932            // set the DRQ bit
933            status |= STATUS_DRQ_BIT;
934
935            // clear the data buffer to get it ready for writes
936            memset(dataBuffer, 0, MAX_DMA_SIZE);
937
938            // reset the drqBytes for this block
939            drqBytesLeft = SectorSize;
940
941            if (cmdBytesLeft == cmdBytes || isIENSet()) {
942                devState = Transfer_Data_Out;
943            } else {
944                devState = Data_Ready_INTRQ_Out;
945                intrPost();
946            }
947        }
948        break;
949
950      case Data_Ready_INTRQ_Out:
951        if (action == ACT_STAT_READ) {
952            devState = Transfer_Data_Out;
953            intrClear();
954        }
955        break;
956
957      case Transfer_Data_Out:
958        if (action == ACT_DATA_WRITE_BYTE ||
959            action == ACT_DATA_WRITE_SHORT) {
960
961            if (action == ACT_DATA_READ_BYTE) {
962                panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
963            } else {
964                // copy the latest short into the data buffer
965                memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
966                       (void *)&cmdReg.data,
967                       sizeof(uint16_t));
968
969                drqBytesLeft -= 2;
970                cmdBytesLeft -= 2;
971            }
972
973            if (drqBytesLeft == 0) {
974                // copy the block to the disk
975                writeDisk(curSector++, dataBuffer);
976
977                // set the BSY bit
978                status |= STATUS_BSY_BIT;
979                // set the seek bit
980                status |= STATUS_SEEK_BIT;
981                // clear the DRQ bit
982                status &= ~STATUS_DRQ_BIT;
983
984                devState = Prepare_Data_Out;
985
986                /** @todo change this to a scheduled event to simulate
987                    disk delay */
988                updateState(ACT_DATA_READY);
989            }
990        }
991        break;
992
993      case Prepare_Data_Dma:
994        if (action == ACT_CMD_ERROR) {
995            // clear the BSY bit
996            setComplete();
997
998            if (!isIENSet()) {
999                devState = Device_Idle_SI;
1000                intrPost();
1001            } else {
1002                devState = Device_Idle_S;
1003            }
1004        } else if (action == ACT_DMA_READY) {
1005            // clear the BSY bit
1006            status &= ~STATUS_BSY_BIT;
1007            // set the DRQ bit
1008            status |= STATUS_DRQ_BIT;
1009
1010            devState = Transfer_Data_Dma;
1011
1012            if (dmaState != Dma_Idle)
1013                panic("Inconsistent DMA state, should be Dma_Idle\n");
1014
1015            dmaState = Dma_Start;
1016            // wait for the write to the DMA start bit
1017        }
1018        break;
1019
1020      case Transfer_Data_Dma:
1021        if (action == ACT_CMD_ERROR) {
1022            dmaAborted = true;
1023            devState = Device_Dma_Abort;
1024        } else if (action == ACT_DMA_DONE) {
1025            // clear the BSY bit
1026            setComplete();
1027            // set the seek bit
1028            status |= STATUS_SEEK_BIT;
1029            // clear the controller state for DMA transfer
1030            ctrl->setDmaComplete(this);
1031
1032            if (!isIENSet()) {
1033                devState = Device_Idle_SI;
1034                intrPost();
1035            } else {
1036                devState = Device_Idle_S;
1037            }
1038        }
1039        break;
1040
1041      case Device_Dma_Abort:
1042        if (action == ACT_CMD_ERROR) {
1043            setComplete();
1044            status |= STATUS_SEEK_BIT;
1045            ctrl->setDmaComplete(this);
1046            dmaAborted = false;
1047            dmaState = Dma_Idle;
1048
1049            if (!isIENSet()) {
1050                devState = Device_Idle_SI;
1051                intrPost();
1052            } else {
1053                devState = Device_Idle_S;
1054            }
1055        } else {
1056            DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1057        }
1058        break;
1059
1060      default:
1061        panic("Unknown IDE device state: %#x\n", devState);
1062    }
1063}
1064
1065void
1066IdeDisk::serialize(CheckpointOut &cp) const
1067{
1068    // Check all outstanding events to see if they are scheduled
1069    // these are all mutually exclusive
1070    Tick reschedule = 0;
1071    Events_t event = None;
1072
1073    int eventCount = 0;
1074
1075    if (dmaTransferEvent.scheduled()) {
1076        reschedule = dmaTransferEvent.when();
1077        event = Transfer;
1078        eventCount++;
1079    }
1080    if (dmaReadWaitEvent.scheduled()) {
1081        reschedule = dmaReadWaitEvent.when();
1082        event = ReadWait;
1083        eventCount++;
1084    }
1085    if (dmaWriteWaitEvent.scheduled()) {
1086        reschedule = dmaWriteWaitEvent.when();
1087        event = WriteWait;
1088        eventCount++;
1089    }
1090    if (dmaPrdReadEvent.scheduled()) {
1091        reschedule = dmaPrdReadEvent.when();
1092        event = PrdRead;
1093        eventCount++;
1094    }
1095    if (dmaReadEvent.scheduled()) {
1096        reschedule = dmaReadEvent.when();
1097        event = DmaRead;
1098        eventCount++;
1099    }
1100    if (dmaWriteEvent.scheduled()) {
1101        reschedule = dmaWriteEvent.when();
1102        event = DmaWrite;
1103        eventCount++;
1104    }
1105
1106    assert(eventCount <= 1);
1107
1108    SERIALIZE_SCALAR(reschedule);
1109    SERIALIZE_ENUM(event);
1110
1111    // Serialize device registers
1112    SERIALIZE_SCALAR(cmdReg.data);
1113    SERIALIZE_SCALAR(cmdReg.sec_count);
1114    SERIALIZE_SCALAR(cmdReg.sec_num);
1115    SERIALIZE_SCALAR(cmdReg.cyl_low);
1116    SERIALIZE_SCALAR(cmdReg.cyl_high);
1117    SERIALIZE_SCALAR(cmdReg.drive);
1118    SERIALIZE_SCALAR(cmdReg.command);
1119    SERIALIZE_SCALAR(status);
1120    SERIALIZE_SCALAR(nIENBit);
1121    SERIALIZE_SCALAR(devID);
1122
1123    // Serialize the PRD related information
1124    SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1125    SERIALIZE_SCALAR(curPrd.entry.byteCount);
1126    SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1127    SERIALIZE_SCALAR(curPrdAddr);
1128
1129    /** @todo need to serialized chunk generator stuff!! */
1130    // Serialize current transfer related information
1131    SERIALIZE_SCALAR(cmdBytesLeft);
1132    SERIALIZE_SCALAR(cmdBytes);
1133    SERIALIZE_SCALAR(drqBytesLeft);
1134    SERIALIZE_SCALAR(curSector);
1135    SERIALIZE_SCALAR(dmaRead);
1136    SERIALIZE_SCALAR(intrPending);
1137    SERIALIZE_SCALAR(dmaAborted);
1138    SERIALIZE_ENUM(devState);
1139    SERIALIZE_ENUM(dmaState);
1140    SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1141}
1142
1143void
1144IdeDisk::unserialize(CheckpointIn &cp)
1145{
1146    // Reschedule events that were outstanding
1147    // these are all mutually exclusive
1148    Tick reschedule = 0;
1149    Events_t event = None;
1150
1151    UNSERIALIZE_SCALAR(reschedule);
1152    UNSERIALIZE_ENUM(event);
1153
1154    switch (event) {
1155      case None : break;
1156      case Transfer : schedule(dmaTransferEvent, reschedule); break;
1157      case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
1158      case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
1159      case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
1160      case DmaRead : schedule(dmaReadEvent, reschedule); break;
1161      case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1162    }
1163
1164    // Unserialize device registers
1165    UNSERIALIZE_SCALAR(cmdReg.data);
1166    UNSERIALIZE_SCALAR(cmdReg.sec_count);
1167    UNSERIALIZE_SCALAR(cmdReg.sec_num);
1168    UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1169    UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1170    UNSERIALIZE_SCALAR(cmdReg.drive);
1171    UNSERIALIZE_SCALAR(cmdReg.command);
1172    UNSERIALIZE_SCALAR(status);
1173    UNSERIALIZE_SCALAR(nIENBit);
1174    UNSERIALIZE_SCALAR(devID);
1175
1176    // Unserialize the PRD related information
1177    UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1178    UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1179    UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1180    UNSERIALIZE_SCALAR(curPrdAddr);
1181
1182    /** @todo need to serialized chunk generator stuff!! */
1183    // Unserialize current transfer related information
1184    UNSERIALIZE_SCALAR(cmdBytes);
1185    UNSERIALIZE_SCALAR(cmdBytesLeft);
1186    UNSERIALIZE_SCALAR(drqBytesLeft);
1187    UNSERIALIZE_SCALAR(curSector);
1188    UNSERIALIZE_SCALAR(dmaRead);
1189    UNSERIALIZE_SCALAR(intrPending);
1190    UNSERIALIZE_SCALAR(dmaAborted);
1191    UNSERIALIZE_ENUM(devState);
1192    UNSERIALIZE_ENUM(dmaState);
1193    UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1194}
1195
1196IdeDisk *
1197IdeDiskParams::create()
1198{
1199    return new IdeDisk(this);
1200}
1201