]> Git Repo - qemu.git/blobdiff - hw/usb/dev-uas.c
Merge remote-tracking branch 'remotes/armbru/tags/pull-misc-2019-06-11-v3' into staging
[qemu.git] / hw / usb / dev-uas.c
index 36a75b2f49b8ef77c085824d2b8f3858e13a6035..abd8070d0c71fac1d05fc79ec885f89d69d76555 100644 (file)
@@ -9,15 +9,17 @@
  * See the COPYING file in the top-level directory.
  */
 
-#include "qemu-common.h"
+#include "qemu/osdep.h"
 #include "qemu/option.h"
 #include "qemu/config-file.h"
 #include "trace.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
 
 #include "hw/usb.h"
-#include "hw/usb/desc.h"
+#include "desc.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 
 /* --------------------------------------------------------------------- */
 
@@ -55,7 +57,7 @@ typedef struct {
     uint8_t    id;
     uint8_t    reserved;
     uint16_t   tag;
-} QEMU_PACKED  uas_ui_header;
+} QEMU_PACKED  uas_iu_header;
 
 typedef struct {
     uint8_t    prio_taskattr;   /* 6:3 priority, 2:0 task attribute   */
@@ -65,7 +67,7 @@ typedef struct {
     uint64_t   lun;
     uint8_t    cdb[16];
     uint8_t    add_cdb[];
-} QEMU_PACKED  uas_ui_command;
+} QEMU_PACKED  uas_iu_command;
 
 typedef struct {
     uint16_t   status_qualifier;
@@ -73,29 +75,29 @@ typedef struct {
     uint8_t    reserved[7];
     uint16_t   sense_length;
     uint8_t    sense_data[18];
-} QEMU_PACKED  uas_ui_sense;
+} QEMU_PACKED  uas_iu_sense;
 
 typedef struct {
-    uint16_t   add_response_info;
+    uint8_t    add_response_info[3];
     uint8_t    response_code;
-} QEMU_PACKED  uas_ui_response;
+} QEMU_PACKED  uas_iu_response;
 
 typedef struct {
     uint8_t    function;
     uint8_t    reserved;
     uint16_t   task_tag;
     uint64_t   lun;
-} QEMU_PACKED  uas_ui_task_mgmt;
+} QEMU_PACKED  uas_iu_task_mgmt;
 
 typedef struct {
-    uas_ui_header  hdr;
+    uas_iu_header  hdr;
     union {
-        uas_ui_command   command;
-        uas_ui_sense     sense;
-        uas_ui_task_mgmt task;
-        uas_ui_response  response;
+        uas_iu_command   command;
+        uas_iu_sense     sense;
+        uas_iu_task_mgmt task;
+        uas_iu_response  response;
     };
-} QEMU_PACKED  uas_ui;
+} QEMU_PACKED  uas_iu;
 
 /* --------------------------------------------------------------------- */
 
@@ -122,10 +124,13 @@ struct UASDevice {
     UASRequest                *dataout2;
 
     /* usb 3.0 only */
-    USBPacket                 *data3[UAS_MAX_STREAMS];
-    USBPacket                 *status3[UAS_MAX_STREAMS];
+    USBPacket                 *data3[UAS_MAX_STREAMS + 1];
+    USBPacket                 *status3[UAS_MAX_STREAMS + 1];
 };
 
+#define TYPE_USB_UAS "usb-uas"
+#define USB_UAS(obj) OBJECT_CHECK(UASDevice, (obj), TYPE_USB_UAS)
+
 struct UASRequest {
     uint16_t     tag;
     uint64_t     lun;
@@ -145,7 +150,7 @@ struct UASRequest {
 
 struct UASStatus {
     uint32_t                  stream;
-    uas_ui                    status;
+    uas_iu                    status;
     uint32_t                  length;
     QTAILQ_ENTRY(UASStatus)   next;
 };
@@ -286,7 +291,7 @@ static const USBDescDevice desc_device_high = {
             .bNumInterfaces        = 1,
             .bConfigurationValue   = 1,
             .iConfiguration        = STR_CONFIG_HIGH,
-            .bmAttributes          = 0xc0,
+            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
             .nif = 1,
             .ifs = &desc_iface_high,
         },
@@ -302,7 +307,7 @@ static const USBDescDevice desc_device_super = {
             .bNumInterfaces        = 1,
             .bConfigurationValue   = 1,
             .iConfiguration        = STR_CONFIG_SUPER,
-            .bmAttributes          = 0xc0,
+            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
             .nif = 1,
             .ifs = &desc_iface_super,
         },
@@ -338,7 +343,7 @@ static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag)
 
     st->status.hdr.id = id;
     st->status.hdr.tag = cpu_to_be16(tag);
-    st->length = sizeof(uas_ui_header);
+    st->length = sizeof(uas_iu_header);
     if (uas_using_streams(uas)) {
         st->stream = tag;
     }
@@ -392,15 +397,13 @@ static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
     }
 }
 
