dev-storage.c 23.8 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
pbrook 已提交
10
#include "qemu-common.h"
11 12
#include "qemu/option.h"
#include "qemu/config-file.h"
G
Gerd Hoffmann 已提交
13 14
#include "hw/usb.h"
#include "hw/usb/desc.h"
P
Paolo Bonzini 已提交
15
#include "hw/scsi/scsi.h"
16
#include "ui/console.h"
17
#include "monitor/monitor.h"
18
#include "sysemu/sysemu.h"
19
#include "sysemu/block-backend.h"
20
#include "sysemu/blockdev.h"
21
#include "qapi/visitor.h"
P
pbrook 已提交
22 23 24 25

//#define DEBUG_MSD

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

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

enum USBMSDMode {
    USB_MSDM_CBW, /* Command Block.  */
B
Brad Hards 已提交
38
    USB_MSDM_DATAOUT, /* Transfer data to device.  */
P
pbrook 已提交
39 40 41 42
    USB_MSDM_DATAIN, /* Transfer data from device.  */
    USB_MSDM_CSW /* Command Status.  */
};

43 44 45 46 47 48 49
struct usb_msd_csw {
    uint32_t sig;
    uint32_t tag;
    uint32_t residue;
    uint8_t status;
};

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

P
pbrook 已提交
67 68 69 70 71 72 73 74 75 76
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];
};

77 78 79 80
enum {
    STR_MANUFACTURER = 1,
    STR_PRODUCT,
    STR_SERIALNUMBER,
G
Gerd Hoffmann 已提交
81 82
    STR_CONFIG_FULL,
    STR_CONFIG_HIGH,
G
Gerd Hoffmann 已提交
83
    STR_CONFIG_SUPER,
P
pbrook 已提交
84 85
};

86
static const USBDescStrings desc_strings = {
87
    [STR_MANUFACTURER] = "QEMU",
88 89
    [STR_PRODUCT]      = "QEMU USB HARDDRIVE",
    [STR_SERIALNUMBER] = "1",
G
Gerd Hoffmann 已提交
90 91
    [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
    [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
G
Gerd Hoffmann 已提交
92
    [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
93 94
};

G
Gerd Hoffmann 已提交
95
static const USBDescIface desc_iface_full = {
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
    .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 已提交
114 115
static const USBDescDevice desc_device_full = {
    .bcdUSB                        = 0x0200,
116 117 118 119 120 121
    .bMaxPacketSize0               = 8,
    .bNumConfigurations            = 1,
    .confs = (USBDescConfig[]) {
        {
            .bNumInterfaces        = 1,
            .bConfigurationValue   = 1,
G
Gerd Hoffmann 已提交
122
            .iConfiguration        = STR_CONFIG_FULL,
123
            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
124
            .nif = 1,
G
Gerd Hoffmann 已提交
125 126 127 128 129 130 131 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
            .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,
158
            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
159
            .nif = 1,
G
Gerd Hoffmann 已提交
160
            .ifs = &desc_iface_high,
161 162 163 164
        },
    },
};

G
Gerd Hoffmann 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
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,
195
            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
G
Gerd Hoffmann 已提交
196 197 198 199 200 201
            .nif = 1,
            .ifs = &desc_iface_super,
        },
    },
};

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

G
Gerd Hoffmann 已提交
217
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
P
pbrook 已提交
218 219
{
    uint32_t len;
220
    len = p->iov.size - p->actual_length;
P
pbrook 已提交
221 222
    if (len > s->scsi_len)
        len = s->scsi_len;
223
    usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
P
pbrook 已提交
224
    s->scsi_len -= len;
225
    s->scsi_off += len;
P
pbrook 已提交
226
    s->data_len -= len;
227
    if (s->scsi_len == 0 || s->data_len == 0) {
228
        scsi_req_continue(s->req);
P
pbrook 已提交
229 230 231
    }
}

232
static void usb_msd_send_status(MSDState *s, USBPacket *p)
P
pbrook 已提交
233
{
234
    int len;
P
pbrook 已提交
235

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

239
    assert(s->csw.sig == cpu_to_le32(0x53425355));
240 241 242
    len = MIN(sizeof(s->csw), p->iov.size);
    usb_packet_copy(p, &s->csw, len);
    memset(&s->csw, 0, sizeof(s->csw));
P
pbrook 已提交
243 244
}

245 246 247 248 249 250 251 252 253 254 255 256
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);
}

