aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2013-01-14 15:29:44 +0100
committerGerd Hoffmann <kraxel@redhat.com>2013-01-22 11:09:54 +0100
commit347073336d393a819928de0d4fd56563134c0e1a (patch)
tree7329052639f59ba20b9a0798dbe594d5eea7266c
parent7fa96d73893728752ec7b832a62a48c434748497 (diff)
usb: add usb-bot device (scsi bulk-only transport).
Basically the same as usb-storage, but without automatic scsi device setup. Also features support for up to 16 LUNs. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-rw-r--r--docs/usb-storage.txt11
-rw-r--r--hw/usb/dev-storage.c94
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);
}