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 "dma.h"
  21#include "qemu-error.h"
  22#include <hw/ide/internal.h>
  23#include "blockdev.h"
  24#include "sysemu.h"
  25
  26/* --------------------------------- */
  27
  28static char *idebus_get_fw_dev_path(DeviceState *dev);
  29
  30static struct BusInfo ide_bus_info = {
  31    .name  = "IDE",
  32    .size  = sizeof(IDEBus),
  33    .get_fw_dev_path = idebus_get_fw_dev_path,
  34    .props = (Property[]) {
  35        DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
  36        DEFINE_PROP_END_OF_LIST(),
  37    },
  38};
  39
  40void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
  41{
  42    qbus_create_inplace(&idebus->qbus, &ide_bus_info, dev, NULL);
  43    idebus->bus_id = bus_id;
  44}
  45
  46static char *idebus_get_fw_dev_path(DeviceState *dev)
  47{
  48    char path[30];
  49
  50    snprintf(path, sizeof(path), "%s@%d", qdev_fw_name(dev),
  51             ((IDEBus*)dev->parent_bus)->bus_id);
  52
  53    return strdup(path);
  54}
  55
  56static int ide_qdev_init(DeviceState *qdev)
  57{
  58    IDEDevice *dev = IDE_DEVICE(qdev);
  59    IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
  60    IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
  61
  62    if (!dev->conf.bs) {
  63        error_report("No drive specified");
  64        goto err;
  65    }
  66    if (dev->unit == -1) {
  67        dev->unit = bus->master ? 1 : 0;
  68    }
  69    switch (dev->unit) {
  70    case 0:
  71        if (bus->master) {
  72            error_report("IDE unit %d is in use", dev->unit);
  73            goto err;
  74        }
  75        bus->master = dev;
  76        break;
  77    case 1:
  78        if (bus->slave) {
  79            error_report("IDE unit %d is in use", dev->unit);
  80            goto err;
  81        }
  82        bus->slave = dev;
  83        break;
  84    default:
  85        error_report("Invalid IDE unit %d", dev->unit);
  86        goto err;
  87    }
  88    return dc->init(dev);
  89
  90err:
  91    return -1;
  92}
  93
  94IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
  95{
  96    DeviceState *dev;
  97
  98    dev = qdev_create(&bus->qbus, drive->media_cd ? "ide-cd" : "ide-hd");
  99    qdev_prop_set_uint32(dev, "unit", unit);
 100    qdev_prop_set_drive_nofail(dev, "drive", drive->bdrv);
 101    qdev_init_nofail(dev);
 102    return DO_UPCAST(IDEDevice, qdev, dev);
 103}
 104
 105void ide_get_bs(BlockDriverState *bs[], BusState *qbus)
 106{
 107    IDEBus *bus = DO_UPCAST(IDEBus, qbus, qbus);
 108    bs[0] = bus->master ? bus->master->conf.bs : NULL;
 109    bs[1] = bus->slave  ? bus->slave->conf.bs  : NULL;
 110}
 111
 112/* --------------------------------- */
 113
 114typedef struct IDEDrive {
 115    IDEDevice dev;
 116} IDEDrive;
 117
 118static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
 119{
 120    IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
 121    IDEState *s = bus->ifs + dev->unit;
 122    const char *serial;
 123    DriveInfo *dinfo;
 124
 125    if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) {
 126        error_report("discard_granularity must be 512 for ide");
 127        return -1;
 128    }
 129
 130    serial = dev->serial;
 131    if (!serial) {
 132        /* try to fall back to value set with legacy -drive serial=... */
 133        dinfo = drive_get_by_blockdev(dev->conf.bs);
 134        if (*dinfo->serial) {
 135            serial = dinfo->serial;
 136        }
 137    }
 138
 139    if (ide_init_drive(s, dev->conf.bs, kind,
 140                       dev->version, serial, dev->model, dev->wwn) < 0) {
 141        return -1;
 142    }
 143
 144    if (!dev->version) {
 145        dev->version = g_strdup(s->version);
 146    }
 147    if (!dev->serial) {
 148        dev->serial = g_strdup(s->drive_serial_str);
 149    }
 150
 151    add_boot_device_path(dev->conf.bootindex, &dev->qdev,
 152                         dev->unit ? "/disk@1" : "/disk@0");
 153
 154    return 0;
 155}
 156
 157static int ide_hd_initfn(IDEDevice *dev)
 158{
 159    return ide_dev_initfn(dev, IDE_HD);
 160}
 161
 162static int ide_cd_initfn(IDEDevice *dev)
 163{
 164    return ide_dev_initfn(dev, IDE_CD);
 165}
 166
 167static int ide_drive_initfn(IDEDevice *dev)
 168{
 169    DriveInfo *dinfo = drive_get_by_blockdev(dev->conf.bs);
 170
 171    return ide_dev_initfn(dev, dinfo->media_cd ? IDE_CD : IDE_HD);
 172}
 173
 174#define DEFINE_IDE_DEV_PROPERTIES()                     \
 175    DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf),        \
 176    DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),  \
 177    DEFINE_PROP_HEX64("wwn",  IDEDrive, dev.wwn, 0),    \
 178    DEFINE_PROP_STRING("serial",  IDEDrive, dev.serial),\
 179    DEFINE_PROP_STRING("model", IDEDrive, dev.model)
 180
 181static Property ide_hd_properties[] = {
 182    DEFINE_IDE_DEV_PROPERTIES(),
 183    DEFINE_PROP_END_OF_LIST(),
 184};
 185
 186static void ide_hd_class_init(ObjectClass *klass, void *data)
 187{
 188    DeviceClass *dc = DEVICE_CLASS(klass);
 189    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
 190    k->init = ide_hd_initfn;
 191    dc->fw_name = "drive";
 192    dc->desc = "virtual IDE disk";
 193    dc->props = ide_hd_properties;
 194}
 195
 196static TypeInfo ide_hd_info = {
 197    .name          = "ide-hd",
 198    .parent        = TYPE_IDE_DEVICE,
 199    .instance_size = sizeof(IDEDrive),
 200    .class_init    = ide_hd_class_init,
 201};
 202
 203static Property ide_cd_properties[] = {
 204    DEFINE_IDE_DEV_PROPERTIES(),
 205    DEFINE_PROP_END_OF_LIST(),
 206};
 207
 208static void ide_cd_class_init(ObjectClass *klass, void *data)
 209{
 210    DeviceClass *dc = DEVICE_CLASS(klass);
 211    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
 212    k->init = ide_cd_initfn;
 213    dc->fw_name = "drive";
 214    dc->desc = "virtual IDE CD-ROM";
 215    dc->props = ide_cd_properties;
 216}
 217
 218static TypeInfo ide_cd_info = {
 219    .name          = "ide-cd",
 220    .parent        = TYPE_IDE_DEVICE,
 221    .instance_size = sizeof(IDEDrive),
 222    .class_init    = ide_cd_class_init,
 223};
 224
 225static Property ide_drive_properties[] = {
 226    DEFINE_IDE_DEV_PROPERTIES(),
 227    DEFINE_PROP_END_OF_LIST(),
 228};
 229
 230static void ide_drive_class_init(ObjectClass *klass, void *data)
 231{
 232    DeviceClass *dc = DEVICE_CLASS(klass);
 233    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
 234    k->init = ide_drive_initfn;
 235    dc->fw_name = "drive";
 236    dc->desc = "virtual IDE disk or CD-ROM (legacy)";
 237    dc->props = ide_drive_properties;
 238}
 239
 240static TypeInfo ide_drive_info = {
 241    .name          = "ide-drive",
 242    .parent        = TYPE_IDE_DEVICE,
 243    .instance_size = sizeof(IDEDrive),
 244    .class_init    = ide_drive_class_init,
 245};
 246
 247static void ide_device_class_init(ObjectClass *klass, void *data)
 248{
 249    DeviceClass *k = DEVICE_CLASS(klass);
 250    k->init = ide_qdev_init;
 251    k->bus_info = &ide_bus_info;
 252}
 253
 254static TypeInfo ide_device_type_info = {
 255    .name = TYPE_IDE_DEVICE,
 256    .parent = TYPE_DEVICE,
 257    .instance_size = sizeof(IDEDevice),
 258    .abstract = true,
 259    .class_size = sizeof(IDEDeviceClass),
 260    .class_init = ide_device_class_init,
 261};
 262
 263static void ide_register_types(void)
 264{
 265    type_register_static(&ide_hd_info);
 266    type_register_static(&ide_cd_info);
 267    type_register_static(&ide_drive_info);
 268    type_register_static(&ide_device_type_info);
 269}
 270
 271type_init(ide_register_types)
 272