ide_ctrl.cc revision 1817
1955SN/A/*
2955SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
31762SN/A * All rights reserved.
4955SN/A *
5955SN/A * Redistribution and use in source and binary forms, with or without
6955SN/A * modification, are permitted provided that the following conditions are
7955SN/A * met: redistributions of source code must retain the above copyright
8955SN/A * notice, this list of conditions and the following disclaimer;
9955SN/A * redistributions in binary form must reproduce the above copyright
10955SN/A * notice, this list of conditions and the following disclaimer in the
11955SN/A * documentation and/or other materials provided with the distribution;
12955SN/A * neither the name of the copyright holders nor the names of its
13955SN/A * contributors may be used to endorse or promote products derived from
14955SN/A * this software without specific prior written permission.
15955SN/A *
16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27955SN/A */
282665Ssaidi@eecs.umich.edu
292665Ssaidi@eecs.umich.edu#include <cstddef>
30955SN/A#include <cstdlib>
31955SN/A#include <string>
32955SN/A#include <vector>
333583Sbinkertn@umich.edu
34955SN/A#include "base/trace.hh"
35955SN/A#include "cpu/intr_control.hh"
36955SN/A#include "dev/ide_ctrl.hh"
37955SN/A#include "dev/ide_disk.hh"
38955SN/A#include "dev/pciconfigall.hh"
39955SN/A#include "dev/pcireg.h"
40955SN/A#include "dev/platform.hh"
41955SN/A#include "mem/bus/bus.hh"
42955SN/A#include "mem/bus/dma_interface.hh"
43955SN/A#include "mem/bus/pio_interface.hh"
44955SN/A#include "mem/bus/pio_interface_impl.hh"
45955SN/A#include "mem/functional/memory_control.hh"
46955SN/A#include "mem/functional/physical.hh"
47955SN/A#include "sim/builder.hh"
482023SN/A#include "sim/sim_object.hh"
49955SN/A
503089Ssaidi@eecs.umich.eduusing namespace std;
51955SN/A
52955SN/A////
53955SN/A// Initialization and destruction
54955SN/A////
55955SN/A
56955SN/AIdeController::IdeController(Params *p)
57955SN/A    : PciDev(p)
58955SN/A{
591031SN/A    // initialize the PIO interface addresses
60955SN/A    pri_cmd_addr = 0;
611388SN/A    pri_cmd_size = BARSize[0];
62955SN/A
63955SN/A    pri_ctrl_addr = 0;
641296SN/A    pri_ctrl_size = BARSize[1];
65955SN/A
66955SN/A    sec_cmd_addr = 0;
67955SN/A    sec_cmd_size = BARSize[2];
68955SN/A
69955SN/A    sec_ctrl_addr = 0;
70955SN/A    sec_ctrl_size = BARSize[3];
71955SN/A
72955SN/A    // initialize the bus master interface (BMI) address to be configured
73955SN/A    // via PCI
74955SN/A    bmi_addr = 0;
75955SN/A    bmi_size = BARSize[4];
76955SN/A
773584Ssaidi@eecs.umich.edu    // zero out all of the registers
78955SN/A    memset(bmi_regs.data, 0, sizeof(bmi_regs));
79955SN/A    memset(config_regs.data, 0, sizeof(config_regs.data));
80955SN/A
81955SN/A    // setup initial values
82955SN/A    // enable both channels
83955SN/A    config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN);
84955SN/A    config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN);
852325SN/A    bmi_regs.bmis0 = DMA1CAP | DMA0CAP;
861717SN/A    bmi_regs.bmis1 = DMA1CAP | DMA0CAP;
872652Ssaidi@eecs.umich.edu
88955SN/A    // reset all internal variables
892736Sktlim@umich.edu    io_enabled = false;
902410SN/A    bm_enabled = false;
91955SN/A    memset(cmd_in_progress, 0, sizeof(cmd_in_progress));
922290SN/A
93955SN/A    // create the PIO and DMA interfaces
942683Sktlim@umich.edu    if (params()->host_bus) {
952683Sktlim@umich.edu        pioInterface = newPioInterface(name(), params()->hier,
962669Sktlim@umich.edu                                       params()->host_bus, this,
972568SN/A                                       &IdeController::cacheAccess);
982568SN/A
993012Ssaidi@eecs.umich.edu        dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1002462SN/A                                             params()->host_bus,
1012568SN/A                                             params()->host_bus, 1,
1022395SN/A                                             true);
1032405SN/A        pioLatency = params()->pio_latency * params()->host_bus->clockRate;
1042914Ssaidi@eecs.umich.edu    }
105955SN/A
1062811Srdreslin@umich.edu    // setup the disks attached to controller
1072811Srdreslin@umich.edu    memset(disks, 0, sizeof(IdeDisk *) * 4);
1082811Srdreslin@umich.edu    dev[0] = 0;
1092811Srdreslin@umich.edu    dev[1] = 0;
1102811Srdreslin@umich.edu
1112811Srdreslin@umich.edu    if (params()->disks.size() > 3)
1122811Srdreslin@umich.edu        panic("IDE controllers support a maximum of 4 devices attached!\n");
1132811Srdreslin@umich.edu
1142811Srdreslin@umich.edu    for (int i = 0; i < params()->disks.size(); i++) {
1152811Srdreslin@umich.edu        disks[i] = params()->disks[i];
1162811Srdreslin@umich.edu        disks[i]->setController(this, dmaInterface);
1172811Srdreslin@umich.edu    }
1182811Srdreslin@umich.edu}
1192811Srdreslin@umich.edu
1202811Srdreslin@umich.eduIdeController::~IdeController()
1212811Srdreslin@umich.edu{
1222814Srdreslin@umich.edu    for (int i = 0; i < 4; i++)
1232811Srdreslin@umich.edu        if (disks[i])
1242811Srdreslin@umich.edu            delete disks[i];
1252811Srdreslin@umich.edu}
1262811Srdreslin@umich.edu
1272811Srdreslin@umich.edu////
1282811Srdreslin@umich.edu// Utility functions
1292811Srdreslin@umich.edu///
1302813Srdreslin@umich.edu
1312813Srdreslin@umich.eduvoid
1323645Sbinkertn@umich.eduIdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
1333624Sbinkertn@umich.edu                         IdeRegType &reg_type)
1343624Sbinkertn@umich.edu{
135955SN/A    offset = addr;
136955SN/A
137955SN/A    if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
1382090SN/A        offset -= pri_cmd_addr;
139955SN/A        reg_type = COMMAND_BLOCK;
140955SN/A        channel = PRIMARY;
1411696SN/A    } else if (addr >= pri_ctrl_addr &&
142955SN/A               addr < (pri_ctrl_addr + pri_ctrl_size)) {
143955SN/A        offset -= pri_ctrl_addr;
144955SN/A        reg_type = CONTROL_BLOCK;
1451127SN/A        channel = PRIMARY;
146955SN/A    } else if (addr >= sec_cmd_addr &&
147955SN/A               addr < (sec_cmd_addr + sec_cmd_size)) {
1482379SN/A        offset -= sec_cmd_addr;
149955SN/A        reg_type = COMMAND_BLOCK;
150955SN/A        channel = SECONDARY;
151955SN/A    } else if (addr >= sec_ctrl_addr &&
1522422SN/A               addr < (sec_ctrl_addr + sec_ctrl_size)) {
1532422SN/A        offset -= sec_ctrl_addr;
1542422SN/A        reg_type = CONTROL_BLOCK;
1552422SN/A        channel = SECONDARY;
1562422SN/A    } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
1572422SN/A        offset -= bmi_addr;
1582422SN/A        reg_type = BMI_BLOCK;
1592397SN/A        channel = (offset < BMIC1) ? PRIMARY : SECONDARY;
1602397SN/A    } else {
1612422SN/A        panic("IDE controller access to invalid address: %#x\n", addr);
1622422SN/A    }
163955SN/A}
164955SN/A
165955SN/Aint
166955SN/AIdeController::getDisk(IdeChannel channel)
167955SN/A{
168955SN/A    int disk = 0;
169955SN/A    uint8_t *devBit = &dev[0];
170955SN/A
1711078SN/A    if (channel == SECONDARY) {
172955SN/A        disk += 2;
173955SN/A        devBit = &dev[1];
174955SN/A    }
175955SN/A
1761917SN/A    disk += *devBit;
177955SN/A
178955SN/A    assert(*devBit == 0 || *devBit == 1);
1791730SN/A
180955SN/A    return disk;
1812521SN/A}
1822521SN/A
1832507SN/Aint
1842507SN/AIdeController::getDisk(IdeDisk *diskPtr)
1852989Ssaidi@eecs.umich.edu{
1863408Ssaidi@eecs.umich.edu    for (int i = 0; i < 4; i++) {
1872507SN/A        if ((long)diskPtr == (long)disks[i])
1882507SN/A            return i;
1892507SN/A    }
190955SN/A    return -1;
191955SN/A}
192955SN/A
193955SN/Abool
194955SN/AIdeController::isDiskSelected(IdeDisk *diskPtr)
195955SN/A{
196955SN/A    for (int i = 0; i < 4; i++) {
197955SN/A        if ((long)diskPtr == (long)disks[i]) {
1982520SN/A            // is disk is on primary or secondary channel
1992517SN/A            int channel = i/2;
2002253SN/A            // is disk the master or slave
2012253SN/A            int devID = i%2;
2022253SN/A
2032253SN/A            return (dev[channel] == devID);
2042553SN/A        }
2052553SN/A    }
2062553SN/A    panic("Unable to find disk by pointer!!\n");
2072553SN/A}
2082507SN/A
2092400SN/A////
2102400SN/A// Command completion
211955SN/A////
212955SN/A
2132667Sstever@eecs.umich.eduvoid
2142667Sstever@eecs.umich.eduIdeController::setDmaComplete(IdeDisk *disk)
2152667Sstever@eecs.umich.edu{
2162667Sstever@eecs.umich.edu    int diskNum = getDisk(disk);
2172667Sstever@eecs.umich.edu
2182667Sstever@eecs.umich.edu    if (diskNum < 0)
2192037SN/A        panic("Unable to find disk based on pointer %#x\n", disk);
2202037SN/A
2212037SN/A    if (diskNum < 2) {
2223534Sgblack@eecs.umich.edu        // clear the start/stop bit in the command register
2232139SN/A        bmi_regs.bmic0 &= ~SSBM;
2243534Sgblack@eecs.umich.edu        // clear the bus master active bit in the status register
2253534Sgblack@eecs.umich.edu        bmi_regs.bmis0 &= ~BMIDEA;
2263542Sgblack@eecs.umich.edu        // set the interrupt bit
2273583Sbinkertn@umich.edu        bmi_regs.bmis0 |= IDEINTS;
2283583Sbinkertn@umich.edu    } else {
2293542Sgblack@eecs.umich.edu        // clear the start/stop bit in the command register
2303499Ssaidi@eecs.umich.edu        bmi_regs.bmic1 &= ~SSBM;
2313583Sbinkertn@umich.edu        // clear the bus master active bit in the status register
2323583Sbinkertn@umich.edu        bmi_regs.bmis1 &= ~BMIDEA;
2333547Sgblack@eecs.umich.edu        // set the interrupt bit
2342155SN/A        bmi_regs.bmis1 |= IDEINTS;
235955SN/A    }
2362155SN/A}
237955SN/A
2383583Sbinkertn@umich.edu////
2393583Sbinkertn@umich.edu// Bus timing and bus access functions
2403583Sbinkertn@umich.edu////
2413583Sbinkertn@umich.edu
2423583Sbinkertn@umich.eduTick
243955SN/AIdeController::cacheAccess(MemReqPtr &req)
244955SN/A{
245955SN/A    // @todo Add more accurate timing to cache access
246955SN/A    return curTick + pioLatency;
247955SN/A}
2481858SN/A
249955SN/A////
2501858SN/A// Read and write handling
2511858SN/A////
2521858SN/A
2531085SN/Avoid
254955SN/AIdeController::readConfig(int offset, int size, uint8_t *data)
255955SN/A{
256955SN/A    int config_offset;
257955SN/A
258955SN/A    if (offset < PCI_DEVICE_SPECIFIC) {
259955SN/A        PciDev::readConfig(offset, size, data);
260955SN/A    } else if (offset >= IDE_CTRL_CONF_START &&
261955SN/A               (offset + size) <= IDE_CTRL_CONF_END) {
262955SN/A
263955SN/A        config_offset = offset - IDE_CTRL_CONF_START;
264955SN/A
265955SN/A        switch (size) {
2662667Sstever@eecs.umich.edu          case sizeof(uint8_t):
2671045SN/A            *data = config_regs.data[config_offset];
268955SN/A            break;
269955SN/A          case sizeof(uint16_t):
270955SN/A            *(uint16_t*)data = *(uint16_t*)&config_regs.data[config_offset];
271955SN/A            break;
2721108SN/A          case sizeof(uint32_t):
273955SN/A            *(uint32_t*)data = *(uint32_t*)&config_regs.data[config_offset];
274955SN/A            break;
275955SN/A          default:
276955SN/A            panic("Invalid PCI configuration read size!\n");
277955SN/A        }
278955SN/A
279955SN/A        DPRINTF(IdeCtrl, "PCI read offset: %#x size: %#x data: %#x\n",
280955SN/A                offset, size, *(uint32_t*)data);
281955SN/A
282955SN/A    } else {
283955SN/A        panic("Read of unimplemented PCI config. register: %x\n", offset);
284955SN/A    }
285955SN/A}
286955SN/A
287955SN/Avoid
288955SN/AIdeController::writeConfig(int offset, int size, const uint8_t *data)
2892655Sstever@eecs.umich.edu{
2902655Sstever@eecs.umich.edu    int config_offset;
2912655Sstever@eecs.umich.edu
2922655Sstever@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC) {
2932655Sstever@eecs.umich.edu        PciDev::writeConfig(offset, size, data);
2942655Sstever@eecs.umich.edu    } else if (offset >= IDE_CTRL_CONF_START &&
2952655Sstever@eecs.umich.edu               (offset + size) <= IDE_CTRL_CONF_END) {
2962655Sstever@eecs.umich.edu
2972655Sstever@eecs.umich.edu        config_offset = offset - IDE_CTRL_CONF_START;
2982655Sstever@eecs.umich.edu
2992655Sstever@eecs.umich.edu        switch(size) {
3002655Sstever@eecs.umich.edu          case sizeof(uint8_t):
3012655Sstever@eecs.umich.edu            config_regs.data[config_offset] = *data;
3022655Sstever@eecs.umich.edu          case sizeof(uint16_t):
3032655Sstever@eecs.umich.edu            *(uint16_t*)&config_regs.data[config_offset] = *(uint16_t*)data;
3042655Sstever@eecs.umich.edu          case sizeof(uint32_t):
3052655Sstever@eecs.umich.edu            *(uint32_t*)&config_regs.data[config_offset] = *(uint32_t*)data;
3062655Sstever@eecs.umich.edu            break;
3072655Sstever@eecs.umich.edu          default:
3082655Sstever@eecs.umich.edu            panic("Invalid PCI configuration write size!\n");
3092655Sstever@eecs.umich.edu        }
3102655Sstever@eecs.umich.edu    } else {
311955SN/A        panic("Write of unimplemented PCI config. register: %x\n", offset);
3123515Ssaidi@eecs.umich.edu    }
3133515Ssaidi@eecs.umich.edu
3143515Ssaidi@eecs.umich.edu    DPRINTF(IdeCtrl, "PCI write offset: %#x size: %#x data: %#x\n",
3153515Ssaidi@eecs.umich.edu            offset, size, data);
3163515Ssaidi@eecs.umich.edu
3173515Ssaidi@eecs.umich.edu    // Catch the writes to specific PCI registers that have side affects
3183515Ssaidi@eecs.umich.edu    // (like updating the PIO ranges)
3192655Sstever@eecs.umich.edu    switch (offset) {
3203515Ssaidi@eecs.umich.edu      case PCI_COMMAND:
3213619Sbinkertn@umich.edu        if (letoh(config.command) & PCI_CMD_IOSE)
322955SN/A            io_enabled = true;
323955SN/A        else
3242655Sstever@eecs.umich.edu            io_enabled = false;
3253619Sbinkertn@umich.edu
3263619Sbinkertn@umich.edu        if (letoh(config.command) & PCI_CMD_BME)
327955SN/A            bm_enabled = true;
328955SN/A        else
3292655Sstever@eecs.umich.edu            bm_enabled = false;
3302655Sstever@eecs.umich.edu        break;
3313619Sbinkertn@umich.edu
332955SN/A      case PCI0_BASE_ADDR0:
333955SN/A        if (BARAddrs[0] != 0) {
3342655Sstever@eecs.umich.edu            pri_cmd_addr = BARAddrs[0];
3352655Sstever@eecs.umich.edu            if (pioInterface)
3363683Sstever@eecs.umich.edu                pioInterface->addAddrRange(RangeSize(pri_cmd_addr,
3372655Sstever@eecs.umich.edu                                                     pri_cmd_size));
3381869SN/A
3391869SN/A            pri_cmd_addr &= EV5::PAddrUncachedMask;
340        }
341        break;
342
343      case PCI0_BASE_ADDR1:
344        if (BARAddrs[1] != 0) {
345            pri_ctrl_addr = BARAddrs[1];
346            if (pioInterface)
347                pioInterface->addAddrRange(RangeSize(pri_ctrl_addr,
348                                                     pri_ctrl_size));
349
350            pri_ctrl_addr &= EV5::PAddrUncachedMask;
351        }
352        break;
353
354      case PCI0_BASE_ADDR2:
355        if (BARAddrs[2] != 0) {
356            sec_cmd_addr = BARAddrs[2];
357            if (pioInterface)
358                pioInterface->addAddrRange(RangeSize(sec_cmd_addr,
359                                                     sec_cmd_size));
360
361            sec_cmd_addr &= EV5::PAddrUncachedMask;
362        }
363        break;
364
365      case PCI0_BASE_ADDR3:
366        if (BARAddrs[3] != 0) {
367            sec_ctrl_addr = BARAddrs[3];
368            if (pioInterface)
369                pioInterface->addAddrRange(RangeSize(sec_ctrl_addr,
370                                                     sec_ctrl_size));
371
372            sec_ctrl_addr &= EV5::PAddrUncachedMask;
373        }
374        break;
375
376      case PCI0_BASE_ADDR4:
377        if (BARAddrs[4] != 0) {
378            bmi_addr = BARAddrs[4];
379            if (pioInterface)
380                pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size));
381
382            bmi_addr &= EV5::PAddrUncachedMask;
383        }
384        break;
385    }
386}
387
388Fault
389IdeController::read(MemReqPtr &req, uint8_t *data)
390{
391    Addr offset;
392    IdeChannel channel;
393    IdeRegType reg_type;
394    int disk;
395
396    parseAddr(req->paddr, offset, channel, reg_type);
397
398    if (!io_enabled)
399        return No_Fault;
400
401    switch (reg_type) {
402      case BMI_BLOCK:
403        switch (req->size) {
404          case sizeof(uint8_t):
405            *data = bmi_regs.data[offset];
406            break;
407          case sizeof(uint16_t):
408            *(uint16_t*)data = *(uint16_t*)&bmi_regs.data[offset];
409            break;
410          case sizeof(uint32_t):
411            *(uint32_t*)data = *(uint32_t*)&bmi_regs.data[offset];
412            break;
413          default:
414            panic("IDE read of BMI reg invalid size: %#x\n", req->size);
415        }
416        break;
417
418      case COMMAND_BLOCK:
419      case CONTROL_BLOCK:
420        disk = getDisk(channel);
421
422        if (disks[disk] == NULL)
423            break;
424
425        switch (offset) {
426          case DATA_OFFSET:
427            switch (req->size) {
428              case sizeof(uint16_t):
429                disks[disk]->read(offset, reg_type, data);
430                break;
431
432              case sizeof(uint32_t):
433                disks[disk]->read(offset, reg_type, data);
434                disks[disk]->read(offset, reg_type, &data[2]);
435                break;
436
437              default:
438                panic("IDE read of data reg invalid size: %#x\n", req->size);
439            }
440            break;
441          default:
442            if (req->size == sizeof(uint8_t)) {
443                disks[disk]->read(offset, reg_type, data);
444            } else
445                panic("IDE read of command reg of invalid size: %#x\n", req->size);
446        }
447        break;
448      default:
449        panic("IDE controller read of unknown register block type!\n");
450    }
451
452    DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
453            offset, req->size, *(uint32_t*)data);
454
455    return No_Fault;
456}
457
458Fault
459IdeController::write(MemReqPtr &req, const uint8_t *data)
460{
461    Addr offset;
462    IdeChannel channel;
463    IdeRegType reg_type;
464    int disk;
465    uint8_t oldVal, newVal;
466
467    parseAddr(req->paddr, offset, channel, reg_type);
468
469    if (!io_enabled)
470        return No_Fault;
471
472    switch (reg_type) {
473      case BMI_BLOCK:
474        if (!bm_enabled)
475            return No_Fault;
476
477        switch (offset) {
478            // Bus master IDE command register
479          case BMIC1:
480          case BMIC0:
481            if (req->size != sizeof(uint8_t))
482                panic("Invalid BMIC write size: %x\n", req->size);
483
484            // select the current disk based on DEV bit
485            disk = getDisk(channel);
486
487            oldVal = letoh(bmi_regs.chan[channel].bmic);
488            newVal = letoh(*data);
489
490            // if a DMA transfer is in progress, R/W control cannot change
491            if (oldVal & SSBM) {
492                if ((oldVal & RWCON) ^ (newVal & RWCON)) {
493                    (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
494                }
495            }
496
497            // see if the start/stop bit is being changed
498            if ((oldVal & SSBM) ^ (newVal & SSBM)) {
499                if (oldVal & SSBM) {
500                    // stopping DMA transfer
501                    DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
502
503                    // clear the BMIDEA bit
504                    bmi_regs.chan[channel].bmis = letoh(
505                        letoh(bmi_regs.chan[channel].bmis) & ~BMIDEA);
506
507                    if (disks[disk] == NULL)
508                        panic("DMA stop for disk %d which does not exist\n",
509                              disk);
510
511                    // inform the disk of the DMA transfer abort
512                    disks[disk]->abortDma();
513                } else {
514                    // starting DMA transfer
515                    DPRINTF(IdeCtrl, "Starting DMA transfer\n");
516
517                    // set the BMIDEA bit
518                    bmi_regs.chan[channel].bmis = letoh(
519                        letoh(bmi_regs.chan[channel].bmis) | BMIDEA);
520
521                    if (disks[disk] == NULL)
522                        panic("DMA start for disk %d which does not exist\n",
523                              disk);
524
525                    // inform the disk of the DMA transfer start
526                    disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));
527                }
528            }
529
530            // update the register value
531            bmi_regs.chan[channel].bmic = letoh(newVal);
532            break;
533
534            // Bus master IDE status register
535          case BMIS0:
536          case BMIS1:
537            if (req->size != sizeof(uint8_t))
538                panic("Invalid BMIS write size: %x\n", req->size);
539
540            oldVal = letoh(bmi_regs.chan[channel].bmis);
541            newVal = letoh(*data);
542
543            // the BMIDEA bit is RO
544            newVal |= (oldVal & BMIDEA);
545
546            // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
547            if ((oldVal & IDEINTS) && (newVal & IDEINTS))
548                newVal &= ~IDEINTS; // clear the interrupt?
549            else
550                (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
551
552            if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
553                newVal &= ~IDEDMAE;
554            else
555                (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
556
557            bmi_regs.chan[channel].bmis = letoh(newVal);
558            break;
559
560            // Bus master IDE descriptor table pointer register
561          case BMIDTP0:
562          case BMIDTP1:
563            if (req->size != sizeof(uint32_t))
564                panic("Invalid BMIDTP write size: %x\n", req->size);
565
566            bmi_regs.chan[channel].bmidtp = letoh(
567                letoh(*(uint32_t*)data) & ~0x3);
568            break;
569
570          default:
571            if (req->size != sizeof(uint8_t) &&
572                req->size != sizeof(uint16_t) &&
573                req->size != sizeof(uint32_t))
574                panic("IDE controller write of invalid write size: %x\n",
575                      req->size);
576
577            // do a default copy of data into the registers
578            memcpy(&bmi_regs.data[offset], data, req->size);
579        }
580        break;
581      case COMMAND_BLOCK:
582        if (offset == IDE_SELECT_OFFSET) {
583            uint8_t *devBit = &dev[channel];
584            *devBit = (letoh(*data) & IDE_SELECT_DEV_BIT) ? 1 : 0;
585        }
586        // fall-through ok!
587      case CONTROL_BLOCK:
588        disk = getDisk(channel);
589
590        if (disks[disk] == NULL)
591            break;
592
593        switch (offset) {
594          case DATA_OFFSET:
595            switch (req->size) {
596              case sizeof(uint16_t):
597                disks[disk]->write(offset, reg_type, data);
598                break;
599
600              case sizeof(uint32_t):
601                disks[disk]->write(offset, reg_type, data);
602                disks[disk]->write(offset, reg_type, &data[2]);
603                break;
604              default:
605                panic("IDE write of data reg invalid size: %#x\n", req->size);
606            }
607            break;
608          default:
609            if (req->size == sizeof(uint8_t)) {
610                disks[disk]->write(offset, reg_type, data);
611            } else
612                panic("IDE write of command reg of invalid size: %#x\n", req->size);
613        }
614        break;
615      default:
616        panic("IDE controller write of unknown register block type!\n");
617    }
618
619    DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
620            offset, req->size, *(uint32_t*)data);
621
622    return No_Fault;
623}
624
625////
626// Serialization
627////
628
629void
630IdeController::serialize(std::ostream &os)
631{
632    // Serialize the PciDev base class
633    PciDev::serialize(os);
634
635    // Serialize register addresses and sizes
636    SERIALIZE_SCALAR(pri_cmd_addr);
637    SERIALIZE_SCALAR(pri_cmd_size);
638    SERIALIZE_SCALAR(pri_ctrl_addr);
639    SERIALIZE_SCALAR(pri_ctrl_size);
640    SERIALIZE_SCALAR(sec_cmd_addr);
641    SERIALIZE_SCALAR(sec_cmd_size);
642    SERIALIZE_SCALAR(sec_ctrl_addr);
643    SERIALIZE_SCALAR(sec_ctrl_size);
644    SERIALIZE_SCALAR(bmi_addr);
645    SERIALIZE_SCALAR(bmi_size);
646
647    // Serialize registers
648    SERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
649    SERIALIZE_ARRAY(dev, sizeof(dev));
650    SERIALIZE_ARRAY(config_regs.data, sizeof(config_regs));
651
652    // Serialize internal state
653    SERIALIZE_SCALAR(io_enabled);
654    SERIALIZE_SCALAR(bm_enabled);
655    SERIALIZE_ARRAY(cmd_in_progress, sizeof(cmd_in_progress));
656}
657
658void
659IdeController::unserialize(Checkpoint *cp, const std::string &section)
660{
661    // Unserialize the PciDev base class
662    PciDev::unserialize(cp, section);
663
664    // Unserialize register addresses and sizes
665    UNSERIALIZE_SCALAR(pri_cmd_addr);
666    UNSERIALIZE_SCALAR(pri_cmd_size);
667    UNSERIALIZE_SCALAR(pri_ctrl_addr);
668    UNSERIALIZE_SCALAR(pri_ctrl_size);
669    UNSERIALIZE_SCALAR(sec_cmd_addr);
670    UNSERIALIZE_SCALAR(sec_cmd_size);
671    UNSERIALIZE_SCALAR(sec_ctrl_addr);
672    UNSERIALIZE_SCALAR(sec_ctrl_size);
673    UNSERIALIZE_SCALAR(bmi_addr);
674    UNSERIALIZE_SCALAR(bmi_size);
675
676    // Unserialize registers
677    UNSERIALIZE_ARRAY(bmi_regs.data, sizeof(bmi_regs));
678    UNSERIALIZE_ARRAY(dev, sizeof(dev));
679    UNSERIALIZE_ARRAY(config_regs.data, sizeof(config_regs));
680
681    // Unserialize internal state
682    UNSERIALIZE_SCALAR(io_enabled);
683    UNSERIALIZE_SCALAR(bm_enabled);
684    UNSERIALIZE_ARRAY(cmd_in_progress, sizeof(cmd_in_progress));
685
686    if (pioInterface) {
687        pioInterface->addAddrRange(RangeSize(pri_cmd_addr, pri_cmd_size));
688        pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, pri_ctrl_size));
689        pioInterface->addAddrRange(RangeSize(sec_cmd_addr, sec_cmd_size));
690        pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, sec_ctrl_size));
691        pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size));
692   }
693}
694
695#ifndef DOXYGEN_SHOULD_SKIP_THIS
696
697BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
698
699    Param<Addr> addr;
700    SimObjectVectorParam<IdeDisk *> disks;
701    SimObjectParam<MemoryController *> mmu;
702    SimObjectParam<PciConfigAll *> configspace;
703    SimObjectParam<PciConfigData *> configdata;
704    SimObjectParam<Platform *> platform;
705    Param<uint32_t> pci_bus;
706    Param<uint32_t> pci_dev;
707    Param<uint32_t> pci_func;
708    SimObjectParam<Bus *> io_bus;
709    Param<Tick> pio_latency;
710    SimObjectParam<HierParams *> hier;
711
712END_DECLARE_SIM_OBJECT_PARAMS(IdeController)
713
714BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
715
716    INIT_PARAM(addr, "Device Address"),
717    INIT_PARAM(disks, "IDE disks attached to this controller"),
718    INIT_PARAM(mmu, "Memory controller"),
719    INIT_PARAM(configspace, "PCI Configspace"),
720    INIT_PARAM(configdata, "PCI Config data"),
721    INIT_PARAM(platform, "Platform pointer"),
722    INIT_PARAM(pci_bus, "PCI bus ID"),
723    INIT_PARAM(pci_dev, "PCI device number"),
724    INIT_PARAM(pci_func, "PCI function code"),
725    INIT_PARAM_DFLT(io_bus, "Host bus to attach to", NULL),
726    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
727    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
728
729END_INIT_SIM_OBJECT_PARAMS(IdeController)
730
731CREATE_SIM_OBJECT(IdeController)
732{
733    IdeController::Params *params = new IdeController::Params;
734    params->name = getInstanceName();
735    params->mmu = mmu;
736    params->configSpace = configspace;
737    params->configData = configdata;
738    params->plat = platform;
739    params->busNum = pci_bus;
740    params->deviceNum = pci_dev;
741    params->functionNum = pci_func;
742
743    params->disks = disks;
744    params->host_bus = io_bus;
745    params->pio_latency = pio_latency;
746    params->hier = hier;
747    return new IdeController(params);
748}
749
750REGISTER_SIM_OBJECT("IdeController", IdeController)
751
752#endif //DOXYGEN_SHOULD_SKIP_THIS
753