xref: /openbmc/qemu/hw/usb/dev-storage-classic.c (revision a12214d1c4204d2f51d8724993b8dfcf50dd7d94)
165561351SGerd Hoffmann /*
265561351SGerd Hoffmann  * USB Mass Storage Device emulation
365561351SGerd Hoffmann  *
465561351SGerd Hoffmann  * Copyright (c) 2006 CodeSourcery.
565561351SGerd Hoffmann  * Written by Paul Brook
665561351SGerd Hoffmann  *
765561351SGerd Hoffmann  * This code is licensed under the LGPL.
865561351SGerd Hoffmann  */
965561351SGerd Hoffmann 
1065561351SGerd Hoffmann #include "qemu/osdep.h"
1165561351SGerd Hoffmann #include "qapi/error.h"
1265561351SGerd Hoffmann #include "qapi/visitor.h"
1365561351SGerd Hoffmann #include "hw/usb.h"
1465561351SGerd Hoffmann #include "hw/usb/desc.h"
1565561351SGerd Hoffmann #include "hw/usb/msd.h"
1665561351SGerd Hoffmann #include "sysemu/sysemu.h"
1765561351SGerd Hoffmann #include "sysemu/block-backend.h"
1865561351SGerd Hoffmann 
1965561351SGerd Hoffmann static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
2065561351SGerd Hoffmann     .tcq = false,
2165561351SGerd Hoffmann     .max_target = 0,
2265561351SGerd Hoffmann     .max_lun = 0,
2365561351SGerd Hoffmann 
2465561351SGerd Hoffmann     .transfer_data = usb_msd_transfer_data,
2565561351SGerd Hoffmann     .complete = usb_msd_command_complete,
2665561351SGerd Hoffmann     .cancel = usb_msd_request_cancelled,
2765561351SGerd Hoffmann     .load_request = usb_msd_load_request,
2865561351SGerd Hoffmann };
2965561351SGerd Hoffmann 
usb_msd_storage_realize(USBDevice * dev,Error ** errp)3065561351SGerd Hoffmann static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
3165561351SGerd Hoffmann {
3265561351SGerd Hoffmann     MSDState *s = USB_STORAGE_DEV(dev);
3365561351SGerd Hoffmann     BlockBackend *blk = s->conf.blk;
3465561351SGerd Hoffmann     SCSIDevice *scsi_dev;
3565561351SGerd Hoffmann 
3665561351SGerd Hoffmann     if (!blk) {
3765561351SGerd Hoffmann         error_setg(errp, "drive property not set");
3865561351SGerd Hoffmann         return;
3965561351SGerd Hoffmann     }
4065561351SGerd Hoffmann 
4165561351SGerd Hoffmann     /*
4265561351SGerd Hoffmann      * Hack alert: this pretends to be a block device, but it's really
4365561351SGerd Hoffmann      * a SCSI bus that can serve only a single device, which it
4465561351SGerd Hoffmann      * creates automatically.  But first it needs to detach from its
4565561351SGerd Hoffmann      * blockdev, or else scsi_bus_legacy_add_drive() dies when it
4665561351SGerd Hoffmann      * attaches again. We also need to take another reference so that
4765561351SGerd Hoffmann      * blk_detach_dev() doesn't free blk while we still need it.
4865561351SGerd Hoffmann      *
4965561351SGerd Hoffmann      * The hack is probably a bad idea.
5065561351SGerd Hoffmann      */
5165561351SGerd Hoffmann     blk_ref(blk);
5265561351SGerd Hoffmann     blk_detach_dev(blk, DEVICE(s));
5365561351SGerd Hoffmann     s->conf.blk = NULL;
5465561351SGerd Hoffmann 
5565561351SGerd Hoffmann     usb_desc_create_serial(dev);
5665561351SGerd Hoffmann     usb_desc_init(dev);
57b7b2a60bSGerd Hoffmann     dev->flags |= (1 << USB_DEV_FLAG_IS_SCSI_STORAGE);
58739e95f5SPeter Maydell     scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(dev),
59739e95f5SPeter Maydell                  &usb_msd_scsi_info_storage);
6065561351SGerd Hoffmann     scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
61*30896374SKevin Wolf                                          &s->conf, dev->serial, errp);
6265561351SGerd Hoffmann     blk_unref(blk);
6365561351SGerd Hoffmann     if (!scsi_dev) {
6465561351SGerd Hoffmann         return;
6565561351SGerd Hoffmann     }
6665561351SGerd Hoffmann     usb_msd_handle_reset(dev);
6765561351SGerd Hoffmann     s->scsi_dev = scsi_dev;
6865561351SGerd Hoffmann }
6965561351SGerd Hoffmann 
7065561351SGerd Hoffmann static Property msd_properties[] = {
7165561351SGerd Hoffmann     DEFINE_BLOCK_PROPERTIES(MSDState, conf),
7265561351SGerd Hoffmann     DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf),
7365561351SGerd Hoffmann     DEFINE_PROP_BOOL("removable", MSDState, removable, false),
7465561351SGerd Hoffmann     DEFINE_PROP_BOOL("commandlog", MSDState, commandlog, false),
7565561351SGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
7665561351SGerd Hoffmann };
7765561351SGerd Hoffmann 
usb_msd_class_storage_initfn(ObjectClass * klass,void * data)7865561351SGerd Hoffmann static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
7965561351SGerd Hoffmann {
8065561351SGerd Hoffmann     DeviceClass *dc = DEVICE_CLASS(klass);
8165561351SGerd Hoffmann     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
8265561351SGerd Hoffmann 
8365561351SGerd Hoffmann     uc->realize = usb_msd_storage_realize;
8465561351SGerd Hoffmann     device_class_set_props(dc, msd_properties);
8565561351SGerd Hoffmann }
8665561351SGerd Hoffmann 
usb_msd_get_bootindex(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)8765561351SGerd Hoffmann static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
8865561351SGerd Hoffmann                                   void *opaque, Error **errp)
8965561351SGerd Hoffmann {
9065561351SGerd Hoffmann     USBDevice *dev = USB_DEVICE(obj);
9165561351SGerd Hoffmann     MSDState *s = USB_STORAGE_DEV(dev);
9265561351SGerd Hoffmann 
9365561351SGerd Hoffmann     visit_type_int32(v, name, &s->conf.bootindex, errp);
9465561351SGerd Hoffmann }
9565561351SGerd Hoffmann 
usb_msd_set_bootindex(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)9665561351SGerd Hoffmann static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
9765561351SGerd Hoffmann                                   void *opaque, Error **errp)
9865561351SGerd Hoffmann {
9965561351SGerd Hoffmann     USBDevice *dev = USB_DEVICE(obj);
10065561351SGerd Hoffmann     MSDState *s = USB_STORAGE_DEV(dev);
10165561351SGerd Hoffmann     int32_t boot_index;
10265561351SGerd Hoffmann     Error *local_err = NULL;
10365561351SGerd Hoffmann 
10465561351SGerd Hoffmann     if (!visit_type_int32(v, name, &boot_index, errp)) {
10565561351SGerd Hoffmann         return;
10665561351SGerd Hoffmann     }
10765561351SGerd Hoffmann     /* check whether bootindex is present in fw_boot_order list  */
10865561351SGerd Hoffmann     check_boot_index(boot_index, &local_err);
10965561351SGerd Hoffmann     if (local_err) {
11065561351SGerd Hoffmann         goto out;
11165561351SGerd Hoffmann     }
11265561351SGerd Hoffmann     /* change bootindex to a new one */
11365561351SGerd Hoffmann     s->conf.bootindex = boot_index;
11465561351SGerd Hoffmann 
11565561351SGerd Hoffmann     if (s->scsi_dev) {
11665561351SGerd Hoffmann         object_property_set_int(OBJECT(s->scsi_dev), "bootindex", boot_index,
11765561351SGerd Hoffmann                                 &error_abort);
11865561351SGerd Hoffmann     }
11965561351SGerd Hoffmann 
12065561351SGerd Hoffmann out:
12165561351SGerd Hoffmann     error_propagate(errp, local_err);
12265561351SGerd Hoffmann }
12365561351SGerd Hoffmann 
usb_msd_instance_init(Object * obj)12465561351SGerd Hoffmann static void usb_msd_instance_init(Object *obj)
12565561351SGerd Hoffmann {
12665561351SGerd Hoffmann     object_property_add(obj, "bootindex", "int32",
12765561351SGerd Hoffmann                         usb_msd_get_bootindex,
12865561351SGerd Hoffmann                         usb_msd_set_bootindex, NULL, NULL);
12965561351SGerd Hoffmann     object_property_set_int(obj, "bootindex", -1, NULL);
13065561351SGerd Hoffmann }
13165561351SGerd Hoffmann 
13265561351SGerd Hoffmann static const TypeInfo msd_info = {
13365561351SGerd Hoffmann     .name          = "usb-storage",
13465561351SGerd Hoffmann     .parent        = TYPE_USB_STORAGE,
13565561351SGerd Hoffmann     .class_init    = usb_msd_class_storage_initfn,
13665561351SGerd Hoffmann     .instance_init = usb_msd_instance_init,
13765561351SGerd Hoffmann };
13865561351SGerd Hoffmann 
register_types(void)13965561351SGerd Hoffmann static void register_types(void)
14065561351SGerd Hoffmann {
14165561351SGerd Hoffmann     type_register_static(&msd_info);
14265561351SGerd Hoffmann }
14365561351SGerd Hoffmann 
14465561351SGerd Hoffmann type_init(register_types)
145