dev-storage.c 24.2 KB
Newer Older
1
/*
P
pbrook 已提交
2 3 4 5 6
 * USB Mass Storage Device emulation
 *
 * Copyright (c) 2006 CodeSourcery.
 * Written by Paul Brook
 *
M
Matthew Fernandez 已提交
7
 * This code is licensed under the LGPL.
P
pbrook 已提交
8 9
 */

P
Peter Maydell 已提交
10
#include "qemu/osdep.h"
11
#include "qapi/error.h"
P
pbrook 已提交
12
#include "qemu-common.h"
13
#include "qemu/error-report.h"
14 15
#include "qemu/option.h"
#include "qemu/config-file.h"
G
Gerd Hoffmann 已提交
16 17
#include "hw/usb.h"
#include "hw/usb/desc.h"
P
Paolo Bonzini 已提交
18
#include "hw/scsi/scsi.h"
19
#include "ui/console.h"
20
#include "monitor/monitor.h"
21
#include "sysemu/sysemu.h"
22
#include "sysemu/block-backend.h"
23
#include "sysemu/blockdev.h"
24
#include "qapi/visitor.h"
25
#include "qemu/cutils.h"
P
pbrook 已提交
26 27 28 29

//#define DEBUG_MSD

#ifdef DEBUG_MSD
30 31
#define DPRINTF(fmt, ...) \
do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
P
pbrook 已提交
32
#else
33
#define DPRINTF(fmt, ...) do {} while(0)
P
pbrook 已提交
34 35 36 37 38 39 40 41
#endif

/* USB requests.  */
#define MassStorageReset  0xff
#define GetMaxLun         0xfe

enum USBMSDMode {
    USB_MSDM_CBW, /* Command Block.  */
B
Brad Hards 已提交
42
    USB_MSDM_DATAOUT, /* Transfer data to device.  */
P
pbrook 已提交
43 44 45 46
    USB_MSDM_DATAIN, /* Transfer data from device.  */
    USB_MSDM_CSW /* Command Status.  */
};

47 48 49 50 51 52 53
struct usb_msd_csw {
    uint32_t sig;
    uint32_t tag;
    uint32_t residue;
    uint8_t status;
};

P
pbrook 已提交
54 55 56
typedef struct {
    USBDevice dev;
    enum USBMSDMode mode;
57
    uint32_t scsi_off;
P
pbrook 已提交
58
    uint32_t scsi_len;
P
pbrook 已提交
59
    uint32_t data_len;
60
    struct usb_msd_csw csw;
61
    SCSIRequest *req;
62
    SCSIBus bus;
63 64 65
    /* For async completion.  */
    USBPacket *packet;
    /* usb-storage only */
66
    BlockConf conf;
67
    uint32_t removable;
68
    SCSIDevice *scsi_dev;
P
pbrook 已提交
69 70
} MSDState;

G
Gonglei 已提交
71 72 73
#define TYPE_USB_STORAGE "usb-storage-dev"
#define USB_STORAGE_DEV(obj) OBJECT_CHECK(MSDState, (obj), TYPE_USB_STORAGE)

P
pbrook 已提交
74 75 76 77 78 79 80 81 82 83
struct usb_msd_cbw {
    uint32_t sig;
    uint32_t tag;
    uint32_t data_len;
    uint8_t flags;
    uint8_t lun;
    uint8_t cmd_len;
    uint8_t cmd[16];
};

84 85 86 87
enum {
    STR_MANUFACTURER = 1,
    STR_PRODUCT,
    STR_SERIALNUMBER,
G
Gerd Hoffmann 已提交
88 89
    STR_CONFIG_FULL,
    STR_CONFIG_HIGH,
G
Gerd Hoffmann 已提交
90
    STR_CONFIG_SUPER,
P
pbrook 已提交
91 92
};

