xref: /openbmc/qemu/hw/usb/dev-storage-classic.c (revision bfe7bf85)
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     if (!blkconf_blocksizes(&s->conf, errp)) {
4265561351SGerd Hoffmann         return;
4365561351SGerd Hoffmann     }
4465561351SGerd Hoffmann 
4565561351SGerd Hoffmann     if (!blkconf_apply_backend_options(&s->conf, !blk_supports_write_perm(blk),
4665561351SGerd Hoffmann                                        true, errp)) {
4765561351SGerd Hoffmann         return;
4865561351SGerd Hoffmann     }
4965561351SGerd Hoffmann 
5065561351SGerd Hoffmann     /*
5165561351SGerd Hoffmann      * Hack alert: this pretends to be a block device, but it's really
5265561351SGerd Hoffmann      * a SCSI bus that can serve only a single device, which it
5365561351SGerd Hoffmann      * creates automatically.  But first it needs to detach from its
5465561351SGerd Hoffmann      * blockdev, or else scsi_bus_legacy_add_drive() dies when it
5565561351SGerd Hoffmann      * attaches again. We also need to take another reference so that
5665561351SGerd Hoffmann      * blk_detach_dev() doesn't free blk while we still need it.
5765561351SGerd Hoffmann      *
5865561351SGerd Hoffmann      * The hack is probably a bad idea.
5965561351SGerd Hoffmann      */
6065561351SGerd Hoffmann     blk_ref(blk);
6165561351SGerd Hoffmann     blk_detach_dev(blk, DEVICE(s));
6265561351SGerd Hoffmann     s->conf.blk = NULL;
6365561351SGerd Hoffmann 
6465561351SGerd Hoffmann     usb_desc_create_serial(dev);
6565561351SGerd Hoffmann     usb_desc_init(dev);
66b7b2a60bSGerd Hoffmann     dev->flags |= (1 << USB_DEV_FLAG_IS_SCSI_STORAGE);
67*739e95f5SPeter Maydell     scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(dev),
68*739e95f5SPeter Maydell                  &usb_msd_scsi_info_storage);
6965561351SGerd Hoffmann     scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
7065561351SGerd Hoffmann                                          s->conf.bootindex, s->conf.share_rw,
7165561351SGerd Hoffmann                                          s->conf.rerror, s->conf.werror,
7265561351SGerd Hoffmann                                          dev->serial,
7365561351SGerd Hoffmann                                          errp);
7465561351SGerd Hoffmann     blk_unref(blk);
7565561351SGerd Hoffmann     if (!scsi_dev) {
7665561351SGerd Hoffmann         return;
7765561351SGerd Hoffmann     }
7865561351SGerd Hoffmann     usb_msd_handle_reset(dev);
7965561351SGerd Hoffmann     s->scsi_dev = scsi_dev;
8065561351SGerd Hoffmann }
8165561351SGerd Hoffmann 
8265561351SGerd Hoffmann static Property msd_properties[] = {
8365561351SGerd Hoffmann     DEFINE_BLOCK_PROPERTIES(MSDState, conf),
8465561351SGerd Hoffmann     DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf),
8565561351SGerd Hoffmann     DEFINE_PROP_BOOL("removable", MSDState, removable, false),
8665561351SGerd Hoffmann     DEFINE_PROP_BOOL("commandlog", MSDState, commandlog, false),
8765561351SGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
8865561351SGerd Hoffmann };
8965561351SGerd Hoffmann 
usb_msd_class_storage_initfn(ObjectClass * klass,void * data)9065561351SGerd Hoffmann static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
9165561351SGerd Hoffmann {
9265561351SGerd Hoffmann     DeviceClass *dc = DEVICE_CLASS(klass);
9365561351SGerd Hoffmann     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
9465561351SGerd Hoffmann 
9565561351SGerd Hoffmann     uc->realize = usb_msd_storage_realize;
9665561351SGerd Hoffmann     device_class_set_props(dc, msd_properties);
9765561351SGerd Hoffmann }
9865561351SGerd Hoffmann 
usb_msd_get_bootindex(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)9965561351SGerd Hoffmann static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
10065561351SGerd Hoffmann                                   void *opaque, Error **errp)
10165561351SGerd Hoffmann {
10265561351SGerd Hoffmann     USBDevice *dev = USB_DEVICE(obj);
10365561351SGerd Hoffmann     MSDState *s = USB_STORAGE_DEV(dev);
10465561351SGerd Hoffmann 
10565561351SGerd Hoffmann     visit_type_int32(v, name, &s->conf.bootindex, errp);
10665561351SGerd Hoffmann }
10765561351SGerd Hoffmann 
usb_msd_set_bootindex(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)10865561351SGerd Hoffmann static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
10965561351SGerd Hoffmann                                   void *opaque, Error **errp)
11065561351SGerd Hoffmann {
11165561351SGerd Hoffmann     USBDevice *dev = USB_DEVICE(obj);
11265561351SGerd Hoffmann     MSDState *s = USB_STORAGE_DEV(dev);
11365561351SGerd Hoffmann     int32_t boot_index;
11465561351SGerd Hoffmann     Error *local_err = NULL;
11565561351SGerd Hoffmann 
11665561351SGerd Hoffmann     if (!visit_type_int32(v, name, &boot_index, errp)) {
11765561351SGerd Hoffmann         return;
11865561351SGerd Hoffmann     }
11965561351SGerd Hoffmann     /* check whether bootindex is present in fw_boot_order list  */
12065561351SGerd Hoffmann     check_boot_index(boot_index, &local_err);
12165561351SGerd Hoffmann     if (local_err) {
12265561351SGerd Hoffmann         goto out;
12365561351SGerd Hoffmann     }
12465561351SGerd Hoffmann     /* change bootindex to a new one */
12565561351SGerd Hoffmann     s->conf.bootindex = boot_index;
12665561351SGerd Hoffmann 
12765561351SGerd Hoffmann     if (s->scsi_dev) {
12865561351SGerd Hoffmann         object_property_set_int(OBJECT(s->scsi_dev), "bootindex", boot_index,
12965561351SGerd Hoffmann                                 &error_abort);
13065561351SGerd Hoffmann     }
13165561351SGerd Hoffmann 
13265561351SGerd Hoffmann out:
13365561351SGerd Hoffmann     error_propagate(errp, local_err);
13465561351SGerd Hoffmann }
13565561351SGerd Hoffmann 
usb_msd_instance_init(Object * obj)13665561351SGerd Hoffmann static void usb_msd_instance_init(Object *obj)
13765561351SGerd Hoffmann {
13865561351SGerd Hoffmann     object_property_add(obj, "bootindex", "int32",
13965561351SGerd Hoffmann                         usb_msd_get_bootindex,
14065561351SGerd Hoffmann                         usb_msd_set_bootindex, NULL, NULL);
14165561351SGerd Hoffmann     object_property_set_int(obj, "bootindex", -1, NULL);
14265561351SGerd Hoffmann }
14365561351SGerd Hoffmann 
14465561351SGerd Hoffmann static const TypeInfo msd_info = {
14565561351SGerd Hoffmann     .name          = "usb-storage",
14665561351SGerd Hoffmann     .parent        = TYPE_USB_STORAGE,
14765561351SGerd Hoffmann     .class_init    = usb_msd_class_storage_initfn,
14865561351SGerd Hoffmann     .instance_init = usb_msd_instance_init,
14965561351SGerd Hoffmann };
15065561351SGerd Hoffmann 
register_types(void)15165561351SGerd Hoffmann static void register_types(void)
15265561351SGerd Hoffmann {
15365561351SGerd Hoffmann     type_register_static(&msd_info);
15465561351SGerd Hoffmann }
15565561351SGerd Hoffmann 
15665561351SGerd Hoffmann type_init(register_types)
157