Statistics
| Branch: | Revision:

root / hw / usb-msd.c @ 079d0b7f

History | View | Annotate | Download (18 kB)

1 5fafdf24 ths
/*
2 2e5d83bb pbrook
 * USB Mass Storage Device emulation
3 2e5d83bb pbrook
 *
4 2e5d83bb pbrook
 * Copyright (c) 2006 CodeSourcery.
5 2e5d83bb pbrook
 * Written by Paul Brook
6 2e5d83bb pbrook
 *
7 8e31bf38 Matthew Fernandez
 * This code is licensed under the LGPL.
8 2e5d83bb pbrook
 */
9 2e5d83bb pbrook
10 87ecb68b pbrook
#include "qemu-common.h"
11 7fc2f2c0 Gerd Hoffmann
#include "qemu-option.h"
12 7fc2f2c0 Gerd Hoffmann
#include "qemu-config.h"
13 87ecb68b pbrook
#include "usb.h"
14 81bfd2f2 Gerd Hoffmann
#include "usb-desc.h"
15 43b443b6 Gerd Hoffmann
#include "scsi.h"
16 c0f4ce77 aliguori
#include "console.h"
17 b3e461d3 Gerd Hoffmann
#include "monitor.h"
18 666daa68 Markus Armbruster
#include "sysemu.h"
19 2446333c Blue Swirl
#include "blockdev.h"
20 2e5d83bb pbrook
21 2e5d83bb pbrook
//#define DEBUG_MSD
22 2e5d83bb pbrook
23 2e5d83bb pbrook
#ifdef DEBUG_MSD
24 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) \
25 001faf32 Blue Swirl
do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
26 2e5d83bb pbrook
#else
27 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do {} while(0)
28 2e5d83bb pbrook
#endif
29 2e5d83bb pbrook
30 2e5d83bb pbrook
/* USB requests.  */
31 2e5d83bb pbrook
#define MassStorageReset  0xff
32 2e5d83bb pbrook
#define GetMaxLun         0xfe
33 2e5d83bb pbrook
34 2e5d83bb pbrook
enum USBMSDMode {
35 2e5d83bb pbrook
    USB_MSDM_CBW, /* Command Block.  */
36 94843f66 Brad Hards
    USB_MSDM_DATAOUT, /* Transfer data to device.  */
37 2e5d83bb pbrook
    USB_MSDM_DATAIN, /* Transfer data from device.  */
38 2e5d83bb pbrook
    USB_MSDM_CSW /* Command Status.  */
39 2e5d83bb pbrook
};
40 2e5d83bb pbrook
41 92a114f6 Gerd Hoffmann
struct usb_msd_csw {
42 92a114f6 Gerd Hoffmann
    uint32_t sig;
43 92a114f6 Gerd Hoffmann
    uint32_t tag;
44 92a114f6 Gerd Hoffmann
    uint32_t residue;
45 92a114f6 Gerd Hoffmann
    uint8_t status;
46 92a114f6 Gerd Hoffmann
};
47 92a114f6 Gerd Hoffmann
48 2e5d83bb pbrook
typedef struct {
49 2e5d83bb pbrook
    USBDevice dev;
50 2e5d83bb pbrook
    enum USBMSDMode mode;
51 a917d384 pbrook
    uint32_t scsi_len;
52 a917d384 pbrook
    uint8_t *scsi_buf;
53 2e5d83bb pbrook
    uint32_t data_len;
54 a917d384 pbrook
    uint32_t residue;
55 92a114f6 Gerd Hoffmann
    struct usb_msd_csw csw;
56 5c6c0e51 Hannes Reinecke
    SCSIRequest *req;
57 ca9c39fa Gerd Hoffmann
    SCSIBus bus;
58 428c149b Christoph Hellwig
    BlockConf conf;
59 c3a90cb1 Markus Armbruster
    char *serial;
60 2e5d83bb pbrook
    SCSIDevice *scsi_dev;
61 6bb7b867 Stefan Hajnoczi
    uint32_t removable;
62 4d611c9a pbrook
    /* For async completion.  */
63 4d611c9a pbrook
    USBPacket *packet;
64 2e5d83bb pbrook
} MSDState;
65 2e5d83bb pbrook
66 a917d384 pbrook
struct usb_msd_cbw {
67 a917d384 pbrook
    uint32_t sig;
68 a917d384 pbrook
    uint32_t tag;
69 a917d384 pbrook
    uint32_t data_len;
70 a917d384 pbrook
    uint8_t flags;
71 a917d384 pbrook
    uint8_t lun;
72 a917d384 pbrook
    uint8_t cmd_len;
73 a917d384 pbrook
    uint8_t cmd[16];
74 a917d384 pbrook
};
75 a917d384 pbrook
76 81bfd2f2 Gerd Hoffmann
enum {
77 81bfd2f2 Gerd Hoffmann
    STR_MANUFACTURER = 1,
78 81bfd2f2 Gerd Hoffmann
    STR_PRODUCT,
79 81bfd2f2 Gerd Hoffmann
    STR_SERIALNUMBER,
80 ca0c730d Gerd Hoffmann
    STR_CONFIG_FULL,
81 ca0c730d Gerd Hoffmann
    STR_CONFIG_HIGH,
82 2e5d83bb pbrook
};
83 2e5d83bb pbrook
84 81bfd2f2 Gerd Hoffmann
static const USBDescStrings desc_strings = {
85 81bfd2f2 Gerd Hoffmann
    [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
86 81bfd2f2 Gerd Hoffmann
    [STR_PRODUCT]      = "QEMU USB HARDDRIVE",
87 81bfd2f2 Gerd Hoffmann
    [STR_SERIALNUMBER] = "1",
88 ca0c730d Gerd Hoffmann
    [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
89 ca0c730d Gerd Hoffmann
    [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
90 81bfd2f2 Gerd Hoffmann
};
91 81bfd2f2 Gerd Hoffmann
92 ca0c730d Gerd Hoffmann
static const USBDescIface desc_iface_full = {
93 81bfd2f2 Gerd Hoffmann
    .bInterfaceNumber              = 0,
94 81bfd2f2 Gerd Hoffmann
    .bNumEndpoints                 = 2,
95 81bfd2f2 Gerd Hoffmann
    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
96 81bfd2f2 Gerd Hoffmann
    .bInterfaceSubClass            = 0x06, /* SCSI */
97 81bfd2f2 Gerd Hoffmann
    .bInterfaceProtocol            = 0x50, /* Bulk */
98 81bfd2f2 Gerd Hoffmann
    .eps = (USBDescEndpoint[]) {
99 81bfd2f2 Gerd Hoffmann
        {
100 81bfd2f2 Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_IN | 0x01,
101 81bfd2f2 Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
102 81bfd2f2 Gerd Hoffmann
            .wMaxPacketSize        = 64,
103 81bfd2f2 Gerd Hoffmann
        },{
104 81bfd2f2 Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_OUT | 0x02,
105 81bfd2f2 Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
106 81bfd2f2 Gerd Hoffmann
            .wMaxPacketSize        = 64,
107 81bfd2f2 Gerd Hoffmann
        },
108 81bfd2f2 Gerd Hoffmann
    }
109 81bfd2f2 Gerd Hoffmann
};
110 81bfd2f2 Gerd Hoffmann
111 ca0c730d Gerd Hoffmann
static const USBDescDevice desc_device_full = {
112 ca0c730d Gerd Hoffmann
    .bcdUSB                        = 0x0200,
113 81bfd2f2 Gerd Hoffmann
    .bMaxPacketSize0               = 8,
114 81bfd2f2 Gerd Hoffmann
    .bNumConfigurations            = 1,
115 81bfd2f2 Gerd Hoffmann
    .confs = (USBDescConfig[]) {
116 81bfd2f2 Gerd Hoffmann
        {
117 81bfd2f2 Gerd Hoffmann
            .bNumInterfaces        = 1,
118 81bfd2f2 Gerd Hoffmann
            .bConfigurationValue   = 1,
119 ca0c730d Gerd Hoffmann
            .iConfiguration        = STR_CONFIG_FULL,
120 81bfd2f2 Gerd Hoffmann
            .bmAttributes          = 0xc0,
121 add75088 Brad Hards
            .nif = 1,
122 ca0c730d Gerd Hoffmann
            .ifs = &desc_iface_full,
123 ca0c730d Gerd Hoffmann
        },
124 ca0c730d Gerd Hoffmann
    },
125 ca0c730d Gerd Hoffmann
};
126 ca0c730d Gerd Hoffmann
127 ca0c730d Gerd Hoffmann
static const USBDescIface desc_iface_high = {
128 ca0c730d Gerd Hoffmann
    .bInterfaceNumber              = 0,
129 ca0c730d Gerd Hoffmann
    .bNumEndpoints                 = 2,
130 ca0c730d Gerd Hoffmann
    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
131 ca0c730d Gerd Hoffmann
    .bInterfaceSubClass            = 0x06, /* SCSI */
132 ca0c730d Gerd Hoffmann
    .bInterfaceProtocol            = 0x50, /* Bulk */
133 ca0c730d Gerd Hoffmann
    .eps = (USBDescEndpoint[]) {
134 ca0c730d Gerd Hoffmann
        {
135 ca0c730d Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_IN | 0x01,
136 ca0c730d Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
137 ca0c730d Gerd Hoffmann
            .wMaxPacketSize        = 512,
138 ca0c730d Gerd Hoffmann
        },{
139 ca0c730d Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_OUT | 0x02,
140 ca0c730d Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
141 ca0c730d Gerd Hoffmann
            .wMaxPacketSize        = 512,
142 ca0c730d Gerd Hoffmann
        },
143 ca0c730d Gerd Hoffmann
    }
144 ca0c730d Gerd Hoffmann
};
145 ca0c730d Gerd Hoffmann
146 ca0c730d Gerd Hoffmann
static const USBDescDevice desc_device_high = {
147 ca0c730d Gerd Hoffmann
    .bcdUSB                        = 0x0200,
148 ca0c730d Gerd Hoffmann
    .bMaxPacketSize0               = 64,
149 ca0c730d Gerd Hoffmann
    .bNumConfigurations            = 1,
150 ca0c730d Gerd Hoffmann
    .confs = (USBDescConfig[]) {
151 ca0c730d Gerd Hoffmann
        {
152 ca0c730d Gerd Hoffmann
            .bNumInterfaces        = 1,
153 ca0c730d Gerd Hoffmann
            .bConfigurationValue   = 1,
154 ca0c730d Gerd Hoffmann
            .iConfiguration        = STR_CONFIG_HIGH,
155 ca0c730d Gerd Hoffmann
            .bmAttributes          = 0xc0,
156 add75088 Brad Hards
            .nif = 1,
157 ca0c730d Gerd Hoffmann
            .ifs = &desc_iface_high,
158 81bfd2f2 Gerd Hoffmann
        },
159 81bfd2f2 Gerd Hoffmann
    },
160 81bfd2f2 Gerd Hoffmann
};
161 81bfd2f2 Gerd Hoffmann
162 81bfd2f2 Gerd Hoffmann
static const USBDesc desc = {
163 81bfd2f2 Gerd Hoffmann
    .id = {
164 db80358a Roy Tam
        .idVendor          = 0x46f4, /* CRC16() of "QEMU" */
165 db80358a Roy Tam
        .idProduct         = 0x0001,
166 81bfd2f2 Gerd Hoffmann
        .bcdDevice         = 0,
167 81bfd2f2 Gerd Hoffmann
        .iManufacturer     = STR_MANUFACTURER,
168 81bfd2f2 Gerd Hoffmann
        .iProduct          = STR_PRODUCT,
169 81bfd2f2 Gerd Hoffmann
        .iSerialNumber     = STR_SERIALNUMBER,
170 81bfd2f2 Gerd Hoffmann
    },
171 ca0c730d Gerd Hoffmann
    .full = &desc_device_full,
172 ca0c730d Gerd Hoffmann
    .high = &desc_device_high,
173 81bfd2f2 Gerd Hoffmann
    .str  = desc_strings,
174 2e5d83bb pbrook
};
175 2e5d83bb pbrook
176 29c74f76 Gerd Hoffmann
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
177 a917d384 pbrook
{
178 a917d384 pbrook
    uint32_t len;
179 29c74f76 Gerd Hoffmann
    len = p->iov.size - p->result;
180 a917d384 pbrook
    if (len > s->scsi_len)
181 a917d384 pbrook
        len = s->scsi_len;
182 29c74f76 Gerd Hoffmann
    usb_packet_copy(p, s->scsi_buf, len);
183 a917d384 pbrook
    s->scsi_len -= len;
184 a917d384 pbrook
    s->scsi_buf += len;
185 a917d384 pbrook
    s->data_len -= len;
186 fa7935c1 Gerd Hoffmann
    if (s->scsi_len == 0 || s->data_len == 0) {
187 ad3376cc Paolo Bonzini
        scsi_req_continue(s->req);
188 a917d384 pbrook
    }
189 a917d384 pbrook
}
190 a917d384 pbrook
191 ab4797ad Gerd Hoffmann
static void usb_msd_send_status(MSDState *s, USBPacket *p)
192 a917d384 pbrook
{
193 ab4797ad Gerd Hoffmann
    int len;
194 a917d384 pbrook
195 e04da7c3 Gerd Hoffmann
    DPRINTF("Command status %d tag 0x%x, len %zd\n",
196 92a114f6 Gerd Hoffmann
            s->csw.status, s->csw.tag, p->iov.size);
197 92a114f6 Gerd Hoffmann
198 92a114f6 Gerd Hoffmann
    assert(s->csw.sig == 0x53425355);
199 92a114f6 Gerd Hoffmann
    len = MIN(sizeof(s->csw), p->iov.size);
200 92a114f6 Gerd Hoffmann
    usb_packet_copy(p, &s->csw, len);
201 92a114f6 Gerd Hoffmann
    memset(&s->csw, 0, sizeof(s->csw));
202 a917d384 pbrook
}
203 a917d384 pbrook
204 aba1f023 Paolo Bonzini
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
205 2e5d83bb pbrook
{
206 5c6c0e51 Hannes Reinecke
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
207 a917d384 pbrook
    USBPacket *p = s->packet;
208 4d611c9a pbrook
209 ad3376cc Paolo Bonzini
    assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
210 aba1f023 Paolo Bonzini
    s->scsi_len = len;
211 0c34459b Paolo Bonzini
    s->scsi_buf = scsi_req_get_buf(req);
212 a917d384 pbrook
    if (p) {
213 29c74f76 Gerd Hoffmann
        usb_msd_copy_data(s, p);
214 29c74f76 Gerd Hoffmann
        p = s->packet;
215 29c74f76 Gerd Hoffmann
        if (p && p->result == p->iov.size) {
216 a917d384 pbrook
            /* Set s->packet to NULL before calling usb_packet_complete
217 94843f66 Brad Hards
               because another request may be issued before
218 a917d384 pbrook
               usb_packet_complete returns.  */
219 a917d384 pbrook
            DPRINTF("Packet complete %p\n", p);
220 a917d384 pbrook
            s->packet = NULL;
221 13a9a0d3 Gerd Hoffmann
            usb_packet_complete(&s->dev, p);
222 a917d384 pbrook
        }
223 4d611c9a pbrook
    }
224 2e5d83bb pbrook
}
225 2e5d83bb pbrook
226 aba1f023 Paolo Bonzini
static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
227 c6df7102 Paolo Bonzini
{
228 c6df7102 Paolo Bonzini
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
229 c6df7102 Paolo Bonzini
    USBPacket *p = s->packet;
230 c6df7102 Paolo Bonzini
231 7b863f41 Gerd Hoffmann
    DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
232 c6df7102 Paolo Bonzini
    s->residue = s->data_len;
233 92a114f6 Gerd Hoffmann
234 92a114f6 Gerd Hoffmann
    s->csw.sig = cpu_to_le32(0x53425355);
235 7b863f41 Gerd Hoffmann
    s->csw.tag = cpu_to_le32(req->tag);
236 92a114f6 Gerd Hoffmann
    s->csw.residue = s->residue;
237 414c4604 Gerd Hoffmann
    s->csw.status = status != 0;
238 92a114f6 Gerd Hoffmann
239 c6df7102 Paolo Bonzini
    if (s->packet) {
240 c6df7102 Paolo Bonzini
        if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
241 c6df7102 Paolo Bonzini
            /* A deferred packet with no write data remaining must be
242 c6df7102 Paolo Bonzini
               the status read packet.  */
243 c6df7102 Paolo Bonzini
            usb_msd_send_status(s, p);
244 c6df7102 Paolo Bonzini
            s->mode = USB_MSDM_CBW;
245 c6df7102 Paolo Bonzini
        } else {
246 c6df7102 Paolo Bonzini
            if (s->data_len) {
247 29c74f76 Gerd Hoffmann
                int len = (p->iov.size - p->result);
248 29c74f76 Gerd Hoffmann
                usb_packet_skip(p, len);
249 29c74f76 Gerd Hoffmann
                s->data_len -= len;
250 c6df7102 Paolo Bonzini
            }
251 c6df7102 Paolo Bonzini
            if (s->data_len == 0) {
252 c6df7102 Paolo Bonzini
                s->mode = USB_MSDM_CSW;
253 c6df7102 Paolo Bonzini
            }
254 c6df7102 Paolo Bonzini
        }
255 c6df7102 Paolo Bonzini
        s->packet = NULL;
256 c6df7102 Paolo Bonzini
        usb_packet_complete(&s->dev, p);
257 c6df7102 Paolo Bonzini
    } else if (s->data_len == 0) {
258 c6df7102 Paolo Bonzini
        s->mode = USB_MSDM_CSW;
259 c6df7102 Paolo Bonzini
    }
260 c6df7102 Paolo Bonzini
    scsi_req_unref(req);
261 c6df7102 Paolo Bonzini
    s->req = NULL;
262 c6df7102 Paolo Bonzini
}
263 c6df7102 Paolo Bonzini
264 94d3f98a Paolo Bonzini
static void usb_msd_request_cancelled(SCSIRequest *req)
265 94d3f98a Paolo Bonzini
{
266 94d3f98a Paolo Bonzini
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
267 94d3f98a Paolo Bonzini
268 94d3f98a Paolo Bonzini
    if (req == s->req) {
269 94d3f98a Paolo Bonzini
        scsi_req_unref(s->req);
270 94d3f98a Paolo Bonzini
        s->req = NULL;
271 94d3f98a Paolo Bonzini
        s->packet = NULL;
272 94d3f98a Paolo Bonzini
        s->scsi_len = 0;
273 94d3f98a Paolo Bonzini
    }
274 94d3f98a Paolo Bonzini
}
275 94d3f98a Paolo Bonzini
276 059809e4 bellard
static void usb_msd_handle_reset(USBDevice *dev)
277 2e5d83bb pbrook
{
278 2e5d83bb pbrook
    MSDState *s = (MSDState *)dev;
279 2e5d83bb pbrook
280 2e5d83bb pbrook
    DPRINTF("Reset\n");
281 24a5bbe1 Gerd Hoffmann
    if (s->req) {
282 24a5bbe1 Gerd Hoffmann
        scsi_req_cancel(s->req);
283 24a5bbe1 Gerd Hoffmann
    }
284 24a5bbe1 Gerd Hoffmann
    assert(s->req == NULL);
285 24a5bbe1 Gerd Hoffmann
286 24a5bbe1 Gerd Hoffmann
    if (s->packet) {
287 24a5bbe1 Gerd Hoffmann
        USBPacket *p = s->packet;
288 24a5bbe1 Gerd Hoffmann
        s->packet = NULL;
289 24a5bbe1 Gerd Hoffmann
        p->result = USB_RET_STALL;
290 24a5bbe1 Gerd Hoffmann
        usb_packet_complete(dev, p);
291 24a5bbe1 Gerd Hoffmann
    }
292 24a5bbe1 Gerd Hoffmann
293 2e5d83bb pbrook
    s->mode = USB_MSDM_CBW;
294 2e5d83bb pbrook
}
295 2e5d83bb pbrook
296 007fd62f Hans de Goede
static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
297 007fd62f Hans de Goede
               int request, int value, int index, int length, uint8_t *data)
298 2e5d83bb pbrook
{
299 2e5d83bb pbrook
    MSDState *s = (MSDState *)dev;
300 81bfd2f2 Gerd Hoffmann
    int ret;
301 2e5d83bb pbrook
302 007fd62f Hans de Goede
    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
303 81bfd2f2 Gerd Hoffmann
    if (ret >= 0) {
304 81bfd2f2 Gerd Hoffmann
        return ret;
305 81bfd2f2 Gerd Hoffmann
    }
306 81bfd2f2 Gerd Hoffmann
307 81bfd2f2 Gerd Hoffmann
    ret = 0;
308 2e5d83bb pbrook
    switch (request) {
309 2e5d83bb pbrook
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
310 e5322f76 Arnaud Patard (Rtp)
        ret = 0;
311 e5322f76 Arnaud Patard (Rtp)
        break;
312 2e5d83bb pbrook
        /* Class specific requests.  */
313 f3571b1a Max Reitz
    case ClassInterfaceOutRequest | MassStorageReset:
314 2e5d83bb pbrook
        /* Reset state ready for the next CBW.  */
315 2e5d83bb pbrook
        s->mode = USB_MSDM_CBW;
316 2e5d83bb pbrook
        ret = 0;
317 2e5d83bb pbrook
        break;
318 f3571b1a Max Reitz
    case ClassInterfaceRequest | GetMaxLun:
319 2e5d83bb pbrook
        data[0] = 0;
320 2e5d83bb pbrook
        ret = 1;
321 2e5d83bb pbrook
        break;
322 2e5d83bb pbrook
    default:
323 2e5d83bb pbrook
        ret = USB_RET_STALL;
324 2e5d83bb pbrook
        break;
325 2e5d83bb pbrook
    }
326 2e5d83bb pbrook
    return ret;
327 2e5d83bb pbrook
}
328 2e5d83bb pbrook
329 eb5e680a Gerd Hoffmann
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
330 4d611c9a pbrook
{
331 eb5e680a Gerd Hoffmann
    MSDState *s = DO_UPCAST(MSDState, dev, dev);
332 d3ac1a87 Gerd Hoffmann
333 d3ac1a87 Gerd Hoffmann
    if (s->req) {
334 d3ac1a87 Gerd Hoffmann
        scsi_req_cancel(s->req);
335 d3ac1a87 Gerd Hoffmann
    }
336 4d611c9a pbrook
}
337 4d611c9a pbrook
338 4d611c9a pbrook
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
339 2e5d83bb pbrook
{
340 2e5d83bb pbrook
    MSDState *s = (MSDState *)dev;
341 7b863f41 Gerd Hoffmann
    uint32_t tag;
342 2e5d83bb pbrook
    int ret = 0;
343 2e5d83bb pbrook
    struct usb_msd_cbw cbw;
344 079d0b7f Gerd Hoffmann
    uint8_t devep = p->ep->nr;
345 2e5d83bb pbrook
346 4d611c9a pbrook
    switch (p->pid) {
347 2e5d83bb pbrook
    case USB_TOKEN_OUT:
348 2e5d83bb pbrook
        if (devep != 2)
349 2e5d83bb pbrook
            goto fail;
350 2e5d83bb pbrook
351 2e5d83bb pbrook
        switch (s->mode) {
352 2e5d83bb pbrook
        case USB_MSDM_CBW:
353 29c74f76 Gerd Hoffmann
            if (p->iov.size != 31) {
354 2e5d83bb pbrook
                fprintf(stderr, "usb-msd: Bad CBW size");
355 2e5d83bb pbrook
                goto fail;
356 2e5d83bb pbrook
            }
357 29c74f76 Gerd Hoffmann
            usb_packet_copy(p, &cbw, 31);
358 2e5d83bb pbrook
            if (le32_to_cpu(cbw.sig) != 0x43425355) {
359 2e5d83bb pbrook
                fprintf(stderr, "usb-msd: Bad signature %08x\n",
360 2e5d83bb pbrook
                        le32_to_cpu(cbw.sig));
361 2e5d83bb pbrook
                goto fail;
362 2e5d83bb pbrook
            }
363 2e5d83bb pbrook
            DPRINTF("Command on LUN %d\n", cbw.lun);
364 2e5d83bb pbrook
            if (cbw.lun != 0) {
365 2e5d83bb pbrook
                fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
366 2e5d83bb pbrook
                goto fail;
367 2e5d83bb pbrook
            }
368 7b863f41 Gerd Hoffmann
            tag = le32_to_cpu(cbw.tag);
369 2e5d83bb pbrook
            s->data_len = le32_to_cpu(cbw.data_len);
370 2e5d83bb pbrook
            if (s->data_len == 0) {
371 2e5d83bb pbrook
                s->mode = USB_MSDM_CSW;
372 2e5d83bb pbrook
            } else if (cbw.flags & 0x80) {
373 2e5d83bb pbrook
                s->mode = USB_MSDM_DATAIN;
374 2e5d83bb pbrook
            } else {
375 2e5d83bb pbrook
                s->mode = USB_MSDM_DATAOUT;
376 2e5d83bb pbrook
            }
377 2e5d83bb pbrook
            DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
378 7b863f41 Gerd Hoffmann
                    tag, cbw.flags, cbw.cmd_len, s->data_len);
379 a917d384 pbrook
            s->residue = 0;
380 ef0bdf77 Gerd Hoffmann
            s->scsi_len = 0;
381 7b863f41 Gerd Hoffmann
            s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL);
382 c39ce112 Paolo Bonzini
            scsi_req_enqueue(s->req);
383 59310659 Gerd Hoffmann
            if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
384 ad3376cc Paolo Bonzini
                scsi_req_continue(s->req);
385 a917d384 pbrook
            }
386 29c74f76 Gerd Hoffmann
            ret = p->result;
387 2e5d83bb pbrook
            break;
388 2e5d83bb pbrook
389 2e5d83bb pbrook
        case USB_MSDM_DATAOUT:
390 29c74f76 Gerd Hoffmann
            DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
391 29c74f76 Gerd Hoffmann
            if (p->iov.size > s->data_len) {
392 2e5d83bb pbrook
                goto fail;
393 29c74f76 Gerd Hoffmann
            }
394 2e5d83bb pbrook
395 a917d384 pbrook
            if (s->scsi_len) {
396 29c74f76 Gerd Hoffmann
                usb_msd_copy_data(s, p);
397 a917d384 pbrook
            }
398 29c74f76 Gerd Hoffmann
            if (s->residue) {
399 29c74f76 Gerd Hoffmann
                int len = p->iov.size - p->result;
400 29c74f76 Gerd Hoffmann
                if (len) {
401 29c74f76 Gerd Hoffmann
                    usb_packet_skip(p, len);
402 29c74f76 Gerd Hoffmann
                    s->data_len -= len;
403 29c74f76 Gerd Hoffmann
                    if (s->data_len == 0) {
404 29c74f76 Gerd Hoffmann
                        s->mode = USB_MSDM_CSW;
405 29c74f76 Gerd Hoffmann
                    }
406 29c74f76 Gerd Hoffmann
                }
407 a917d384 pbrook
            }
408 29c74f76 Gerd Hoffmann
            if (p->result < p->iov.size) {
409 4d611c9a pbrook
                DPRINTF("Deferring packet %p\n", p);
410 4d611c9a pbrook
                s->packet = p;
411 4d611c9a pbrook
                ret = USB_RET_ASYNC;
412 a917d384 pbrook
            } else {
413 29c74f76 Gerd Hoffmann
                ret = p->result;
414 4d611c9a pbrook
            }
415 2e5d83bb pbrook
            break;
416 2e5d83bb pbrook
417 2e5d83bb pbrook
        default:
418 29c74f76 Gerd Hoffmann
            DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
419 2e5d83bb pbrook
            goto fail;
420 2e5d83bb pbrook
        }