-static void usb_uas_queue_response(UASDevice *uas, uint16_t tag,
-                                   uint8_t code, uint16_t add_info)
+static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, uint8_t code)
 {
     UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag);
 
     trace_usb_uas_response(uas->dev.addr, tag, code);
     st->status.response.response_code = code;
-    st->status.response.add_response_info = cpu_to_be16(add_info);
-    usb_uas_queue_status(uas, st, sizeof(uas_ui_response));
+    usb_uas_queue_status(uas, st, sizeof(uas_iu_response));
 }
 
 static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
@@ -416,7 +419,7 @@ static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
                                   sizeof(st->status.sense.sense_data));
         st->status.sense.sense_length = cpu_to_be16(slen);
     }
-    len = sizeof(uas_ui_sense) - sizeof(st->status.sense.sense_data) + slen;
+    len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
     usb_uas_queue_status(req->uas, st, len);
 }
 
@@ -434,7 +437,7 @@ static void usb_uas_queue_fake_sense(UASDevice *uas, uint16_t tag,
     st->status.sense.sense_data[12] = sense.asc;
     st->status.sense.sense_data[13] = sense.ascq;
     slen = 18;
-    len = sizeof(uas_ui_sense) - sizeof(st->status.sense.sense_data) + slen;
+    len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
     usb_uas_queue_status(uas, st, len);
 }
 
@@ -536,14 +539,14 @@ static void usb_uas_start_next_transfer(UASDevice *uas)
     }
 }
 
-static UASRequest *usb_uas_alloc_request(UASDevice *uas, uas_ui *ui)
+static UASRequest *usb_uas_alloc_request(UASDevice *uas, uas_iu *iu)
 {
     UASRequest *req;
 
     req = g_new0(UASRequest, 1);
     req->uas = uas;
-    req->tag = be16_to_cpu(ui->hdr.tag);
-    req->lun = be64_to_cpu(ui->command.lun);
+    req->tag = be16_to_cpu(iu->hdr.tag);
+    req->lun = be64_to_cpu(iu->command.lun);
     req->dev = usb_uas_get_dev(req->uas, req->lun);
     return req;
 }
