2 * ide bus support for qdev.
4 * Copyright (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
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.1 of the License, or (at your option) any later version.
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.
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/>.
20 #include "qemu/osdep.h"
21 #include "sysemu/dma.h"
22 #include "qapi/error.h"
23 #include "qapi/qapi-types-block.h"
24 #include "qemu/error-report.h"
25 #include "qemu/main-loop.h"
26 #include "qemu/module.h"
27 #include "hw/ide/internal.h"
28 #include "hw/qdev-properties.h"
29 #include "hw/qdev-properties-system.h"
30 #include "sysemu/block-backend.h"
31 #include "sysemu/blockdev.h"
32 #include "hw/block/block.h"
33 #include "sysemu/sysemu.h"
34 #include "sysemu/runstate.h"
35 #include "qapi/visitor.h"
37 /* --------------------------------- */
39 static char *idebus_get_fw_dev_path(DeviceState
*dev
);
40 static void idebus_unrealize(BusState
*qdev
);
42 static Property ide_props
[] = {
43 DEFINE_PROP_UINT32("unit", IDEDevice
, unit
, -1),
44 DEFINE_PROP_END_OF_LIST(),
47 static void ide_bus_class_init(ObjectClass
*klass
, void *data
)
49 BusClass
*k
= BUS_CLASS(klass
);
51 k
->get_fw_dev_path
= idebus_get_fw_dev_path
;
52 k
->unrealize
= idebus_unrealize
;
55 static void idebus_unrealize(BusState
*bus
)
57 IDEBus
*ibus
= IDE_BUS(bus
);
60 qemu_del_vm_change_state_handler(ibus
->vmstate
);
64 static const TypeInfo ide_bus_info
= {
67 .instance_size
= sizeof(IDEBus
),
68 .class_init
= ide_bus_class_init
,
71 void ide_bus_new(IDEBus
*idebus
, size_t idebus_size
, DeviceState
*dev
,
72 int bus_id
, int max_units
)
74 qbus_create_inplace(idebus
, idebus_size
, TYPE_IDE_BUS
, dev
, NULL
);
75 idebus
->bus_id
= bus_id
;
76 idebus
->max_units
= max_units
;
79 static char *idebus_get_fw_dev_path(DeviceState
*dev
)
83 snprintf(path
, sizeof(path
), "%s@%x", qdev_fw_name(dev
),
84 ((IDEBus
*)dev
->parent_bus
)->bus_id
);
86 return g_strdup(path
);
89 static void ide_qdev_realize(DeviceState
*qdev
, Error
**errp
)
91 IDEDevice
*dev
= IDE_DEVICE(qdev
);
92 IDEDeviceClass
*dc
= IDE_DEVICE_GET_CLASS(dev
);
93 IDEBus
*bus
= DO_UPCAST(IDEBus
, qbus
, qdev
->parent_bus
);
95 if (dev
->unit
== -1) {
96 dev
->unit
= bus
->master
? 1 : 0;
99 if (dev
->unit
>= bus
->max_units
) {
100 error_setg(errp
, "Can't create IDE unit %d, bus supports only %d units",
101 dev
->unit
, bus
->max_units
);
108 error_setg(errp
, "IDE unit %d is in use", dev
->unit
);
115 error_setg(errp
, "IDE unit %d is in use", dev
->unit
);
121 error_setg(errp
, "Invalid IDE unit %d", dev
->unit
);
124 dc
->realize(dev
, errp
);
127 IDEDevice
*ide_create_drive(IDEBus
*bus
, int unit
, DriveInfo
*drive
)
131 dev
= qdev_new(drive
->media_cd
? "ide-cd" : "ide-hd");
132 qdev_prop_set_uint32(dev
, "unit", unit
);
133 qdev_prop_set_drive_err(dev
, "drive", blk_by_legacy_dinfo(drive
),
135 qdev_realize_and_unref(dev
, &bus
->qbus
, &error_fatal
);
136 return DO_UPCAST(IDEDevice
, qdev
, dev
);
139 int ide_get_geometry(BusState
*bus
, int unit
,
140 int16_t *cyls
, int8_t *heads
, int8_t *secs
)
142 IDEState
*s
= &DO_UPCAST(IDEBus
, qbus
, bus
)->ifs
[unit
];
144 if (s
->drive_kind
!= IDE_HD
|| !s
->blk
) {
148 *cyls
= s
->cylinders
;
154 int ide_get_bios_chs_trans(BusState
*bus
, int unit
)
156 return DO_UPCAST(IDEBus
, qbus
, bus
)->ifs
[unit
].chs_trans
;
159 /* --------------------------------- */
161 typedef struct IDEDrive
{
165 static void ide_dev_initfn(IDEDevice
*dev
, IDEDriveKind kind
, Error
**errp
)
167 IDEBus
*bus
= DO_UPCAST(IDEBus
, qbus
, dev
->qdev
.parent_bus
);
168 IDEState
*s
= bus
->ifs
+ dev
->unit
;
171 if (!dev
->conf
.blk
) {
172 if (kind
!= IDE_CD
) {
173 error_setg(errp
, "No drive specified");
176 /* Anonymous BlockBackend for an empty drive */
177 dev
->conf
.blk
= blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL
);
178 ret
= blk_attach_dev(dev
->conf
.blk
, &dev
->qdev
);
183 if (dev
->conf
.discard_granularity
== -1) {
184 dev
->conf
.discard_granularity
= 512;
185 } else if (dev
->conf
.discard_granularity
&&
186 dev
->conf
.discard_granularity
!= 512) {
187 error_setg(errp
, "discard_granularity must be 512 for ide");
191 if (!blkconf_blocksizes(&dev
->conf
, errp
)) {
195 if (dev
->conf
.logical_block_size
!= 512) {
196 error_setg(errp
, "logical_block_size must be 512 for IDE");
200 if (kind
!= IDE_CD
) {
201 if (!blkconf_geometry(&dev
->conf
, &dev
->chs_trans
, 65535, 16, 255,
206 if (!blkconf_apply_backend_options(&dev
->conf
, kind
== IDE_CD
,
207 kind
!= IDE_CD
, errp
)) {
211 if (ide_init_drive(s
, dev
->conf
.blk
, kind
,
212 dev
->version
, dev
->serial
, dev
->model
, dev
->wwn
,
213 dev
->conf
.cyls
, dev
->conf
.heads
, dev
->conf
.secs
,
214 dev
->chs_trans
, errp
) < 0) {
219 dev
->version
= g_strdup(s
->version
);
222 dev
->serial
= g_strdup(s
->drive_serial_str
);
225 add_boot_device_path(dev
->conf
.bootindex
, &dev
->qdev
,
226 dev
->unit
? "/disk@1" : "/disk@0");
228 add_boot_device_lchs(&dev
->qdev
, dev
->unit
? "/disk@1" : "/disk@0",
234 static void ide_dev_get_bootindex(Object
*obj
, Visitor
*v
, const char *name
,
235 void *opaque
, Error
**errp
)
237 IDEDevice
*d
= IDE_DEVICE(obj
);
239 visit_type_int32(v
, name
, &d
->conf
.bootindex
, errp
);
242 static void ide_dev_set_bootindex(Object
*obj
, Visitor
*v
, const char *name
,
243 void *opaque
, Error
**errp
)
245 IDEDevice
*d
= IDE_DEVICE(obj
);
247 Error
*local_err
= NULL
;
249 if (!visit_type_int32(v
, name
, &boot_index
, errp
)) {
252 /* check whether bootindex is present in fw_boot_order list */
253 check_boot_index(boot_index
, &local_err
);
257 /* change bootindex to a new one */
258 d
->conf
.bootindex
= boot_index
;
261 add_boot_device_path(d
->conf
.bootindex
, &d
->qdev
,
262 d
->unit
? "/disk@1" : "/disk@0");
265 error_propagate(errp
, local_err
);
268 static void ide_dev_instance_init(Object
*obj
)
270 object_property_add(obj
, "bootindex", "int32",
271 ide_dev_get_bootindex
,
272 ide_dev_set_bootindex
, NULL
, NULL
);
273 object_property_set_int(obj
, "bootindex", -1, NULL
);
276 static void ide_hd_realize(IDEDevice
*dev
, Error
**errp
)
278 ide_dev_initfn(dev
, IDE_HD
, errp
);
281 static void ide_cd_realize(IDEDevice
*dev
, Error
**errp
)
283 ide_dev_initfn(dev
, IDE_CD
, errp
);
286 static void ide_drive_realize(IDEDevice
*dev
, Error
**errp
)
288 DriveInfo
*dinfo
= NULL
;
290 warn_report("'ide-drive' is deprecated, "
291 "please use 'ide-hd' or 'ide-cd' instead");
294 dinfo
= blk_legacy_dinfo(dev
->conf
.blk
);
297 ide_dev_initfn(dev
, dinfo
&& dinfo
->media_cd
? IDE_CD
: IDE_HD
, errp
);
300 #define DEFINE_IDE_DEV_PROPERTIES() \
301 DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), \
302 DEFINE_BLOCK_ERROR_PROPERTIES(IDEDrive, dev.conf), \
303 DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \
304 DEFINE_PROP_UINT64("wwn", IDEDrive, dev.wwn, 0), \
305 DEFINE_PROP_STRING("serial", IDEDrive, dev.serial),\
306 DEFINE_PROP_STRING("model", IDEDrive, dev.model)
308 static Property ide_hd_properties
[] = {
309 DEFINE_IDE_DEV_PROPERTIES(),
310 DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive
, dev
.conf
),
311 DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
312 IDEDrive
, dev
.chs_trans
, BIOS_ATA_TRANSLATION_AUTO
),
313 DEFINE_PROP_UINT16("rotation_rate", IDEDrive
, dev
.rotation_rate
, 0),
314 DEFINE_PROP_END_OF_LIST(),
317 static void ide_hd_class_init(ObjectClass
*klass
, void *data
)
319 DeviceClass
*dc
= DEVICE_CLASS(klass
);
320 IDEDeviceClass
*k
= IDE_DEVICE_CLASS(klass
);
322 k
->realize
= ide_hd_realize
;
323 dc
->fw_name
= "drive";
324 dc
->desc
= "virtual IDE disk";
325 device_class_set_props(dc
, ide_hd_properties
);
328 static const TypeInfo ide_hd_info
= {
330 .parent
= TYPE_IDE_DEVICE
,
331 .instance_size
= sizeof(IDEDrive
),
332 .class_init
= ide_hd_class_init
,
335 static Property ide_cd_properties
[] = {
336 DEFINE_IDE_DEV_PROPERTIES(),
337 DEFINE_PROP_END_OF_LIST(),
340 static void ide_cd_class_init(ObjectClass
*klass
, void *data
)
342 DeviceClass
*dc
= DEVICE_CLASS(klass
);
343 IDEDeviceClass
*k
= IDE_DEVICE_CLASS(klass
);
345 k
->realize
= ide_cd_realize
;
346 dc
->fw_name
= "drive";
347 dc
->desc
= "virtual IDE CD-ROM";
348 device_class_set_props(dc
, ide_cd_properties
);
351 static const TypeInfo ide_cd_info
= {
353 .parent
= TYPE_IDE_DEVICE
,
354 .instance_size
= sizeof(IDEDrive
),
355 .class_init
= ide_cd_class_init
,
358 static Property ide_drive_properties
[] = {
359 DEFINE_IDE_DEV_PROPERTIES(),
360 DEFINE_PROP_END_OF_LIST(),
363 static void ide_drive_class_init(ObjectClass
*klass
, void *data
)
365 DeviceClass
*dc
= DEVICE_CLASS(klass
);
366 IDEDeviceClass
*k
= IDE_DEVICE_CLASS(klass
);
368 k
->realize
= ide_drive_realize
;
369 dc
->fw_name
= "drive";
370 dc
->desc
= "virtual IDE disk or CD-ROM (legacy)";
371 device_class_set_props(dc
, ide_drive_properties
);
374 static const TypeInfo ide_drive_info
= {
376 .parent
= TYPE_IDE_DEVICE
,
377 .instance_size
= sizeof(IDEDrive
),
378 .class_init
= ide_drive_class_init
,
381 static void ide_device_class_init(ObjectClass
*klass
, void *data
)
383 DeviceClass
*k
= DEVICE_CLASS(klass
);
384 k
->realize
= ide_qdev_realize
;
385 set_bit(DEVICE_CATEGORY_STORAGE
, k
->categories
);
386 k
->bus_type
= TYPE_IDE_BUS
;
387 device_class_set_props(k
, ide_props
);
390 static const TypeInfo ide_device_type_info
= {
391 .name
= TYPE_IDE_DEVICE
,
392 .parent
= TYPE_DEVICE
,
393 .instance_size
= sizeof(IDEDevice
),
395 .class_size
= sizeof(IDEDeviceClass
),
396 .class_init
= ide_device_class_init
,
397 .instance_init
= ide_dev_instance_init
,
400 static void ide_register_types(void)
402 type_register_static(&ide_bus_info
);
403 type_register_static(&ide_hd_info
);
404 type_register_static(&ide_cd_info
);
405 type_register_static(&ide_drive_info
);
406 type_register_static(&ide_device_type_info
);
409 type_init(ide_register_types
)