93
static const USBDescStrings desc_strings = {
94
    [STR_MANUFACTURER] = "QEMU",
95 96
    [STR_PRODUCT]      = "QEMU USB HARDDRIVE",
    [STR_SERIALNUMBER] = "1",
G
Gerd Hoffmann 已提交
97 98
    [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
    [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
G
Gerd Hoffmann 已提交
99
    [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
100 101
};

G
Gerd Hoffmann 已提交
102
static const USBDescIface desc_iface_full = {
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    .bInterfaceNumber              = 0,
    .bNumEndpoints                 = 2,
    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
    .bInterfaceSubClass            = 0x06, /* SCSI */
    .bInterfaceProtocol            = 0x50, /* Bulk */
    .eps = (USBDescEndpoint[]) {
        {
            .bEndpointAddress      = USB_DIR_IN | 0x01,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 64,
        },{
            .bEndpointAddress      = USB_DIR_OUT | 0x02,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 64,
        },
    }
};

G
Gerd Hoffmann 已提交
121 122
static const USBDescDevice desc_device_full = {
    .bcdUSB                        = 0x0200,
123 124 125 126 127 128
    .bMaxPacketSize0               = 8,
    .bNumConfigurations            = 1,
    .confs = (USBDescConfig[]) {
        {
            .bNumInterfaces        = 1,
            .bConfigurationValue   = 1,
G
Gerd Hoffmann 已提交
129
            .iConfiguration        = STR_CONFIG_FULL,
130
            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
131
            .nif = 1,
G
Gerd Hoffmann 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
            .ifs = &desc_iface_full,
        },
    },
};

static const USBDescIface desc_iface_high = {
    .bInterfaceNumber              = 0,
    .bNumEndpoints                 = 2,
    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
    .bInterfaceSubClass            = 0x06, /* SCSI */
    .bInterfaceProtocol            = 0x50, /* Bulk */
    .eps = (USBDescEndpoint[]) {
        {
            .bEndpointAddress      = USB_DIR_IN | 0x01,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 512,
        },{
            .bEndpointAddress      = USB_DIR_OUT | 0x02,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 512,
        },
    }
};

static const USBDescDevice desc_device_high = {
    .bcdUSB                        = 0x0200,
    .bMaxPacketSize0               = 64,
    .bNumConfigurations            = 1,
    .confs = (USBDescConfig[]) {
        {
            .bNumInterfaces        = 1,
            .bConfigurationValue   = 1,
            .iConfiguration        = STR_CONFIG_HIGH,
165
            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
166
            .nif = 1,
G
Gerd Hoffmann 已提交
167
            .ifs = &desc_iface_high,
168 169 170 171
        },
    },
};

G
Gerd Hoffmann 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
static const USBDescIface desc_iface_super = {
    .bInterfaceNumber              = 0,
    .bNumEndpoints                 = 2,
    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
    .bInterfaceSubClass            = 0x06, /* SCSI */
    .bInterfaceProtocol            = 0x50, /* Bulk */
    .eps = (USBDescEndpoint[]) {
        {
            .bEndpointAddress      = USB_DIR_IN | 0x01,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 1024,
            .bMaxBurst             = 15,
        },{
            .bEndpointAddress      = USB_DIR_OUT | 0x02,
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
            .wMaxPacketSize        = 1024,
            .bMaxBurst             = 15,
        },
    }
};

static const USBDescDevice desc_device_super = {
    .bcdUSB                        = 0x0300,
    .bMaxPacketSize0               = 9,
    .bNumConfigurations            = 1,
    .confs = (USBDescConfig[]) {
        {
            .bNumInterfaces        = 1,
            .bConfigurationValue   = 1,
            .iConfiguration        = STR_CONFIG_SUPER,
202
            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
G
Gerd Hoffmann 已提交
203 204 205 206 207 208
            .nif = 1,
            .ifs = &desc_iface_super,
        },
    },
};

209 210
static const USBDesc desc = {
    .id = {
211 212
        .idVendor          = 0x46f4, /* CRC16() of "QEMU" */
        .idProduct         = 0x0001,
213 214 215 216 217
        .bcdDevice         = 0,
        .iManufacturer     = STR_MANUFACTURER,
        .iProduct          = STR_PRODUCT,
        .iSerialNumber     = STR_SERIALNUMBER,
    },
G
Gerd Hoffmann 已提交
218 219 220 221
    .full  = &desc_device_full,
    .high  = &desc_device_high,
    .super = &desc_device_super,
    .str   = desc_strings,
P
pbrook 已提交
222 223
};

G
Gerd Hoffmann 已提交
224
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
P
pbrook 已提交
225 226
{
    uint32_t len;
227
    len = p->iov.size - p->actual_length;
P
pbrook 已提交
228 229
    if (len > s->scsi_len)
        len = s->scsi_len;
230
    usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
P
pbrook 已提交
231
    s->scsi_len -= len;
232
    s->scsi_off += len;
P
pbrook 已提交
233
    s->data_len -= len;
234
    if (s->scsi_len == 0 || s->data_len == 0) {
235
        scsi_req_continue(s->req);
P
pbrook 已提交
236 237 238
    }
}

239
static void usb_msd_send_status(MSDState *s, USBPacket *p)
P
pbrook 已提交
240
{
241
    int len;
P
pbrook 已提交
242

243
    DPRINTF("Command status %d tag 0x%x, len %zd\n",
244
            s->csw.status, le32_to_cpu(s->csw.tag), p->iov.size);
245

246
    assert(s->csw.sig == cpu_to_le32(0x53425355));
247 248 249
    len = MIN(sizeof(s->csw), p->iov.size);
    usb_packet_copy(p, &s->csw, len);
    memset(&s->csw, 0, sizeof(s->csw));
P
pbrook 已提交
250 251
}

252 253 254 255 256 257 258 259 260 261 262 263
static void usb_msd_packet_complete(MSDState *s)
{
    USBPacket *p = s->packet;

    /* Set s->packet to NULL before calling usb_packet_complete
       because another request may be issued before
       usb_packet_complete returns.  */
    DPRINTF("Packet complete %p\n", p);
    s->packet = NULL;
    usb_packet_complete(&s->dev, p);
}

264
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
P
pbrook 已提交
265
{
266
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
P
pbrook 已提交
267
    USBPacket *p = s->packet;
P
pbrook 已提交
268

269
    assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
270
    s->scsi_len = len;
271
    s->scsi_off = 0;
P
pbrook 已提交
272
    if (p) {
G
Gerd Hoffmann 已提交
273 274
        usb_msd_copy_data(s, p);
        p = s->packet;
275 276
        if (p && p->actual_length == p->iov.size) {
            p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
277
            usb_msd_packet_complete(s);
P
pbrook 已提交
278
        }
P
pbrook 已提交
279
    }
P
pbrook 已提交
280 281
}

282
static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
283 284 285 286
{
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
    USBPacket *p = s->packet;

287
    DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
288 289

    s->csw.sig = cpu_to_le32(0x53425355);
290
    s->csw.tag = cpu_to_le32(req->tag);
291
    s->csw.residue = cpu_to_le32(s->data_len);
292
    s->csw.status = status != 0;
293

294 295 296 297 298 299
    if (s->packet) {
        if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
            /* A deferred packet with no write data remaining must be
               the status read packet.  */
            usb_msd_send_status(s, p);
            s->mode = USB_MSDM_CBW;
300 301 302
        } else if (s->mode == USB_MSDM_CSW) {
            usb_msd_send_status(s, p);
            s->mode = USB_MSDM_CBW;
303 304
        } else {
            if (s->data_len) {
305
                int len = (p->iov.size - p->actual_length);
G
Gerd Hoffmann 已提交
306 307
                usb_packet_skip(p, len);
                s->data_len -= len;
308 309 310 311 312
            }
            if (s->data_len == 0) {
                s->mode = USB_MSDM_CSW;
            }
        }
313
        p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
314
        usb_msd_packet_complete(s);
315 316 317 318 319 320 321
    } else if (s->data_len == 0) {
        s->mode = USB_MSDM_CSW;
    }
    scsi_req_unref(req);
    s->req = NULL;
}

P
Paolo Bonzini 已提交
322 323 324 325 326 327 328 329 330 331 332
static void usb_msd_request_cancelled(SCSIRequest *req)
{
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);

    if (req == s->req) {
        scsi_req_unref(s->req);
        s->req = NULL;
        s->scsi_len = 0;
    }
}

B
bellard 已提交
333
static void usb_msd_handle_reset(USBDevice *dev)
P
pbrook 已提交
334 335 336 337
{
    MSDState *s = (MSDState *)dev;

    DPRINTF("Reset\n");
G
Gerd Hoffmann 已提交
338 339 340 341 342 343
    if (s->req) {
        scsi_req_cancel(s->req);
    }
    assert(s->req == NULL);

    if (s->packet) {
344
        s->packet->status = USB_RET_STALL;
345
        usb_msd_packet_complete(s);
G
Gerd Hoffmann 已提交
346 347
    }

P
pbrook 已提交
348 349 350
    s->mode = USB_MSDM_CBW;
}

351
static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
352
               int request, int value, int index, int length, uint8_t *data)