@@ -627,7 +630,7 @@ static const struct SCSIBusInfo usb_uas_scsi_info = {
 
 static void usb_uas_handle_reset(USBDevice *dev)
 {
-    UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
+    UASDevice *uas = USB_UAS(dev);
     UASRequest *req, *nreq;
     UASStatus *st, *nst;
 
@@ -650,13 +653,14 @@ static void usb_uas_handle_control(USBDevice *dev, USBPacket *p,
     if (ret >= 0) {
         return;
     }
-    fprintf(stderr, "%s: unhandled control request\n", __func__);
+    error_report("%s: unhandled control request (req 0x%x, val 0x%x, idx 0x%x",
+                 __func__, request, value, index);
     p->status = USB_RET_STALL;
 }
 
 static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
 {
-    UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
+    UASDevice *uas = USB_UAS(dev);
     UASRequest *req, *nreq;
     int i;
 
@@ -666,7 +670,7 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
         return;
     }
     if (uas_using_streams(uas)) {
-        for (i = 0; i < UAS_MAX_STREAMS; i++) {
+        for (i = 0; i <= UAS_MAX_STREAMS; i++) {
             if (uas->status3[i] == p) {
                 uas->status3[i] = NULL;
                 return;
@@ -686,17 +690,20 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
     assert(!"canceled usb packet not found");
 }
 
-static void usb_uas_command(UASDevice *uas, uas_ui *ui)
+static void usb_uas_command(UASDevice *uas, uas_iu *iu)
 {
     UASRequest *req;
     uint32_t len;
-    uint16_t tag = be16_to_cpu(ui->hdr.tag);
+    uint16_t tag = be16_to_cpu(iu->hdr.tag);
 
+    if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
+        goto invalid_tag;
+    }
     req = usb_uas_find_request(uas, tag);
     if (req) {
         goto overlapped_tag;
     }
-    req = usb_uas_alloc_request(uas, ui);
+    req = usb_uas_alloc_request(uas, iu);
     if (req->dev == NULL) {
         goto bad_target;
     }
@@ -713,7 +720,7 @@ static void usb_uas_command(UASDevice *uas, uas_ui *ui)
 
     req->req = scsi_req_new(req->dev, req->tag,
                             usb_uas_get_lun(req->lun),
-                            ui->command.cdb, req);
+                            iu->command.cdb, req);
     if (uas->requestlog) {
         scsi_req_print(req->req);
     }
@@ -724,6 +731,10 @@ static void usb_uas_command(UASDevice *uas, uas_ui *ui)
     }
     return;
 
+invalid_tag:
+    usb_uas_queue_fake_sense(uas, tag, sense_code_INVALID_TAG);
+    return;
+
 overlapped_tag:
     usb_uas_queue_fake_sense(uas, tag, sense_code_OVERLAPPED_COMMANDS);
     return;
@@ -733,91 +744,84 @@ bad_target:
     g_free(req);
 }
 
-static void usb_uas_task(UASDevice *uas, uas_ui *ui)
+static void usb_uas_task(UASDevice *uas, uas_iu *iu)
 {
-    uint16_t tag = be16_to_cpu(ui->hdr.tag);
-    uint64_t lun64 = be64_to_cpu(ui->task.lun);
+    uint16_t tag = be16_to_cpu(iu->hdr.tag);
+    uint64_t lun64 = be64_to_cpu(iu->task.lun);
     SCSIDevice *dev = usb_uas_get_dev(uas, lun64);
     int lun = usb_uas_get_lun(lun64);
     UASRequest *req;
     uint16_t task_tag;
 
-    req = usb_uas_find_request(uas, be16_to_cpu(ui->hdr.tag));
+    if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
+        goto invalid_tag;
+    }
+    req = usb_uas_find_request(uas, be16_to_cpu(iu->hdr.tag));
     if (req) {
         goto overlapped_tag;
     }
+    if (dev == NULL) {
+        goto incorrect_lun;
+    }
 
-    switch (ui->task.function) {
+    switch (iu->task.function) {
     case UAS_TMF_ABORT_TASK:
-        task_tag = be16_to_cpu(ui->task.task_tag);
+        task_tag = be16_to_cpu(iu->task.task_tag);
         trace_usb_uas_tmf_abort_task(uas->dev.addr, tag, task_tag);
-        if (dev == NULL) {
-            goto bad_target;
-        }
-        if (dev->lun != lun) {
-            goto incorrect_lun;
-        }
         req = usb_uas_find_request(uas, task_tag);
         if (req && req->dev == dev) {
             scsi_req_cancel(req->req);
         }
-        usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE, 0);
+        usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
         break;
 
     case UAS_TMF_LOGICAL_UNIT_RESET:
         trace_usb_uas_tmf_logical_unit_reset(uas->dev.addr, tag, lun);
-        if (dev == NULL) {
-            goto bad_target;
-        }
-        if (dev->lun != lun) {
-            goto incorrect_lun;
-        }
         qdev_reset_all(&dev->qdev);
-        usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE, 0);
+        usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
         break;
 
     default:
-        trace_usb_uas_tmf_unsupported(uas->dev.addr, tag, ui->task.function);
-        usb_uas_queue_response(uas, tag, UAS_RC_TMF_NOT_SUPPORTED, 0);
+        trace_usb_uas_tmf_unsupported(uas->dev.addr, tag, iu->task.function);
+        usb_uas_queue_response(uas, tag, UAS_RC_TMF_NOT_SUPPORTED);
         break;
     }
     return;
 
-overlapped_tag:
-    usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG, 0);
+invalid_tag:
+    usb_uas_queue_response(uas, tag, UAS_RC_INVALID_INFO_UNIT);
     return;
 
-bad_target:
-    /* FIXME: correct?  [see long comment in usb_uas_command()] */
-    usb_uas_queue_response(uas, tag, UAS_RC_INVALID_INFO_UNIT, 0);
+overlapped_tag:
+    usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG);
     return;
 
 incorrect_lun:
