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