dev-storage.c 22.3 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
#include "hw/usb.h"
17
#include "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 "qapi/visitor.h"
24
#include "qemu/cutils.h"
P
pbrook 已提交
25 26 27 28

//#define DEBUG_MSD

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

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

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

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

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

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

P
pbrook 已提交
73 74 75 76 77 78 79 80 81 82
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];
};

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

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

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

G
Gerd Hoffmann 已提交
171 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
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,
201
            .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
G
Gerd Hoffmann 已提交
202 203 204 205 206 207
            .nif = 1,
            .ifs = &desc_iface_super,
        },
    },
};

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

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

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

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

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

251 252 253 254 255 256 257 258 259 260 261 262
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);
}

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

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

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

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

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

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

P
Paolo Bonzini 已提交
321 322 323 324 325 326 327 328 329 330 331
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 已提交
332
static void usb_msd_handle_reset(USBDevice *dev)
P
pbrook 已提交
333 334 335 336
{
    MSDState *s = (MSDState *)dev;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

G
Gerd Hoffmann 已提交
558 559 560 561 562 563 564 565 566 567 568
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;
}

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

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

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

591
static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
592
{
G
Gonglei 已提交
593
    MSDState *s = USB_STORAGE_DEV(dev);
594
    BlockBackend *blk = s->conf.blk;
595
    SCSIDevice *scsi_dev;
596

597
    if (!blk) {
G
Gonglei 已提交
598 599
        error_setg(errp, "drive property not set");
        return;
600 601
    }

602
    blkconf_blocksizes(&s->conf);
603 604
    if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
                                       errp)) {
K
Kevin Wolf 已提交
605 606
        return;
    }
607

608 609 610
    /*
     * 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
611 612
     * creates automatically.  But first it needs to detach from its
     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
613 614
     * attaches again. We also need to take another reference so that
     * blk_detach_dev() doesn't free blk while we still need it.
615 616 617
     *
     * The hack is probably a bad idea.
     */
618
    blk_ref(blk);
619 620
    blk_detach_dev(blk, &s->dev.qdev);
    s->conf.blk = NULL;
621

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

638
static void usb_msd_bot_realize(USBDevice *dev, Error **errp)
639
{
G
Gonglei 已提交
640
    MSDState *s = USB_STORAGE_DEV(dev);
G
Gerd Hoffmann 已提交
641
    DeviceState *d = DEVICE(dev);
642 643 644

    usb_desc_create_serial(dev);
    usb_desc_init(dev);
G
Gerd Hoffmann 已提交
645 646 647 648
    if (d->hotplugged) {
        s->dev.auto_attach = 0;
    }

649 650
    scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
                 &usb_msd_scsi_info_bot, NULL);
651 652 653
    usb_msd_handle_reset(dev);
}

654 655 656 657
static const VMStateDescription vmstate_usb_msd = {
    .name = "usb-storage",
    .version_id = 1,
    .minimum_version_id = 1,
658
    .fields = (VMStateField[]) {
659
        VMSTATE_USB_DEVICE(dev, MSDState),
G
Gerd Hoffmann 已提交
660 661 662 663 664 665 666 667
        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),
668 669 670 671
        VMSTATE_END_OF_LIST()
    }
};

672 673 674 675 676 677
static Property msd_properties[] = {
    DEFINE_BLOCK_PROPERTIES(MSDState, conf),
    DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
    DEFINE_PROP_END_OF_LIST(),
};

G
Gonglei 已提交
678
static void usb_msd_class_initfn_common(ObjectClass *klass, void *data)
679
{
680
    DeviceClass *dc = DEVICE_CLASS(klass);
681 682 683 684 685 686 687 688 689
    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;
690
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
691 692
    dc->fw_name = "storage";
    dc->vmsd = &vmstate_usb_msd;
693 694
}

695
static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data)
696 697 698 699
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

700
    uc->realize = usb_msd_storage_realize;
701
    dc->props = msd_properties;
702 703
}

704 705
static void usb_msd_get_bootindex(Object *obj, Visitor *v, const char *name,
                                  void *opaque, Error **errp)
706 707
{
    USBDevice *dev = USB_DEVICE(obj);
G
Gonglei 已提交
708
    MSDState *s = USB_STORAGE_DEV(dev);
709

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

713 714
static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name,
                                  void *opaque, Error **errp)
715 716
{
    USBDevice *dev = USB_DEVICE(obj);
G
Gonglei 已提交
717
    MSDState *s = USB_STORAGE_DEV(dev);
718 719 720
    int32_t boot_index;
    Error *local_err = NULL;

721
    visit_type_int32(v, name, &boot_index, &local_err);
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
    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:
739
    error_propagate(errp, local_err);
740 741
}

G
Gonglei 已提交
742 743 744 745 746 747 748 749
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,
};

750 751 752 753 754 755 756 757
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);
}

758
static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data)
759 760 761
{
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

762
    uc->realize = usb_msd_bot_realize;
G
Gerd Hoffmann 已提交
763
    uc->attached_settable = true;
764 765
}

766
static const TypeInfo msd_info = {
767
    .name          = "usb-storage",
G
Gonglei 已提交
768
    .parent        = TYPE_USB_STORAGE,
769
    .class_init    = usb_msd_class_storage_initfn,
770
    .instance_init = usb_msd_instance_init,
771 772 773 774
};

static const TypeInfo bot_info = {
    .name          = "usb-bot",
G
Gonglei 已提交
775
    .parent        = TYPE_USB_STORAGE,
776
    .class_init    = usb_msd_class_bot_initfn,
777 778
};

A
Andreas Färber 已提交
779
static void usb_msd_register_types(void)
780
{
G
Gonglei 已提交
781
    type_register_static(&usb_storage_dev_type_info);
782
    type_register_static(&msd_info);
783
    type_register_static(&bot_info);
784
}
A
Andreas Färber 已提交
785 786

type_init(usb_msd_register_types)