421 2e5d83bb pbrook
        break;
422 2e5d83bb pbrook
423 2e5d83bb pbrook
    case USB_TOKEN_IN:
424 2e5d83bb pbrook
        if (devep != 1)
425 2e5d83bb pbrook
            goto fail;
426 2e5d83bb pbrook
427 2e5d83bb pbrook
        switch (s->mode) {
428 a917d384 pbrook
        case USB_MSDM_DATAOUT:
429 29c74f76 Gerd Hoffmann
            if (s->data_len != 0 || p->iov.size < 13) {
430 a917d384 pbrook
                goto fail;
431 29c74f76 Gerd Hoffmann
            }
432 a917d384 pbrook
            /* Waiting for SCSI write to complete.  */
433 a917d384 pbrook
            s->packet = p;
434 a917d384 pbrook
            ret = USB_RET_ASYNC;
435 a917d384 pbrook
            break;
436 a917d384 pbrook
437 2e5d83bb pbrook
        case USB_MSDM_CSW:
438 29c74f76 Gerd Hoffmann
            if (p->iov.size < 13) {
439 2e5d83bb pbrook
                goto fail;
440 29c74f76 Gerd Hoffmann
            }
441 2e5d83bb pbrook
442 59310659 Gerd Hoffmann
            if (s->req) {
443 59310659 Gerd Hoffmann
                /* still in flight */
444 59310659 Gerd Hoffmann
                s->packet = p;
445 59310659 Gerd Hoffmann
                ret = USB_RET_ASYNC;
446 59310659 Gerd Hoffmann
            } else {
447 59310659 Gerd Hoffmann
                usb_msd_send_status(s, p);
448 59310659 Gerd Hoffmann
                s->mode = USB_MSDM_CBW;
449 59310659 Gerd Hoffmann
                ret = 13;
450 59310659 Gerd Hoffmann
            }
451 2e5d83bb pbrook
            break;
452 2e5d83bb pbrook
453 2e5d83bb pbrook
        case USB_MSDM_DATAIN:
454 29c74f76 Gerd Hoffmann
            DPRINTF("Data in %zd/%d, scsi_len %d\n",
455 29c74f76 Gerd Hoffmann
                    p->iov.size, s->data_len, s->scsi_len);
456 a917d384 pbrook
            if (s->scsi_len) {
457 29c74f76 Gerd Hoffmann
                usb_msd_copy_data(s, p);
458 a917d384 pbrook
            }
459 29c74f76 Gerd Hoffmann
            if (s->residue) {
460 29c74f76 Gerd Hoffmann
                int len = p->iov.size - p->result;
461 29c74f76 Gerd Hoffmann
                if (len) {
462 29c74f76 Gerd Hoffmann
                    usb_packet_skip(p, len);
463 29c74f76 Gerd Hoffmann
                    s->data_len -= len;
464 29c74f76 Gerd Hoffmann
                    if (s->data_len == 0) {
465 29c74f76 Gerd Hoffmann
                        s->mode = USB_MSDM_CSW;
466 29c74f76 Gerd Hoffmann
                    }
467 29c74f76 Gerd Hoffmann
                }
468 a917d384 pbrook
            }
469 29c74f76 Gerd Hoffmann
            if (p->result < p->iov.size) {
470 4d611c9a pbrook
                DPRINTF("Deferring packet %p\n", p);
471 4d611c9a pbrook
                s->packet = p;
472 4d611c9a pbrook
                ret = USB_RET_ASYNC;
473 a917d384 pbrook
            } else {
474 29c74f76 Gerd Hoffmann
                ret = p->result;
475 4d611c9a pbrook
            }
476 2e5d83bb pbrook
            break;
477 2e5d83bb pbrook
478 2e5d83bb pbrook
        default:
479 29c74f76 Gerd Hoffmann
            DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
480 2e5d83bb pbrook
            goto fail;
481 2e5d83bb pbrook
        }