P
pbrook 已提交
353 354
{
    MSDState *s = (MSDState *)dev;
355 356
    SCSIDevice *scsi_dev;
    int ret, maxlun;
P
pbrook 已提交
357

358
    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
359
    if (ret >= 0) {
360
        return;
361 362
    }

P
pbrook 已提交
363 364
    switch (request) {
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
365
        break;
P
pbrook 已提交
366
        /* Class specific requests.  */
367
    case ClassInterfaceOutRequest | MassStorageReset:
P
pbrook 已提交
368 369 370
        /* Reset state ready for the next CBW.  */
        s->mode = USB_MSDM_CBW;
        break;
371
    case ClassInterfaceRequest | GetMaxLun:
372 373 374 375 376 377 378 379 380 381 382 383 384
        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;
385
        p->actual_length = 1;
P
pbrook 已提交
386 387
        break;
    default:
388
        p->status = USB_RET_STALL;
P
pbrook 已提交
389 390 391 392
        break;
    }
}

393
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
P
pbrook 已提交
394
{
G
Gonglei 已提交
395
    MSDState *s = USB_STORAGE_DEV(dev);
396

397 398 399
    assert(s->packet == p);
    s->packet = NULL;

400 401 402
    if (s->req) {
        scsi_req_cancel(s->req);
    }
P
pbrook 已提交
403 404
}

