1848SN/A/*
29956SN/A * Copyright (c) 2013 ARM Limited
39956SN/A * All rights reserved
49956SN/A *
59956SN/A * The license below extends only to copyright in the software and shall
69956SN/A * not be construed as granting a license to any other intellectual
79956SN/A * property including but not limited to intellectual property relating
89956SN/A * to a hardware implementation of the functionality of the software
99956SN/A * licensed hereunder.  You may use the software subject to the license
109956SN/A * terms below provided that you ensure that this notice is replicated
119956SN/A * unmodified and in its entirety in all distributions of the software,
129956SN/A * modified or unmodified, in source code or in binary form.
139956SN/A *
141762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
15848SN/A * All rights reserved.
16848SN/A *
17848SN/A * Redistribution and use in source and binary forms, with or without
18848SN/A * modification, are permitted provided that the following conditions are
19848SN/A * met: redistributions of source code must retain the above copyright
20848SN/A * notice, this list of conditions and the following disclaimer;
21848SN/A * redistributions in binary form must reproduce the above copyright
22848SN/A * notice, this list of conditions and the following disclaimer in the
23848SN/A * documentation and/or other materials provided with the distribution;
24848SN/A * neither the name of the copyright holders nor the names of its
25848SN/A * contributors may be used to endorse or promote products derived from
26848SN/A * this software without specific prior written permission.
27848SN/A *
28848SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29848SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30848SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31848SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32848SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33848SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34848SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35848SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36848SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37848SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38848SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392665SN/A *
402665SN/A * Authors: Andrew Schultz
41848SN/A */
42848SN/A
43848SN/A/** @file
44848SN/A * Device model for an IDE disk
45848SN/A */
46848SN/A
4711264Sandreas.sandberg@arm.com#ifndef __DEV_STORAGE_IDE_DISK_HH__
4811264Sandreas.sandberg@arm.com#define __DEV_STORAGE_IDE_DISK_HH__
49848SN/A
502275SN/A#include "base/statistics.hh"
51848SN/A#include "dev/io_device.hh"
5211264Sandreas.sandberg@arm.com#include "dev/storage/disk_image.hh"
5311264Sandreas.sandberg@arm.com#include "dev/storage/ide_atareg.h"
5411264Sandreas.sandberg@arm.com#include "dev/storage/ide_ctrl.hh"
5511264Sandreas.sandberg@arm.com#include "dev/storage/ide_wdcreg.h"
568229SN/A#include "params/IdeDisk.hh"
57849SN/A#include "sim/eventq.hh"
58848SN/A
593090SN/Aclass ChunkGenerator;
603090SN/A
618522SN/A#define DMA_BACKOFF_PERIOD      200
62849SN/A
638522SN/A#define MAX_DMA_SIZE            0x20000  // 128K
648522SN/A#define MAX_SINGLE_DMA_SIZE     0x10000
658522SN/A#define MAX_MULTSECT            (128)
66849SN/A
67849SN/A#define PRD_BASE_MASK  0xfffffffe
68849SN/A#define PRD_COUNT_MASK 0xfffe
69849SN/A#define PRD_EOT_MASK   0x8000
70849SN/A
71849SN/Atypedef struct PrdEntry {
72849SN/A    uint32_t baseAddr;
73849SN/A    uint16_t byteCount;
74849SN/A    uint16_t endOfTable;
75849SN/A} PrdEntry_t;
76849SN/A
77849SN/Aclass PrdTableEntry {
78849SN/A  public:
79849SN/A    PrdEntry_t entry;
80849SN/A
81849SN/A    uint32_t getBaseAddr()
82849SN/A    {
83849SN/A        return (entry.baseAddr & PRD_BASE_MASK);
84849SN/A    }
85849SN/A
86896SN/A    uint32_t getByteCount()
87849SN/A    {
888522SN/A        return ((entry.byteCount == 0) ? MAX_SINGLE_DMA_SIZE :
89849SN/A                (entry.byteCount & PRD_COUNT_MASK));
90849SN/A    }
91849SN/A
92849SN/A    uint16_t getEOT()
93849SN/A    {
94849SN/A        return (entry.endOfTable & PRD_EOT_MASK);
95849SN/A    }
96849SN/A};
97849SN/A
98849SN/A#define DATA_OFFSET     (0)
99849SN/A#define ERROR_OFFSET    (1)
100849SN/A#define FEATURES_OFFSET (1)
101849SN/A#define NSECTOR_OFFSET  (2)
102849SN/A#define SECTOR_OFFSET   (3)
103849SN/A#define LCYL_OFFSET     (4)
104849SN/A#define HCYL_OFFSET     (5)
105849SN/A#define SELECT_OFFSET   (6)
1061817SN/A#define DRIVE_OFFSET    (6)
107849SN/A#define STATUS_OFFSET   (7)
108849SN/A#define COMMAND_OFFSET  (7)
109849SN/A
110849SN/A#define CONTROL_OFFSET  (2)
111849SN/A#define ALTSTAT_OFFSET  (2)
112849SN/A
113849SN/A#define SELECT_DEV_BIT  0x10
114849SN/A#define CONTROL_RST_BIT 0x04
115849SN/A#define CONTROL_IEN_BIT 0x02
116849SN/A#define STATUS_BSY_BIT  0x80
117849SN/A#define STATUS_DRDY_BIT 0x40
118849SN/A#define STATUS_DRQ_BIT  0x08
119893SN/A#define STATUS_SEEK_BIT 0x10
120893SN/A#define STATUS_DF_BIT   0x20
121864SN/A#define DRIVE_LBA_BIT   0x40
122849SN/A
123849SN/A#define DEV0 (0)
124849SN/A#define DEV1 (1)
125849SN/A
126849SN/Atypedef struct CommandReg {
1271817SN/A    uint16_t data;
1281817SN/A    uint8_t error;
129849SN/A    uint8_t sec_count;
130849SN/A    uint8_t sec_num;
131849SN/A    uint8_t cyl_low;
132849SN/A    uint8_t cyl_high;
133849SN/A    union {
134849SN/A        uint8_t drive;
135849SN/A        uint8_t head;
136849SN/A    };
137893SN/A    uint8_t command;
138849SN/A} CommandReg_t;
139849SN/A
140864SN/Atypedef enum Events {
141864SN/A    None = 0,
142864SN/A    Transfer,
143864SN/A    ReadWait,
144864SN/A    WriteWait,
145864SN/A    PrdRead,
146864SN/A    DmaRead,
147864SN/A    DmaWrite
148864SN/A} Events_t;
149864SN/A
150849SN/Atypedef enum DevAction {
151849SN/A    ACT_NONE = 0,
152849SN/A    ACT_CMD_WRITE,
153849SN/A    ACT_CMD_COMPLETE,
154849SN/A    ACT_CMD_ERROR,
155893SN/A    ACT_SELECT_WRITE,
156849SN/A    ACT_STAT_READ,
157849SN/A    ACT_DATA_READY,
158849SN/A    ACT_DATA_READ_BYTE,
159849SN/A    ACT_DATA_READ_SHORT,
160849SN/A    ACT_DATA_WRITE_BYTE,
161849SN/A    ACT_DATA_WRITE_SHORT,
162849SN/A    ACT_DMA_READY,
163893SN/A    ACT_DMA_DONE,
164893SN/A    ACT_SRST_SET,
165893SN/A    ACT_SRST_CLEAR
166849SN/A} DevAction_t;
167849SN/A
168849SN/Atypedef enum DevState {
169849SN/A    // Device idle
170849SN/A    Device_Idle_S = 0,
171849SN/A    Device_Idle_SI,
172849SN/A    Device_Idle_NS,
173849SN/A
174893SN/A    // Software reset
175893SN/A    Device_Srst,
176893SN/A
177849SN/A    // Non-data commands
178849SN/A    Command_Execution,
179849SN/A
180849SN/A    // PIO data-in (data to host)
181849SN/A    Prepare_Data_In,
182849SN/A    Data_Ready_INTRQ_In,
183849SN/A    Transfer_Data_In,
184849SN/A
185849SN/A    // PIO data-out (data from host)
186849SN/A    Prepare_Data_Out,
187849SN/A    Data_Ready_INTRQ_Out,
188849SN/A    Transfer_Data_Out,
189849SN/A
190849SN/A    // DMA protocol
191849SN/A    Prepare_Data_Dma,
1929956SN/A    Transfer_Data_Dma,
1939956SN/A    Device_Dma_Abort
194849SN/A} DevState_t;
195849SN/A
196849SN/Atypedef enum DmaState {
197849SN/A    Dma_Idle = 0,
198849SN/A    Dma_Start,
199849SN/A    Dma_Transfer
200849SN/A} DmaState_t;
201849SN/A
202848SN/Aclass IdeController;
203848SN/A
204848SN/A/**
205849SN/A * IDE Disk device model
206848SN/A */
207848SN/Aclass IdeDisk : public SimObject
208848SN/A{
209848SN/A  protected:
210848SN/A    /** The IDE controller for this disk. */
211848SN/A    IdeController *ctrl;
212848SN/A    /** The image that contains the data of this disk. */
213848SN/A    DiskImage *image;
214848SN/A
215848SN/A  protected:
216864SN/A    /** The disk delay in microseconds. */
217848SN/A    int diskDelay;
218848SN/A
219849SN/A  private:
220849SN/A    /** Drive identification structure for this disk */
2211722SN/A    struct ataparams driveID;
222849SN/A    /** Data buffer for transfers */
223849SN/A    uint8_t *dataBuffer;
224893SN/A    /** Number of bytes in command data transfer */
225893SN/A    uint32_t cmdBytes;
226849SN/A    /** Number of bytes left in command data transfer */
227849SN/A    uint32_t cmdBytesLeft;
228849SN/A    /** Number of bytes left in DRQ block */
229849SN/A    uint32_t drqBytesLeft;
230849SN/A    /** Current sector in access */
231849SN/A    uint32_t curSector;
232849SN/A    /** Command block registers */
233849SN/A    CommandReg_t cmdReg;
234893SN/A    /** Status register */
235893SN/A    uint8_t status;
236849SN/A    /** Interrupt enable bit */
237849SN/A    bool nIENBit;
238849SN/A    /** Device state */
239849SN/A    DevState_t devState;
240849SN/A    /** Dma state */
241849SN/A    DmaState_t dmaState;
242849SN/A    /** Dma transaction is a read */
243849SN/A    bool dmaRead;
244849SN/A    /** PRD table base address */
245849SN/A    uint32_t curPrdAddr;
246849SN/A    /** PRD entry */
247849SN/A    PrdTableEntry curPrd;
248849SN/A    /** Device ID (master=0/slave=1) */
249849SN/A    int devID;
250849SN/A    /** Interrupt pending */
251849SN/A    bool intrPending;
2529956SN/A    /** DMA Aborted */
2539956SN/A    bool dmaAborted;
254849SN/A
2555999SN/A    Stats::Scalar dmaReadFullPages;
2565999SN/A    Stats::Scalar dmaReadBytes;
2575999SN/A    Stats::Scalar dmaReadTxs;
2585999SN/A    Stats::Scalar dmaWriteFullPages;
2595999SN/A    Stats::Scalar dmaWriteBytes;
2605999SN/A    Stats::Scalar dmaWriteTxs;
2612275SN/A
262848SN/A  public:
2635034SN/A    typedef IdeDiskParams Params;
2645034SN/A    IdeDisk(const Params *p);
265848SN/A
266848SN/A    /**
267848SN/A     * Delete the data buffer.
268848SN/A     */
269848SN/A    ~IdeDisk();
270848SN/A
271848SN/A    /**
272893SN/A     * Reset the device state
273893SN/A     */
274893SN/A    void reset(int id);
275893SN/A
276893SN/A    /**
2772629SN/A     * Register Statistics
2782629SN/A     */
27911169SN/A    void regStats() override;
2802629SN/A
2812629SN/A    /**
282848SN/A     * Set the controller for this device
283848SN/A     * @param c The IDE controller
284848SN/A     */
2852565SN/A    void setController(IdeController *c) {
286848SN/A        if (ctrl) panic("Cannot change the controller once set!\n");
287848SN/A        ctrl = c;
288848SN/A    }
289848SN/A
290849SN/A    // Device register read/write
2915772SN/A    void readCommand(const Addr offset, int size, uint8_t *data);
2925772SN/A    void readControl(const Addr offset, int size, uint8_t *data);
2935772SN/A    void writeCommand(const Addr offset, int size, const uint8_t *data);
2945772SN/A    void writeControl(const Addr offset, int size, const uint8_t *data);
295848SN/A
296849SN/A    // Start/abort functions
297849SN/A    void startDma(const uint32_t &prdTableBase);
298849SN/A    void abortDma();
299849SN/A
300849SN/A  private:
301849SN/A    void startCommand();
302849SN/A
303849SN/A    // Interrupt management
304849SN/A    void intrPost();
305849SN/A    void intrClear();
306849SN/A
307849SN/A    // DMA stuff
308849SN/A    void doDmaTransfer();
30912087Sspwilson2@wisc.edu    EventFunctionWrapper dmaTransferEvent;
310849SN/A
3112565SN/A    void doDmaDataRead();
3122565SN/A
313849SN/A    void doDmaRead();
3142565SN/A    ChunkGenerator *dmaReadCG;
31512087Sspwilson2@wisc.edu    EventFunctionWrapper dmaReadWaitEvent;
316849SN/A
3172565SN/A    void doDmaDataWrite();
3182565SN/A
319849SN/A    void doDmaWrite();
3202565SN/A    ChunkGenerator *dmaWriteCG;
32112087Sspwilson2@wisc.edu    EventFunctionWrapper dmaWriteWaitEvent;
322849SN/A
323849SN/A    void dmaPrdReadDone();
32412087Sspwilson2@wisc.edu    EventFunctionWrapper dmaPrdReadEvent;
325849SN/A
326849SN/A    void dmaReadDone();
32712087Sspwilson2@wisc.edu    EventFunctionWrapper dmaReadEvent;
328849SN/A
329849SN/A    void dmaWriteDone();
33012087Sspwilson2@wisc.edu    EventFunctionWrapper dmaWriteEvent;
331849SN/A
332849SN/A    // Disk image read/write
333849SN/A    void readDisk(uint32_t sector, uint8_t *data);
334849SN/A    void writeDisk(uint32_t sector, uint8_t *data);
335849SN/A
336849SN/A    // State machine management
337849SN/A    void updateState(DevAction_t action);
338849SN/A
339849SN/A    // Utility functions
340893SN/A    bool isBSYSet() { return (status & STATUS_BSY_BIT); }
341849SN/A    bool isIENSet() { return nIENBit; }
342929SN/A    bool isDEVSelect();
343849SN/A
344849SN/A    void setComplete()
345849SN/A    {
346849SN/A        // clear out the status byte
347893SN/A        status = 0;
348849SN/A        // set the DRDY bit
349893SN/A        status |= STATUS_DRDY_BIT;
350893SN/A        // set the SEEK bit
351893SN/A        status |= STATUS_SEEK_BIT;
352849SN/A    }
353849SN/A
354849SN/A    uint32_t getLBABase()
355849SN/A    {
356849SN/A        return  (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
357849SN/A                       (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
358849SN/A    }
359848SN/A
360864SN/A    inline Addr pciToDma(Addr pciAddr);
361864SN/A
36211168SN/A    void serialize(CheckpointOut &cp) const override;
36311168SN/A    void unserialize(CheckpointIn &cp) override;
364848SN/A};
365848SN/A
366848SN/A
36711264Sandreas.sandberg@arm.com#endif // __DEV_STORAGE_IDE_DISK_HH__
368