xref: /openbmc/qemu/hw/ide/ide-dev.c (revision 7d87775f)
1 /*
2  * IDE device functions
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.1 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 
20 #include "qemu/osdep.h"
21 #include "qapi/error.h"
22 #include "qapi/qapi-types-block.h"
23 #include "qemu/error-report.h"
24 #include "qemu/module.h"
25 #include "hw/ide/ide-dev.h"
26 #include "sysemu/block-backend.h"
27 #include "sysemu/blockdev.h"
28 #include "sysemu/sysemu.h"
29 #include "qapi/visitor.h"
30 #include "ide-internal.h"
31 
32 static Property ide_props[] = {
33     DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
34     DEFINE_PROP_BOOL("win2k-install-hack", IDEDevice, win2k_install_hack, false),
35     DEFINE_PROP_END_OF_LIST(),
36 };
37 
38 static void ide_qdev_realize(DeviceState *qdev, Error **errp)
39 {
40     IDEDevice *dev = IDE_DEVICE(qdev);
41     IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
42     IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
43 
44     if (dev->unit == -1) {
45         dev->unit = bus->master ? 1 : 0;
46     }
47 
48     if (dev->unit >= bus->max_units) {
49         error_setg(errp, "Can't create IDE unit %d, bus supports only %d units",
50                      dev->unit, bus->max_units);
51         return;
52     }
53 
54     switch (dev->unit) {
55     case 0:
56         if (bus->master) {
57             error_setg(errp, "IDE unit %d is in use", dev->unit);
58             return;
59         }
60         bus->master = dev;
61         break;
62     case 1:
63         if (bus->slave) {
64             error_setg(errp, "IDE unit %d is in use", dev->unit);
65             return;
66         }
67         bus->slave = dev;
68         break;
69     default:
70         error_setg(errp, "Invalid IDE unit %d", dev->unit);
71         return;
72     }
73     dc->realize(dev, errp);
74 }
75 
76 void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
77 {
78     IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
79     IDEState *s = bus->ifs + dev->unit;
80     int ret;
81 
82     if (!dev->conf.blk) {
83         if (kind != IDE_CD) {
84             error_setg(errp, "No drive specified");
85             return;
86         } else {
87             /* Anonymous BlockBackend for an empty drive */
88             dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
89             ret = blk_attach_dev(dev->conf.blk, &dev->qdev);
90             assert(ret == 0);
91         }
92     }
93 
94     if (dev->conf.discard_granularity == -1) {
95         dev->conf.discard_granularity = 512;
96     } else if (dev->conf.discard_granularity &&
97                dev->conf.discard_granularity != 512) {
98         error_setg(errp, "discard_granularity must be 512 for ide");
99         return;
100     }
101 
102     if (!blkconf_blocksizes(&dev->conf, errp)) {
103         return;
104     }
105 
106     if (dev->conf.logical_block_size != 512) {
107         error_setg(errp, "logical_block_size must be 512 for IDE");
108         return;
109     }
110 
111     if (kind != IDE_CD) {
112         if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
113                               errp)) {
114             return;
115         }
116     }
117     if (!blkconf_apply_backend_options(&dev->conf, kind == IDE_CD,
118                                        kind != IDE_CD, errp)) {
119         return;
120     }
121 
122     if (ide_init_drive(s, dev, kind, errp) < 0) {
123         return;
124     }
125 
126     if (!dev->version) {
127         dev->version = g_strdup(s->version);
128     }
129     if (!dev->serial) {
130         dev->serial = g_strdup(s->drive_serial_str);
131     }
132 
133     add_boot_device_path(dev->conf.bootindex, &dev->qdev,
134                          dev->unit ? "/disk@1" : "/disk@0");
135 
136     add_boot_device_lchs(&dev->qdev, dev->unit ? "/disk@1" : "/disk@0",
137                          dev->conf.lcyls,
138                          dev->conf.lheads,
139                          dev->conf.lsecs);
140 }
141 
142 static void ide_dev_get_bootindex(Object *obj, Visitor *v, const char *name,
143                                   void *opaque, Error **errp)
144 {
145     IDEDevice *d = IDE_DEVICE(obj);
146 
147     visit_type_int32(v, name, &d->conf.bootindex, errp);
148 }
149 
150 static void ide_dev_set_bootindex(Object *obj, Visitor *v, const char *name,
151                                   void *opaque, Error **errp)
152 {
153     IDEDevice *d = IDE_DEVICE(obj);
154     int32_t boot_index;
155     Error *local_err = NULL;
156 
157     if (!visit_type_int32(v, name, &boot_index, errp)) {
158         return;
159     }
160     /* check whether bootindex is present in fw_boot_order list  */
161     check_boot_index(boot_index, &local_err);
162     if (local_err) {
163         goto out;
164     }
165     /* change bootindex to a new one */
166     d->conf.bootindex = boot_index;
167 
168     if (d->unit != -1) {
169         add_boot_device_path(d->conf.bootindex, &d->qdev,
170                              d->unit ? "/disk@1" : "/disk@0");
171     }
172 out:
173     error_propagate(errp, local_err);
174 }
175 
176 static void ide_dev_instance_init(Object *obj)
177 {
178     object_property_add(obj, "bootindex", "int32",
179                         ide_dev_get_bootindex,
180                         ide_dev_set_bootindex, NULL, NULL);
181     object_property_set_int(obj, "bootindex", -1, NULL);
182 }
183 
184 static void ide_hd_realize(IDEDevice *dev, Error **errp)
185 {
186     ide_dev_initfn(dev, IDE_HD, errp);
187 }
188 
189 static void ide_cd_realize(IDEDevice *dev, Error **errp)
190 {
191     ide_dev_initfn(dev, IDE_CD, errp);
192 }
193 
194 static Property ide_hd_properties[] = {
195     DEFINE_IDE_DEV_PROPERTIES(),
196     DEFINE_BLOCK_CHS_PROPERTIES(IDEDrive, dev.conf),
197     DEFINE_PROP_BIOS_CHS_TRANS("bios-chs-trans",
198                 IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO),
199     DEFINE_PROP_UINT16("rotation_rate", IDEDrive, dev.rotation_rate, 0),
200     DEFINE_PROP_END_OF_LIST(),
201 };
202 
203 static void ide_hd_class_init(ObjectClass *klass, void *data)
204 {
205     DeviceClass *dc = DEVICE_CLASS(klass);
206     IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
207 
208     k->realize  = ide_hd_realize;
209     dc->fw_name = "drive";
210     dc->desc    = "virtual IDE disk";
211     device_class_set_props(dc, ide_hd_properties);
212 }
213 
214 static const TypeInfo ide_hd_info = {
215     .name          = "ide-hd",
216     .parent        = TYPE_IDE_DEVICE,
217     .instance_size = sizeof(IDEDrive),
218     .class_init    = ide_hd_class_init,
219 };
220 
221 static Property ide_cd_properties[] = {
222     DEFINE_IDE_DEV_PROPERTIES(),
223     DEFINE_PROP_END_OF_LIST(),
224 };
225 
226 static void ide_cd_class_init(ObjectClass *klass, void *data)
227 {
228     DeviceClass *dc = DEVICE_CLASS(klass);
229     IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
230 
231     k->realize  = ide_cd_realize;
232     dc->fw_name = "drive";
233     dc->desc    = "virtual IDE CD-ROM";
234     device_class_set_props(dc, ide_cd_properties);
235 }
236 
237 static const TypeInfo ide_cd_info = {
238     .name          = "ide-cd",
239     .parent        = TYPE_IDE_DEVICE,
240     .instance_size = sizeof(IDEDrive),
241     .class_init    = ide_cd_class_init,
242 };
243 
244 static void ide_device_class_init(ObjectClass *klass, void *data)
245 {
246     DeviceClass *k = DEVICE_CLASS(klass);
247     k->realize = ide_qdev_realize;
248     set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
249     k->bus_type = TYPE_IDE_BUS;
250     device_class_set_props(k, ide_props);
251 }
252 
253 static const TypeInfo ide_device_type_info = {
254     .name = TYPE_IDE_DEVICE,
255     .parent = TYPE_DEVICE,
256     .instance_size = sizeof(IDEDevice),
257     .abstract = true,
258     .class_size = sizeof(IDEDeviceClass),
259     .class_init = ide_device_class_init,
260     .instance_init = ide_dev_instance_init,
261 };
262 
263 static 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_device_type_info);
268 }
269 
270 type_init(ide_register_types)
271