257
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
P
pbrook 已提交
258
{
259
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
P
pbrook 已提交
260
    USBPacket *p = s->packet;
P
pbrook 已提交
261

262
    assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
263
    s->scsi_len = len;
264
    s->scsi_off = 0;
P
pbrook 已提交
265
    if (p) {
G
Gerd Hoffmann 已提交
266 267
        usb_msd_copy_data(s, p);
        p = s->packet;
268 269
        if (p && p->actual_length == p->iov.size) {
            p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
270
            usb_msd_packet_complete(s);
P
pbrook 已提交
271
        }
P
pbrook 已提交
272
    }
P
pbrook 已提交
273 274
}

275
static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
276 277 278 279
{
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
    USBPacket *p = s->packet;

280
    DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
281 282

    s->csw.sig = cpu_to_le32(0x53425355);
283
    s->csw.tag = cpu_to_le32(req->tag);
284
    s->csw.residue = cpu_to_le32(s->data_len);
285
    s->csw.status = status != 0;
286

287 288 289 290 291 292
    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;
293 294 295
        } else if (s->mode == USB_MSDM_CSW) {
            usb_msd_send_status(s, p);
            s->mode = USB_MSDM_CBW;
296 297
        } else {
            if (s->data_len) {
298
                int len = (p->iov.size - p->actual_length);
G
Gerd Hoffmann 已提交
299 300
                usb_packet_skip(p, len);
                s->data_len -= len;
301 302 303 304 305
            }
            if (s->data_len == 0) {
                s->mode = USB_MSDM_CSW;
            }
        }
306
        p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
307
        usb_msd_packet_complete(s);
308 309 310 311 312 313 314
    } else if (s->data_len == 0) {
        s->mode = USB_MSDM_CSW;
    }
    scsi_req_unref(req);
    s->req = NULL;
}

P
Paolo Bonzini 已提交
315 316 317 318 319 320 321 322 323 324 325
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 已提交
326
static void usb_msd_handle_reset(USBDevice *dev)
P
pbrook 已提交
327 328 329 330
{
    MSDState *s = (MSDState *)dev;

    DPRINTF("Reset\n");
G
Gerd Hoffmann 已提交
331 332 333 334 335 336
    if (s->req) {
        scsi_req_cancel(s->req);
    }
    assert(s->req == NULL);

    if (s->packet) {
337
        s->packet->status = USB_RET_STALL;
338
        usb_msd_packet_complete(s);
G
Gerd Hoffmann 已提交
339 340
    }

P
pbrook 已提交
341 342 343
    s->mode = USB_MSDM_CBW;
}

344
static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
345
               int request, int value, int index, int length, uint8_t *data)
P
pbrook 已提交
346 347
{
    MSDState *s = (MSDState *)dev;
348 349
    SCSIDevice *scsi_dev;
    int ret, maxlun;
P
pbrook 已提交
350

351
    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
352
    if (ret >= 0) {
353
        return;
354 355
    }

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

386
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
P
pbrook 已提交
387
{
388
    MSDState *s = DO_UPCAST(MSDState, dev, dev);
389

390 391 392
    assert(s->packet == p);
    s->packet = NULL;

393 394 395
    if (s->req) {
        scsi_req_cancel(s->req);
    }
P
pbrook 已提交
396 397
}

398
static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
P
pbrook 已提交
399 400
{
    MSDState *s = (MSDState *)dev;
401
    uint32_t tag;
P
pbrook 已提交
402
    struct usb_msd_cbw cbw;
403
    uint8_t devep = p->ep->nr;
404
    SCSIDevice *scsi_dev;
405
    uint32_t len;
P
pbrook 已提交
406

P
pbrook 已提交
407
    switch (p->pid) {
P
pbrook 已提交
408 409 410 411 412 413
    case USB_TOKEN_OUT:
        if (devep != 2)
            goto fail;

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

        case USB_MSDM_DATAOUT:
G
Gerd Hoffmann 已提交
454 455
            DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
            if (p->iov.size > s->data_len) {
P
pbrook 已提交
456
                goto fail;
G
Gerd Hoffmann 已提交
457
            }
P
pbrook 已提交
458

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

        default:
G
Gerd Hoffmann 已提交
480
            DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
P
pbrook 已提交
481 482 483 484 485 486 487 488 489
            goto fail;
        }
        break;

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

        switch (s->mode) {
P
pbrook 已提交
490
        case USB_MSDM_DATAOUT:
G
Gerd Hoffmann 已提交
491
            if (s->data_len != 0 || p->iov.size < 13) {
P
pbrook 已提交
492
                goto fail;
G
Gerd Hoffmann 已提交
493
            }
P
pbrook 已提交
494 495
            /* Waiting for SCSI write to complete.  */
            s->packet = p;
496
            p->status = USB_RET_ASYNC;
P
pbrook 已提交
497 498
            break;

P
pbrook 已提交
499
        case USB_MSDM_CSW:
G
Gerd Hoffmann 已提交
500
            if (p->iov.size < 13) {
P
pbrook 已提交
501
                goto fail;
G
Gerd Hoffmann 已提交
502
            }
P
pbrook 已提交
503

504 505
            if (s->req) {
                /* still in flight */
506
                DPRINTF("Deferring packet %p [wait status]\n", p);
507
                s->packet = p;
508
                p->status = USB_RET_ASYNC;
509 510 511 512
            } else {
                usb_msd_send_status(s, p);
                s->mode = USB_MSDM_CBW;
            }
P
pbrook 已提交
513 514 515
            break;

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

        default:
G
Gerd Hoffmann 已提交
539
            DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
P
pbrook 已提交
540 541 542 543 544 545 546
            goto fail;
        }
        break;

    default:
        DPRINTF("Bad token\n");
    fail:
547
        p->status = USB_RET_STALL;
P
pbrook 已提交
548 549 550 551
        break;
    }
}