405
static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
P
pbrook 已提交
406 407
{
    MSDState *s = (MSDState *)dev;
408
    uint32_t tag;
P
pbrook 已提交
409
    struct usb_msd_cbw cbw;
410
    uint8_t devep = p->ep->nr;
411
    SCSIDevice *scsi_dev;
412
    uint32_t len;
P
pbrook 已提交
413

P
pbrook 已提交
414
    switch (p->pid) {
P
pbrook 已提交
415 416 417 418 419 420
    case USB_TOKEN_OUT:
        if (devep != 2)
            goto fail;

        switch (s->mode) {
        case USB_MSDM_CBW:
G
Gerd Hoffmann 已提交
421
            if (p->iov.size != 31) {
422
                error_report("usb-msd: Bad CBW size");
P
pbrook 已提交
423 424
                goto fail;
            }
G
Gerd Hoffmann 已提交
425
            usb_packet_copy(p, &cbw, 31);
P
pbrook 已提交
426
            if (le32_to_cpu(cbw.sig) != 0x43425355) {
427 428
                error_report("usb-msd: Bad signature %08x",
                             le32_to_cpu(cbw.sig));
P
pbrook 已提交
429 430 431
                goto fail;
            }
            DPRINTF("Command on LUN %d\n", cbw.lun);
432 433
            scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun);
            if (scsi_dev == NULL) {
434
                error_report("usb-msd: Bad LUN %d", cbw.lun);
P
pbrook 已提交
435 436
                goto fail;
            }
437
            tag = le32_to_cpu(cbw.tag);
P
pbrook 已提交
438 439 440 441 442 443 444 445 446
            s->data_len = le32_to_cpu(cbw.data_len);
            if (s->data_len == 0) {
                s->mode = USB_MSDM_CSW;
            } else if (cbw.flags & 0x80) {
                s->mode = USB_MSDM_DATAIN;
            } else {
                s->mode = USB_MSDM_DATAOUT;
            }
            DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
447
                    tag, cbw.flags, cbw.cmd_len, s->data_len);
448
            assert(le32_to_cpu(s->csw.residue) == 0);
G
Gerd Hoffmann 已提交
449
            s->scsi_len = 0;
450
            s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL);
