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 "qemu/typedefs.h" 12 #include "qapi/error.h" 13 #include "qapi/visitor.h" 14 #include "hw/usb.h" 15 #include "hw/usb/desc.h" 16 #include "hw/usb/msd.h" 17 #include "sysemu/sysemu.h" 18 #include "sysemu/block-backend.h" 19 20 static const struct SCSIBusInfo usb_msd_scsi_info_storage = { 21 .tcq = false, 22 .max_target = 0, 23 .max_lun = 0, 24 25 .transfer_data = usb_msd_transfer_data, 26 .complete = usb_msd_command_complete, 27 .cancel = usb_msd_request_cancelled, 28 .load_request = usb_msd_load_request, 29 }; 30 31 static void usb_msd_storage_realize(USBDevice *dev, Error **errp) 32 { 33 MSDState *s = USB_STORAGE_DEV(dev); 34 BlockBackend *blk = s->conf.blk; 35 SCSIDevice *scsi_dev; 36 37 if (!blk) { 38 error_setg(errp, "drive property not set"); 39 return; 40 } 41 42 if (!blkconf_blocksizes(&s->conf, errp)) { 43 return; 44 } 45 46 if (!blkconf_apply_backend_options(&s->conf, !blk_supports_write_perm(blk), 47 true, errp)) { 48 return; 49 } 50 51 /* 52 * Hack alert: this pretends to be a block device, but it's really 53 * a SCSI bus that can serve only a single device, which it 54 * creates automatically. But first it needs to detach from its 55 * blockdev, or else scsi_bus_legacy_add_drive() dies when it 56 * attaches again. We also need to take another reference so that 57 * blk_detach_dev() doesn't free blk while we still need it. 58 * 59 * The hack is probably a bad idea. 60 */ 61 blk_ref(blk); 62 blk_detach_dev(blk, DEVICE(s)); 63 s->conf.blk = NULL; 64 65 usb_desc_create_serial(dev); 66 usb_desc_init(dev); 67 dev->flags |= (1 << USB_DEV_FLAG_IS_SCSI_STORAGE); 68 scsi_bus_init(&s->bus, sizeof(s->bus), DEVICE(dev), 69 &usb_msd_scsi_info_storage); 70 scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable, 71 s->conf.bootindex, s->conf.share_rw, 72 s->conf.rerror, s->conf.werror, 73 dev->serial, 74 errp); 75 blk_unref(blk); 76 if (!scsi_dev) { 77 return; 78 } 79 usb_msd_handle_reset(dev); 80 s->scsi_dev = scsi_dev; 81 } 82 83 static Property msd_properties[] = { 84 DEFINE_BLOCK_PROPERTIES(MSDState, conf), 85 DEFINE_BLOCK_ERROR_PROPERTIES(MSDState, conf), 86 DEFINE_PROP_BOOL("removable", MSDState, removable, false), 87 DEFINE_PROP_BOOL("commandlog", MSDState, commandlog, false), 88 DEFINE_PROP_END_OF_LIST(), 89 }; 90 91 static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data) 92 { 93 DeviceClass *dc = DEVICE_CLASS(klass); 94 USBDeviceClass *uc = USB_DEVICE_CLASS(klass); 95 96 uc->realize = usb_msd_storage_realize; 97 device_class_set_props(dc, msd_properties); 98 } 99 100 static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name, 101 void *opaque, Error **errp) 102 { 103 USBDevice *dev = USB_DEVICE(obj); 104 MSDState *s = USB_STORAGE_DEV(dev); 105 106 visit_type_int32(v, name, &s->conf.bootindex, errp); 107 } 108 109 static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name, 110 void *opaque, Error **errp) 111 { 112 USBDevice *dev = USB_DEVICE(obj); 113 MSDState *s = USB_STORAGE_DEV(dev); 114 int32_t boot_index; 115 Error *local_err = NULL; 116 117 if (!visit_type_int32(v, name, &boot_index, errp)) { 118 return; 119 } 120 /* check whether bootindex is present in fw_boot_order list */ 121 check_boot_index(boot_index, &local_err); 122 if (local_err) { 123 goto out; 124 } 125 /* change bootindex to a new one */ 126 s->conf.bootindex = boot_index; 127 128 if (s->scsi_dev) { 129 object_property_set_int(OBJECT(s->scsi_dev), "bootindex", boot_index, 130 &error_abort); 131 } 132 133 out: 134 error_propagate(errp, local_err); 135 } 136 137 static void usb_msd_instance_init(Object *obj) 138 { 139 object_property_add(obj, "bootindex", "int32", 140 usb_msd_get_bootindex, 141 usb_msd_set_bootindex, NULL, NULL); 142 object_property_set_int(obj, "bootindex", -1, NULL); 143 } 144 145 static const TypeInfo msd_info = { 146 .name = "usb-storage", 147 .parent = TYPE_USB_STORAGE, 148 .class_init = usb_msd_class_storage_initfn, 149 .instance_init = usb_msd_instance_init, 150 }; 151 152 static void register_types(void) 153 { 154 type_register_static(&msd_info); 155 } 156 157 type_init(register_types) 158