552 553 554
static void usb_msd_password_cb(void *opaque, int err)
{
    MSDState *s = opaque;
555
    Error *local_err = NULL;
556

557 558 559
    if (!err) {
        usb_device_attach(&s->dev, &local_err);
    }
560

561 562 563
    if (local_err) {
        qerror_report_err(local_err);
        error_free(local_err);
564
        qdev_unplug(&s->dev.qdev, NULL);
565
    }
566 567
}

G
Gerd Hoffmann 已提交
568 569 570 571 572 573 574 575 576 577 578
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;
}

579
static const struct SCSIBusInfo usb_msd_scsi_info_storage = {
580
    .tcq = false,
P
Paolo Bonzini 已提交
581 582
    .max_target = 0,
    .max_lun = 0,
583

584
    .transfer_data = usb_msd_transfer_data,
P
Paolo Bonzini 已提交
585
    .complete = usb_msd_command_complete,
G
Gerd Hoffmann 已提交
586 587
    .cancel = usb_msd_request_cancelled,
    .load_request = usb_msd_load_request,
P
Paolo Bonzini 已提交
588 589
};

590 591 592 593 594 595 596 597 598 599 600
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 已提交
601
static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
602 603
{
    MSDState *s = DO_UPCAST(MSDState, dev, dev);
604
    BlockBackend *blk = s->conf.blk;
605
    SCSIDevice *scsi_dev;
606
    Error *err = NULL;
607

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

G
Gerd Hoffmann 已提交
613
    blkconf_serial(&s->conf, &dev->serial);
614

615 616 617
    /*
     * 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
618 619 620
     * creates automatically.  But first it needs to detach from its
     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
     * attaches again.
621 622 623
     *
     * The hack is probably a bad idea.
     */
624 625
    blk_detach_dev(blk, &s->dev.qdev);
    s->conf.blk = NULL;
626

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

641
    if (bdrv_key_required(blk_bs(blk))) {
642
        if (cur_mon) {
643 644
            monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
                                        usb_msd_password_cb, s);
645 646 647 648 649
            s->dev.auto_attach = 0;
        } else {
            autostart = 0;
        }
    }
650 651
}

G
Gonglei 已提交
652
static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
653 654 655 656 657
{
    MSDState *s = DO_UPCAST(MSDState, dev, dev);

    usb_desc_create_serial(dev);
    usb_desc_init(dev);
658 659
    scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
                 &usb_msd_scsi_info_bot, NULL);
660 661 662
    usb_msd_handle_reset(dev);
}