482 2e5d83bb pbrook
        break;
483 2e5d83bb pbrook
484 2e5d83bb pbrook
    default:
485 2e5d83bb pbrook
        DPRINTF("Bad token\n");
486 2e5d83bb pbrook
    fail:
487 2e5d83bb pbrook
        ret = USB_RET_STALL;
488 2e5d83bb pbrook
        break;
489 2e5d83bb pbrook
    }
490 2e5d83bb pbrook
491 2e5d83bb pbrook
    return ret;
492 2e5d83bb pbrook
}
493 2e5d83bb pbrook
494 b3e461d3 Gerd Hoffmann
static void usb_msd_password_cb(void *opaque, int err)
495 b3e461d3 Gerd Hoffmann
{
496 b3e461d3 Gerd Hoffmann
    MSDState *s = opaque;
497 b3e461d3 Gerd Hoffmann
498 b3e461d3 Gerd Hoffmann
    if (!err)
499 fa19bf83 Hans de Goede
        err = usb_device_attach(&s->dev);
500 fa19bf83 Hans de Goede
501 fa19bf83 Hans de Goede
    if (err)
502 b3e461d3 Gerd Hoffmann
        qdev_unplug(&s->dev.qdev);
503 b3e461d3 Gerd Hoffmann
}
504 b3e461d3 Gerd Hoffmann
505 afd4030c Paolo Bonzini
static const struct SCSIBusInfo usb_msd_scsi_info = {
506 afd4030c Paolo Bonzini
    .tcq = false,
507 7e0380b9 Paolo Bonzini
    .max_target = 0,
508 7e0380b9 Paolo Bonzini
    .max_lun = 0,
509 afd4030c Paolo Bonzini
510 c6df7102 Paolo Bonzini
    .transfer_data = usb_msd_transfer_data,
511 94d3f98a Paolo Bonzini
    .complete = usb_msd_command_complete,
512 94d3f98a Paolo Bonzini
    .cancel = usb_msd_request_cancelled
513 cfdc1bb0 Paolo Bonzini
};
514 cfdc1bb0 Paolo Bonzini
515 806b6024 Gerd Hoffmann
static int usb_msd_initfn(USBDevice *dev)
516 806b6024 Gerd Hoffmann
{
517 806b6024 Gerd Hoffmann
    MSDState *s = DO_UPCAST(MSDState, dev, dev);
518 f8b6cc00 Markus Armbruster
    BlockDriverState *bs = s->conf.bs;
519 4a1e1bc4 Gerd Hoffmann
    DriveInfo *dinfo;
520 806b6024 Gerd Hoffmann
521 f8b6cc00 Markus Armbruster
    if (!bs) {
522 6a84cb1f Markus Armbruster
        error_report("drive property not set");
523 7fc2f2c0 Gerd Hoffmann
        return -1;
524 7fc2f2c0 Gerd Hoffmann
    }
525 7fc2f2c0 Gerd Hoffmann
526 14bafc54 Markus Armbruster
    /*
527 14bafc54 Markus Armbruster
     * Hack alert: this pretends to be a block device, but it's really
528 14bafc54 Markus Armbruster
     * a SCSI bus that can serve only a single device, which it
529 18846dee Markus Armbruster
     * creates automatically.  But first it needs to detach from its
530 18846dee Markus Armbruster
     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
531 18846dee Markus Armbruster
     * attaches again.
532 14bafc54 Markus Armbruster
     *
533 14bafc54 Markus Armbruster
     * The hack is probably a bad idea.
534 14bafc54 Markus Armbruster
     */
535 fa879d62 Markus Armbruster
    bdrv_detach_dev(bs, &s->dev.qdev);
536 f8b6cc00 Markus Armbruster
    s->conf.bs = NULL;
537 14bafc54 Markus Armbruster
538 c3a90cb1 Markus Armbruster
    if (!s->serial) {
539 c3a90cb1 Markus Armbruster
        /* try to fall back to value set with legacy -drive serial=... */
540 c3a90cb1 Markus Armbruster
        dinfo = drive_get_by_blockdev(bs);
541 c3a90cb1 Markus Armbruster
        if (*dinfo->serial) {
542 c3a90cb1 Markus Armbruster
            s->serial = strdup(dinfo->serial);
543 c3a90cb1 Markus Armbruster
        }
544 c3a90cb1 Markus Armbruster
    }
545 c3a90cb1 Markus Armbruster
    if (s->serial) {
546 c3a90cb1 Markus Armbruster
        usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial);
547 4a1e1bc4 Gerd Hoffmann
    }
