qemu/hw/ide/qdev.c
<<
>>
Prefs
   1/*
   2 * ide bus support for qdev.
   3 *
   4 * Copyright (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19#include <hw/hw.h>
  20#include "sysemu/dma.h"
  21#include "qemu/error-report.h"
  22#include <hw/ide/internal.h>
  23#include "sysemu/blockdev.h"
  24#include "hw/block/block.h"
  25#include "sysemu/sysemu.h"
  26
  27/* --------------------------------- */
  28
  29static char *idebus_get_fw_dev_path(DeviceState *dev);
  30
  31static Property ide_props[] = {
  32    DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
  33    DEFINE_PROP_END_OF_LIST(),
  34};
  35
  36static void ide_bus_class_init(ObjectClass *klass, void *data)
  37{
  38    BusClass *k = BUS_CLASS(klass);
  39
  40    k->get_fw_dev_path = idebus_get_fw_dev_path;
  41}
  42
  43static const TypeInfo ide_bus_info = {
  44    .name = TYPE_IDE_BUS,
  45    .parent = TYPE_BUS,
  46    .instance_size = sizeof(IDEBus),
  47    .class_init = ide_bus_class_init,
  48};
  49
  50void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id, int max_units)
  51{
  52    qbus_create_inplace(&idebus->qbus, TYPE_IDE_BUS, dev, NULL);
  53    idebus->bus_id = bus_id;
  54    idebus->max_units = max_units;
  55}
  56
  57static char *idebus_get_fw_dev_path(DeviceState *dev)
  58{
  59    char path[30];
  60
  61    snprintf(path, sizeof(path), "%s@%d", qdev_fw_name(dev),
  62             ((IDEBus*)dev->parent_bus)->bus_id);
  63
  64    return g_strdup(path);
  65}
  66
  67static int ide_qdev_init(DeviceState *qdev)
  68{
  69    IDEDevice *dev = IDE_DEVICE(qdev);
  70    IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
  71    IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
  72
  73    if (!dev->conf.bs) {
  74        error_report("No drive specified");
  75        goto err;
  76    }
  77    if (dev->unit == -1) {
  78        dev->unit = bus->master ? 1 : 0;
  79    }
  80
  81    if (dev->unit >= bus->max_units) {
  82        error_report("Can't create IDE unit %d, bus supports only %d units",
  83                     dev->unit, bus->max_units);
  84        goto err;
  85    }
  86
  87    switch (dev->unit) {
  88    case 0:
  89        if (bus->master) {
  90            error_report("IDE unit %d is in use", dev->unit);
  91            goto err;
  92        }
  93        bus->master = dev;
  94        break;
  95    case 1:
  96        if (bus->slave) {
  97            error_report("IDE unit %d is in use", dev->unit);
  98            goto err;
  99        }
 100        bus->slave = dev;
 101        break;
 102    default:
 103        error_report("Invalid IDE unit %d", dev->unit);
 104        goto err;
 105    }
 106    return dc->init(dev);
 107
 108err:
 109    return -1;
 110}
 111
 112IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
 113{
 114    DeviceState *dev;
 115
 116    dev = qdev_create(&bus->qbus, drive->media_cd ? "ide-cd" : "ide-hd");
 117    qdev_prop_set_uint32(dev, "unit", unit);
 118    qdev_prop_set_drive_nofail(dev, "drive", drive->bdrv);
 119    qdev_init_nofail(dev);
 120    return DO_UPCAST(IDEDevice, qdev, dev);
 121}
 122
 123int ide_get_geometry(BusState *bus, int unit,
 124                     int16_t *cyls, int8_t *heads, int8_t *secs)
 125{
 126    IDEState *s = &DO_UPCAST(IDEBus, qbus, bus)->ifs[unit];
 127
 128    if (s->drive_kind != IDE_HD || !s->bs) {
 129        return -1;
 130    }
 131
 132    *cyls = s->cylinders;
 133    *heads = s->heads;
 134    *secs = s->sectors;
 135    return 0;
 136}
 137
 138int ide_get_bios_chs_trans(BusState *bus, int unit)
 139{
 140    return DO_UPCAST(IDEBus, qbus, bus)->ifs[unit].chs_trans;
 141}
 142
 143/* --------------------------------- */
 144
 145typedef struct IDEDrive {
 146    IDEDevice dev;
 147} IDEDrive;
 148
 149static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
 150{
 151    IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
 152    IDEState *s = bus->ifs + dev->unit;
 153
 154    if (dev->conf.discard_granularity == -1) {
 155        dev->conf.discard_granularity = 512;
 156    } else if (dev->conf.discard_granularity &&
 157               dev->conf.discard_granularity != 512) {
 158        error_report("discard_granularity must be 512 for ide");
 159        return -1;
 160    }
 161
 162    blkconf_serial(&dev->conf, &dev->serial);
 163    if (kind != IDE_CD
 164        && blkconf_geometry(&dev->conf, &dev->chs_trans, 65536, 16, 255) < 0) {
 165        return -1;
 166    }
 167
 168    if (ide_init_drive(s, dev->conf.bs, kind,
 169                       dev->version, dev->serial, dev->model, dev->wwn,
 170                       dev->conf.cyls, dev->conf.heads, dev->conf.secs,
 171                       dev->chs_trans) < 0) {
 172        return -1;
 173    }
 174
 175    if (!dev->version) {
 176        dev->version = g_strdup(s->version);
 177    }
 178    if (!dev->serial) {
 179        dev->serial = g_strdup(s->drive_serial_str);
 180    }
 181
 182    add_boot_device_path(dev->conf.bootindex, &dev->qdev,
 183                         dev->unit ? "/disk@1" : "/disk@0");
 184
 185    return 0;
 186}
 187
 188static int ide_hd_initfn(IDEDevice *dev)
 189{
 190    return ide_dev_initfn(dev, IDE_HD);
 191}
 192
 193static int ide_cd_initfn(IDEDevice *dev)
 194{
 195    return ide_dev_initfn(dev, IDE_CD);
 196}
 197
 198static int ide_drive_initfn(IDEDevice *dev)
 199{
 200    DriveInfo *dinfo = drive_get_by_blockdev(dev->conf.bs);
 201
 202    return ide_dev_initfn(dev, dinfo->media_cd ? IDE_CD : IDE_HD);
 203}
 204
 205#define DEFINE_IDE_DEV_PROPERTIES()                     \
 206    DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf),        \
 207    DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),  \
 208    DEFINE_PROP_HEX64("wwn",  IDEDrive, dev.wwn, 0),    \
 209    DEFINE_PROP_STRING("serial",  IDEDrive, dev.serial),\
 210    DEFINE_PROP_STRING("model", IDEDrive, dev.model)
 211
 212static Property ide_hd_properties[] = {
 213    DEFINE_IDE_DEV_PROPERTIES(),
 214    DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
 215    DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
 216                IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
 217    DEFINE_PROP_END_OF_LIST(),
 218};
 219
 220static void ide_hd_class_init(ObjectClass *klass, void *data)
 221{
 222    DeviceClass *dc = DEVICE_CLASS(klass);
 223    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
 224    k->init = ide_hd_initfn;
 225    dc->fw_name = "drive";
 226    dc->desc = "virtual IDE disk";
 227    dc->props = ide_hd_properties;
 228}
 229
 230static const TypeInfo ide_hd_info = {
 231    .name          = "ide-hd",
 232    .parent        = TYPE_IDE_DEVICE,
 233    .instance_size = sizeof(IDEDrive),
 234    .class_init    = ide_hd_class_init,
 235};
 236
 237static Property ide_cd_properties[] = {
 238    DEFINE_IDE_DEV_PROPERTIES(),
 239    DEFINE_PROP_END_OF_LIST(),
 240};
 241
 242static void ide_cd_class_init(ObjectClass *klass, void *data)
 243{
 244    DeviceClass *dc = DEVICE_CLASS(klass);
 245    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
 246    k->init = ide_cd_initfn;
 247    dc->fw_name = "drive";
 248    dc->desc = "virtual IDE CD-ROM";
 249    dc->props = ide_cd_properties;
 250}
 251
 252static const TypeInfo ide_cd_info = {
 253    .name          = "ide-cd",
 254    .parent        = TYPE_IDE_DEVICE,
 255    .instance_size = sizeof(IDEDrive),
 256    .class_init    = ide_cd_class_init,
 257};
 258
 259static Property ide_drive_properties[] = {
 260    DEFINE_IDE_DEV_PROPERTIES(),
 261    DEFINE_PROP_END_OF_LIST(),
 262};
 263
 264static void ide_drive_class_init(ObjectClass *klass, void *data)
 265{
 266    DeviceClass *dc = DEVICE_CLASS(klass);
 267    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
 268    k->init = ide_drive_initfn;
 269    dc->fw_name = "drive";
 270    dc->desc = "virtual IDE disk or CD-ROM (legacy)";
 271    dc->props = ide_drive_properties;
 272}
 273
 274static const TypeInfo ide_drive_info = {
 275    .name          = "ide-drive",
 276    .parent        = TYPE_IDE_DEVICE,
 277    .instance_size = sizeof(IDEDrive),
 278    .class_init    = ide_drive_class_init,
 279};
 280
 281static void ide_device_class_init(ObjectClass *klass, void *data)
 282{
 283    DeviceClass *k = DEVICE_CLASS(klass);
 284    k->init = ide_qdev_init;
 285    set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
 286    k->bus_type = TYPE_IDE_BUS;
 287    k->props = ide_props;
 288}
 289
 290static const TypeInfo ide_device_type_info = {
 291    .name = TYPE_IDE_DEVICE,
 292    .parent = TYPE_DEVICE,
 293    .instance_size = sizeof(IDEDevice),
 294    .abstract = true,
 295    .class_size = sizeof(IDEDeviceClass),
 296    .class_init = ide_device_class_init,
 297};
 298
 299static void ide_register_types(void)
 300{
 301    type_register_static(&ide_bus_info);
 302    type_register_static(&ide_hd_info);
 303    type_register_static(&ide_cd_info);
 304    type_register_static(&ide_drive_info);
 305    type_register_static(&ide_device_type_info);
 306}
 307
 308type_init(ide_register_types)
 309