dev-storage.c 24.0 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
    if (local_err) {
562
        error_report_err(local_err);
563
        qdev_unplug(&s->dev.qdev, NULL);
564
    }
565 566
}

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

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

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

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

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

612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
    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;
        }
    }

G
Gerd Hoffmann 已提交
629
    blkconf_serial(&s->conf, &dev->serial);
630
    blkconf_blocksizes(&s->conf);
631

632 633 634
    /*
     * 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
635 636 637
     * creates automatically.  But first it needs to detach from its
     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
     * attaches again.
638 639 640
     *
     * The hack is probably a bad idea.
     */
641 642
    blk_detach_dev(blk, &s->dev.qdev);
    s->conf.blk = NULL;
643

G
Gerd Hoffmann 已提交
644
    usb_desc_create_serial(dev);
645
    usb_desc_init(dev);
646 647
    scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
                 &usb_msd_scsi_info_storage, NULL);
648
    scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable,
649 650
                                         s->conf.bootindex, dev->serial,
                                         &err);
651
    if (!scsi_dev) {
G
Gonglei 已提交
652 653
        error_propagate(errp, err);
        return;
654
    }
655
    usb_msd_handle_reset(dev);
656
    s->scsi_dev = scsi_dev;
657 658
}

G
Gonglei 已提交
659
static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
660 661 662 663 664
{
    MSDState *s = DO_UPCAST(MSDState, dev, dev);

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

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

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

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

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

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

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

727 728 729 730
static const VMStateDescription vmstate_usb_msd = {
    .name = "usb-storage",
    .version_id = 1,
    .minimum_version_id = 1,
731
    .fields = (VMStateField[]) {
732
        VMSTATE_USB_DEVICE(dev, MSDState),
G
Gerd Hoffmann 已提交
733 734 735 736 737 738 739 740
        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),
741 742 743 744
        VMSTATE_END_OF_LIST()
    }
};

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

751
static void usb_msd_class_initfn_common(ObjectClass *klass)
752
{
753
    DeviceClass *dc = DEVICE_CLASS(klass);
754 755 756 757 758 759 760 761 762
    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;
763
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
764 765
    dc->fw_name = "storage";
    dc->vmsd = &vmstate_usb_msd;
766 767 768 769 770 771 772
}

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

G
Gonglei 已提交
773
    uc->realize = usb_msd_realize_storage;
774
    dc->props = msd_properties;
775 776 777
    usb_msd_class_initfn_common(klass);
}

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 819 820 821 822 823 824 825
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);
}

826 827 828
static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
{
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
829
    DeviceClass *dc = DEVICE_CLASS(klass);
830

G
Gonglei 已提交
831
    uc->realize = usb_msd_realize_bot;
832
    usb_msd_class_initfn_common(klass);
833
    dc->hotpluggable = false;
834 835
}

836
static const TypeInfo msd_info = {
837 838 839
    .name          = "usb-storage",
    .parent        = TYPE_USB_DEVICE,
    .instance_size = sizeof(MSDState),
840
    .class_init    = usb_msd_class_initfn_storage,
841
    .instance_init = usb_msd_instance_init,
842 843 844 845 846 847 848
};

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

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

type_init(usb_msd_register_types)