548 4a1e1bc4 Gerd Hoffmann
549 a980a065 Gerd Hoffmann
    usb_desc_init(dev);
550 afd4030c Paolo Bonzini
    scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info);
551 ce4e7e46 Paolo Bonzini
    s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
552 ce4e7e46 Paolo Bonzini
                                            s->conf.bootindex);
553 fa66b909 Markus Armbruster
    if (!s->scsi_dev) {
554 fa66b909 Markus Armbruster
        return -1;
555 fa66b909 Markus Armbruster
    }
556 cb23117b Gerd Hoffmann
    s->bus.qbus.allow_hotplug = 0;
557 7fc2f2c0 Gerd Hoffmann
    usb_msd_handle_reset(dev);
558 b3e461d3 Gerd Hoffmann
559 f8b6cc00 Markus Armbruster
    if (bdrv_key_required(bs)) {
560 a4426488 Markus Armbruster
        if (cur_mon) {
561 f8b6cc00 Markus Armbruster
            monitor_read_bdrv_key_start(cur_mon, bs, usb_msd_password_cb, s);
562 b3e461d3 Gerd Hoffmann
            s->dev.auto_attach = 0;
563 b3e461d3 Gerd Hoffmann
        } else {
564 b3e461d3 Gerd Hoffmann
            autostart = 0;
565 b3e461d3 Gerd Hoffmann
        }
566 b3e461d3 Gerd Hoffmann
    }