451 452 453
#ifdef DEBUG_MSD
            scsi_req_print(s->req);
#endif
454 455
            len = scsi_req_enqueue(s->req);
            if (len) {
456
                scsi_req_continue(s->req);
P
pbrook 已提交
457
            }
P
pbrook 已提交
458 459 460
            break;

        case USB_MSDM_DATAOUT:
G
Gerd Hoffmann 已提交
461 462
            DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
            if (p->iov.size > s->data_len) {
P
pbrook 已提交
463
                goto fail;
G
Gerd Hoffmann 已提交
464
            }
P
pbrook 已提交
465

P
pbrook 已提交
466
            if (s->scsi_len) {
G
Gerd Hoffmann 已提交
467
                usb_msd_copy_data(s, p);
P
pbrook 已提交
468
            }
469
            if (le32_to_cpu(s->csw.residue)) {
470
                int len = p->iov.size - p->actual_length;
G
Gerd Hoffmann 已提交
471 472 473 474 475 476 477
                if (len) {
                    usb_packet_skip(p, len);
                    s->data_len -= len;
                    if (s->data_len == 0) {
                        s->mode = USB_MSDM_CSW;
                    }
                }
P
pbrook 已提交
478
            }
479
            if (p->actual_length < p->iov.size) {
480
                DPRINTF("Deferring packet %p [wait data-out]\n", p);
P
pbrook 已提交
481
                s->packet = p;
482
                p->status = USB_RET_ASYNC;
P
pbrook 已提交
483
            }
P
pbrook 已提交
484 485 486
            break;

        default:
G
Gerd Hoffmann 已提交
487
            DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
P
pbrook 已提交
488 489 490 491 492 493 494 495 496
            goto fail;
        }
        break;

    case USB_TOKEN_IN:
        if (devep != 1)
            goto fail;

        switch (s->mode) {
P
pbrook 已提交
497
        case USB_MSDM_DATAOUT:
G
Gerd Hoffmann 已提交
498
            if (s->data_len != 0 || p->iov.size < 13) {
P
pbrook 已提交
499
                goto fail;
G
Gerd Hoffmann 已提交
500
            }
P
pbrook 已提交
501 502
            /* Waiting for SCSI write to complete.  */
            s->packet = p;
503
            p->status = USB_RET_ASYNC;
P
pbrook 已提交
504 505
            break;

P
pbrook 已提交
506
        case USB_MSDM_CSW:
G
Gerd Hoffmann 已提交
507
            if (p->iov.size < 13) {
P
pbrook 已提交
508
                goto fail;
G
Gerd Hoffmann 已提交
509
            }
P
pbrook 已提交
510

511 512
            if (s->req) {
                /* still in flight */
513
                DPRINTF("Deferring packet %p [wait status]\n", p);
514
                s->packet = p;
515
                p->status = USB_RET_ASYNC;
516 517 518 519
            } else {
                usb_msd_send_status(s, p);
                s->mode = USB_MSDM_CBW;
            }
P
pbrook 已提交
520 521 522
            break;

        case USB_MSDM_DATAIN:
G
Gerd Hoffmann 已提交
523 524
            DPRINTF("Data in %zd/%d, scsi_len %d\n",
                    p->iov.size, s->data_len, s->scsi_len);
P
pbrook 已提交
525
            if (s->scsi_len) {
G
Gerd Hoffmann 已提交
526
                usb_msd_copy_data(s, p);
P
pbrook 已提交
527
            }
528
            if (le32_to_cpu(s->csw.residue)) {
529
                int len = p->iov.size - p->actual_length;
G
Gerd Hoffmann 已提交
530 531 532 533 534 535 536
                if (len) {
                    usb_packet_skip(p, len);
                    s->data_len -= len;
                    if (s->data_len == 0) {
                        s->mode = USB_MSDM_CSW;
                    }
                }
P
pbrook 已提交
537
            }
538
            if (p->actual_length < p->iov.size) {
539
                DPRINTF("Deferring packet %p [wait data-in]\n", p);
P
pbrook 已提交
540
                s->packet = p;
541
                p->status = USB_RET_ASYNC;
P
pbrook 已提交
542
            }
P
pbrook 已提交
543 544 545
            break;

        default:
G
Gerd Hoffmann 已提交
546
            DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
P
pbrook 已提交
547 548 549 550 551 552 553
            goto fail;
        }
        break;

    default:
        DPRINTF("Bad token\n");
    fail:
