diff options
-rw-r--r-- | docs/usb-storage.txt | 11 | ||||
-rw-r--r-- | hw/usb/dev-storage.c | 94 |
2 files changed, 89 insertions, 16 deletions
diff --git a/docs/usb-storage.txt b/docs/usb-storage.txt index e58e849d4d..fa93111cf6 100644 --- a/docs/usb-storage.txt +++ b/docs/usb-storage.txt @@ -2,7 +2,7 @@ qemu usb storage emulation -------------------------- -QEMU has two emulations for usb storage devices. +QEMU has three devices for usb storage emulation. Number one emulates the classic bulk-only transport protocol which is used by 99% of the usb sticks on the marked today and is called @@ -31,6 +31,15 @@ with tree logical units: -device scsi-cd,bus=uas.0,scsi-id=0,lun=5,drive=uas-cdrom +Number three emulates the classic bulk-only transport protocol too. +It's called "usb-bot". It shares most code with "usb-storage", and +the guest will not be able to see the difference. The qemu command +line interface is simliar to usb-uas though, i.e. no automatic scsi +disk creation. It also features support for up to 16 LUNs. The LUN +numbers must be continous, i.e. for three devices you must use 0+1+2. +The 0+1+5 numbering from the "usb-uas" example isn't going to work +with "usb-bot". + enjoy, Gerd diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 1b87352db0..b89d00f7cf 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -54,12 +54,12 @@ typedef struct { struct usb_msd_csw csw; SCSIRequest *req; SCSIBus bus; + /* For async completion. */ + USBPacket *packet; + /* usb-storage only */ BlockConf conf; char *serial; - SCSIDevice *scsi_dev; uint32_t removable; - /* For async completion. */ - USBPacket *packet; } MSDState; struct usb_msd_cbw { @@ -343,7 +343,8 @@ static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { MSDState *s = (MSDState *)dev; - int ret; + SCSIDevice *scsi_dev; + int ret, maxlun; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { @@ -359,7 +360,19 @@ static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, s->mode = USB_MSDM_CBW; break; case ClassInterfaceRequest | GetMaxLun: - data[0] = 0; + maxlun = 0; + for (;;) { + scsi_dev = scsi_device_find(&s->bus, 0, 0, maxlun+1); + if (scsi_dev == NULL) { + break; + } + if (scsi_dev->lun != maxlun+1) { + break; + } + maxlun++; + } + DPRINTF("MaxLun %d\n", maxlun); + data[0] = maxlun; p->actual_length = 1; break; default: @@ -386,6 +399,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) uint32_t tag; struct usb_msd_cbw cbw; uint8_t devep = p->ep->nr; + SCSIDevice *scsi_dev; switch (p->pid) { case USB_TOKEN_OUT: @@ -405,7 +419,8 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) goto fail; } DPRINTF("Command on LUN %d\n", cbw.lun); - if (cbw.lun != 0) { + scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun); + if (scsi_dev == NULL) { fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun); goto fail; } @@ -422,7 +437,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) tag, cbw.flags, cbw.cmd_len, s->data_len); assert(le32_to_cpu(s->csw.residue) == 0); s->scsi_len = 0; - s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL); + s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL); #ifdef DEBUG_MSD scsi_req_print(s->req); #endif @@ -553,7 +568,7 @@ static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req) return NULL; } -static const struct SCSIBusInfo usb_msd_scsi_info = { +static const struct SCSIBusInfo usb_msd_scsi_info_storage = { .tcq = false, .max_target = 0, .max_lun = 0, @@ -564,10 +579,22 @@ static const struct SCSIBusInfo usb_msd_scsi_info = { .load_request = usb_msd_load_request, }; -static int usb_msd_initfn(USBDevice *dev) +static const struct SCSIBusInfo usb_msd_scsi_info_bot = { + .tcq = false, + .max_target = 0, + .max_lun = 15, + + .transfer_data = usb_msd_transfer_data, + .complete = usb_msd_command_complete, + .cancel = usb_msd_request_cancelled, + .load_request = usb_msd_load_request, +}; + +static int usb_msd_initfn_storage(USBDevice *dev) { MSDState *s = DO_UPCAST(MSDState, dev, dev); BlockDriverState *bs = s->conf.bs; + SCSIDevice *scsi_dev; if (!bs) { error_report("drive property not set"); @@ -595,10 +622,10 @@ static int usb_msd_initfn(USBDevice *dev) } usb_desc_init(dev); - scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info); - s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, + scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage); + scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, s->conf.bootindex); - if (!s->scsi_dev) { + if (!scsi_dev) { return -1; } s->bus.qbus.allow_hotplug = 0; @@ -616,6 +643,19 @@ static int usb_msd_initfn(USBDevice *dev) return 0; } +static int usb_msd_initfn_bot(USBDevice *dev) +{ + MSDState *s = DO_UPCAST(MSDState, dev, dev); + + usb_desc_create_serial(dev); + usb_desc_init(dev); + scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_bot); + s->bus.qbus.allow_hotplug = 0; + usb_msd_handle_reset(dev); + + return 0; +} + static USBDevice *usb_msd_init(USBBus *bus, const char *filename) { static int nr=0; @@ -698,12 +738,11 @@ static Property msd_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void usb_msd_class_initfn(ObjectClass *klass, void *data) +static void usb_msd_class_initfn_common(ObjectClass *klass) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_msd_initfn; uc->product_desc = "QEMU USB MSD"; uc->usb_desc = &desc; uc->cancel_packet = usb_msd_cancel_io; @@ -713,19 +752,44 @@ static void usb_msd_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_msd_handle_data; dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_msd; +} + +static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_msd_initfn_storage; dc->props = msd_properties; + usb_msd_class_initfn_common(klass); +} + +static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data) +{ + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_msd_initfn_bot; + usb_msd_class_initfn_common(klass); } static const TypeInfo msd_info = { .name = "usb-storage", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(MSDState), - .class_init = usb_msd_class_initfn, + .class_init = usb_msd_class_initfn_storage, +}; + +static const TypeInfo bot_info = { + .name = "usb-bot", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(MSDState), + .class_init = usb_msd_class_initfn_bot, }; static void usb_msd_register_types(void) { type_register_static(&msd_info); + type_register_static(&bot_info); usb_legacy_register("usb-storage", "disk", usb_msd_init); } |