663
static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
P
pbrook 已提交
664
{
665 666 667 668
    static int nr=0;
    char id[8];
    QemuOpts *opts;
    DriveInfo *dinfo;
669
    USBDevice *dev;
670 671 672
    const char *p1;
    char fmt[32];

673
    /* parse -usbdevice disk: syntax into drive opts */
674 675 676 677
    do {
        snprintf(id, sizeof(id), "usb%d", nr++);
        opts = qemu_opts_create(qemu_find_opts("drive"), id, 1, NULL);
    } while (!opts);
678

679 680 681 682 683 684 685
    p1 = strchr(filename, ':');
    if (p1++) {
        const char *p2;

        if (strstart(filename, "format=", &p2)) {
            int len = MIN(p1 - p2, sizeof(fmt));
            pstrcpy(fmt, len, p2);
686
            qemu_opt_set(opts, "format", fmt);
687
        } else if (*filename != ':') {
688
            error_report("unrecognized USB mass-storage option %s", filename);
689 690 691 692 693
            return NULL;
        }
        filename = p1;
    }
    if (!*filename) {
694
        error_report("block device specification needed");
695 696
        return NULL;
    }
697 698
    qemu_opt_set(opts, "file", filename);
    qemu_opt_set(opts, "if", "none");
P
pbrook 已提交
699

700
    /* create host drive */
701
    dinfo = drive_new(opts, 0);
702 703
    if (!dinfo) {
        qemu_opts_del(opts);
704
        return NULL;
705
    }
P
pbrook 已提交
706

707
    /* create guest device */
708
    dev = usb_create(bus, "usb-storage");
709
    if (qdev_prop_set_drive(&dev->qdev, "drive",
710
                            blk_by_legacy_dinfo(dinfo)) < 0) {
711
        object_unparent(OBJECT(dev));
712 713
        return NULL;
    }
714 715
    if (qdev_init(&dev->qdev) < 0)
        return NULL;
716

717
    return dev;
P
pbrook 已提交
718
}
719

720 721 722 723
static const VMStateDescription vmstate_usb_msd = {
    .name = "usb-storage",
    .version_id = 1,
    .minimum_version_id = 1,
724
    .fields = (VMStateField[]) {
725
        VMSTATE_USB_DEVICE(dev, MSDState),
G
Gerd Hoffmann 已提交
726 727 728 729 730 731 732 733
        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),
734 735 736 737
        VMSTATE_END_OF_LIST()
    }
};

738 739 740 741 742 743
static Property msd_properties[] = {
    DEFINE_BLOCK_PROPERTIES(MSDState, conf),
    DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
    DEFINE_PROP_END_OF_LIST(),
};

744
static void usb_msd_class_initfn_common(ObjectClass *klass)
745
{
746
    DeviceClass *dc = DEVICE_CLASS(klass);
747 748 749 750 751 752 753 754 755
    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;
756
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
757 758
    dc->fw_name = "storage";
    dc->vmsd = &vmstate_usb_msd;
759 760 761 762 763 764 765
}

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

G
Gonglei 已提交
766
    uc->realize = usb_msd_realize_storage;
767
    dc->props = msd_properties;
768 769 770
    usb_msd_class_initfn_common(klass);
}

771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
static void usb_msd_get_bootindex(Object *obj, Visitor *v, void *opaque,
                                  const char *name, Error **errp)
{
    USBDevice *dev = USB_DEVICE(obj);
    MSDState *s = DO_UPCAST(MSDState, dev, dev);

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

static void usb_msd_set_bootindex(Object *obj, Visitor *v, void *opaque,
                                  const char *name, Error **errp)
{
    USBDevice *dev = USB_DEVICE(obj);
    MSDState *s = DO_UPCAST(MSDState, dev, dev);
    int32_t boot_index;
    Error *local_err = NULL;

    visit_type_int32(v, &boot_index, name, &local_err);
    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:
    if (local_err) {
        error_propagate(errp, local_err);
    }
}

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);
}

819 820 821
static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
{
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
822
    DeviceClass *dc = DEVICE_CLASS(klass);
823

G
Gonglei 已提交
824
    uc->realize = usb_msd_realize_bot;
825
    usb_msd_class_initfn_common(klass);
826
    dc->hotpluggable = false;
827 828
}

829
static const TypeInfo msd_info = {
830 831 832
    .name          = "usb-storage",
    .parent        = TYPE_USB_DEVICE,
    .instance_size = sizeof(MSDState),
833
    .class_init    = usb_msd_class_initfn_storage,
834
    .instance_init = usb_msd_instance_init,
835 836 837 838 839 840 841
};

static const TypeInfo bot_info = {
    .name          = "usb-bot",
    .parent        = TYPE_USB_DEVICE,
    .instance_size = sizeof(MSDState),
    .class_init    = usb_msd_class_initfn_bot,
842 843
};

A
Andreas Färber 已提交
844
static void usb_msd_register_types(void)
845
{
846
    type_register_static(&msd_info);
847
    type_register_static(&bot_info);
848
    usb_legacy_register("usb-storage", "disk", usb_msd_init);
849
}
A
Andreas Färber 已提交
850 851

type_init(usb_msd_register_types)