-    usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN, 0);
+    usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN);
 }
 
 static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
 {
-    UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
-    uas_ui ui;
+    UASDevice *uas = USB_UAS(dev);
+    uas_iu iu;
     UASStatus *st;
     UASRequest *req;
     int length;
 
     switch (p->ep->nr) {
     case UAS_PIPE_ID_COMMAND:
-        length = MIN(sizeof(ui), p->iov.size);
-        usb_packet_copy(p, &ui, length);
-        switch (ui.hdr.id) {
+        length = MIN(sizeof(iu), p->iov.size);
+        usb_packet_copy(p, &iu, length);
+        switch (iu.hdr.id) {
         case UAS_UI_COMMAND:
-            usb_uas_command(uas, &ui);
+            usb_uas_command(uas, &iu);
             break;
         case UAS_UI_TASK_MGMT:
-            usb_uas_task(uas, &ui);
+            usb_uas_task(uas, &iu);
             break;
         default:
-            fprintf(stderr, "%s: unknown command ui: id 0x%x\n",
-                    __func__, ui.hdr.id);
+            error_report("%s: unknown command iu: id 0x%x",
+                         __func__, iu.hdr.id);
             p->status = USB_RET_STALL;
             break;
         }
@@ -863,7 +867,7 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
                 p->status = USB_RET_ASYNC;
                 break;
             } else {
-                fprintf(stderr, "%s: no inflight request\n", __func__);
+                error_report("%s: no inflight request", __func__);
                 p->status = USB_RET_STALL;
                 break;
             }
@@ -881,25 +885,29 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
         usb_uas_start_next_transfer(uas);
         break;
     default:
-        fprintf(stderr, "%s: invalid endpoint %d\n", __func__, p->ep->nr);
+        error_report("%s: invalid endpoint %d", __func__, p->ep->nr);
         p->status = USB_RET_STALL;
         break;
     }
 }
 
-static void usb_uas_handle_destroy(USBDevice *dev)
+static void usb_uas_unrealize(USBDevice *dev, Error **errp)
 {
-    UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
+    UASDevice *uas = USB_UAS(dev);
 
     qemu_bh_delete(uas->status_bh);
 }
 
-static int usb_uas_init(USBDevice *dev)
+static void usb_uas_realize(USBDevice *dev, Error **errp)
 {
-    UASDevice *uas = DO_UPCAST(UASDevice, dev, dev);
+    UASDevice *uas = USB_UAS(dev);
+    DeviceState *d = DEVICE(dev);
 
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
+    if (d->hotplugged) {
+        uas->dev.auto_attach = 0;
+    }
 
     QTAILQ_INIT(&uas->results);
     QTAILQ_INIT(&uas->requests);
@@ -907,8 +915,6 @@ static int usb_uas_init(USBDevice *dev)
 
     scsi_bus_new(&uas->bus, sizeof(uas->bus), DEVICE(dev),
                  &usb_uas_scsi_info, NULL);
-
-    return 0;
 }
 
 static const VMStateDescription vmstate_usb_uas = {
@@ -930,7 +936,7 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
 
-    uc->init           = usb_uas_init;
+    uc->realize        = usb_uas_realize;
     uc->product_desc   = desc_strings[STR_PRODUCT];
     uc->usb_desc       = &desc;
     uc->cancel_packet  = usb_uas_cancel_io;
@@ -938,7 +944,8 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data)
     uc->handle_reset   = usb_uas_handle_reset;
     uc->handle_control = usb_uas_handle_control;
     uc->handle_data    = usb_uas_handle_data;
-    uc->handle_destroy = usb_uas_handle_destroy;
+    uc->unrealize      = usb_uas_unrealize;
+    uc->attached_settable = true;
     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
     dc->fw_name = "storage";
     dc->vmsd = &vmstate_usb_uas;
@@ -946,7 +953,7 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data)
 }
 
 static const TypeInfo uas_info = {
-    .name          = "usb-uas",
+    .name          = TYPE_USB_UAS,
     .parent        = TYPE_USB_DEVICE,
     .instance_size = sizeof(UASDevice),
     .class_init    = usb_uas_class_initfn,
This page took 0.043312 seconds and 4 git commands to generate.