554
        p->status = USB_RET_STALL;
P
pbrook 已提交
555 556 557 558
        break;
    }
}

G
Gerd Hoffmann 已提交
559 560 561 562 563 564 565 566 567 568 569
static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
{
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);

    /* nothing to load, just store req in our state struct */
    assert(s->req == NULL);
    scsi_req_ref(req);
    s->req = req;
    return NULL;
}

570
static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
571
    .tcq = false,
P
Paolo Bonzini 已提交
572 573
    .max_target = 0,
    .max_lun = 0,
574

575
    .transfer_data = usb_msd_transfer_data,
P
Paolo Bonzini 已提交
576
    .complete = usb_msd_command_complete,
G
Gerd Hoffmann 已提交
577 578
    .cancel = usb_msd_request_cancelled,
    .load_request = usb_msd_load_request,
P
Paolo Bonzini 已提交
579 580
};

581 582 583 584 585 586 587 588 589 590 591
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,
};

592 593 594 595 596 597 598
static void usb_msd_unrealize_storage(USBDevice *dev, Error **errp)
{
    MSDState *s = USB_STORAGE_DEV(dev);

    object_unref(OBJECT(&s->bus));
}

599
static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
600
{
G
Gonglei 已提交
601
    MSDState *s = USB_STORAGE_DEV(dev);
602
    BlockBackend *blk = s->conf.blk;
603
    SCSIDevice *scsi_dev;
604

605
    if (!blk) {
G
Gonglei 已提交
606 607
        error_setg(errp, "drive property not set");
        return;
608 609
    }

G
Gerd Hoffmann 已提交
610
    blkconf_serial(&s->conf, &dev->serial);
611
    blkconf_blocksizes(&s->conf);
612 613
    if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
                                       errp)) {
K
Kevin Wolf 已提交
614 615
        return;
    }
616

617 618 619
    /*
     * Hack alert: this pretends to be a block device, but it's really
     * a SCSI bus that can serve only a single device, which it
620 621
     * creates automatically.  But first it needs to detach from its
     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
622 623
     * attaches again. We also need to take another reference so that
     * blk_detach_dev() doesn't free blk while we still need it.
624 625 626
     *
     * The hack is probably a bad idea.
     */
627
    blk_ref(blk);
628 629
    blk_detach_dev(blk, &s->dev.qdev);
    s->conf.blk = NULL;
630

G
Gerd Hoffmann 已提交
631
    usb_desc_create_serial(dev);
632
    usb_desc_init(dev);
633 634
    scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
                 &usb_msd_scsi_info_storage, NULL);
635
    scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
636
                                         s->conf.bootindex, dev->serial,
637
                                         errp);
638
    blk_unref(blk);
639
    if (!scsi_dev) {
G
Gonglei 已提交
640
        return;
641
    }
642
    usb_msd_handle_reset(dev);
643
    s->scsi_dev = scsi_dev;
644 645
}

