ide_disk.cc revision 12087
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      case WDCC_READDMA:
709        if (!(cmdReg.drive & DRIVE_LBA_BIT))
710            panic("Attempt to perform CHS access, only supports LBA\n");
711
712        if (cmdReg.sec_count == 0)
713            cmdBytes = cmdBytesLeft = (256 * SectorSize);
714        else
715            cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
716        DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
717
718        curSector = getLBABase();
719
720        devState = Prepare_Data_Dma;
721        action = ACT_DMA_READY;
722        break;
723
724      default:
725        panic("Unsupported ATA command: %#x\n", cmdReg.command);
726    }
727
728    if (action != ACT_NONE) {
729        // set the BSY bit
730        status |= STATUS_BSY_BIT;
731        // clear the DRQ bit
732        status &= ~STATUS_DRQ_BIT;
733        // clear the DF bit
734        status &= ~STATUS_DF_BIT;
735
736        updateState(action);
737    }
738}
739
740////
741// Handle setting and clearing interrupts
742////
743
744void
745IdeDisk::intrPost()
746{
747    DPRINTF(IdeDisk, "Posting Interrupt\n");
748    if (intrPending)
749        panic("Attempt to post an interrupt with one pending\n");
750
751    intrPending = true;
752
753    // talk to controller to set interrupt
754    if (ctrl) {
755        ctrl->intrPost();
756    }
757}
758
759void
760IdeDisk::intrClear()
761{
762    DPRINTF(IdeDisk, "Clearing Interrupt\n");
763    if (!intrPending)
764        panic("Attempt to clear a non-pending interrupt\n");
765
766    intrPending = false;
767
768    // talk to controller to clear interrupt
769    if (ctrl)
770        ctrl->intrClear();
771}
772
773////
774// Manage the device internal state machine
775////
776
777void
778IdeDisk::updateState(DevAction_t action)
779{
780    switch (devState) {
781      case Device_Srst:
782        if (action == ACT_SRST_SET) {
783            // set the BSY bit
784            status |= STATUS_BSY_BIT;
785        } else if (action == ACT_SRST_CLEAR) {
786            // clear the BSY bit
787            status &= ~STATUS_BSY_BIT;
788
789            // reset the device state
790            reset(devID);
791        }
792        break;
793
794      case Device_Idle_S:
795        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
796            devState = Device_Idle_NS;
797        } else if (action == ACT_CMD_WRITE) {
798            startCommand();
799        }
800
801        break;
802
803      case Device_Idle_SI:
804        if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
805            devState = Device_Idle_NS;
806            intrClear();
807        } else if (action == ACT_STAT_READ || isIENSet()) {
808            devState = Device_Idle_S;
809            intrClear();
810        } else if (action == ACT_CMD_WRITE) {
811            intrClear();
812            startCommand();
813        }
814
815        break;
816
817      case Device_Idle_NS:
818        if (action == ACT_SELECT_WRITE && isDEVSelect()) {
819            if (!isIENSet() && intrPending) {
820                devState = Device_Idle_SI;
821                intrPost();
822            }
823            if (isIENSet() || !intrPending) {
824                devState = Device_Idle_S;
825            }
826        }
827        break;
828
829      case Command_Execution:
830        if (action == ACT_CMD_COMPLETE) {
831            // clear the BSY bit
832            setComplete();
833
834            if (!isIENSet()) {
835                devState = Device_Idle_SI;
836                intrPost();
837            } else {
838                devState = Device_Idle_S;
839            }
840        }
841        break;
842
843      case Prepare_Data_In:
844        if (action == ACT_CMD_ERROR) {
845            // clear the BSY bit
846            setComplete();
847
848            if (!isIENSet()) {
849                devState = Device_Idle_SI;
850                intrPost();
851            } else {
852                devState = Device_Idle_S;
853            }
854        } else if (action == ACT_DATA_READY) {
855            // clear the BSY bit
856            status &= ~STATUS_BSY_BIT;
857            // set the DRQ bit
858            status |= STATUS_DRQ_BIT;
859
860            // copy the data into the data buffer
861            if (cmdReg.command == WDCC_IDENTIFY ||
862                cmdReg.command == ATAPI_IDENTIFY_DEVICE) {
863                // Reset the drqBytes for this block
864                drqBytesLeft = sizeof(struct ataparams);
865
866                memcpy((void *)dataBuffer, (void *)&driveID,
867                       sizeof(struct ataparams));
868            } else {
869                // Reset the drqBytes for this block
870                drqBytesLeft = SectorSize;
871
872                readDisk(curSector++, dataBuffer);
873            }
874
875            // put the first two bytes into the data register
876            memcpy((void *)&cmdReg.data, (void *)dataBuffer,
877                   sizeof(uint16_t));
878
879            if (!isIENSet()) {
880                devState = Data_Ready_INTRQ_In;
881                intrPost();
882            } else {
883                devState = Transfer_Data_In;
884            }
885        }
886        break;
887
888      case Data_Ready_INTRQ_In:
889        if (action == ACT_STAT_READ) {
890            devState = Transfer_Data_In;
891            intrClear();
892        }
893        break;
894
895      case Transfer_Data_In:
896        if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
897            if (action == ACT_DATA_READ_BYTE) {
898                panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
899            } else {
900                drqBytesLeft -= 2;
901                cmdBytesLeft -= 2;
902
903                // copy next short into data registers
904                if (drqBytesLeft)
905                    memcpy((void *)&cmdReg.data,
906                           (void *)&dataBuffer[SectorSize - drqBytesLeft],
907                           sizeof(uint16_t));
908            }
909
910            if (drqBytesLeft == 0) {
911                if (cmdBytesLeft == 0) {
912                    // Clear the BSY bit
913                    setComplete();
914                    devState = Device_Idle_S;
915                } else {
916                    devState = Prepare_Data_In;
917                    // set the BSY_BIT
918                    status |= STATUS_BSY_BIT;
919                    // clear the DRQ_BIT
920                    status &= ~STATUS_DRQ_BIT;
921
922                    /** @todo change this to a scheduled event to simulate
923                        disk delay */
924                    updateState(ACT_DATA_READY);
925                }
926            }
927        }
928        break;
929
930      case Prepare_Data_Out:
931        if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
932            // clear the BSY bit
933            setComplete();
934
935            if (!isIENSet()) {
936                devState = Device_Idle_SI;
937                intrPost();
938            } else {
939                devState = Device_Idle_S;
940            }
941        } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
942            // clear the BSY bit
943            status &= ~STATUS_BSY_BIT;
944            // set the DRQ bit
945            status |= STATUS_DRQ_BIT;
946
947            // clear the data buffer to get it ready for writes
948            memset(dataBuffer, 0, MAX_DMA_SIZE);
949
950            // reset the drqBytes for this block
951            drqBytesLeft = SectorSize;
952
953            if (cmdBytesLeft == cmdBytes || isIENSet()) {
954                devState = Transfer_Data_Out;
955            } else {
956                devState = Data_Ready_INTRQ_Out;
957                intrPost();
958            }
959        }
960        break;
961
962      case Data_Ready_INTRQ_Out:
963        if (action == ACT_STAT_READ) {
964            devState = Transfer_Data_Out;
965            intrClear();
966        }
967        break;
968
969      case Transfer_Data_Out:
970        if (action == ACT_DATA_WRITE_BYTE ||
971            action == ACT_DATA_WRITE_SHORT) {
972
973            if (action == ACT_DATA_READ_BYTE) {
974                panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
975            } else {
976                // copy the latest short into the data buffer
977                memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
978                       (void *)&cmdReg.data,
979                       sizeof(uint16_t));
980
981                drqBytesLeft -= 2;
982                cmdBytesLeft -= 2;
983            }
984
985            if (drqBytesLeft == 0) {
986                // copy the block to the disk
987                writeDisk(curSector++, dataBuffer);
988
989                // set the BSY bit
990                status |= STATUS_BSY_BIT;
991                // set the seek bit
992                status |= STATUS_SEEK_BIT;
993                // clear the DRQ bit
994                status &= ~STATUS_DRQ_BIT;
995
996                devState = Prepare_Data_Out;
997
998                /** @todo change this to a scheduled event to simulate
999                    disk delay */
1000                updateState(ACT_DATA_READY);
1001            }
1002        }
1003        break;
1004
1005      case Prepare_Data_Dma:
1006        if (action == ACT_CMD_ERROR) {
1007            // clear the BSY bit
1008            setComplete();
1009
1010            if (!isIENSet()) {
1011                devState = Device_Idle_SI;
1012                intrPost();
1013            } else {
1014                devState = Device_Idle_S;
1015            }
1016        } else if (action == ACT_DMA_READY) {
1017            // clear the BSY bit
1018            status &= ~STATUS_BSY_BIT;
1019            // set the DRQ bit
1020            status |= STATUS_DRQ_BIT;
1021
1022            devState = Transfer_Data_Dma;
1023
1024            if (dmaState != Dma_Idle)
1025                panic("Inconsistent DMA state, should be Dma_Idle\n");
1026
1027            dmaState = Dma_Start;
1028            // wait for the write to the DMA start bit
1029        }
1030        break;
1031
1032      case Transfer_Data_Dma:
1033        if (action == ACT_CMD_ERROR) {
1034            dmaAborted = true;
1035            devState = Device_Dma_Abort;
1036        } else if (action == ACT_DMA_DONE) {
1037            // clear the BSY bit
1038            setComplete();
1039            // set the seek bit
1040            status |= STATUS_SEEK_BIT;
1041            // clear the controller state for DMA transfer
1042            ctrl->setDmaComplete(this);
1043
1044            if (!isIENSet()) {
1045                devState = Device_Idle_SI;
1046                intrPost();
1047            } else {
1048                devState = Device_Idle_S;
1049            }
1050        }
1051        break;
1052
1053      case Device_Dma_Abort:
1054        if (action == ACT_CMD_ERROR) {
1055            setComplete();
1056            status |= STATUS_SEEK_BIT;
1057            ctrl->setDmaComplete(this);
1058            dmaAborted = false;
1059            dmaState = Dma_Idle;
1060
1061            if (!isIENSet()) {
1062                devState = Device_Idle_SI;
1063                intrPost();
1064            } else {
1065                devState = Device_Idle_S;
1066            }
1067        } else {
1068            DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1069        }
1070        break;
1071
1072      default:
1073        panic("Unknown IDE device state: %#x\n", devState);
1074    }
1075}
1076
1077void
1078IdeDisk::serialize(CheckpointOut &cp) const
1079{
1080    // Check all outstanding events to see if they are scheduled
1081    // these are all mutually exclusive
1082    Tick reschedule = 0;
1083    Events_t event = None;
1084
1085    int eventCount = 0;
1086
1087    if (dmaTransferEvent.scheduled()) {
1088        reschedule = dmaTransferEvent.when();
1089        event = Transfer;
1090        eventCount++;
1091    }
1092    if (dmaReadWaitEvent.scheduled()) {
1093        reschedule = dmaReadWaitEvent.when();
1094        event = ReadWait;
1095        eventCount++;
1096    }
1097    if (dmaWriteWaitEvent.scheduled()) {
1098        reschedule = dmaWriteWaitEvent.when();
1099        event = WriteWait;
1100        eventCount++;
1101    }
1102    if (dmaPrdReadEvent.scheduled()) {
1103        reschedule = dmaPrdReadEvent.when();
1104        event = PrdRead;
1105        eventCount++;
1106    }
1107    if (dmaReadEvent.scheduled()) {
1108        reschedule = dmaReadEvent.when();
1109        event = DmaRead;
1110        eventCount++;
1111    }
1112    if (dmaWriteEvent.scheduled()) {
1113        reschedule = dmaWriteEvent.when();
1114        event = DmaWrite;
1115        eventCount++;
1116    }
1117
1118    assert(eventCount <= 1);
1119
1120    SERIALIZE_SCALAR(reschedule);
1121    SERIALIZE_ENUM(event);
1122
1123    // Serialize device registers
1124    SERIALIZE_SCALAR(cmdReg.data);
1125    SERIALIZE_SCALAR(cmdReg.sec_count);
1126    SERIALIZE_SCALAR(cmdReg.sec_num);
1127    SERIALIZE_SCALAR(cmdReg.cyl_low);
1128    SERIALIZE_SCALAR(cmdReg.cyl_high);
1129    SERIALIZE_SCALAR(cmdReg.drive);
1130    SERIALIZE_SCALAR(cmdReg.command);
1131    SERIALIZE_SCALAR(status);
1132    SERIALIZE_SCALAR(nIENBit);
1133    SERIALIZE_SCALAR(devID);
1134
1135    // Serialize the PRD related information
1136    SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1137    SERIALIZE_SCALAR(curPrd.entry.byteCount);
1138    SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1139    SERIALIZE_SCALAR(curPrdAddr);
1140
1141    /** @todo need to serialized chunk generator stuff!! */
1142    // Serialize current transfer related information
1143    SERIALIZE_SCALAR(cmdBytesLeft);
1144    SERIALIZE_SCALAR(cmdBytes);
1145    SERIALIZE_SCALAR(drqBytesLeft);
1146    SERIALIZE_SCALAR(curSector);
1147    SERIALIZE_SCALAR(dmaRead);
1148    SERIALIZE_SCALAR(intrPending);
1149    SERIALIZE_SCALAR(dmaAborted);
1150    SERIALIZE_ENUM(devState);
1151    SERIALIZE_ENUM(dmaState);
1152    SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1153}
1154
1155void
1156IdeDisk::unserialize(CheckpointIn &cp)
1157{
1158    // Reschedule events that were outstanding
1159    // these are all mutually exclusive
1160    Tick reschedule = 0;
1161    Events_t event = None;
1162
1163    UNSERIALIZE_SCALAR(reschedule);
1164    UNSERIALIZE_ENUM(event);
1165
1166    switch (event) {
1167      case None : break;
1168      case Transfer : schedule(dmaTransferEvent, reschedule); break;
1169      case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
1170      case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
1171      case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
1172      case DmaRead : schedule(dmaReadEvent, reschedule); break;
1173      case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1174    }
1175
1176    // Unserialize device registers
1177    UNSERIALIZE_SCALAR(cmdReg.data);
1178    UNSERIALIZE_SCALAR(cmdReg.sec_count);
1179    UNSERIALIZE_SCALAR(cmdReg.sec_num);
1180    UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1181    UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1182    UNSERIALIZE_SCALAR(cmdReg.drive);
1183    UNSERIALIZE_SCALAR(cmdReg.command);
1184    UNSERIALIZE_SCALAR(status);
1185    UNSERIALIZE_SCALAR(nIENBit);
1186    UNSERIALIZE_SCALAR(devID);
1187
1188    // Unserialize the PRD related information
1189    UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1190    UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1191    UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1192    UNSERIALIZE_SCALAR(curPrdAddr);
1193
1194    /** @todo need to serialized chunk generator stuff!! */
1195    // Unserialize current transfer related information
1196    UNSERIALIZE_SCALAR(cmdBytes);
1197    UNSERIALIZE_SCALAR(cmdBytesLeft);
1198    UNSERIALIZE_SCALAR(drqBytesLeft);
1199    UNSERIALIZE_SCALAR(curSector);
1200    UNSERIALIZE_SCALAR(dmaRead);
1201    UNSERIALIZE_SCALAR(intrPending);
1202    UNSERIALIZE_SCALAR(dmaAborted);
1203    UNSERIALIZE_ENUM(devState);
1204    UNSERIALIZE_ENUM(dmaState);
1205    UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1206}
1207
1208IdeDisk *
1209IdeDiskParams::create()
1210{
1211    return new IdeDisk(this);
1212}
1213