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