dev-storage.c 24.4 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;
    }
}

559 560 561
static void usb_msd_password_cb(void *opaque, int err)
{
    MSDState *s = opaque;
562
    Error *local_err = NULL;
563

564 565 566
    if (!err) {
        usb_device_attach(&s->dev, &local_err);
    }
567

568
    if (local_err) {
569
        error_report_err(local_err);
570
        qdev_unplug(&s->dev.qdev, NULL);
571
    }
572 573
}

G
Gerd Hoffmann 已提交
574 575 576 577 578 579 580 581 582 583 584
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;
}

585
static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
586
    .tcq = false,
P
Paolo Bonzini 已提交
587 588
    .max_target = 0,
    .max_lun = 0,
589

590
    .transfer_data = usb_msd_transfer_data,
P
Paolo Bonzini 已提交
591
    .complete = usb_msd_command_complete,
G
Gerd Hoffmann 已提交
592 593
    .cancel = usb_msd_request_cancelled,
    .load_request = usb_msd_load_request,
P
Paolo Bonzini 已提交
594 595
};

596 597 598 599 600 601 602 603 604 605 606
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,
};

G
Gonglei 已提交
607
static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
608
{
G
Gonglei 已提交
609
    MSDState *s = USB_STORAGE_DEV(dev);
610
    BlockBackend *blk = s->conf.blk;
611
    SCSIDevice *scsi_dev;
612
    Error *err = NULL;
613

614
    if (!blk) {
G
Gonglei 已提交
615 616
        error_setg(errp, "drive property not set");
        return;
617 618
    }

619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
    if (blk_bs(blk)) {
        bdrv_add_key(blk_bs(blk), NULL, &err);
        if (err) {
            if (monitor_cur_is_qmp()) {
                error_propagate(errp, err);
                return;
            }
            error_free(err);
            err = NULL;
            if (cur_mon) {
                monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
                                            usb_msd_password_cb, s);
                s->dev.auto_attach = 0;
            } else {
                autostart = 0;
            }
635 636 637
        }
    }

G
Gerd Hoffmann 已提交
638
    blkconf_serial(&s->conf, &dev->serial);
639
    blkconf_blocksizes(&s->conf);
640

641 642 643
    /*
     * 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
644 645 646
     * creates automatically.  But first it needs to detach from its
     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
     * attaches again.
647 648 649
     *
     * The hack is probably a bad idea.
     */
650 651
    blk_detach_dev(blk, &s->dev.qdev);
    s->conf.blk = NULL;
652

G
Gerd Hoffmann 已提交
653
    usb_desc_create_serial(dev);
654
    usb_desc_init(dev);
655 656
    scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
                 &usb_msd_scsi_info_storage, NULL);
657
    scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
658 659
                                         s->conf.bootindex, dev->serial,
                                         &err);
660
    if (!scsi_dev) {
G
Gonglei 已提交
661 662
        error_propagate(errp, err);
        return;
663
    }
664
    usb_msd_handle_reset(dev);
665
    s->scsi_dev = scsi_dev;
666 667
}

G
Gonglei 已提交
668
static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
669
{
G
Gonglei 已提交
670
    MSDState *s = USB_STORAGE_DEV(dev);
671 672 673

    usb_desc_create_serial(dev);
    usb_desc_init(dev);
674 675
    scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
                 &usb_msd_scsi_info_bot, NULL);
676 677 678
    usb_msd_handle_reset(dev);
}