567 b3e461d3 Gerd Hoffmann
568 806b6024 Gerd Hoffmann
    return 0;
569 806b6024 Gerd Hoffmann
}
570 806b6024 Gerd Hoffmann
571 b3e461d3 Gerd Hoffmann
static USBDevice *usb_msd_init(const char *filename)
572 2e5d83bb pbrook
{
573 7fc2f2c0 Gerd Hoffmann
    static int nr=0;
574 7fc2f2c0 Gerd Hoffmann
    char id[8];
575 7fc2f2c0 Gerd Hoffmann
    QemuOpts *opts;
576 7fc2f2c0 Gerd Hoffmann
    DriveInfo *dinfo;
577 806b6024 Gerd Hoffmann
    USBDevice *dev;
578 334c0241 aurel32
    const char *p1;
579 334c0241 aurel32
    char fmt[32];
580 334c0241 aurel32
581 7fc2f2c0 Gerd Hoffmann
    /* parse -usbdevice disk: syntax into drive opts */
582 7fc2f2c0 Gerd Hoffmann
    snprintf(id, sizeof(id), "usb%d", nr++);
583 3329f07b Gerd Hoffmann
    opts = qemu_opts_create(qemu_find_opts("drive"), id, 0);
584 7fc2f2c0 Gerd Hoffmann
585 334c0241 aurel32
    p1 = strchr(filename, ':');
586 334c0241 aurel32
    if (p1++) {
587 334c0241 aurel32
        const char *p2;
588 334c0241 aurel32
589 334c0241 aurel32
        if (strstart(filename, "format=", &p2)) {
590 334c0241 aurel32
            int len = MIN(p1 - p2, sizeof(fmt));
591 334c0241 aurel32
            pstrcpy(fmt, len, p2);
592 7fc2f2c0 Gerd Hoffmann
            qemu_opt_set(opts, "format", fmt);
593 334c0241 aurel32
        } else if (*filename != ':') {
594 334c0241 aurel32
            printf("unrecognized USB mass-storage option %s\n", filename);
595 334c0241 aurel32
            return NULL;
596 334c0241 aurel32
        }
597 334c0241 aurel32
        filename = p1;
598 334c0241 aurel32
    }
599 334c0241 aurel32
    if (!*filename) {
600 334c0241 aurel32
        printf("block device specification needed\n");
601 334c0241 aurel32
        return NULL;
602 334c0241 aurel32
    }
603 7fc2f2c0 Gerd Hoffmann
    qemu_opt_set(opts, "file", filename);
604 7fc2f2c0 Gerd Hoffmann
    qemu_opt_set(opts, "if", "none");
605 2e5d83bb pbrook
606 7fc2f2c0 Gerd Hoffmann
    /* create host drive */
607 319ae529 Markus Armbruster
    dinfo = drive_init(opts, 0);
608 7fc2f2c0 Gerd Hoffmann
    if (!dinfo) {
609 7fc2f2c0 Gerd Hoffmann
        qemu_opts_del(opts);
610 806b6024 Gerd Hoffmann
        return NULL;
611 7fc2f2c0 Gerd Hoffmann
    }
612 2e5d83bb pbrook
613 7fc2f2c0 Gerd Hoffmann
    /* create guest device */
614 556cd098 Markus Armbruster
    dev = usb_create(NULL /* FIXME */, "usb-storage");
615 d44168ff Paul Brook
    if (!dev) {
616 d44168ff Paul Brook
        return NULL;
617 d44168ff Paul Brook
    }
618 18846dee Markus Armbruster
    if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
619 18846dee Markus Armbruster
        qdev_free(&dev->qdev);
620 18846dee Markus Armbruster
        return NULL;
621 18846dee Markus Armbruster
    }
