xref: /qemu/hw/usb/dev-storage.c (revision bbd8323d3196c9979385cba1b8b38859836e63c3)
1 /*
2  * USB Mass Storage Device emulation
3  *
4  * Copyright (c) 2006 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licensed under the LGPL.
8  */
9 
10 #include "qemu/osdep.h"
11 #include "qapi/error.h"
12 #include "qemu/error-report.h"
13 #include "qemu/module.h"
14 #include "qemu/option.h"
15 #include "qemu/config-file.h"
16 #include "hw/usb.h"
17 #include "hw/usb/msd.h"
18 #include "desc.h"
19 #include "hw/qdev-properties.h"
20 #include "hw/scsi/scsi.h"
21 #include "migration/vmstate.h"
22 #include "sysemu/sysemu.h"
23 #include "sysemu/block-backend.h"
24 #include "qapi/visitor.h"
25 #include "qemu/cutils.h"
26 #include "qom/object.h"
27 #include "trace.h"
28 
29 /* USB requests.  */
30 #define MassStorageReset  0xff
31 #define GetMaxLun         0xfe
32 
33 struct usb_msd_cbw {
34     uint32_t sig;
35     uint32_t tag;
36     uint32_t data_len;
37     uint8_t flags;
38     uint8_t lun;
39     uint8_t cmd_len;
40     uint8_t cmd[16];
41 };
42 
43 enum {
44     STR_MANUFACTURER = 1,
45     STR_PRODUCT,
46     STR_SERIALNUMBER,
47     STR_CONFIG_FULL,
48     STR_CONFIG_HIGH,
49     STR_CONFIG_SUPER,
50 };
51 
52 static const USBDescStrings desc_strings = {
53     [STR_MANUFACTURER] = "QEMU",
54     [STR_PRODUCT]      = "QEMU USB HARDDRIVE",
55     [STR_SERIALNUMBER] = "1",
56     [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
57     [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
58     [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
59 };
60 
61 static const USBDescIface desc_iface_full = {
62     .bInterfaceNumber              = 0,
63     .bNumEndpoints                 = 2,
64     .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
65     .bInterfaceSubClass            = 0x06, /* SCSI */
66     .bInterfaceProtocol            = 0x50, /* Bulk */
67     .eps = (USBDescEndpoint[]) {
68         {
69             .bEndpointAddress      = USB_DIR_IN | 0x01,
70             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
71             .wMaxPacketSize        = 64,
72         },{
73             .bEndpointAddress      = USB_DIR_OUT | 0x02,
74             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
75             .wMaxPacketSize        = 64,
76         },
77     }
78 };
79 
80 static const USBDescDevice desc_device_full = {
81     .bcdUSB                        = 0x0200,
82     .bMaxPacketSize0               = 8,
83     .bNumConfigurations            = 1,
84     .confs = (USBDescConfig[]) {
85         {
86             .bNumInterfaces        = 1,
87             .bConfigurationValue   = 1,
88             .iConfiguration        = STR_CONFIG_FULL,
89             .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
90             .nif = 1,
91             .ifs = &desc_iface_full,
92         },
93     },
94 };
95 
96 static const USBDescIface desc_iface_high = {
97     .bInterfaceNumber              = 0,
98     .bNumEndpoints                 = 2,
99     .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
100     .bInterfaceSubClass            = 0x06, /* SCSI */
101     .bInterfaceProtocol            = 0x50, /* Bulk */
102     .eps = (USBDescEndpoint[]) {
103         {
104             .bEndpointAddress      = USB_DIR_IN | 0x01,
105             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
106             .wMaxPacketSize        = 512,
107         },{
108             .bEndpointAddress      = USB_DIR_OUT | 0x02,
109             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
110             .wMaxPacketSize        = 512,
111         },
112     }
113 };
114 
115 static const USBDescDevice desc_device_high = {
116     .bcdUSB                        = 0x0200,
117     .bMaxPacketSize0               = 64,
118     .bNumConfigurations            = 1,
119     .confs = (USBDescConfig[]) {
120         {
121             .bNumInterfaces        = 1,
122             .bConfigurationValue   = 1,
123             .iConfiguration        = STR_CONFIG_HIGH,
124             .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
125             .nif = 1,
126             .ifs = &desc_iface_high,
127         },
128     },
129 };
130 
131 static const USBDescIface desc_iface_super = {
132     .bInterfaceNumber              = 0,
133     .bNumEndpoints                 = 2,
134     .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
135     .bInterfaceSubClass            = 0x06, /* SCSI */
136     .bInterfaceProtocol            = 0x50, /* Bulk */
137     .eps = (USBDescEndpoint[]) {
138         {
139             .bEndpointAddress      = USB_DIR_IN | 0x01,
140             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
141             .wMaxPacketSize        = 1024,
142             .bMaxBurst             = 15,
143         },{
144             .bEndpointAddress      = USB_DIR_OUT | 0x02,
145             .bmAttributes          = USB_ENDPOINT_XFER_BULK,
146             .wMaxPacketSize        = 1024,
147             .bMaxBurst             = 15,
148         },
149     }
150 };
151 
152 static const USBDescDevice desc_device_super = {
153     .bcdUSB                        = 0x0300,
154     .bMaxPacketSize0               = 9,
155     .bNumConfigurations            = 1,
156     .confs = (USBDescConfig[]) {
157         {
158             .bNumInterfaces        = 1,
159             .bConfigurationValue   = 1,
160             .iConfiguration        = STR_CONFIG_SUPER,
161             .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
162             .nif = 1,
163             .ifs = &desc_iface_super,
164         },
165     },
166 };
167 
168 static const USBDesc desc = {
169     .id = {
170         .idVendor          = 0x46f4, /* CRC16() of "QEMU" */
171         .idProduct         = 0x0001,
172         .bcdDevice         = 0,
173         .iManufacturer     = STR_MANUFACTURER,
174         .iProduct          = STR_PRODUCT,
175         .iSerialNumber     = STR_SERIALNUMBER,
176     },
177     .full  = &desc_device_full,
178     .high  = &desc_device_high,
179     .super = &desc_device_super,
180     .str   = desc_strings,
181 };
182 
183 static void usb_msd_copy_data(MSDState *s, USBPacket *p)
184 {
185     uint32_t len;
186     len = p->iov.size - p->actual_length;
187     if (len > s->scsi_len)
188         len = s->scsi_len;
189     usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
190     s->scsi_len -= len;
191     s->scsi_off += len;
192     if (len > s->data_len) {
193         len = s->data_len;
194     }
195     s->data_len -= len;
196     if (s->scsi_len == 0 || s->data_len == 0) {
197         scsi_req_continue(s->req);
198     }
199 }
200 
201 static void usb_msd_send_status(MSDState *s, USBPacket *p)
202 {
203     int len;
204 
205     trace_usb_msd_send_status(s->csw.status, le32_to_cpu(s->csw.tag),
206                               p->iov.size);
207 
208     assert(s->csw.sig == cpu_to_le32(0x53425355));
209     len = MIN(sizeof(s->csw), p->iov.size);
210     usb_packet_copy(p, &s->csw, len);
211     memset(&s->csw, 0, sizeof(s->csw));
212 }
213 
214 static void usb_msd_packet_complete(MSDState *s)
215 {
216     USBPacket *p = s->packet;
217 
218     /* Set s->packet to NULL before calling usb_packet_complete
219        because another request may be issued before
220        usb_packet_complete returns.  */
221     trace_usb_msd_packet_complete();
222     s->packet = NULL;
223     usb_packet_complete(&s->dev, p);
224 }
225 
226 void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
227 {
228     MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
229     USBPacket *p = s->packet;
230 
231     assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
232     s->scsi_len = len;
233     s->scsi_off = 0;
234     if (p) {
235         usb_msd_copy_data(s, p);
236         p = s->packet;
237         if (p && p->actual_length == p->iov.size) {
238             p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
239             usb_msd_packet_complete(s);
240         }
241     }
242 }
243 
244 void usb_msd_command_complete(SCSIRequest *req, size_t resid)
245 {
246     MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
247     USBPacket *p = s->packet;
248 
249     trace_usb_msd_cmd_complete(req->status, req->tag);
250 
251     s->csw.sig = cpu_to_le32(0x53425355);
252     s->csw.tag = cpu_to_le32(req->tag);
253     s->csw.residue = cpu_to_le32(s->data_len);
254     s->csw.status = req->status != 0;
255 
256     if (s->packet) {
257         if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
258             /* A deferred packet with no write data remaining must be
259                the status read packet.  */
260             usb_msd_send_status(s, p);
261             s->mode = USB_MSDM_CBW;
262         } else if (s->mode == USB_MSDM_CSW) {
263             usb_msd_send_status(s, p);
264             s->mode = USB_MSDM_CBW;
265         } else {
266             if (s->data_len) {
267                 int len = (p->iov.size - p->actual_length);
268                 usb_packet_skip(p, len);
269                 if (len > s->data_len) {
270                     len = s->data_len;
271                 }
272                 s->data_len -= len;
273             }
274             if (s->data_len == 0) {
275                 s->mode = USB_MSDM_CSW;
276             }
277         }
278         p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
279         usb_msd_packet_complete(s);
280     } else if (s->data_len == 0) {
281         s->mode = USB_MSDM_CSW;
282     }
283     scsi_req_unref(req);
284     s->req = NULL;
285 }
286 
287 void usb_msd_request_cancelled(SCSIRequest *req)
288 {
289     MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
290 
291     trace_usb_msd_cmd_cancel(req->tag);
292 
293     if (req == s->req) {
294         s->csw.sig = cpu_to_le32(0x53425355);
295         s->csw.tag = cpu_to_le32(req->tag);
296         s->csw.status = 1; /* error */
297 
298         scsi_req_unref(s->req);
299         s->req = NULL;
300         s->scsi_len = 0;
301     }
302 }
303 
304 void usb_msd_handle_reset(USBDevice *dev)
305 {
306     MSDState *s = (MSDState *)dev;
307 
308     trace_usb_msd_reset();
309     if (s->req) {
310         scsi_req_cancel(s->req);
311     }
312     assert(s->req == NULL);
313 
314     if (s->packet) {
315         s->packet->status = USB_RET_STALL;
316         usb_msd_packet_complete(s);
317     }
318 
319     s->mode = USB_MSDM_CBW;
320 }
321 
322 static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
323                int request, int value, int index, int length, uint8_t *data)
324 {
325     MSDState *s = (MSDState *)dev;
326     SCSIDevice *scsi_dev;
327     int ret, maxlun;
328 
329     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
330     if (ret >= 0) {
331         return;
332     }
333 
334     switch (request) {
335     case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
336         break;
337         /* Class specific requests.  */
338     case ClassInterfaceOutRequest | MassStorageReset:
339         /* Reset state ready for the next CBW.  */
340         s->mode = USB_MSDM_CBW;
341         break;
342     case ClassInterfaceRequest | GetMaxLun:
343         maxlun = 0;
344         for (;;) {
345             scsi_dev = scsi_device_find(&s->bus, 0, 0, maxlun+1);
346             if (scsi_dev == NULL) {
347                 break;
348             }
349             if (scsi_dev->lun != maxlun+1) {
350                 break;
351             }
352             maxlun++;
353         }
354         trace_usb_msd_maxlun(maxlun);
355         data[0] = maxlun;
356         p->actual_length = 1;
357         break;
358     default:
359         p->status = USB_RET_STALL;
360         break;
361     }
362 }
363 
364 static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
365 {
366     MSDState *s = USB_STORAGE_DEV(dev);
367 
368     assert(s->packet == p);
369     s->packet = NULL;
370 
371     if (s->req) {
372         scsi_req_cancel(s->req);
373     }
374 }
375 
376 static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
377 {
378     MSDState *s = (MSDState *)dev;
379     uint32_t tag;
380     struct usb_msd_cbw cbw;
381     uint8_t devep = p->ep->nr;
382     SCSIDevice *scsi_dev;
383     uint32_t len;
384 
385     switch (p->pid) {
386     case USB_TOKEN_OUT:
387         if (devep != 2)
388             goto fail;
389 
390         switch (s->mode) {
391         case USB_MSDM_CBW:
392             if (p->iov.size != 31) {
393                 error_report("usb-msd: Bad CBW size");
394                 goto fail;
395             }
396             usb_packet_copy(p, &cbw, 31);
397             if (le32_to_cpu(cbw.sig) != 0x43425355) {
398                 error_report("usb-msd: Bad signature %08x",
399                              le32_to_cpu(cbw.sig));
400                 goto fail;
401             }
402             scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun);
403             if (scsi_dev == NULL) {
404                 error_report("usb-msd: Bad LUN %d", cbw.lun);
405                 goto fail;
406             }
407             tag = le32_to_cpu(cbw.tag);
408             s->data_len = le32_to_cpu(cbw.data_len);
409             if (s->data_len == 0) {
410                 s->mode = USB_MSDM_CSW;
411             } else if (cbw.flags & 0x80) {
412                 s->mode = USB_MSDM_DATAIN;
413             } else {
414                 s->mode = USB_MSDM_DATAOUT;
415             }
416             trace_usb_msd_cmd_submit(cbw.lun, tag, cbw.flags,
417                                      cbw.cmd_len, s->data_len);
418             assert(le32_to_cpu(s->csw.residue) == 0);
419             s->scsi_len = 0;
420             s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL);
421             if (s->commandlog) {
422                 scsi_req_print(s->req);
423             }
424             len = scsi_req_enqueue(s->req);
425             if (len) {
426                 scsi_req_continue(s->req);
427             }
428             break;
429 
430         case USB_MSDM_DATAOUT:
431             trace_usb_msd_data_out(p->iov.size, s->data_len);
432             if (p->iov.size > s->data_len) {
433                 goto fail;
434             }
435 
436             if (s->scsi_len) {
437                 usb_msd_copy_data(s, p);
438             }
439             if (le32_to_cpu(s->csw.residue)) {
440                 int len = p->iov.size - p->actual_length;
441                 if (len) {
442                     usb_packet_skip(p, len);
443                     if (len > s->data_len) {
444                         len = s->data_len;
445                     }
446                     s->data_len -= len;
447                     if (s->data_len == 0) {
448                         s->mode = USB_MSDM_CSW;
449                     }
450                 }
451             }
452             if (p->actual_length < p->iov.size) {
453                 trace_usb_msd_packet_async();
454                 s->packet = p;
455                 p->status = USB_RET_ASYNC;
456             }
457             break;
458 
459         default:
460             goto fail;
461         }
462         break;
463 
464     case USB_TOKEN_IN:
465         if (devep != 1)
466             goto fail;
467 
468         switch (s->mode) {
469         case USB_MSDM_DATAOUT:
470             if (s->data_len != 0 || p->iov.size < 13) {
471                 goto fail;
472             }
473             /* Waiting for SCSI write to complete.  */
474             trace_usb_msd_packet_async();
475             s->packet = p;
476             p->status = USB_RET_ASYNC;
477             break;
478 
479         case USB_MSDM_CSW:
480             if (p->iov.size < 13) {
481                 goto fail;
482             }
483 
484             if (s->req) {
485                 /* still in flight */
486                 trace_usb_msd_packet_async();
487                 s->packet = p;
488                 p->status = USB_RET_ASYNC;
489             } else {
490                 usb_msd_send_status(s, p);
491                 s->mode = USB_MSDM_CBW;
492             }
493             break;
494 
495         case USB_MSDM_DATAIN:
496             trace_usb_msd_data_in(p->iov.size, s->data_len, s->scsi_len);
497             if (s->scsi_len) {
498                 usb_msd_copy_data(s, p);
499             }
500             if (le32_to_cpu(s->csw.residue)) {
501                 int len = p->iov.size - p->actual_length;
502                 if (len) {
503                     usb_packet_skip(p, len);
504                     if (len > s->data_len) {
505                         len = s->data_len;
506                     }
507                     s->data_len -= len;
508                     if (s->data_len == 0) {
509                         s->mode = USB_MSDM_CSW;
510                     }
511                 }
512             }
513             if (p->actual_length < p->iov.size && s->mode == USB_MSDM_DATAIN) {
514                 trace_usb_msd_packet_async();
515                 s->packet = p;
516                 p->status = USB_RET_ASYNC;
517             }
518             break;
519 
520         default:
521             goto fail;
522         }
523         break;
524 
525     default:
526     fail:
527         p->status = USB_RET_STALL;
528         break;
529     }
530 }
531 
532 void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
533 {
534     MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
535 
536     /* nothing to load, just store req in our state struct */
537     assert(s->req == NULL);
538     scsi_req_ref(req);
539     s->req = req;
540     return NULL;
541 }
542 
543 static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
544     .tcq = false,
545     .max_target = 0,
546     .max_lun = 0,
547 
548     .transfer_data = usb_msd_transfer_data,
549     .complete = usb_msd_command_complete,
550     .cancel = usb_msd_request_cancelled,
551     .load_request = usb_msd_load_request,
552 };
553 
554 static const struct SCSIBusInfo usb_msd_scsi_info_bot = {
555     .tcq = false,
556     .max_target = 0,
557     .max_lun = 15,
558 
559     .transfer_data = usb_msd_transfer_data,
560     .complete = usb_msd_command_complete,
561     .cancel = usb_msd_request_cancelled,
562     .load_request = usb_msd_load_request,
563 };
564 
565 static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
566 {
567     MSDState *s = USB_STORAGE_DEV(dev);
568     BlockBackend *blk = s->conf.blk;
569     SCSIDevice *scsi_dev;
570 
571     if (!blk) {
572         error_setg(errp, "drive property not set");
573         return;
574     }
575 
576     if (!blkconf_blocksizes(&s->conf, errp)) {
577         return;
578     }
579 
580     if (!blkconf_apply_backend_options(&s->conf, !blk_supports_write_perm(blk),
581                                        true, errp)) {
582         return;
583     }
584 
585     /*
586      * Hack alert: this pretends to be a block device, but it's really
587      * a SCSI bus that can serve only a single device, which it
588      * creates automatically.  But first it needs to detach from its
589      * blockdev, or else scsi_bus_legacy_add_drive() dies when it
590      * attaches again. We also need to take another reference so that
591      * blk_detach_dev() doesn't free blk while we still need it.
592      *
593      * The hack is probably a bad idea.
594      */
595     blk_ref(blk);
596     blk_detach_dev(blk, DEVICE(s));
597     s->conf.blk = NULL;
598 
599     usb_desc_create_serial(dev);
600     usb_desc_init(dev);
601     scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
602                  &usb_msd_scsi_info_storage, NULL);
603     scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
604                                          s->conf.bootindex, s->conf.share_rw,
605                                          s->conf.rerror, s->conf.werror,
606                                          dev->serial,
607                                          errp);
608     blk_unref(blk);
609     if (!scsi_dev) {
610         return;
611     }
612     usb_msd_handle_reset(dev);
613     s->scsi_dev = scsi_dev;
614 }
615 
616 static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
617 {
618     MSDState *s = USB_STORAGE_DEV(dev);
619     DeviceState *d = DEVICE(dev);
620 
621     usb_desc_create_serial(dev);
622     usb_desc_init(dev);
623     if (d->hotplugged) {
624         s->dev.auto_attach = 0;
625     }
626 
627     scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
628                  &usb_msd_scsi_info_bot, NULL);
629     usb_msd_handle_reset(dev);
630 }
631 
632 static const VMStateDescription vmstate_usb_msd = {
633     .name = "usb-storage",
634     .version_id = 1,
635     .minimum_version_id = 1,
636     .fields = (VMStateField[]) {
637         VMSTATE_USB_DEVICE(dev, MSDState),
638         VMSTATE_UINT32(mode, MSDState),
639         VMSTATE_UINT32(scsi_len, MSDState),
640         VMSTATE_UINT32(scsi_off, MSDState),
641         VMSTATE_UINT32(data_len, MSDState),
642         VMSTATE_UINT32(csw.sig, MSDState),
643         VMSTATE_UINT32(csw.tag, MSDState),
644         VMSTATE_UINT32(csw.residue, MSDState),
645         VMSTATE_UINT8(csw.status, MSDState),
646         VMSTATE_END_OF_LIST()
647     }
648 };
649 
650 static Property msd_properties[] = {
651     DEFINE_BLOCK_PROPERTIES(MSDState, conf),
652     DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf),
653     DEFINE_PROP_BOOL("removable", MSDState, removable, false),
654     DEFINE_PROP_BOOL("commandlog", MSDState, commandlog, false),
655     DEFINE_PROP_END_OF_LIST(),
656 };
657 
658 static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
659 {
660     DeviceClass *dc = DEVICE_CLASS(klass);
661     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
662 
663     uc->product_desc   = "QEMU USB MSD";
664     uc->usb_desc       = &desc;
665     uc->cancel_packet  = usb_msd_cancel_io;
666     uc->handle_attach  = usb_desc_attach;
667     uc->handle_reset   = usb_msd_handle_reset;
668     uc->handle_control = usb_msd_handle_control;
669     uc->handle_data    = usb_msd_handle_data;
670     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
671     dc->fw_name = "storage";
672     dc->vmsd = &vmstate_usb_msd;
673 }
674 
675 static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
676 {
677     DeviceClass *dc = DEVICE_CLASS(klass);
678     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
679 
680     uc->realize = usb_msd_storage_realize;
681     device_class_set_props(dc, msd_properties);
682 }
683 
684 static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
685                                   void *opaque, Error **errp)
686 {
687     USBDevice *dev = USB_DEVICE(obj);
688     MSDState *s = USB_STORAGE_DEV(dev);
689 
690     visit_type_int32(v, name, &s->conf.bootindex, errp);
691 }
692 
693 static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
694                                   void *opaque, Error **errp)
695 {
696     USBDevice *dev = USB_DEVICE(obj);
697     MSDState *s = USB_STORAGE_DEV(dev);
698     int32_t boot_index;
699     Error *local_err = NULL;
700 
701     if (!visit_type_int32(v, name, &boot_index, errp)) {
702         return;
703     }
704     /* check whether bootindex is present in fw_boot_order list  */
705     check_boot_index(boot_index, &local_err);
706     if (local_err) {
707         goto out;
708     }
709     /* change bootindex to a new one */
710     s->conf.bootindex = boot_index;
711 
712     if (s->scsi_dev) {
713         object_property_set_int(OBJECT(s->scsi_dev), "bootindex", boot_index,
714                                 &error_abort);
715     }
716 
717 out:
718     error_propagate(errp, local_err);
719 }
720 
721 static const TypeInfo usb_storage_dev_type_info = {
722     .name = TYPE_USB_STORAGE,
723     .parent = TYPE_USB_DEVICE,
724     .instance_size = sizeof(MSDState),
725     .abstract = true,
726     .class_init = usb_msd_class_initfn_common,
727 };
728 
729 static void usb_msd_instance_init(Object *obj)
730 {
731     object_property_add(obj, "bootindex", "int32",
732                         usb_msd_get_bootindex,
733                         usb_msd_set_bootindex, NULL, NULL);
734     object_property_set_int(obj, "bootindex", -1, NULL);
735 }
736 
737 static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data)
738 {
739     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
740 
741     uc->realize = usb_msd_bot_realize;
742     uc->attached_settable = true;
743 }
744 
745 static const TypeInfo msd_info = {
746     .name          = "usb-storage",
747     .parent        = TYPE_USB_STORAGE,
748     .class_init    = usb_msd_class_storage_initfn,
749     .instance_init = usb_msd_instance_init,
750 };
751 
752 static const TypeInfo bot_info = {
753     .name          = "usb-bot",
754     .parent        = TYPE_USB_STORAGE,
755     .class_init    = usb_msd_class_bot_initfn,
756 };
757 
758 static void usb_msd_register_types(void)
759 {
760     type_register_static(&usb_storage_dev_type_info);
761     type_register_static(&msd_info);
762     type_register_static(&bot_info);
763 }
764 
765 type_init(usb_msd_register_types)
766