xref: /qemu/hw/ide/ide-dev.c (revision 7bd8b0d4f5e8abfd9bdca40555d92db27918777b)
1da4d0419SGerd Hoffmann /*
2*7bd8b0d4SThomas 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"
26fa1d36dfSMarkus Armbruster #include "sysemu/block-backend.h"
279c17d615SPaolo Bonzini #include "sysemu/blockdev.h"
289c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
2945563630SGonglei #include "qapi/visitor.h"
30da4d0419SGerd Hoffmann 
313cb75a7cSPaolo Bonzini static Property ide_props[] = {
323cb75a7cSPaolo Bonzini     DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
333cb75a7cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
343cb75a7cSPaolo Bonzini };
353cb75a7cSPaolo Bonzini 
36794939e8SMao Zhongyi static void ide_qdev_realize(DeviceState *qdev, Error **errp)
37da4d0419SGerd Hoffmann {
38d148211cSAnthony Liguori     IDEDevice *dev = IDE_DEVICE(qdev);
39d148211cSAnthony Liguori     IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
40da4d0419SGerd Hoffmann     IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
41da4d0419SGerd Hoffmann 
42da4d0419SGerd Hoffmann     if (dev->unit == -1) {
43da4d0419SGerd Hoffmann         dev->unit = bus->master ? 1 : 0;
44da4d0419SGerd Hoffmann     }
450ee20e66SKevin Wolf 
460ee20e66SKevin Wolf     if (dev->unit >= bus->max_units) {
47794939e8SMao Zhongyi         error_setg(errp, "Can't create IDE unit %d, bus supports only %d units",
480ee20e66SKevin Wolf                      dev->unit, bus->max_units);
49794939e8SMao Zhongyi         return;
500ee20e66SKevin Wolf     }
510ee20e66SKevin Wolf 
52da4d0419SGerd Hoffmann     switch (dev->unit) {
53da4d0419SGerd Hoffmann     case 0:
54da4d0419SGerd Hoffmann         if (bus->master) {
55794939e8SMao Zhongyi             error_setg(errp, "IDE unit %d is in use", dev->unit);
56794939e8SMao Zhongyi             return;
57da4d0419SGerd Hoffmann         }
58da4d0419SGerd Hoffmann         bus->master = dev;
59da4d0419SGerd Hoffmann         break;
60da4d0419SGerd Hoffmann     case 1:
61da4d0419SGerd Hoffmann         if (bus->slave) {
62794939e8SMao Zhongyi             error_setg(errp, "IDE unit %d is in use", dev->unit);
63794939e8SMao Zhongyi             return;
64da4d0419SGerd Hoffmann         }
65da4d0419SGerd Hoffmann         bus->slave = dev;
66da4d0419SGerd Hoffmann         break;
67da4d0419SGerd Hoffmann     default:
68794939e8SMao Zhongyi         error_setg(errp, "Invalid IDE unit %d", dev->unit);
69794939e8SMao Zhongyi         return;
70da4d0419SGerd Hoffmann     }
71794939e8SMao Zhongyi     dc->realize(dev, errp);
72da4d0419SGerd Hoffmann }
73da4d0419SGerd Hoffmann 
74bd217d88SThomas Huth void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
75da4d0419SGerd Hoffmann {
76da4d0419SGerd Hoffmann     IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
776ced55a5SMarkus Armbruster     IDEState *s = bus->ifs + dev->unit;
78947231adSKevin Wolf     int ret;
796ced55a5SMarkus Armbruster 
8067c75f3dSKevin Wolf     if (!dev->conf.blk) {
8167c75f3dSKevin Wolf         if (kind != IDE_CD) {
82794939e8SMao Zhongyi             error_setg(errp, "No drive specified");
83794939e8SMao Zhongyi             return;
8467c75f3dSKevin Wolf         } else {
8567c75f3dSKevin Wolf             /* Anonymous BlockBackend for an empty drive */
86d861ab3aSKevin Wolf             dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
87947231adSKevin Wolf             ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
88947231adSKevin Wolf             assert(ret == 0);
8967c75f3dSKevin Wolf         }
9067c75f3dSKevin Wolf     }
9167c75f3dSKevin Wolf 
92215e47b9SPaolo Bonzini     if (dev->conf.discard_granularity == -1) {
93215e47b9SPaolo Bonzini         dev->conf.discard_granularity = 512;
94215e47b9SPaolo Bonzini     } else if (dev->conf.discard_granularity &&
95215e47b9SPaolo Bonzini                dev->conf.discard_granularity != 512) {
96794939e8SMao Zhongyi         error_setg(errp, "discard_granularity must be 512 for ide");
97794939e8SMao Zhongyi         return;
98d353fb72SChristoph Hellwig     }
99d353fb72SChristoph Hellwig 
100c56ee92fSRoman Kagan     if (!blkconf_blocksizes(&dev->conf, errp)) {
101c56ee92fSRoman Kagan         return;
102c56ee92fSRoman Kagan     }
103c56ee92fSRoman Kagan 
104d2005185SKevin Wolf     if (dev->conf.logical_block_size != 512) {
105794939e8SMao Zhongyi         error_setg(errp, "logical_block_size must be 512 for IDE");
106794939e8SMao Zhongyi         return;
107d2005185SKevin Wolf     }
108d2005185SKevin Wolf 
1095ff5efb4SFam Zheng     if (kind != IDE_CD) {
110ceff3e1fSMao Zhongyi         if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
111ceff3e1fSMao Zhongyi                               errp)) {
112794939e8SMao Zhongyi             return;
113ba801960SMarkus Armbruster         }
1145ff5efb4SFam Zheng     }
115ceff3e1fSMao Zhongyi     if (!blkconf_apply_backend_options(&dev->conf, kind == IDE_CD,
116ceff3e1fSMao Zhongyi                                        kind != IDE_CD, errp)) {
117794939e8SMao Zhongyi         return;
118a17c17a2SKevin Wolf     }
119ba801960SMarkus Armbruster 
1204be74634SMarkus Armbruster     if (ide_init_drive(s, dev->conf.blk, kind,
121911525dbSMarkus Armbruster                        dev->version, dev->serial, dev->model, dev->wwn,
122ba801960SMarkus Armbruster                        dev->conf.cyls, dev->conf.heads, dev->conf.secs,
123794939e8SMao Zhongyi                        dev->chs_trans, errp) < 0) {
124794939e8SMao Zhongyi         return;
125c4d74df7SMarkus Armbruster     }
1266ced55a5SMarkus Armbruster 
12703432407SMarkus Armbruster     if (!dev->version) {
1287267c094SAnthony Liguori         dev->version = g_strdup(s->version);
12903432407SMarkus Armbruster     }
1306ced55a5SMarkus Armbruster     if (!dev->serial) {
1317267c094SAnthony Liguori         dev->serial = g_strdup(s->drive_serial_str);
1326ced55a5SMarkus Armbruster     }
1331ca4d09aSGleb Natapov 
1341ca4d09aSGleb Natapov     add_boot_device_path(dev->conf.bootindex, &dev->qdev,
1351ca4d09aSGleb Natapov                          dev->unit ? "/disk@1" : "/disk@0");
13671f571a2SSam Eiderman 
13771f571a2SSam Eiderman     add_boot_device_lchs(&dev->qdev, dev->unit ? "/disk@1" : "/disk@0",
13871f571a2SSam Eiderman                          dev->conf.lcyls,
13971f571a2SSam Eiderman                          dev->conf.lheads,
14071f571a2SSam Eiderman                          dev->conf.lsecs);
141da4d0419SGerd Hoffmann }
142da4d0419SGerd Hoffmann 
143d7bce999SEric Blake static void ide_dev_get_bootindex(Object *obj, Visitor *v, const char *name,
144d7bce999SEric Blake                                   void *opaque, Error **errp)
14545563630SGonglei {
14645563630SGonglei     IDEDevice *d = IDE_DEVICE(obj);
14745563630SGonglei 
14851e72bc1SEric Blake     visit_type_int32(v, name, &d->conf.bootindex, errp);
14945563630SGonglei }
15045563630SGonglei 
151d7bce999SEric Blake static void ide_dev_set_bootindex(Object *obj, Visitor *v, const char *name,
152d7bce999SEric Blake                                   void *opaque, Error **errp)
15345563630SGonglei {
15445563630SGonglei     IDEDevice *d = IDE_DEVICE(obj);
15545563630SGonglei     int32_t boot_index;
15645563630SGonglei     Error *local_err = NULL;
15745563630SGonglei 
15814217038SMarkus Armbruster     if (!visit_type_int32(v, name, &boot_index, errp)) {
15914217038SMarkus Armbruster         return;
16045563630SGonglei     }
16145563630SGonglei     /* check whether bootindex is present in fw_boot_order list  */
16245563630SGonglei     check_boot_index(boot_index, &local_err);
16345563630SGonglei     if (local_err) {
16445563630SGonglei         goto out;
16545563630SGonglei     }
16645563630SGonglei     /* change bootindex to a new one */
16745563630SGonglei     d->conf.bootindex = boot_index;
16845563630SGonglei 
169d2b186f9SGonglei     if (d->unit != -1) {
170d2b186f9SGonglei         add_boot_device_path(d->conf.bootindex, &d->qdev,
171d2b186f9SGonglei                              d->unit ? "/disk@1" : "/disk@0");
172d2b186f9SGonglei     }
17345563630SGonglei out:
17445563630SGonglei     error_propagate(errp, local_err);
17545563630SGonglei }
17645563630SGonglei 
17745563630SGonglei static void ide_dev_instance_init(Object *obj)
17845563630SGonglei {
17945563630SGonglei     object_property_add(obj, "bootindex", "int32",
18045563630SGonglei                         ide_dev_get_bootindex,
181d2623129SMarkus Armbruster                         ide_dev_set_bootindex, NULL, NULL);
1825325cc34SMarkus Armbruster     object_property_set_int(obj, "bootindex", -1, NULL);
18345563630SGonglei }
18445563630SGonglei 
185794939e8SMao Zhongyi static void ide_hd_realize(IDEDevice *dev, Error **errp)
1861f56e32aSMarkus Armbruster {
187794939e8SMao Zhongyi     ide_dev_initfn(dev, IDE_HD, errp);
1881f56e32aSMarkus Armbruster }
1891f56e32aSMarkus Armbruster 
190794939e8SMao Zhongyi static void ide_cd_realize(IDEDevice *dev, Error **errp)
1911f56e32aSMarkus Armbruster {
192794939e8SMao Zhongyi     ide_dev_initfn(dev, IDE_CD, errp);
1931f56e32aSMarkus Armbruster }
1941f56e32aSMarkus Armbruster 
19539bffca2SAnthony Liguori static Property ide_hd_properties[] = {
1961f56e32aSMarkus Armbruster     DEFINE_IDE_DEV_PROPERTIES(),
197ba801960SMarkus Armbruster     DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
1986e6f61a6SMarkus Armbruster     DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
1996e6f61a6SMarkus Armbruster                 IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
2003b19f450SDaniel P. Berrange     DEFINE_PROP_UINT16("rotation_rate", IDEDrive, dev.rotation_rate, 0),
2011f56e32aSMarkus Armbruster     DEFINE_PROP_END_OF_LIST(),
20239bffca2SAnthony Liguori };
20339bffca2SAnthony Liguori 
20439bffca2SAnthony Liguori static void ide_hd_class_init(ObjectClass *klass, void *data)
20539bffca2SAnthony Liguori {
20639bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
20739bffca2SAnthony Liguori     IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
208794939e8SMao Zhongyi 
209794939e8SMao Zhongyi     k->realize  = ide_hd_realize;
21039bffca2SAnthony Liguori     dc->fw_name = "drive";
21139bffca2SAnthony Liguori     dc->desc    = "virtual IDE disk";
2124f67d30bSMarc-André Lureau     device_class_set_props(dc, ide_hd_properties);
2131f56e32aSMarkus Armbruster }
21439bffca2SAnthony Liguori 
2158c43a6f0SAndreas Färber static const TypeInfo ide_hd_info = {
21639bffca2SAnthony Liguori     .name          = "ide-hd",
21739bffca2SAnthony Liguori     .parent        = TYPE_IDE_DEVICE,
21839bffca2SAnthony Liguori     .instance_size = sizeof(IDEDrive),
21939bffca2SAnthony Liguori     .class_init    = ide_hd_class_init,
22039bffca2SAnthony Liguori };
22139bffca2SAnthony Liguori 
22239bffca2SAnthony Liguori static Property ide_cd_properties[] = {
22339bffca2SAnthony Liguori     DEFINE_IDE_DEV_PROPERTIES(),
22439bffca2SAnthony Liguori     DEFINE_PROP_END_OF_LIST(),
225d148211cSAnthony Liguori };
226d148211cSAnthony Liguori 
227d148211cSAnthony Liguori static void ide_cd_class_init(ObjectClass *klass, void *data)
228d148211cSAnthony Liguori {
22939bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
230d148211cSAnthony Liguori     IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
231794939e8SMao Zhongyi 
232794939e8SMao Zhongyi     k->realize  = ide_cd_realize;
23339bffca2SAnthony Liguori     dc->fw_name = "drive";
23439bffca2SAnthony Liguori     dc->desc    = "virtual IDE CD-ROM";
2354f67d30bSMarc-André Lureau     device_class_set_props(dc, ide_cd_properties);
236d148211cSAnthony Liguori }
237d148211cSAnthony Liguori 
2388c43a6f0SAndreas Färber static const TypeInfo ide_cd_info = {
239d148211cSAnthony Liguori     .name          = "ide-cd",
24039bffca2SAnthony Liguori     .parent        = TYPE_IDE_DEVICE,
24139bffca2SAnthony Liguori     .instance_size = sizeof(IDEDrive),
242d148211cSAnthony Liguori     .class_init    = ide_cd_class_init,
24339bffca2SAnthony Liguori };
24439bffca2SAnthony Liguori 
24539bffca2SAnthony Liguori static void ide_device_class_init(ObjectClass *klass, void *data)
24639bffca2SAnthony Liguori {
24739bffca2SAnthony Liguori     DeviceClass *k = DEVICE_CLASS(klass);
248794939e8SMao Zhongyi     k->realize = ide_qdev_realize;
249125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
2500d936928SAnthony Liguori     k->bus_type = TYPE_IDE_BUS;
2514f67d30bSMarc-André Lureau     device_class_set_props(k, ide_props);
25239bffca2SAnthony Liguori }
25339bffca2SAnthony Liguori 
2548c43a6f0SAndreas Färber static const TypeInfo ide_device_type_info = {
255d148211cSAnthony Liguori     .name = TYPE_IDE_DEVICE,
256d148211cSAnthony Liguori     .parent = TYPE_DEVICE,
257d148211cSAnthony Liguori     .instance_size = sizeof(IDEDevice),
258d148211cSAnthony Liguori     .abstract = true,
259d148211cSAnthony Liguori     .class_size = sizeof(IDEDeviceClass),
26039bffca2SAnthony Liguori     .class_init = ide_device_class_init,
26145563630SGonglei     .instance_init = ide_dev_instance_init,
262da4d0419SGerd Hoffmann };
263da4d0419SGerd Hoffmann 
26483f7d43aSAndreas Färber static void ide_register_types(void)
265da4d0419SGerd Hoffmann {
26639bffca2SAnthony Liguori     type_register_static(&ide_hd_info);
26739bffca2SAnthony Liguori     type_register_static(&ide_cd_info);
268d148211cSAnthony Liguori     type_register_static(&ide_device_type_info);
2691f56e32aSMarkus Armbruster }
27083f7d43aSAndreas Färber 
27183f7d43aSAndreas Färber type_init(ide_register_types)
272