ide_ctrl.cc revision 2846
110259SAndrew.Bardsley@arm.com/*
210259SAndrew.Bardsley@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
310259SAndrew.Bardsley@arm.com * All rights reserved.
410259SAndrew.Bardsley@arm.com *
510259SAndrew.Bardsley@arm.com * Redistribution and use in source and binary forms, with or without
610259SAndrew.Bardsley@arm.com * modification, are permitted provided that the following conditions are
710259SAndrew.Bardsley@arm.com * met: redistributions of source code must retain the above copyright
810259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer;
910259SAndrew.Bardsley@arm.com * redistributions in binary form must reproduce the above copyright
1010259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer in the
1110259SAndrew.Bardsley@arm.com * documentation and/or other materials provided with the distribution;
1210259SAndrew.Bardsley@arm.com * neither the name of the copyright holders nor the names of its
1310259SAndrew.Bardsley@arm.com * contributors may be used to endorse or promote products derived from
1410259SAndrew.Bardsley@arm.com * this software without specific prior written permission.
1510259SAndrew.Bardsley@arm.com *
1610259SAndrew.Bardsley@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1710259SAndrew.Bardsley@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1810259SAndrew.Bardsley@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1910259SAndrew.Bardsley@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2010259SAndrew.Bardsley@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2110259SAndrew.Bardsley@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2210259SAndrew.Bardsley@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2310259SAndrew.Bardsley@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2410259SAndrew.Bardsley@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2510259SAndrew.Bardsley@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2610259SAndrew.Bardsley@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2710259SAndrew.Bardsley@arm.com *
2810259SAndrew.Bardsley@arm.com * Authors: Andrew Schultz
2910259SAndrew.Bardsley@arm.com *          Ali Saidi
3010259SAndrew.Bardsley@arm.com *          Miguel Serrano
3110259SAndrew.Bardsley@arm.com */
3210259SAndrew.Bardsley@arm.com
3310259SAndrew.Bardsley@arm.com#include <cstddef>
3410259SAndrew.Bardsley@arm.com#include <cstdlib>
3510259SAndrew.Bardsley@arm.com#include <string>
3610259SAndrew.Bardsley@arm.com#include <vector>
3710259SAndrew.Bardsley@arm.com
3810259SAndrew.Bardsley@arm.com#include "base/trace.hh"
3910259SAndrew.Bardsley@arm.com#include "cpu/intr_control.hh"
4011793Sbrandon.potter@amd.com#include "dev/ide_ctrl.hh"
4111793Sbrandon.potter@amd.com#include "dev/ide_disk.hh"
4210259SAndrew.Bardsley@arm.com#include "dev/pciconfigall.hh"
4310259SAndrew.Bardsley@arm.com#include "dev/pcireg.h"
4410259SAndrew.Bardsley@arm.com#include "dev/platform.hh"
4510259SAndrew.Bardsley@arm.com#include "mem/packet.hh"
4610259SAndrew.Bardsley@arm.com#include "sim/builder.hh"
4710259SAndrew.Bardsley@arm.com#include "sim/sim_object.hh"
4810259SAndrew.Bardsley@arm.com#include "sim/byteswap.hh"
4910259SAndrew.Bardsley@arm.com
5010259SAndrew.Bardsley@arm.comusing namespace std;
5110259SAndrew.Bardsley@arm.com
5210259SAndrew.Bardsley@arm.com////
5310259SAndrew.Bardsley@arm.com// Initialization and destruction
5410259SAndrew.Bardsley@arm.com////
5510259SAndrew.Bardsley@arm.com
5610259SAndrew.Bardsley@arm.comIdeController::IdeController(Params *p)
5710259SAndrew.Bardsley@arm.com    : PciDev(p)
5810259SAndrew.Bardsley@arm.com{
5910259SAndrew.Bardsley@arm.com    // initialize the PIO interface addresses
6010259SAndrew.Bardsley@arm.com    pri_cmd_addr = 0;
6110259SAndrew.Bardsley@arm.com    pri_cmd_size = BARSize[0];
6210259SAndrew.Bardsley@arm.com
6310259SAndrew.Bardsley@arm.com    pri_ctrl_addr = 0;
6410259SAndrew.Bardsley@arm.com    pri_ctrl_size = BARSize[1];
6510259SAndrew.Bardsley@arm.com
6610259SAndrew.Bardsley@arm.com    sec_cmd_addr = 0;
6710259SAndrew.Bardsley@arm.com    sec_cmd_size = BARSize[2];
6810259SAndrew.Bardsley@arm.com
6910259SAndrew.Bardsley@arm.com    sec_ctrl_addr = 0;
7010259SAndrew.Bardsley@arm.com    sec_ctrl_size = BARSize[3];
7110259SAndrew.Bardsley@arm.com
7210259SAndrew.Bardsley@arm.com    // initialize the bus master interface (BMI) address to be configured
7310259SAndrew.Bardsley@arm.com    // via PCI
7410259SAndrew.Bardsley@arm.com    bmi_addr = 0;
7510259SAndrew.Bardsley@arm.com    bmi_size = BARSize[4];
7610259SAndrew.Bardsley@arm.com
7710259SAndrew.Bardsley@arm.com    // zero out all of the registers
7810259SAndrew.Bardsley@arm.com    memset(bmi_regs.data, 0, sizeof(bmi_regs));
7910259SAndrew.Bardsley@arm.com    memset(config_regs.data, 0, sizeof(config_regs.data));
8010259SAndrew.Bardsley@arm.com
8110259SAndrew.Bardsley@arm.com    // setup initial values
8210259SAndrew.Bardsley@arm.com    // enable both channels
8310259SAndrew.Bardsley@arm.com    config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN);
8410259SAndrew.Bardsley@arm.com    config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN);
8510259SAndrew.Bardsley@arm.com    bmi_regs.bmis0 = DMA1CAP | DMA0CAP;
8610259SAndrew.Bardsley@arm.com    bmi_regs.bmis1 = DMA1CAP | DMA0CAP;
8710259SAndrew.Bardsley@arm.com
8810259SAndrew.Bardsley@arm.com    // reset all internal variables
8910259SAndrew.Bardsley@arm.com    io_enabled = false;
9010259SAndrew.Bardsley@arm.com    bm_enabled = false;
9110259SAndrew.Bardsley@arm.com    memset(cmd_in_progress, 0, sizeof(cmd_in_progress));
9210259SAndrew.Bardsley@arm.com
9310259SAndrew.Bardsley@arm.com    // setup the disks attached to controller
9410259SAndrew.Bardsley@arm.com    memset(disks, 0, sizeof(disks));
9510259SAndrew.Bardsley@arm.com    dev[0] = 0;
9610259SAndrew.Bardsley@arm.com    dev[1] = 0;
9710259SAndrew.Bardsley@arm.com
9810259SAndrew.Bardsley@arm.com    if (params()->disks.size() > 3)
9910259SAndrew.Bardsley@arm.com        panic("IDE controllers support a maximum of 4 devices attached!\n");
10010259SAndrew.Bardsley@arm.com
10110259SAndrew.Bardsley@arm.com    for (int i = 0; i < params()->disks.size(); i++) {
10210259SAndrew.Bardsley@arm.com        disks[i] = params()->disks[i];
10310259SAndrew.Bardsley@arm.com        disks[i]->setController(this);
10410259SAndrew.Bardsley@arm.com    }
10510259SAndrew.Bardsley@arm.com}
10610259SAndrew.Bardsley@arm.com
10710259SAndrew.Bardsley@arm.comIdeController::~IdeController()
10810259SAndrew.Bardsley@arm.com{
10910259SAndrew.Bardsley@arm.com    for (int i = 0; i < 4; i++)
11010259SAndrew.Bardsley@arm.com        if (disks[i])
11110259SAndrew.Bardsley@arm.com            delete disks[i];
11210259SAndrew.Bardsley@arm.com}
11310259SAndrew.Bardsley@arm.com
11410259SAndrew.Bardsley@arm.com////
11510259SAndrew.Bardsley@arm.com// Utility functions
11610259SAndrew.Bardsley@arm.com///
11710259SAndrew.Bardsley@arm.com
11810259SAndrew.Bardsley@arm.comvoid
11910259SAndrew.Bardsley@arm.comIdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
12010259SAndrew.Bardsley@arm.com                         IdeRegType &reg_type)
12110259SAndrew.Bardsley@arm.com{
12210259SAndrew.Bardsley@arm.com    offset = addr;
12310259SAndrew.Bardsley@arm.com
12410259SAndrew.Bardsley@arm.com    if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
12510259SAndrew.Bardsley@arm.com        offset -= pri_cmd_addr;
12610259SAndrew.Bardsley@arm.com        reg_type = COMMAND_BLOCK;
12710259SAndrew.Bardsley@arm.com        channel = PRIMARY;
12810259SAndrew.Bardsley@arm.com    } else if (addr >= pri_ctrl_addr &&
12910259SAndrew.Bardsley@arm.com               addr < (pri_ctrl_addr + pri_ctrl_size)) {
13010259SAndrew.Bardsley@arm.com        offset -= pri_ctrl_addr;
13110259SAndrew.Bardsley@arm.com        reg_type = CONTROL_BLOCK;
13210259SAndrew.Bardsley@arm.com        channel = PRIMARY;
13310259SAndrew.Bardsley@arm.com    } else if (addr >= sec_cmd_addr &&
13410259SAndrew.Bardsley@arm.com               addr < (sec_cmd_addr + sec_cmd_size)) {
13510259SAndrew.Bardsley@arm.com        offset -= sec_cmd_addr;
13610259SAndrew.Bardsley@arm.com        reg_type = COMMAND_BLOCK;
13710259SAndrew.Bardsley@arm.com        channel = SECONDARY;
13810259SAndrew.Bardsley@arm.com    } else if (addr >= sec_ctrl_addr &&
13910259SAndrew.Bardsley@arm.com               addr < (sec_ctrl_addr + sec_ctrl_size)) {
14010259SAndrew.Bardsley@arm.com        offset -= sec_ctrl_addr;
14110259SAndrew.Bardsley@arm.com        reg_type = CONTROL_BLOCK;
14210259SAndrew.Bardsley@arm.com        channel = SECONDARY;
14310259SAndrew.Bardsley@arm.com    } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
14410259SAndrew.Bardsley@arm.com        offset -= bmi_addr;
14510259SAndrew.Bardsley@arm.com        reg_type = BMI_BLOCK;
14610259SAndrew.Bardsley@arm.com        channel = (offset < BMIC1) ? PRIMARY : SECONDARY;
14710259SAndrew.Bardsley@arm.com    } else {
14810259SAndrew.Bardsley@arm.com        panic("IDE controller access to invalid address: %#x\n", addr);
14910259SAndrew.Bardsley@arm.com    }
15010259SAndrew.Bardsley@arm.com}
15110259SAndrew.Bardsley@arm.com
15210259SAndrew.Bardsley@arm.comint
15310259SAndrew.Bardsley@arm.comIdeController::getDisk(IdeChannel channel)
15410259SAndrew.Bardsley@arm.com{
15510259SAndrew.Bardsley@arm.com    int disk = 0;
15610259SAndrew.Bardsley@arm.com    uint8_t *devBit = &dev[0];
15710259SAndrew.Bardsley@arm.com
15810259SAndrew.Bardsley@arm.com    if (channel == SECONDARY) {
15910259SAndrew.Bardsley@arm.com        disk += 2;
16010259SAndrew.Bardsley@arm.com        devBit = &dev[1];
16110259SAndrew.Bardsley@arm.com    }
16210259SAndrew.Bardsley@arm.com
16310259SAndrew.Bardsley@arm.com    disk += *devBit;
16410259SAndrew.Bardsley@arm.com
16510259SAndrew.Bardsley@arm.com    assert(*devBit == 0 || *devBit == 1);
16610259SAndrew.Bardsley@arm.com
16710259SAndrew.Bardsley@arm.com    return disk;
16810259SAndrew.Bardsley@arm.com}
16910259SAndrew.Bardsley@arm.com
17010259SAndrew.Bardsley@arm.comint
17110259SAndrew.Bardsley@arm.comIdeController::getDisk(IdeDisk *diskPtr)
17210259SAndrew.Bardsley@arm.com{
17310259SAndrew.Bardsley@arm.com    for (int i = 0; i < 4; i++) {
17410259SAndrew.Bardsley@arm.com        if ((long)diskPtr == (long)disks[i])
17510259SAndrew.Bardsley@arm.com            return i;
17610259SAndrew.Bardsley@arm.com    }
17710259SAndrew.Bardsley@arm.com    return -1;
17810259SAndrew.Bardsley@arm.com}
17910259SAndrew.Bardsley@arm.com
18010259SAndrew.Bardsley@arm.combool
18110259SAndrew.Bardsley@arm.comIdeController::isDiskSelected(IdeDisk *diskPtr)
18210259SAndrew.Bardsley@arm.com{
18310259SAndrew.Bardsley@arm.com    for (int i = 0; i < 4; i++) {
18410259SAndrew.Bardsley@arm.com        if ((long)diskPtr == (long)disks[i]) {
18510259SAndrew.Bardsley@arm.com            // is disk is on primary or secondary channel
18610259SAndrew.Bardsley@arm.com            int channel = i/2;
18710259SAndrew.Bardsley@arm.com            // is disk the master or slave
18810259SAndrew.Bardsley@arm.com            int devID = i%2;
18910259SAndrew.Bardsley@arm.com
19010259SAndrew.Bardsley@arm.com            return (dev[channel] == devID);
19110259SAndrew.Bardsley@arm.com        }
19210259SAndrew.Bardsley@arm.com    }
19310259SAndrew.Bardsley@arm.com    panic("Unable to find disk by pointer!!\n");
19410259SAndrew.Bardsley@arm.com}
19510259SAndrew.Bardsley@arm.com
19610259SAndrew.Bardsley@arm.com////
19710259SAndrew.Bardsley@arm.com// Command completion
19810259SAndrew.Bardsley@arm.com////
19910259SAndrew.Bardsley@arm.com
20010259SAndrew.Bardsley@arm.comvoid
20110259SAndrew.Bardsley@arm.comIdeController::setDmaComplete(IdeDisk *disk)
20210259SAndrew.Bardsley@arm.com{
20310259SAndrew.Bardsley@arm.com    int diskNum = getDisk(disk);
20410259SAndrew.Bardsley@arm.com
20510259SAndrew.Bardsley@arm.com    if (diskNum < 0)
20610259SAndrew.Bardsley@arm.com        panic("Unable to find disk based on pointer %#x\n", disk);
20710259SAndrew.Bardsley@arm.com
20810259SAndrew.Bardsley@arm.com    if (diskNum < 2) {
20910259SAndrew.Bardsley@arm.com        // clear the start/stop bit in the command register
21010259SAndrew.Bardsley@arm.com        bmi_regs.bmic0 &= ~SSBM;
21110259SAndrew.Bardsley@arm.com        // clear the bus master active bit in the status register
21210259SAndrew.Bardsley@arm.com        bmi_regs.bmis0 &= ~BMIDEA;
21310259SAndrew.Bardsley@arm.com        // set the interrupt bit
21410259SAndrew.Bardsley@arm.com        bmi_regs.bmis0 |= IDEINTS;
21510259SAndrew.Bardsley@arm.com    } else {
21610259SAndrew.Bardsley@arm.com        // clear the start/stop bit in the command register
21710259SAndrew.Bardsley@arm.com        bmi_regs.bmic1 &= ~SSBM;
21810259SAndrew.Bardsley@arm.com        // clear the bus master active bit in the status register
21910259SAndrew.Bardsley@arm.com        bmi_regs.bmis1 &= ~BMIDEA;
22011567Smitch.hayenga@arm.com        // set the interrupt bit
22111567Smitch.hayenga@arm.com        bmi_regs.bmis1 |= IDEINTS;
22210259SAndrew.Bardsley@arm.com    }
22310259SAndrew.Bardsley@arm.com}
22410259SAndrew.Bardsley@arm.com
22510259SAndrew.Bardsley@arm.com
22610259SAndrew.Bardsley@arm.com////
22711567Smitch.hayenga@arm.com// Read and write handling
22810259SAndrew.Bardsley@arm.com////
22910259SAndrew.Bardsley@arm.com
23010259SAndrew.Bardsley@arm.comTick
23110379Sandreas.hansson@arm.comIdeController::readConfig(Packet *pkt)
23210379Sandreas.hansson@arm.com{
23310259SAndrew.Bardsley@arm.com    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
23410259SAndrew.Bardsley@arm.com    if (offset < PCI_DEVICE_SPECIFIC)
23510259SAndrew.Bardsley@arm.com        return  PciDev::readConfig(pkt);
23610259SAndrew.Bardsley@arm.com    assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
23710259SAndrew.Bardsley@arm.com
23810259SAndrew.Bardsley@arm.com    pkt->allocate();
23910259SAndrew.Bardsley@arm.com
24010259SAndrew.Bardsley@arm.com    switch (pkt->getSize()) {
24110259SAndrew.Bardsley@arm.com      case sizeof(uint8_t):
24210259SAndrew.Bardsley@arm.com        switch (offset) {
24310259SAndrew.Bardsley@arm.com          case IDE_CTRL_CONF_DEV_TIMING:
24410259SAndrew.Bardsley@arm.com            pkt->set<uint8_t>(config_regs.sidetim);
24510259SAndrew.Bardsley@arm.com            break;
24610259SAndrew.Bardsley@arm.com          case IDE_CTRL_CONF_UDMA_CNTRL:
24710259SAndrew.Bardsley@arm.com            pkt->set<uint8_t>(config_regs.udmactl);
24810259SAndrew.Bardsley@arm.com            break;
24910259SAndrew.Bardsley@arm.com          case IDE_CTRL_CONF_PRIM_TIMING+1:
25010259SAndrew.Bardsley@arm.com            pkt->set<uint8_t>(htole(config_regs.idetim0) >> 8);
25110259SAndrew.Bardsley@arm.com            break;
25210259SAndrew.Bardsley@arm.com          case IDE_CTRL_CONF_SEC_TIMING+1:
25310259SAndrew.Bardsley@arm.com            pkt->set<uint8_t>(htole(config_regs.idetim1) >> 8);
25410259SAndrew.Bardsley@arm.com            break;
25510259SAndrew.Bardsley@arm.com          case IDE_CTRL_CONF_IDE_CONFIG:
25610259SAndrew.Bardsley@arm.com            pkt->set<uint8_t>(htole(config_regs.ideconfig) & 0xFF);
25710259SAndrew.Bardsley@arm.com            break;
25810259SAndrew.Bardsley@arm.com          case IDE_CTRL_CONF_IDE_CONFIG+1:
25910259SAndrew.Bardsley@arm.com            pkt->set<uint8_t>(htole(config_regs.ideconfig) >> 8);
26010259SAndrew.Bardsley@arm.com            break;
26110259SAndrew.Bardsley@arm.com          default:
26210259SAndrew.Bardsley@arm.com            panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
26310259SAndrew.Bardsley@arm.com                    offset);
26410259SAndrew.Bardsley@arm.com        }
26510259SAndrew.Bardsley@arm.com        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
26610259SAndrew.Bardsley@arm.com                (uint32_t)pkt->get<uint8_t>());
26710259SAndrew.Bardsley@arm.com        break;
26810259SAndrew.Bardsley@arm.com      case sizeof(uint16_t):
26910259SAndrew.Bardsley@arm.com        switch (offset) {
27010259SAndrew.Bardsley@arm.com          case IDE_CTRL_CONF_PRIM_TIMING:
27110259SAndrew.Bardsley@arm.com            pkt->set<uint16_t>(config_regs.idetim0);
27210259SAndrew.Bardsley@arm.com            break;
27310259SAndrew.Bardsley@arm.com          case IDE_CTRL_CONF_SEC_TIMING:
27410259SAndrew.Bardsley@arm.com            pkt->set<uint16_t>(config_regs.idetim1);
27510259SAndrew.Bardsley@arm.com            break;
27610259SAndrew.Bardsley@arm.com          case IDE_CTRL_CONF_UDMA_TIMING:
27710259SAndrew.Bardsley@arm.com            pkt->set<uint16_t>(config_regs.udmatim);
27810379Sandreas.hansson@arm.com            break;
27910379Sandreas.hansson@arm.com          case IDE_CTRL_CONF_IDE_CONFIG:
28010259SAndrew.Bardsley@arm.com            pkt->set<uint16_t>(config_regs.ideconfig);
28110259SAndrew.Bardsley@arm.com            break;
28210259SAndrew.Bardsley@arm.com          default:
28310259SAndrew.Bardsley@arm.com            panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
28410259SAndrew.Bardsley@arm.com                    offset);
28510259SAndrew.Bardsley@arm.com        }
28610259SAndrew.Bardsley@arm.com        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
28710259SAndrew.Bardsley@arm.com                (uint32_t)pkt->get<uint16_t>());
28810259SAndrew.Bardsley@arm.com        break;
28910259SAndrew.Bardsley@arm.com      case sizeof(uint32_t):
29010259SAndrew.Bardsley@arm.com        panic("No 32bit reads implemented for this device.");
29110259SAndrew.Bardsley@arm.com        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
29210259SAndrew.Bardsley@arm.com                (uint32_t)pkt->get<uint32_t>());
29310259SAndrew.Bardsley@arm.com        break;
29410259SAndrew.Bardsley@arm.com      default:
29510259SAndrew.Bardsley@arm.com        panic("invalid access size(?) for PCI configspace!\n");
29610259SAndrew.Bardsley@arm.com    }
29710259SAndrew.Bardsley@arm.com    pkt->result = Packet::Success;
29810259SAndrew.Bardsley@arm.com    return configDelay;
29910259SAndrew.Bardsley@arm.com
30010259SAndrew.Bardsley@arm.com}
30110259SAndrew.Bardsley@arm.com
30210259SAndrew.Bardsley@arm.com
30310259SAndrew.Bardsley@arm.comTick
30410259SAndrew.Bardsley@arm.comIdeController::writeConfig(Packet *pkt)
30510259SAndrew.Bardsley@arm.com{
30610259SAndrew.Bardsley@arm.com    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
30710259SAndrew.Bardsley@arm.com    if (offset < PCI_DEVICE_SPECIFIC) {
30810259SAndrew.Bardsley@arm.com        PciDev::writeConfig(pkt);
30910259SAndrew.Bardsley@arm.com    } else {
31010259SAndrew.Bardsley@arm.com        assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
31110259SAndrew.Bardsley@arm.com
31210259SAndrew.Bardsley@arm.com        switch (pkt->getSize()) {
31310259SAndrew.Bardsley@arm.com          case sizeof(uint8_t):
31410259SAndrew.Bardsley@arm.com            switch (offset) {
31510259SAndrew.Bardsley@arm.com              case IDE_CTRL_CONF_DEV_TIMING:
31610259SAndrew.Bardsley@arm.com                config_regs.sidetim = pkt->get<uint8_t>();
31710259SAndrew.Bardsley@arm.com                break;
31810259SAndrew.Bardsley@arm.com              case IDE_CTRL_CONF_UDMA_CNTRL:
31910259SAndrew.Bardsley@arm.com                config_regs.udmactl = pkt->get<uint8_t>();
32010259SAndrew.Bardsley@arm.com                break;
32110259SAndrew.Bardsley@arm.com              case IDE_CTRL_CONF_IDE_CONFIG:
32210259SAndrew.Bardsley@arm.com                config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) |
32310259SAndrew.Bardsley@arm.com                    (pkt->get<uint8_t>());
32412127Sspwilson2@wisc.edu                break;
32512127Sspwilson2@wisc.edu              case IDE_CTRL_CONF_IDE_CONFIG+1:
32610259SAndrew.Bardsley@arm.com                config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) |
32710259SAndrew.Bardsley@arm.com                    pkt->get<uint8_t>() << 8;
32810259SAndrew.Bardsley@arm.com                break;
32910259SAndrew.Bardsley@arm.com              default:
33010259SAndrew.Bardsley@arm.com                panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
33110259SAndrew.Bardsley@arm.com                        offset);
33210259SAndrew.Bardsley@arm.com            }
33310259SAndrew.Bardsley@arm.com            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
33410259SAndrew.Bardsley@arm.com                    offset, (uint32_t)pkt->get<uint8_t>());
33510259SAndrew.Bardsley@arm.com            break;
33610259SAndrew.Bardsley@arm.com          case sizeof(uint16_t):
33710259SAndrew.Bardsley@arm.com            switch (offset) {
33810259SAndrew.Bardsley@arm.com              case IDE_CTRL_CONF_PRIM_TIMING:
33910259SAndrew.Bardsley@arm.com                config_regs.idetim0 = pkt->get<uint16_t>();
34010259SAndrew.Bardsley@arm.com                break;
34110259SAndrew.Bardsley@arm.com              case IDE_CTRL_CONF_SEC_TIMING:
34210259SAndrew.Bardsley@arm.com                config_regs.idetim1 = pkt->get<uint16_t>();
34310259SAndrew.Bardsley@arm.com                break;
34410259SAndrew.Bardsley@arm.com              case IDE_CTRL_CONF_UDMA_TIMING:
34510259SAndrew.Bardsley@arm.com                config_regs.udmatim = pkt->get<uint16_t>();
34610259SAndrew.Bardsley@arm.com                break;
34710259SAndrew.Bardsley@arm.com              case IDE_CTRL_CONF_IDE_CONFIG:
34810259SAndrew.Bardsley@arm.com                config_regs.ideconfig = pkt->get<uint16_t>();
34910259SAndrew.Bardsley@arm.com                break;
35010259SAndrew.Bardsley@arm.com              default:
35110259SAndrew.Bardsley@arm.com                panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
35210259SAndrew.Bardsley@arm.com                        offset);
35310259SAndrew.Bardsley@arm.com            }
35410259SAndrew.Bardsley@arm.com            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
35510259SAndrew.Bardsley@arm.com                    offset, (uint32_t)pkt->get<uint16_t>());
35610259SAndrew.Bardsley@arm.com            break;
35710259SAndrew.Bardsley@arm.com          case sizeof(uint32_t):
35810259SAndrew.Bardsley@arm.com            panic("Write of unimplemented PCI config. register: %x\n", offset);
35910259SAndrew.Bardsley@arm.com            break;
36010259SAndrew.Bardsley@arm.com          default:
36110259SAndrew.Bardsley@arm.com            panic("invalid access size(?) for PCI configspace!\n");
36210259SAndrew.Bardsley@arm.com        }
36310259SAndrew.Bardsley@arm.com    }
36410259SAndrew.Bardsley@arm.com
36510259SAndrew.Bardsley@arm.com    /* Trap command register writes and enable IO/BM as appropriate as well as
36610259SAndrew.Bardsley@arm.com     * BARs. */
36710259SAndrew.Bardsley@arm.com    switch(offset) {
36810259SAndrew.Bardsley@arm.com      case PCI0_BASE_ADDR0:
36910259SAndrew.Bardsley@arm.com        if (BARAddrs[0] != 0)
37010259SAndrew.Bardsley@arm.com            pri_cmd_addr = BARAddrs[0];
37110259SAndrew.Bardsley@arm.com        break;
37210259SAndrew.Bardsley@arm.com
37310259SAndrew.Bardsley@arm.com      case PCI0_BASE_ADDR1:
37410259SAndrew.Bardsley@arm.com        if (BARAddrs[1] != 0)
37510259SAndrew.Bardsley@arm.com            pri_ctrl_addr = BARAddrs[1];
37610259SAndrew.Bardsley@arm.com        break;
37710259SAndrew.Bardsley@arm.com
37810259SAndrew.Bardsley@arm.com      case PCI0_BASE_ADDR2:
37910259SAndrew.Bardsley@arm.com        if (BARAddrs[2] != 0)
38010259SAndrew.Bardsley@arm.com            sec_cmd_addr = BARAddrs[2];
38110259SAndrew.Bardsley@arm.com        break;
38210259SAndrew.Bardsley@arm.com
38310259SAndrew.Bardsley@arm.com      case PCI0_BASE_ADDR3:
38410259SAndrew.Bardsley@arm.com        if (BARAddrs[3] != 0)
38510259SAndrew.Bardsley@arm.com            sec_ctrl_addr = BARAddrs[3];
38610259SAndrew.Bardsley@arm.com        break;
38710259SAndrew.Bardsley@arm.com
38810259SAndrew.Bardsley@arm.com      case PCI0_BASE_ADDR4:
38910259SAndrew.Bardsley@arm.com        if (BARAddrs[4] != 0)
39010259SAndrew.Bardsley@arm.com            bmi_addr = BARAddrs[4];
39110259SAndrew.Bardsley@arm.com        break;
39210259SAndrew.Bardsley@arm.com
39310259SAndrew.Bardsley@arm.com      case PCI_COMMAND:
39410259SAndrew.Bardsley@arm.com        if (letoh(config.command) & PCI_CMD_IOSE)
39510259SAndrew.Bardsley@arm.com            io_enabled = true;
39610259SAndrew.Bardsley@arm.com        else
39710259SAndrew.Bardsley@arm.com            io_enabled = false;
39810259SAndrew.Bardsley@arm.com
39910259SAndrew.Bardsley@arm.com        if (letoh(config.command) & PCI_CMD_BME)
40010259SAndrew.Bardsley@arm.com            bm_enabled = true;
40110259SAndrew.Bardsley@arm.com        else
40210259SAndrew.Bardsley@arm.com            bm_enabled = false;
40310259SAndrew.Bardsley@arm.com        break;
40410259SAndrew.Bardsley@arm.com    }
40510259SAndrew.Bardsley@arm.com    pkt->result = Packet::Success;
40610259SAndrew.Bardsley@arm.com    return configDelay;
40710259SAndrew.Bardsley@arm.com}
40810259SAndrew.Bardsley@arm.com
40910259SAndrew.Bardsley@arm.com
41010259SAndrew.Bardsley@arm.comTick
41110259SAndrew.Bardsley@arm.comIdeController::read(Packet *pkt)
41210259SAndrew.Bardsley@arm.com{
41310259SAndrew.Bardsley@arm.com    Addr offset;
41410259SAndrew.Bardsley@arm.com    IdeChannel channel;
41510259SAndrew.Bardsley@arm.com    IdeRegType reg_type;
41610259SAndrew.Bardsley@arm.com    int disk;
41710259SAndrew.Bardsley@arm.com
41810259SAndrew.Bardsley@arm.com    pkt->allocate();
41910259SAndrew.Bardsley@arm.com    if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
42010259SAndrew.Bardsley@arm.com         panic("Bad IDE read size: %d\n", pkt->getSize());
42110259SAndrew.Bardsley@arm.com
42210259SAndrew.Bardsley@arm.com    parseAddr(pkt->getAddr(), offset, channel, reg_type);
42310259SAndrew.Bardsley@arm.com
42410259SAndrew.Bardsley@arm.com    if (!io_enabled) {
42510259SAndrew.Bardsley@arm.com        pkt->result = Packet::Success;
42610259SAndrew.Bardsley@arm.com        return pioDelay;
42710259SAndrew.Bardsley@arm.com    }
42811435Smitch.hayenga@arm.com
42910259SAndrew.Bardsley@arm.com    switch (reg_type) {
43010259SAndrew.Bardsley@arm.com      case BMI_BLOCK:
43110259SAndrew.Bardsley@arm.com        switch (pkt->getSize()) {
43210259SAndrew.Bardsley@arm.com          case sizeof(uint8_t):
43310259SAndrew.Bardsley@arm.com            pkt->set(bmi_regs.data[offset]);
43410259SAndrew.Bardsley@arm.com            break;
43510259SAndrew.Bardsley@arm.com          case sizeof(uint16_t):
43610259SAndrew.Bardsley@arm.com            pkt->set(*(uint16_t*)&bmi_regs.data[offset]);
43710259SAndrew.Bardsley@arm.com            break;
43810259SAndrew.Bardsley@arm.com          case sizeof(uint32_t):
43910259SAndrew.Bardsley@arm.com            pkt->set(*(uint32_t*)&bmi_regs.data[offset]);
44010259SAndrew.Bardsley@arm.com            break;
44110259SAndrew.Bardsley@arm.com          default:
44210259SAndrew.Bardsley@arm.com            panic("IDE read of BMI reg invalid size: %#x\n", pkt->getSize());
44310259SAndrew.Bardsley@arm.com        }
44410259SAndrew.Bardsley@arm.com        break;
44510259SAndrew.Bardsley@arm.com
44610259SAndrew.Bardsley@arm.com      case COMMAND_BLOCK:
44710259SAndrew.Bardsley@arm.com      case CONTROL_BLOCK:
44810259SAndrew.Bardsley@arm.com        disk = getDisk(channel);
44910259SAndrew.Bardsley@arm.com
45010259SAndrew.Bardsley@arm.com        if (disks[disk] == NULL) {
45110259SAndrew.Bardsley@arm.com            pkt->set<uint8_t>(0);
45210259SAndrew.Bardsley@arm.com            break;
45310259SAndrew.Bardsley@arm.com        }
45410259SAndrew.Bardsley@arm.com
45510259SAndrew.Bardsley@arm.com        switch (offset) {
45610259SAndrew.Bardsley@arm.com          case DATA_OFFSET:
45710259SAndrew.Bardsley@arm.com            switch (pkt->getSize()) {
45810259SAndrew.Bardsley@arm.com              case sizeof(uint16_t):
45910259SAndrew.Bardsley@arm.com                disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
46010259SAndrew.Bardsley@arm.com                break;
46110259SAndrew.Bardsley@arm.com
46210259SAndrew.Bardsley@arm.com              case sizeof(uint32_t):
46310259SAndrew.Bardsley@arm.com                disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
46410259SAndrew.Bardsley@arm.com                disks[disk]->read(offset, reg_type,
46510259SAndrew.Bardsley@arm.com                        pkt->getPtr<uint8_t>() + sizeof(uint16_t));
46610259SAndrew.Bardsley@arm.com                break;
46710259SAndrew.Bardsley@arm.com
46810259SAndrew.Bardsley@arm.com              default:
46910259SAndrew.Bardsley@arm.com                panic("IDE read of data reg invalid size: %#x\n", pkt->getSize());
47010259SAndrew.Bardsley@arm.com            }
47110259SAndrew.Bardsley@arm.com            break;
47210259SAndrew.Bardsley@arm.com          default:
47310259SAndrew.Bardsley@arm.com            if (pkt->getSize() == sizeof(uint8_t)) {
47410259SAndrew.Bardsley@arm.com                disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
47510259SAndrew.Bardsley@arm.com            } else
47610259SAndrew.Bardsley@arm.com                panic("IDE read of command reg of invalid size: %#x\n", pkt->getSize());
47710259SAndrew.Bardsley@arm.com        }
47810259SAndrew.Bardsley@arm.com        break;
47910259SAndrew.Bardsley@arm.com      default:
48010259SAndrew.Bardsley@arm.com        panic("IDE controller read of unknown register block type!\n");
48110259SAndrew.Bardsley@arm.com    }
48210368SAndrew.Bardsley@arm.com    if (pkt->getSize() == 1)
48310368SAndrew.Bardsley@arm.com    DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
48410259SAndrew.Bardsley@arm.com            offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());
48510259SAndrew.Bardsley@arm.com    else if (pkt->getSize() == 2)
48610259SAndrew.Bardsley@arm.com    DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
48710259SAndrew.Bardsley@arm.com            offset, pkt->getSize(), pkt->get<uint16_t>());
48810259SAndrew.Bardsley@arm.com    else
48910259SAndrew.Bardsley@arm.com    DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
49010259SAndrew.Bardsley@arm.com            offset, pkt->getSize(), pkt->get<uint32_t>());
49110259SAndrew.Bardsley@arm.com
49210259SAndrew.Bardsley@arm.com    pkt->result = Packet::Success;
49310259SAndrew.Bardsley@arm.com    return pioDelay;
49410259SAndrew.Bardsley@arm.com}
49510259SAndrew.Bardsley@arm.com
49610259SAndrew.Bardsley@arm.comTick
49710259SAndrew.Bardsley@arm.comIdeController::write(Packet *pkt)
49810259SAndrew.Bardsley@arm.com{
49910259SAndrew.Bardsley@arm.com    Addr offset;
50010259SAndrew.Bardsley@arm.com    IdeChannel channel;
50110259SAndrew.Bardsley@arm.com    IdeRegType reg_type;
50210259SAndrew.Bardsley@arm.com    int disk;
50310259SAndrew.Bardsley@arm.com    uint8_t oldVal, newVal;
50410259SAndrew.Bardsley@arm.com
50510259SAndrew.Bardsley@arm.com    parseAddr(pkt->getAddr(), offset, channel, reg_type);
50610259SAndrew.Bardsley@arm.com
50710259SAndrew.Bardsley@arm.com    if (!io_enabled) {
50810259SAndrew.Bardsley@arm.com        pkt->result = Packet::Success;
50910259SAndrew.Bardsley@arm.com        DPRINTF(IdeCtrl, "io not enabled\n");
51010259SAndrew.Bardsley@arm.com        return pioDelay;
51110259SAndrew.Bardsley@arm.com    }
51210259SAndrew.Bardsley@arm.com
51310259SAndrew.Bardsley@arm.com    switch (reg_type) {
51410259SAndrew.Bardsley@arm.com      case BMI_BLOCK:
51510259SAndrew.Bardsley@arm.com        if (!bm_enabled) {
51610259SAndrew.Bardsley@arm.com            pkt->result = Packet::Success;
51710259SAndrew.Bardsley@arm.com            return pioDelay;
51810259SAndrew.Bardsley@arm.com        }
51910259SAndrew.Bardsley@arm.com
52010259SAndrew.Bardsley@arm.com        switch (offset) {
52110259SAndrew.Bardsley@arm.com            // Bus master IDE command register
52210259SAndrew.Bardsley@arm.com          case BMIC1:
52310259SAndrew.Bardsley@arm.com          case BMIC0:
52410259SAndrew.Bardsley@arm.com            if (pkt->getSize() != sizeof(uint8_t))
52510259SAndrew.Bardsley@arm.com                panic("Invalid BMIC write size: %x\n", pkt->getSize());
52610259SAndrew.Bardsley@arm.com
52710259SAndrew.Bardsley@arm.com            // select the current disk based on DEV bit
52810259SAndrew.Bardsley@arm.com            disk = getDisk(channel);
52910259SAndrew.Bardsley@arm.com
53010259SAndrew.Bardsley@arm.com            oldVal = bmi_regs.chan[channel].bmic;
53110259SAndrew.Bardsley@arm.com            newVal = pkt->get<uint8_t>();
53210259SAndrew.Bardsley@arm.com
53310259SAndrew.Bardsley@arm.com            // if a DMA transfer is in progress, R/W control cannot change
53410259SAndrew.Bardsley@arm.com            if (oldVal & SSBM) {
53510259SAndrew.Bardsley@arm.com                if ((oldVal & RWCON) ^ (newVal & RWCON)) {
53610259SAndrew.Bardsley@arm.com                    (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
53710259SAndrew.Bardsley@arm.com                }
53810259SAndrew.Bardsley@arm.com            }
53910259SAndrew.Bardsley@arm.com
54010259SAndrew.Bardsley@arm.com            // see if the start/stop bit is being changed
54110259SAndrew.Bardsley@arm.com            if ((oldVal & SSBM) ^ (newVal & SSBM)) {
54210259SAndrew.Bardsley@arm.com                if (oldVal & SSBM) {
54310259SAndrew.Bardsley@arm.com                    // stopping DMA transfer
54410259SAndrew.Bardsley@arm.com                    DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
54510259SAndrew.Bardsley@arm.com
54610259SAndrew.Bardsley@arm.com                    // clear the BMIDEA bit
54710259SAndrew.Bardsley@arm.com                    bmi_regs.chan[channel].bmis =
54810259SAndrew.Bardsley@arm.com                        bmi_regs.chan[channel].bmis & ~BMIDEA;
54910259SAndrew.Bardsley@arm.com
55010259SAndrew.Bardsley@arm.com                    if (disks[disk] == NULL)
55110259SAndrew.Bardsley@arm.com                        panic("DMA stop for disk %d which does not exist\n",
55210259SAndrew.Bardsley@arm.com                              disk);
55310259SAndrew.Bardsley@arm.com
55410259SAndrew.Bardsley@arm.com                    // inform the disk of the DMA transfer abort
55510259SAndrew.Bardsley@arm.com                    disks[disk]->abortDma();
55610259SAndrew.Bardsley@arm.com                } else {
55710259SAndrew.Bardsley@arm.com                    // starting DMA transfer
55810259SAndrew.Bardsley@arm.com                    DPRINTF(IdeCtrl, "Starting DMA transfer\n");
55910259SAndrew.Bardsley@arm.com
56010259SAndrew.Bardsley@arm.com                    // set the BMIDEA bit
56110259SAndrew.Bardsley@arm.com                    bmi_regs.chan[channel].bmis =
56210259SAndrew.Bardsley@arm.com                        bmi_regs.chan[channel].bmis | BMIDEA;
56310259SAndrew.Bardsley@arm.com
56410259SAndrew.Bardsley@arm.com                    if (disks[disk] == NULL)
56510259SAndrew.Bardsley@arm.com                        panic("DMA start for disk %d which does not exist\n",
56610563Sandreas.hansson@arm.com                              disk);
56710259SAndrew.Bardsley@arm.com
56810259SAndrew.Bardsley@arm.com                    // inform the disk of the DMA transfer start
56910259SAndrew.Bardsley@arm.com                    disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));
57010259SAndrew.Bardsley@arm.com                }
57110259SAndrew.Bardsley@arm.com            }
57210259SAndrew.Bardsley@arm.com
57310259SAndrew.Bardsley@arm.com            // update the register value
57410259SAndrew.Bardsley@arm.com            bmi_regs.chan[channel].bmic = newVal;
57510259SAndrew.Bardsley@arm.com            break;
57610259SAndrew.Bardsley@arm.com
57710259SAndrew.Bardsley@arm.com            // Bus master IDE status register
57810259SAndrew.Bardsley@arm.com          case BMIS0:
57910259SAndrew.Bardsley@arm.com          case BMIS1:
58010259SAndrew.Bardsley@arm.com            if (pkt->getSize() != sizeof(uint8_t))
58110259SAndrew.Bardsley@arm.com                panic("Invalid BMIS write size: %x\n", pkt->getSize());
58210259SAndrew.Bardsley@arm.com
58310259SAndrew.Bardsley@arm.com            oldVal = bmi_regs.chan[channel].bmis;
58410259SAndrew.Bardsley@arm.com            newVal = pkt->get<uint8_t>();
58510259SAndrew.Bardsley@arm.com
58610259SAndrew.Bardsley@arm.com            // the BMIDEA bit is RO
58710259SAndrew.Bardsley@arm.com            newVal |= (oldVal & BMIDEA);
58810259SAndrew.Bardsley@arm.com
58910259SAndrew.Bardsley@arm.com            // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
59010259SAndrew.Bardsley@arm.com            if ((oldVal & IDEINTS) && (newVal & IDEINTS))
59110259SAndrew.Bardsley@arm.com                newVal &= ~IDEINTS; // clear the interrupt?
59210259SAndrew.Bardsley@arm.com            else
59310259SAndrew.Bardsley@arm.com                (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
59410259SAndrew.Bardsley@arm.com
59510259SAndrew.Bardsley@arm.com            if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
59610259SAndrew.Bardsley@arm.com                newVal &= ~IDEDMAE;
59710259SAndrew.Bardsley@arm.com            else
59810259SAndrew.Bardsley@arm.com                (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
59910259SAndrew.Bardsley@arm.com
60010259SAndrew.Bardsley@arm.com            bmi_regs.chan[channel].bmis = newVal;
60110259SAndrew.Bardsley@arm.com            break;
60210259SAndrew.Bardsley@arm.com
60310259SAndrew.Bardsley@arm.com            // Bus master IDE descriptor table pointer register
60410259SAndrew.Bardsley@arm.com          case BMIDTP0:
60510259SAndrew.Bardsley@arm.com          case BMIDTP1:
60610259SAndrew.Bardsley@arm.com            {
60710259SAndrew.Bardsley@arm.com                if (pkt->getSize() != sizeof(uint32_t))
60810259SAndrew.Bardsley@arm.com                    panic("Invalid BMIDTP write size: %x\n", pkt->getSize());
60910259SAndrew.Bardsley@arm.com
61010259SAndrew.Bardsley@arm.com                bmi_regs.chan[channel].bmidtp = htole(pkt->get<uint32_t>() & ~0x3);
61110259SAndrew.Bardsley@arm.com            }
61210259SAndrew.Bardsley@arm.com            break;
61310259SAndrew.Bardsley@arm.com
61410259SAndrew.Bardsley@arm.com          default:
61510259SAndrew.Bardsley@arm.com            if (pkt->getSize() != sizeof(uint8_t) &&
61610259SAndrew.Bardsley@arm.com                pkt->getSize() != sizeof(uint16_t) &&
61710259SAndrew.Bardsley@arm.com                pkt->getSize() != sizeof(uint32_t))
61810259SAndrew.Bardsley@arm.com                panic("IDE controller write of invalid write size: %x\n",
61910259SAndrew.Bardsley@arm.com                      pkt->getSize());
62010259SAndrew.Bardsley@arm.com
62110259SAndrew.Bardsley@arm.com            // do a default copy of data into the registers
62210259SAndrew.Bardsley@arm.com            memcpy(&bmi_regs.data[offset], pkt->getPtr<uint8_t>(), pkt->getSize());
62310259SAndrew.Bardsley@arm.com        }
62410259SAndrew.Bardsley@arm.com        break;
62510259SAndrew.Bardsley@arm.com      case COMMAND_BLOCK:
62610259SAndrew.Bardsley@arm.com        if (offset == IDE_SELECT_OFFSET) {
62710259SAndrew.Bardsley@arm.com            uint8_t *devBit = &dev[channel];
62810259SAndrew.Bardsley@arm.com            *devBit = (letoh(pkt->get<uint8_t>()) & IDE_SELECT_DEV_BIT) ? 1 : 0;
62910259SAndrew.Bardsley@arm.com        }
63010259SAndrew.Bardsley@arm.com        // fall-through ok!
63110259SAndrew.Bardsley@arm.com      case CONTROL_BLOCK:
63210259SAndrew.Bardsley@arm.com        disk = getDisk(channel);
63310259SAndrew.Bardsley@arm.com
63410259SAndrew.Bardsley@arm.com        if (disks[disk] == NULL)
63510259SAndrew.Bardsley@arm.com            break;
63610259SAndrew.Bardsley@arm.com
63710259SAndrew.Bardsley@arm.com        switch (offset) {
63810259SAndrew.Bardsley@arm.com          case DATA_OFFSET:
63910259SAndrew.Bardsley@arm.com            switch (pkt->getSize()) {
64010259SAndrew.Bardsley@arm.com              case sizeof(uint16_t):
64110259SAndrew.Bardsley@arm.com                disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
64210259SAndrew.Bardsley@arm.com                break;
64310259SAndrew.Bardsley@arm.com
64410259SAndrew.Bardsley@arm.com              case sizeof(uint32_t):
64510259SAndrew.Bardsley@arm.com                disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
64610259SAndrew.Bardsley@arm.com                disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>() +
64710259SAndrew.Bardsley@arm.com                        sizeof(uint16_t));
64810259SAndrew.Bardsley@arm.com                break;
64910259SAndrew.Bardsley@arm.com              default:
65010259SAndrew.Bardsley@arm.com                panic("IDE write of data reg invalid size: %#x\n", pkt->getSize());
65110259SAndrew.Bardsley@arm.com            }
65210259SAndrew.Bardsley@arm.com            break;
65310259SAndrew.Bardsley@arm.com          default:
65410259SAndrew.Bardsley@arm.com            if (pkt->getSize() == sizeof(uint8_t)) {
65510259SAndrew.Bardsley@arm.com                disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
65610259SAndrew.Bardsley@arm.com            } else
65710259SAndrew.Bardsley@arm.com                panic("IDE write of command reg of invalid size: %#x\n", pkt->getSize());
65810259SAndrew.Bardsley@arm.com        }
65910259SAndrew.Bardsley@arm.com        break;
66010259SAndrew.Bardsley@arm.com      default:
66110259SAndrew.Bardsley@arm.com        panic("IDE controller write of unknown register block type!\n");
66210259SAndrew.Bardsley@arm.com    }
66310259SAndrew.Bardsley@arm.com
66410259SAndrew.Bardsley@arm.com    if (pkt->getSize() == 1)
66510259SAndrew.Bardsley@arm.com    DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
66610259SAndrew.Bardsley@arm.com            offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());
66710259SAndrew.Bardsley@arm.com    else if (pkt->getSize() == 2)
66810259SAndrew.Bardsley@arm.com    DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
66910259SAndrew.Bardsley@arm.com            offset, pkt->getSize(), pkt->get<uint16_t>());
67010259SAndrew.Bardsley@arm.com    else
67110259SAndrew.Bardsley@arm.com    DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
67210259SAndrew.Bardsley@arm.com            offset, pkt->getSize(), pkt->get<uint32_t>());
67310259SAndrew.Bardsley@arm.com
67410259SAndrew.Bardsley@arm.com
67510259SAndrew.Bardsley@arm.com    pkt->result = Packet::Success;
67610259SAndrew.Bardsley@arm.com    return pioDelay;
67710259SAndrew.Bardsley@arm.com}
67810259SAndrew.Bardsley@arm.com
67910259SAndrew.Bardsley@arm.com////
68010259SAndrew.Bardsley@arm.com// Serialization
68110259SAndrew.Bardsley@arm.com////
68211567Smitch.hayenga@arm.com
68311567Smitch.hayenga@arm.comvoid
68410259SAndrew.Bardsley@arm.comIdeController::serialize(std::ostream &os)
68510259SAndrew.Bardsley@arm.com{
68610259SAndrew.Bardsley@arm.com    // Serialize the PciDev base class
68710259SAndrew.Bardsley@arm.com    PciDev::serialize(os);
68810259SAndrew.Bardsley@arm.com
68910259SAndrew.Bardsley@arm.com    // Serialize register addresses and sizes
69010259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(pri_cmd_addr);
69110259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(pri_cmd_size);
69210259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(pri_ctrl_addr);
69310259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(pri_ctrl_size);
69410259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(sec_cmd_addr);
69510259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(sec_cmd_size);
69610259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(sec_ctrl_addr);
69710259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(sec_ctrl_size);
69810259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(bmi_addr);
69910259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(bmi_size);
70010259SAndrew.Bardsley@arm.com
70110259SAndrew.Bardsley@arm.com    // Serialize registers
70210259SAndrew.Bardsley@arm.com    SERIALIZE_ARRAY(bmi_regs.data,
70310259SAndrew.Bardsley@arm.com                    sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
70410259SAndrew.Bardsley@arm.com    SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
70510259SAndrew.Bardsley@arm.com    SERIALIZE_ARRAY(config_regs.data,
70610259SAndrew.Bardsley@arm.com                    sizeof(config_regs.data) / sizeof(config_regs.data[0]));
70710259SAndrew.Bardsley@arm.com
70810259SAndrew.Bardsley@arm.com    // Serialize internal state
70910259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(io_enabled);
71010259SAndrew.Bardsley@arm.com    SERIALIZE_SCALAR(bm_enabled);
71110259SAndrew.Bardsley@arm.com    SERIALIZE_ARRAY(cmd_in_progress,
71210259SAndrew.Bardsley@arm.com                    sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
71310259SAndrew.Bardsley@arm.com}
71410259SAndrew.Bardsley@arm.com
71510259SAndrew.Bardsley@arm.comvoid
71610259SAndrew.Bardsley@arm.comIdeController::unserialize(Checkpoint *cp, const std::string &section)
71710259SAndrew.Bardsley@arm.com{
71810259SAndrew.Bardsley@arm.com    // Unserialize the PciDev base class
71910259SAndrew.Bardsley@arm.com    PciDev::unserialize(cp, section);
72010259SAndrew.Bardsley@arm.com
72110259SAndrew.Bardsley@arm.com    // Unserialize register addresses and sizes
72210259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(pri_cmd_addr);
72310259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(pri_cmd_size);
72410259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(pri_ctrl_addr);
72510259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(pri_ctrl_size);
72610259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(sec_cmd_addr);
72710259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(sec_cmd_size);
72810259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(sec_ctrl_addr);
72910259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(sec_ctrl_size);
73010259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(bmi_addr);
73110259SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(bmi_size);
73210259SAndrew.Bardsley@arm.com
73310259SAndrew.Bardsley@arm.com    // Unserialize registers
73410259SAndrew.Bardsley@arm.com    UNSERIALIZE_ARRAY(bmi_regs.data,
73510259SAndrew.Bardsley@arm.com                      sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
73610259SAndrew.Bardsley@arm.com    UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
73710581SAndrew.Bardsley@arm.com    UNSERIALIZE_ARRAY(config_regs.data,
73810581SAndrew.Bardsley@arm.com                      sizeof(config_regs.data) / sizeof(config_regs.data[0]));
73910581SAndrew.Bardsley@arm.com
74010581SAndrew.Bardsley@arm.com    // Unserialize internal state
74110581SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(io_enabled);
74210581SAndrew.Bardsley@arm.com    UNSERIALIZE_SCALAR(bm_enabled);
74310581SAndrew.Bardsley@arm.com    UNSERIALIZE_ARRAY(cmd_in_progress,
74410581SAndrew.Bardsley@arm.com                      sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
74510581SAndrew.Bardsley@arm.com    pioPort->sendStatusChange(Port::RangeChange);
74610259SAndrew.Bardsley@arm.com}
74710259SAndrew.Bardsley@arm.com
74810259SAndrew.Bardsley@arm.com#ifndef DOXYGEN_SHOULD_SKIP_THIS
74910259SAndrew.Bardsley@arm.com
75010259SAndrew.Bardsley@arm.comBEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
75110259SAndrew.Bardsley@arm.com
75210259SAndrew.Bardsley@arm.com    SimObjectParam<System *> system;
75310259SAndrew.Bardsley@arm.com    SimObjectParam<Platform *> platform;
75410259SAndrew.Bardsley@arm.com    SimObjectParam<PciConfigData *> configdata;
75510259SAndrew.Bardsley@arm.com    Param<uint32_t> pci_bus;
75610259SAndrew.Bardsley@arm.com    Param<uint32_t> pci_dev;
75710259SAndrew.Bardsley@arm.com    Param<uint32_t> pci_func;
75810259SAndrew.Bardsley@arm.com    Param<Tick> pio_latency;
75910259SAndrew.Bardsley@arm.com    SimObjectVectorParam<IdeDisk *> disks;
76010259SAndrew.Bardsley@arm.com
76110259SAndrew.Bardsley@arm.comEND_DECLARE_SIM_OBJECT_PARAMS(IdeController)
76210259SAndrew.Bardsley@arm.com
76310259SAndrew.Bardsley@arm.comBEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
76410259SAndrew.Bardsley@arm.com
76510259SAndrew.Bardsley@arm.com    INIT_PARAM(system, "System pointer"),
76610259SAndrew.Bardsley@arm.com    INIT_PARAM(platform, "Platform pointer"),
76710259SAndrew.Bardsley@arm.com    INIT_PARAM(configdata, "PCI Config data"),
76810259SAndrew.Bardsley@arm.com    INIT_PARAM(pci_bus, "PCI bus ID"),
76910259SAndrew.Bardsley@arm.com    INIT_PARAM(pci_dev, "PCI device number"),
77010259SAndrew.Bardsley@arm.com    INIT_PARAM(pci_func, "PCI function code"),
77110259SAndrew.Bardsley@arm.com    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
77210259SAndrew.Bardsley@arm.com    INIT_PARAM(disks, "IDE disks attached to this controller")
77310259SAndrew.Bardsley@arm.com
77410259SAndrew.Bardsley@arm.comEND_INIT_SIM_OBJECT_PARAMS(IdeController)
77510259SAndrew.Bardsley@arm.com
77610259SAndrew.Bardsley@arm.comCREATE_SIM_OBJECT(IdeController)
77710259SAndrew.Bardsley@arm.com{
77810259SAndrew.Bardsley@arm.com    IdeController::Params *params = new IdeController::Params;
77910259SAndrew.Bardsley@arm.com    params->name = getInstanceName();
78010259SAndrew.Bardsley@arm.com    params->platform = platform;
78110259SAndrew.Bardsley@arm.com    params->system = system;
78210259SAndrew.Bardsley@arm.com    params->configData = configdata;
78310259SAndrew.Bardsley@arm.com    params->busNum = pci_bus;
78410259SAndrew.Bardsley@arm.com    params->deviceNum = pci_dev;
78510259SAndrew.Bardsley@arm.com    params->functionNum = pci_func;
78610259SAndrew.Bardsley@arm.com    params->pio_delay = pio_latency;
78710259SAndrew.Bardsley@arm.com    params->disks = disks;
78810259SAndrew.Bardsley@arm.com    return new IdeController(params);
78910259SAndrew.Bardsley@arm.com}
79010259SAndrew.Bardsley@arm.com
79110259SAndrew.Bardsley@arm.comREGISTER_SIM_OBJECT("IdeController", IdeController)
79210259SAndrew.Bardsley@arm.com
79310259SAndrew.Bardsley@arm.com#endif //DOXYGEN_SHOULD_SKIP_THIS
79410259SAndrew.Bardsley@arm.com