646
static void usb_msd_bot_unrealize(USBDevice *dev, Error **errp)
647 648 649 650 651 652
{
    MSDState *s = USB_STORAGE_DEV(dev);

    object_unref(OBJECT(&s->bus));
}

653
static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
654
{
G
Gonglei 已提交
655
    MSDState *s = USB_STORAGE_DEV(dev);
G
Gerd Hoffmann 已提交
656
    DeviceState *d = DEVICE(dev);
657 658 659

    usb_desc_create_serial(dev);
    usb_desc_init(dev);
G
Gerd Hoffmann 已提交
660 661 662 663
    if (d->hotplugged) {
        s->dev.auto_attach = 0;
    }

664 665
    scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
                 &usb_msd_scsi_info_bot, NULL);
666 667 668
    usb_msd_handle_reset(dev);
}

669
static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
P
pbrook 已提交
670
{
671
    static int nr=0;
672
    Error *err = NULL;
673 674 675
    char id[8];
    QemuOpts *opts;
    DriveInfo *dinfo;
676
    USBDevice *dev;
677 678 679
    const char *p1;
    char fmt[32];

680
    /* parse -usbdevice disk: syntax into drive opts */
681 682 683 684
    do {
        snprintf(id, sizeof(id), "usb%d", nr++);
        opts = qemu_opts_create(qemu_find_opts("drive"), id, 1, NULL);
    } while (!opts);
685

686 687 688 689 690 691 692
    p1 = strchr(filename, ':');
    if (p1++) {
        const char *p2;

        if (strstart(filename, "format=", &p2)) {
            int len = MIN(p1 - p2, sizeof(fmt));
            pstrcpy(fmt, len, p2);
693
            qemu_opt_set(opts, "format", fmt, &error_abort);
694
        } else if (*filename != ':') {
695
            error_report("unrecognized USB mass-storage option %s", filename);
696 697 698 699 700
            return NULL;
        }
        filename = p1;
    }
    if (!*filename) {
701
        error_report("block device specification needed");
702 703
        return NULL;
    }
704 705
    qemu_opt_set(opts, "file", filename, &error_abort);
    qemu_opt_set(opts, "if", "none", &error_abort);
P
pbrook 已提交
706

707
    /* create host drive */
708
    dinfo = drive_new(opts, 0);
709 710
    if (!dinfo) {
        qemu_opts_del(opts);
711
        return NULL;
712
    }
P
pbrook 已提交
713

714
    /* create guest device */
715
    dev = usb_create(bus, "usb-storage");
716 717 718 719
    qdev_prop_set_drive(&dev->qdev, "drive", blk_by_legacy_dinfo(dinfo),
                        &err);
    if (err) {
        error_report_err(err);
720
        object_unparent(OBJECT(dev));
721 722
        return NULL;
    }
723
    return dev;
P
pbrook 已提交
724
}
725

726 727 728 729
static const VMStateDescription vmstate_usb_msd = {
    .name = "usb-storage",
    .version_id = 1,
    .minimum_version_id = 1,
730
    .fields = (VMStateField[]) {
731
        VMSTATE_USB_DEVICE(dev, MSDState),
G
Gerd Hoffmann 已提交
732 733 734 735 736 737 738 739
        VMSTATE_UINT32(mode, MSDState),
        VMSTATE_UINT32(scsi_len, MSDState),
        VMSTATE_UINT32(scsi_off, MSDState),
        VMSTATE_UINT32(data_len, MSDState),
        VMSTATE_UINT32(csw.sig, MSDState),
        VMSTATE_UINT32(csw.tag, MSDState),
        VMSTATE_UINT32(csw.residue, MSDState),
        VMSTATE_UINT8(csw.status, MSDState),
740 741 742 743
        VMSTATE_END_OF_LIST()
    }
};

744 745 746 747 748 749
static Property msd_properties[] = {
    DEFINE_BLOCK_PROPERTIES(MSDState, conf),
    DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
    DEFINE_PROP_END_OF_LIST(),
};

