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