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