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 "hw/block-common.h"
  25#include "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)
  51{
  52    qbus_create_inplace(&idebus->qbus, TYPE_IDE_BUS, dev, NULL);
  53    idebus->bus_id = bus_id;
  54}
  55
  56static char *idebus_get_fw_dev_path(DeviceState *dev)
  57{
  58    char path[30];
  59
  60    snprintf(path, sizeof(path), "%s@%d", qdev_fw_name(dev),
  61             ((IDEBus*)dev->parent_bus)->bus_id);
  62
  63    return g_strdup(path);
  64}
  65
  66static int ide_qdev_init(DeviceState *qdev)
  67{
  68    IDEDevice *dev = IDE_DEVICE(qdev);
  69    IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
  70    IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
  71
  72    if (!dev->conf.bs) {
  73        error_report("No drive specified");
  74        goto err;
  75    }
  76    if (dev->unit == -1) {
  77        dev->unit = bus->master ? 1 : 0;
  78    }
  79    switch (dev->unit) {
  80    case 0:
  81        if (bus->master) {
  82            error_report("IDE unit %d is in use", dev->unit);
  83            goto err;
  84        }
  85        bus->master = dev;
  86        break;
  87    case 1:
  88        if (bus->slave) {
  89            error_report("IDE unit %d is in use", dev->unit);
  90            goto err;
  91        }
  92        bus->slave = dev;
  93        break;
  94    default:
  95        error_report("Invalid IDE unit %d", dev->unit);
  96        goto err;
  97    }
  98    return dc->init(dev);
  99
 100err:
 101    return -1;
 102}
 103
 104IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
 105{
 106    DeviceState *dev;
 107
 108    dev = qdev_create(&bus->qbus, drive->media_cd ? "ide-cd" : "ide-hd");
 109    qdev_prop_set_uint32(dev, "unit", unit);
 110    qdev_prop_set_drive_nofail(dev, "drive", drive->bdrv);
 111    qdev_init_nofail(dev);
 112    return DO_UPCAST(IDEDevice, qdev, dev);
 113}
 114
 115int ide_get_geometry(BusState *bus, int unit,
 116                     int16_t *cyls, int8_t *heads, int8_t *secs)
 117{
 118    IDEState *s = &DO_UPCAST(IDEBus, qbus, bus)->ifs[unit];
 119
 120    if (s->drive_kind != IDE_HD || !s->bs) {
 121        return -1;
 122    }
 123
 124    *cyls = s->cylinders;
 125    *heads = s->heads;
 126    *secs = s->sectors;
 127    return 0;
 128}
 129
 130int ide_get_bios_chs_trans(BusState *bus, int unit)
 131{
 132    return DO_UPCAST(IDEBus, qbus, bus)->ifs[unit].chs_trans;
 133}
 134
 135/* --------------------------------- */
 136
 137typedef struct IDEDrive {
 138    IDEDevice dev;
 139} IDEDrive;
 140
 141static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
 142{
 143    IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
 144    IDEState *s = bus->ifs + dev->unit;
 145
 146    if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) {
 147        error_report("discard_granularity must be 512 for ide");
 148        return -1;
 149    }
 150
 151    blkconf_serial(&dev->conf, &dev->serial);
 152    if (kind != IDE_CD
 153        && blkconf_geometry(&dev->conf, &dev->chs_trans, 65536, 16, 255) < 0) {
 154        return -1;
 155    }
 156
 157    if (ide_init_drive(s, dev->conf.bs, kind,
 158                       dev->version, dev->serial, dev->model, dev->wwn,
 159                       dev->conf.cyls, dev->conf.heads, dev->conf.secs,
 160                       dev->chs_trans) < 0) {
 161        return -1;
 162    }
 163
 164    if (!dev->version) {
 165        dev->version = g_strdup(s->version);
 166    }
 167    if (!dev->serial) {
 168        dev->serial = g_strdup(s->drive_serial_str);
 169    }
 170
 171    add_boot_device_path(dev->conf.bootindex, &dev->qdev,
 172                         dev->unit ? "/disk@1" : "/disk@0");
 173
 174    return 0;
 175}
 176
 177static int ide_hd_initfn(IDEDevice *dev)
 178{
 179    return ide_dev_initfn(dev, IDE_HD);
 180}
 181
 182static int ide_cd_initfn(IDEDevice *dev)
 183{
 184    return ide_dev_initfn(dev, IDE_CD);
 185}
 186
 187static int ide_drive_initfn(IDEDevice *dev)
 188{
 189    DriveInfo *dinfo = drive_get_by_blockdev(dev->conf.bs);
 190
 191    return ide_dev_initfn(dev, dinfo->media_cd ? IDE_CD : IDE_HD);
 192}
 193
 194#define DEFINE_IDE_DEV_PROPERTIES()                     \
 195    DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf),        \
 196    DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),  \
 197    DEFINE_PROP_HEX64("wwn",  IDEDrive, dev.wwn, 0),    \
 198    DEFINE_PROP_STRING("serial",  IDEDrive, dev.serial),\
 199    DEFINE_PROP_STRING("model", IDEDrive, dev.model)
 200
 201static Property ide_hd_properties[] = {
 202    DEFINE_IDE_DEV_PROPERTIES(),
 203    DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
 204    DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
 205                IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
 206    DEFINE_PROP_END_OF_LIST(),
 207};
 208
 209static void ide_hd_class_init(ObjectClass *klass, void *data)
 210{
 211    DeviceClass *dc = DEVICE_CLASS(klass);
 212    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
 213    k->init = ide_hd_initfn;
 214    dc->fw_name = "drive";
 215    dc->desc = "virtual IDE disk";
 216    dc->props = ide_hd_properties;
 217}
 218
 219static TypeInfo ide_hd_info = {
 220    .name          = "ide-hd",
 221    .parent        = TYPE_IDE_DEVICE,
 222    .instance_size = sizeof(IDEDrive),
 223    .class_init    = ide_hd_class_init,
 224};
 225
 226static Property ide_cd_properties[] = {
 227    DEFINE_IDE_DEV_PROPERTIES(),
 228    DEFINE_PROP_END_OF_LIST(),
 229};
 230
 231static void ide_cd_class_init(ObjectClass *klass, void *data)
 232{
 233    DeviceClass *dc = DEVICE_CLASS(klass);
 234    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
 235    k->init = ide_cd_initfn;
 236    dc->fw_name = "drive";
 237    dc->desc = "virtual IDE CD-ROM";
 238    dc->props = ide_cd_properties;
 239}
 240
 241static TypeInfo ide_cd_info = {
 242    .name          = "ide-cd",
 243    .parent        = TYPE_IDE_DEVICE,
 244    .instance_size = sizeof(IDEDrive),
 245    .class_init    = ide_cd_class_init,
 246};
 247
 248static Property ide_drive_properties[] = {
 249    DEFINE_IDE_DEV_PROPERTIES(),
 250    DEFINE_PROP_END_OF_LIST(),
 251};
 252
 253static void ide_drive_class_init(ObjectClass *klass, void *data)
 254{
 255    DeviceClass *dc = DEVICE_CLASS(klass);
 256    IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
 257    k->init = ide_drive_initfn;
 258    dc->fw_name = "drive";
 259    dc->desc = "virtual IDE disk or CD-ROM (legacy)";
 260    dc->props = ide_drive_properties;
 261}
 262
 263static TypeInfo ide_drive_info = {
 264    .name          = "ide-drive",
 265    .parent        = TYPE_IDE_DEVICE,
 266    .instance_size = sizeof(IDEDrive),
 267    .class_init    = ide_drive_class_init,
 268};
 269
 270static void ide_device_class_init(ObjectClass *klass, void *data)
 271{
 272    DeviceClass *k = DEVICE_CLASS(klass);
 273    k->init = ide_qdev_init;
 274    k->bus_type = TYPE_IDE_BUS;
 275    k->props = ide_props;
 276}
 277
 278static TypeInfo ide_device_type_info = {
 279    .name = TYPE_IDE_DEVICE,
 280    .parent = TYPE_DEVICE,
 281    .instance_size = sizeof(IDEDevice),
 282    .abstract = true,
 283    .class_size = sizeof(IDEDeviceClass),
 284    .class_init = ide_device_class_init,
 285};
 286
 287static void ide_register_types(void)
 288{
 289    type_register_static(&ide_bus_info);
 290    type_register_static(&ide_hd_info);
 291    type_register_static(&ide_cd_info);
 292    type_register_static(&ide_drive_info);
 293    type_register_static(&ide_device_type_info);
 294}
 295
 296type_init(ide_register_types)
 297