1da4d0419SGerd Hoffmann /*
27bd8b0d4SThomas Huth * IDE device functions
3da4d0419SGerd Hoffmann *
4da4d0419SGerd Hoffmann * Copyright (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
5da4d0419SGerd Hoffmann *
6da4d0419SGerd Hoffmann * This library is free software; you can redistribute it and/or
7da4d0419SGerd Hoffmann * modify it under the terms of the GNU Lesser General Public
8da4d0419SGerd Hoffmann * License as published by the Free Software Foundation; either
961f3c91aSChetan Pant * version 2.1 of the License, or (at your option) any later version.
10da4d0419SGerd Hoffmann *
11da4d0419SGerd Hoffmann * This library is distributed in the hope that it will be useful,
12da4d0419SGerd Hoffmann * but WITHOUT ANY WARRANTY; without even the implied warranty of
13da4d0419SGerd Hoffmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14da4d0419SGerd Hoffmann * Lesser General Public License for more details.
15da4d0419SGerd Hoffmann *
16da4d0419SGerd Hoffmann * You should have received a copy of the GNU Lesser General Public
17da4d0419SGerd Hoffmann * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18da4d0419SGerd Hoffmann */
190b8fa32fSMarkus Armbruster
2053239262SPeter Maydell #include "qemu/osdep.h"
21da34e65cSMarkus Armbruster #include "qapi/error.h"
222ae16a6aSMarkus Armbruster #include "qapi/qapi-types-block.h"
231de7afc9SPaolo Bonzini #include "qemu/error-report.h"
240b8fa32fSMarkus Armbruster #include "qemu/module.h"
25bd217d88SThomas Huth #include "hw/ide/ide-dev.h"
2632cad1ffSPhilippe Mathieu-Daudé #include "system/block-backend.h"
2732cad1ffSPhilippe Mathieu-Daudé #include "system/blockdev.h"
2832cad1ffSPhilippe Mathieu-Daudé #include "system/system.h"
2945563630SGonglei #include "qapi/visitor.h"
300316482eSPhilippe Mathieu-Daudé #include "ide-internal.h"
31da4d0419SGerd Hoffmann
32aaa1f1a5SRichard Henderson static const Property ide_props[] = {
333cb75a7cSPaolo Bonzini DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
34d13f4035SPaolo Bonzini DEFINE_PROP_BOOL("win2k-install-hack", IDEDevice, win2k_install_hack, false),
353cb75a7cSPaolo Bonzini };
363cb75a7cSPaolo Bonzini
ide_qdev_realize(DeviceState * qdev,Error ** errp)37794939e8SMao Zhongyi static void ide_qdev_realize(DeviceState *qdev, Error **errp)
38da4d0419SGerd Hoffmann {
39d148211cSAnthony Liguori IDEDevice *dev = IDE_DEVICE(qdev);
40d148211cSAnthony Liguori IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
41da4d0419SGerd Hoffmann IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
42da4d0419SGerd Hoffmann
43da4d0419SGerd Hoffmann if (dev->unit == -1) {
44da4d0419SGerd Hoffmann dev->unit = bus->master ? 1 : 0;
45da4d0419SGerd Hoffmann }
460ee20e66SKevin Wolf
470ee20e66SKevin Wolf if (dev->unit >= bus->max_units) {
48794939e8SMao Zhongyi error_setg(errp, "Can't create IDE unit %d, bus supports only %d units",
490ee20e66SKevin Wolf dev->unit, bus->max_units);
50794939e8SMao Zhongyi return;
510ee20e66SKevin Wolf }
520ee20e66SKevin Wolf
53da4d0419SGerd Hoffmann switch (dev->unit) {
54da4d0419SGerd Hoffmann case 0:
55da4d0419SGerd Hoffmann if (bus->master) {
56794939e8SMao Zhongyi error_setg(errp, "IDE unit %d is in use", dev->unit);
57794939e8SMao Zhongyi return;
58da4d0419SGerd Hoffmann }
59da4d0419SGerd Hoffmann bus->master = dev;
60da4d0419SGerd Hoffmann break;
61da4d0419SGerd Hoffmann case 1:
62da4d0419SGerd Hoffmann if (bus->slave) {
63794939e8SMao Zhongyi error_setg(errp, "IDE unit %d is in use", dev->unit);
64794939e8SMao Zhongyi return;
65da4d0419SGerd Hoffmann }
66da4d0419SGerd Hoffmann bus->slave = dev;
67da4d0419SGerd Hoffmann break;
68da4d0419SGerd Hoffmann default:
69794939e8SMao Zhongyi error_setg(errp, "Invalid IDE unit %d", dev->unit);
70794939e8SMao Zhongyi return;
71da4d0419SGerd Hoffmann }
72794939e8SMao Zhongyi dc->realize(dev, errp);
73da4d0419SGerd Hoffmann }
74da4d0419SGerd Hoffmann
ide_dev_initfn(IDEDevice * dev,IDEDriveKind kind,Error ** errp)75bd217d88SThomas Huth void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
76da4d0419SGerd Hoffmann {
77da4d0419SGerd Hoffmann IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
786ced55a5SMarkus Armbruster IDEState *s = bus->ifs + dev->unit;
79947231adSKevin Wolf int ret;
806ced55a5SMarkus Armbruster
8167c75f3dSKevin Wolf if (!dev->conf.blk) {
8267c75f3dSKevin Wolf if (kind != IDE_CD) {
83794939e8SMao Zhongyi error_setg(errp, "No drive specified");
84794939e8SMao Zhongyi return;
8567c75f3dSKevin Wolf } else {
8667c75f3dSKevin Wolf /* Anonymous BlockBackend for an empty drive */
87d861ab3aSKevin Wolf dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
88947231adSKevin Wolf ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
89947231adSKevin Wolf assert(ret == 0);
9067c75f3dSKevin Wolf }
9167c75f3dSKevin Wolf }
9267c75f3dSKevin Wolf
93215e47b9SPaolo Bonzini if (dev->conf.discard_granularity == -1) {
94215e47b9SPaolo Bonzini dev->conf.discard_granularity = 512;
95215e47b9SPaolo Bonzini } else if (dev->conf.discard_granularity &&
96215e47b9SPaolo Bonzini dev->conf.discard_granularity != 512) {
97794939e8SMao Zhongyi error_setg(errp, "discard_granularity must be 512 for ide");
98794939e8SMao Zhongyi return;
99d353fb72SChristoph Hellwig }
100d353fb72SChristoph Hellwig
101c56ee92fSRoman Kagan if (!blkconf_blocksizes(&dev->conf, errp)) {
102c56ee92fSRoman Kagan return;
103c56ee92fSRoman Kagan }
104c56ee92fSRoman Kagan
105d2005185SKevin Wolf if (dev->conf.logical_block_size != 512) {
106794939e8SMao Zhongyi error_setg(errp, "logical_block_size must be 512 for IDE");
107794939e8SMao Zhongyi return;
108d2005185SKevin Wolf }
109d2005185SKevin Wolf
1105ff5efb4SFam Zheng if (kind != IDE_CD) {
111ceff3e1fSMao Zhongyi if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
112ceff3e1fSMao Zhongyi errp)) {
113794939e8SMao Zhongyi return;
114ba801960SMarkus Armbruster }
1155ff5efb4SFam Zheng }
116ceff3e1fSMao Zhongyi if (!blkconf_apply_backend_options(&dev->conf, kind == IDE_CD,
117ceff3e1fSMao Zhongyi kind != IDE_CD, errp)) {
118794939e8SMao Zhongyi return;
119a17c17a2SKevin Wolf }
120ba801960SMarkus Armbruster
121dcaff461SPaolo Bonzini if (ide_init_drive(s, dev, kind, errp) < 0) {
122794939e8SMao Zhongyi return;
123c4d74df7SMarkus Armbruster }
1246ced55a5SMarkus Armbruster
12503432407SMarkus Armbruster if (!dev->version) {
1267267c094SAnthony Liguori dev->version = g_strdup(s->version);
12703432407SMarkus Armbruster }
1286ced55a5SMarkus Armbruster if (!dev->serial) {
1297267c094SAnthony Liguori dev->serial = g_strdup(s->drive_serial_str);
1306ced55a5SMarkus Armbruster }
1311ca4d09aSGleb Natapov
1321ca4d09aSGleb Natapov add_boot_device_path(dev->conf.bootindex, &dev->qdev,
1331ca4d09aSGleb Natapov dev->unit ? "/disk@1" : "/disk@0");
13471f571a2SSam Eiderman
13571f571a2SSam Eiderman add_boot_device_lchs(&dev->qdev, dev->unit ? "/disk@1" : "/disk@0",
13671f571a2SSam Eiderman dev->conf.lcyls,
13771f571a2SSam Eiderman dev->conf.lheads,
13871f571a2SSam Eiderman dev->conf.lsecs);
139da4d0419SGerd Hoffmann }
140da4d0419SGerd Hoffmann
ide_dev_get_bootindex(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)141d7bce999SEric Blake static void ide_dev_get_bootindex(Object *obj, Visitor *v, const char *name,
142d7bce999SEric Blake void *opaque, Error **errp)
14345563630SGonglei {
14445563630SGonglei IDEDevice *d = IDE_DEVICE(obj);
14545563630SGonglei
14651e72bc1SEric Blake visit_type_int32(v, name, &d->conf.bootindex, errp);
14745563630SGonglei }
14845563630SGonglei
ide_dev_set_bootindex(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)149d7bce999SEric Blake static void ide_dev_set_bootindex(Object *obj, Visitor *v, const char *name,
150d7bce999SEric Blake void *opaque, Error **errp)
15145563630SGonglei {
15245563630SGonglei IDEDevice *d = IDE_DEVICE(obj);
15345563630SGonglei int32_t boot_index;
15445563630SGonglei Error *local_err = NULL;
15545563630SGonglei
15614217038SMarkus Armbruster if (!visit_type_int32(v, name, &boot_index, errp)) {
15714217038SMarkus Armbruster return;
15845563630SGonglei }
15945563630SGonglei /* check whether bootindex is present in fw_boot_order list */
16045563630SGonglei check_boot_index(boot_index, &local_err);
16145563630SGonglei if (local_err) {
16245563630SGonglei goto out;
16345563630SGonglei }
16445563630SGonglei /* change bootindex to a new one */
16545563630SGonglei d->conf.bootindex = boot_index;
16645563630SGonglei
167d2b186f9SGonglei if (d->unit != -1) {
168d2b186f9SGonglei add_boot_device_path(d->conf.bootindex, &d->qdev,
169d2b186f9SGonglei d->unit ? "/disk@1" : "/disk@0");
170d2b186f9SGonglei }
17145563630SGonglei out:
17245563630SGonglei error_propagate(errp, local_err);
17345563630SGonglei }
17445563630SGonglei
ide_dev_instance_init(Object * obj)17545563630SGonglei static void ide_dev_instance_init(Object *obj)
17645563630SGonglei {
17745563630SGonglei object_property_add(obj, "bootindex", "int32",
17845563630SGonglei ide_dev_get_bootindex,
179d2623129SMarkus Armbruster ide_dev_set_bootindex, NULL, NULL);
1805325cc34SMarkus Armbruster object_property_set_int(obj, "bootindex", -1, NULL);
18145563630SGonglei }
18245563630SGonglei
ide_hd_realize(IDEDevice * dev,Error ** errp)183794939e8SMao Zhongyi static void ide_hd_realize(IDEDevice *dev, Error **errp)
1841f56e32aSMarkus Armbruster {
185794939e8SMao Zhongyi ide_dev_initfn(dev, IDE_HD, errp);
1861f56e32aSMarkus Armbruster }
1871f56e32aSMarkus Armbruster
ide_cd_realize(IDEDevice * dev,Error ** errp)188794939e8SMao Zhongyi static void ide_cd_realize(IDEDevice *dev, Error **errp)
1891f56e32aSMarkus Armbruster {
190794939e8SMao Zhongyi ide_dev_initfn(dev, IDE_CD, errp);
1911f56e32aSMarkus Armbruster }
1921f56e32aSMarkus Armbruster
193aaa1f1a5SRichard Henderson static const Property ide_hd_properties[] = {
1941f56e32aSMarkus Armbruster DEFINE_IDE_DEV_PROPERTIES(),
195ba801960SMarkus Armbruster DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
1966e6f61a6SMarkus Armbruster DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
1976e6f61a6SMarkus Armbruster IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
1983b19f450SDaniel P. Berrange DEFINE_PROP_UINT16("rotation_rate", IDEDrive, dev.rotation_rate, 0),
19939bffca2SAnthony Liguori };
20039bffca2SAnthony Liguori
ide_hd_class_init(ObjectClass * klass,const void * data)201*12d1a768SPhilippe Mathieu-Daudé static void ide_hd_class_init(ObjectClass *klass, const void *data)
20239bffca2SAnthony Liguori {
20339bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass);
20439bffca2SAnthony Liguori IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
205794939e8SMao Zhongyi
206794939e8SMao Zhongyi k->realize = ide_hd_realize;
20739bffca2SAnthony Liguori dc->fw_name = "drive";
20839bffca2SAnthony Liguori dc->desc = "virtual IDE disk";
2094f67d30bSMarc-André Lureau device_class_set_props(dc, ide_hd_properties);
2101f56e32aSMarkus Armbruster }
21139bffca2SAnthony Liguori
2128c43a6f0SAndreas Färber static const TypeInfo ide_hd_info = {
21339bffca2SAnthony Liguori .name = "ide-hd",
21439bffca2SAnthony Liguori .parent = TYPE_IDE_DEVICE,
21539bffca2SAnthony Liguori .instance_size = sizeof(IDEDrive),
21639bffca2SAnthony Liguori .class_init = ide_hd_class_init,
21739bffca2SAnthony Liguori };
21839bffca2SAnthony Liguori
219aaa1f1a5SRichard Henderson static const Property ide_cd_properties[] = {
22039bffca2SAnthony Liguori DEFINE_IDE_DEV_PROPERTIES(),
221d148211cSAnthony Liguori };
222d148211cSAnthony Liguori
ide_cd_class_init(ObjectClass * klass,const void * data)223*12d1a768SPhilippe Mathieu-Daudé static void ide_cd_class_init(ObjectClass *klass, const void *data)
224d148211cSAnthony Liguori {
22539bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass);
226d148211cSAnthony Liguori IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
227794939e8SMao Zhongyi
228794939e8SMao Zhongyi k->realize = ide_cd_realize;
22939bffca2SAnthony Liguori dc->fw_name = "drive";
23039bffca2SAnthony Liguori dc->desc = "virtual IDE CD-ROM";
2314f67d30bSMarc-André Lureau device_class_set_props(dc, ide_cd_properties);
232d148211cSAnthony Liguori }
233d148211cSAnthony Liguori
2348c43a6f0SAndreas Färber static const TypeInfo ide_cd_info = {
235d148211cSAnthony Liguori .name = "ide-cd",
23639bffca2SAnthony Liguori .parent = TYPE_IDE_DEVICE,
23739bffca2SAnthony Liguori .instance_size = sizeof(IDEDrive),
238d148211cSAnthony Liguori .class_init = ide_cd_class_init,
23939bffca2SAnthony Liguori };
24039bffca2SAnthony Liguori
ide_device_class_init(ObjectClass * klass,const void * data)241*12d1a768SPhilippe Mathieu-Daudé static void ide_device_class_init(ObjectClass *klass, const void *data)
24239bffca2SAnthony Liguori {
24339bffca2SAnthony Liguori DeviceClass *k = DEVICE_CLASS(klass);
244794939e8SMao Zhongyi k->realize = ide_qdev_realize;
245125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
2460d936928SAnthony Liguori k->bus_type = TYPE_IDE_BUS;
2474f67d30bSMarc-André Lureau device_class_set_props(k, ide_props);
24839bffca2SAnthony Liguori }
24939bffca2SAnthony Liguori
2508c43a6f0SAndreas Färber static const TypeInfo ide_device_type_info = {
251d148211cSAnthony Liguori .name = TYPE_IDE_DEVICE,
252d148211cSAnthony Liguori .parent = TYPE_DEVICE,
253d148211cSAnthony Liguori .instance_size = sizeof(IDEDevice),
254d148211cSAnthony Liguori .abstract = true,
255d148211cSAnthony Liguori .class_size = sizeof(IDEDeviceClass),
25639bffca2SAnthony Liguori .class_init = ide_device_class_init,
25745563630SGonglei .instance_init = ide_dev_instance_init,
258da4d0419SGerd Hoffmann };
259da4d0419SGerd Hoffmann
ide_register_types(void)26083f7d43aSAndreas Färber static void ide_register_types(void)
261da4d0419SGerd Hoffmann {
26239bffca2SAnthony Liguori type_register_static(&ide_hd_info);
26339bffca2SAnthony Liguori type_register_static(&ide_cd_info);
264d148211cSAnthony Liguori type_register_static(&ide_device_type_info);
2651f56e32aSMarkus Armbruster }
26683f7d43aSAndreas Färber
26783f7d43aSAndreas Färber type_init(ide_register_types)
268