679
static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
P
pbrook 已提交
680
{
681
    static int nr=0;
682
    Error *err = NULL;
683 684 685
    char id[8];
    QemuOpts *opts;
    DriveInfo *dinfo;
686
    USBDevice *dev;
687 688 689
    const char *p1;
    char fmt[32];

690
    /* parse -usbdevice disk: syntax into drive opts */
691 692 693 694
    do {
        snprintf(id, sizeof(id), "usb%d", nr++);
        opts = qemu_opts_create(qemu_find_opts("drive"), id, 1, NULL);
    } while (!opts);
695

696 697 698 699 700 701 702
    p1 = strchr(filename, ':');
    if (p1++) {
        const char *p2;

        if (strstart(filename, "format=", &p2)) {
            int len = MIN(p1 - p2, sizeof(fmt));
            pstrcpy(fmt, len, p2);
703
            qemu_opt_set(opts, "format", fmt, &error_abort);
704
        } else if (*filename != ':') {
705
            error_report("unrecognized USB mass-storage option %s", filename);
706 707 708 709 710
            return NULL;
        }
        filename = p1;
    }
    if (!*filename) {
711
        error_report("block device specification needed");
712 713
        return NULL;
    }
714 715
    qemu_opt_set(opts, "file", filename, &error_abort);
    qemu_opt_set(opts, "if", "none", &error_abort);
P
pbrook 已提交
716

717
    /* create host drive */
718
    dinfo = drive_new(opts, 0);
719 720
    if (!dinfo) {
        qemu_opts_del(opts);
721
        return NULL;
722
    }
P
pbrook 已提交
723

724
    /* create guest device */
725
    dev = usb_create(bus, "usb-storage");
726 727 728 729
    qdev_prop_set_drive(&dev->qdev, "drive", blk_by_legacy_dinfo(dinfo),
                        &err);
    if (err) {
        error_report_err(err);
730
        object_unparent(OBJECT(dev));
731 732
        return NULL;
    }
733
    return dev;
P
pbrook 已提交
734
}
735

736 737 738 739
static const VMStateDescription vmstate_usb_msd = {
    .name = "usb-storage",
    .version_id = 1,
    .minimum_version_id = 1,
740
    .fields = (VMStateField[]) {
741
        VMSTATE_USB_DEVICE(dev, MSDState),
G
Gerd Hoffmann 已提交
742 743 744 745 746 747 748 749
        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),
750 751 752 753
        VMSTATE_END_OF_LIST()
    }
};

754 755 756 757 758 759
static Property msd_properties[] = {
    DEFINE_BLOCK_PROPERTIES(MSDState, conf),
    DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
    DEFINE_PROP_END_OF_LIST(),
};

G
Gonglei 已提交
760
static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
761
{
762
    DeviceClass *dc = DEVICE_CLASS(klass);
763 764 765 766 767 768 769 770 771
    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;
772
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
773 774
    dc->fw_name = "storage";
    dc->vmsd = &vmstate_usb_msd;
775 776 777 778 779 780 781
}

static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

G
Gonglei 已提交
782
    uc->realize = usb_msd_realize_storage;
783
    dc->props = msd_properties;
784 785
}

786 787
static void usb_msd_get_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
    visit_type_int32(v, name, &s->conf.bootindex, errp);
793 794
}

795 796
static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
                                  void *opaque, Error **errp)
797 798
{
    USBDevice *dev = USB_DEVICE(obj);
G
Gonglei 已提交
799
    MSDState *s = USB_STORAGE_DEV(dev);
800 801 802
    int32_t boot_index;
    Error *local_err = NULL;

803
    visit_type_int32(v, name, &boot_index, &local_err);
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
    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:
821
    error_propagate(errp, local_err);
822 823
}

G
Gonglei 已提交
824 825 826 827 828 829 830 831
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,
};

832 833 834 835 836 837 838 839
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);
}

840 841 842
static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
{
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
843
    DeviceClass *dc = DEVICE_CLASS(klass);
844

G
Gonglei 已提交
845
    uc->realize = usb_msd_realize_bot;
846
    dc->hotpluggable = false;
847 848
}

849
static const TypeInfo msd_info = {
850
    .name          = "usb-storage",
G
Gonglei 已提交
851
    .parent        = TYPE_USB_STORAGE,
852
    .class_init    = usb_msd_class_initfn_storage,
853
    .instance_init = usb_msd_instance_init,
854 855 856 857
};

static const TypeInfo bot_info = {
    .name          = "usb-bot",
G
Gonglei 已提交
858
    .parent        = TYPE_USB_STORAGE,
859
    .class_init    = usb_msd_class_initfn_bot,
860 861
};

A
Andreas Färber 已提交
862
static void usb_msd_register_types(void)
863
{
G
Gonglei 已提交
864
    type_register_static(&usb_storage_dev_type_info);
865
    type_register_static(&msd_info);
866
    type_register_static(&bot_info);
867
    usb_legacy_register("usb-storage", "disk", usb_msd_init);
868
}
A
Andreas Färber 已提交
869 870

type_init(usb_msd_register_types)