622 33e66b86 Markus Armbruster
    if (qdev_init(&dev->qdev) < 0)
623 33e66b86 Markus Armbruster
        return NULL;
624 1f6e24e7 bellard
625 7fc2f2c0 Gerd Hoffmann
    return dev;
626 2e5d83bb pbrook
}
627 bb5fc20f aliguori
628 f54b6563 Gerd Hoffmann
static const VMStateDescription vmstate_usb_msd = {
629 f54b6563 Gerd Hoffmann
    .name = "usb-storage",
630 f54b6563 Gerd Hoffmann
    .unmigratable = 1, /* FIXME: handle transactions which are in flight */
631 f54b6563 Gerd Hoffmann
    .version_id = 1,
632 f54b6563 Gerd Hoffmann
    .minimum_version_id = 1,
633 f54b6563 Gerd Hoffmann
    .fields = (VMStateField []) {
634 f54b6563 Gerd Hoffmann
        VMSTATE_USB_DEVICE(dev, MSDState),
635 f54b6563 Gerd Hoffmann
        VMSTATE_END_OF_LIST()
636 f54b6563 Gerd Hoffmann
    }
637 f54b6563 Gerd Hoffmann
};
638 f54b6563 Gerd Hoffmann
639 39bffca2 Anthony Liguori
static Property msd_properties[] = {
640 39bffca2 Anthony Liguori
    DEFINE_BLOCK_PROPERTIES(MSDState, conf),
641 39bffca2 Anthony Liguori
    DEFINE_PROP_STRING("serial", MSDState, serial),
642 39bffca2 Anthony Liguori
    DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
643 39bffca2 Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
644 39bffca2 Anthony Liguori
};
645 39bffca2 Anthony Liguori
646 62aed765 Anthony Liguori
static void usb_msd_class_initfn(ObjectClass *klass, void *data)
647 62aed765 Anthony Liguori
{
648 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
649 62aed765 Anthony Liguori
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
650 62aed765 Anthony Liguori
651 62aed765 Anthony Liguori
    uc->init           = usb_msd_initfn;
652 62aed765 Anthony Liguori
    uc->product_desc   = "QEMU USB MSD";
653 62aed765 Anthony Liguori
    uc->usb_desc       = &desc;
654 62aed765 Anthony Liguori
    uc->cancel_packet  = usb_msd_cancel_io;
655 62aed765 Anthony Liguori
    uc->handle_attach  = usb_desc_attach;
656 62aed765 Anthony Liguori
    uc->handle_reset   = usb_msd_handle_reset;
657 62aed765 Anthony Liguori
    uc->handle_control = usb_msd_handle_control;
658 62aed765 Anthony Liguori
    uc->handle_data    = usb_msd_handle_data;
659 39bffca2 Anthony Liguori
    dc->fw_name = "storage";
660 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_usb_msd;
661 39bffca2 Anthony Liguori
    dc->props = msd_properties;
662 62aed765 Anthony Liguori
}
663 62aed765 Anthony Liguori
664 39bffca2 Anthony Liguori
static TypeInfo msd_info = {
665 39bffca2 Anthony Liguori
    .name          = "usb-storage",
666 39bffca2 Anthony Liguori
    .parent        = TYPE_USB_DEVICE,
667 39bffca2 Anthony Liguori
    .instance_size = sizeof(MSDState),
668 39bffca2 Anthony Liguori
    .class_init    = usb_msd_class_initfn,
669 806b6024 Gerd Hoffmann
};
670 806b6024 Gerd Hoffmann
671 806b6024 Gerd Hoffmann
static void usb_msd_register_devices(void)
672 806b6024 Gerd Hoffmann
{
673 39bffca2 Anthony Liguori
    type_register_static(&msd_info);
674 ba02430f Anthony Liguori
    usb_legacy_register("usb-storage", "disk", usb_msd_init);
675 806b6024 Gerd Hoffmann
}
676 806b6024 Gerd Hoffmann
device_init(usb_msd_register_devices)