G
Gonglei 已提交
750
static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
751
{
752
    DeviceClass *dc = DEVICE_CLASS(klass);
753 754 755 756 757 758 759 760 761
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

    uc->product_desc   = "QEMU USB MSD";
    uc->usb_desc       = &desc;
    uc->cancel_packet  = usb_msd_cancel_io;
    uc->handle_attach  = usb_desc_attach;
    uc->handle_reset   = usb_msd_handle_reset;
    uc->handle_control = usb_msd_handle_control;
    uc->handle_data    = usb_msd_handle_data;
762
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
763 764
    dc->fw_name = "storage";
    dc->vmsd = &vmstate_usb_msd;
765 766
}

767
static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
768 769 770 771
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

772
    uc->realize = usb_msd_storage_realize;
773
    uc->unrealize = usb_msd_unrealize_storage;
774
    dc->props = msd_properties;
775 776
}

777 778
static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
                                  void *opaque, Error **errp)
779 780
{
    USBDevice *dev = USB_DEVICE(obj);
G
Gonglei 已提交
781
    MSDState *s = USB_STORAGE_DEV(dev);
782

783
    visit_type_int32(v, name, &s->conf.bootindex, errp);
784 785
}

786 787
static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
                                  void *opaque, Error **errp)
788 789
{
    USBDevice *dev = USB_DEVICE(obj);
G
Gonglei 已提交
790
    MSDState *s = USB_STORAGE_DEV(dev);
791 792 793
    int32_t boot_index;
    Error *local_err = NULL;

794
    visit_type_int32(v, name, &boot_index, &local_err);
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
    if (local_err) {
        goto out;
    }
    /* check whether bootindex is present in fw_boot_order list  */
    check_boot_index(boot_index, &local_err);
    if (local_err) {
        goto out;
    }
    /* change bootindex to a new one */
    s->conf.bootindex = boot_index;

    if (s->scsi_dev) {
        object_property_set_int(OBJECT(s->scsi_dev), boot_index, "bootindex",
                                &error_abort);
    }

out:
812
    error_propagate(errp, local_err);
813 814
}

G
Gonglei 已提交
815 816 817 818 819 820 821 822
static const TypeInfo usb_storage_dev_type_info = {
    .name = TYPE_USB_STORAGE,
    .parent = TYPE_USB_DEVICE,
    .instance_size = sizeof(MSDState),
    .abstract = true,
    .class_init = usb_msd_class_initfn_common,
};

823 824 825 826 827 828 829 830
static void usb_msd_instance_init(Object *obj)
{
    object_property_add(obj, "bootindex", "int32",
                        usb_msd_get_bootindex,
                        usb_msd_set_bootindex, NULL, NULL, NULL);
    object_property_set_int(obj, -1, "bootindex", NULL);
}

831
static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data)
832 833 834
{
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

835 836
    uc->realize = usb_msd_bot_realize;
    uc->unrealize = usb_msd_bot_unrealize;
G
Gerd Hoffmann 已提交
837
    uc->attached_settable = true;
838 839
}

840
static const TypeInfo msd_info = {
841
    .name          = "usb-storage",
G
Gonglei 已提交
842
    .parent        = TYPE_USB_STORAGE,
843
    .class_init    = usb_msd_class_storage_initfn,
844
    .instance_init = usb_msd_instance_init,
845 846 847 848
};

static const TypeInfo bot_info = {
    .name          = "usb-bot",
G
Gonglei 已提交
849
    .parent        = TYPE_USB_STORAGE,
850
    .class_init    = usb_msd_class_bot_initfn,
851 852
};

A
Andreas Färber 已提交
853
static void usb_msd_register_types(void)
854
{
G
Gonglei 已提交
855
    type_register_static(&usb_storage_dev_type_info);
856
    type_register_static(&msd_info);
857
    type_register_static(&bot_info);
858
    usb_legacy_register("usb-storage", "disk", usb_msd_init);
859
}
A
Andreas Färber 已提交
860 861

type_init(usb_msd_register_types)