Statistics
| Branch: | Revision:

root / hw / usb-msd.c @ aba1f023

History | View | Annotate | Download (17.3 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 2e5d83bb pbrook
 * This code is licenced 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 2e5d83bb pbrook
typedef struct {
42 2e5d83bb pbrook
    USBDevice dev;
43 2e5d83bb pbrook
    enum USBMSDMode mode;
44 a917d384 pbrook
    uint32_t scsi_len;
45 a917d384 pbrook
    uint8_t *scsi_buf;
46 a917d384 pbrook
    uint32_t usb_len;
47 a917d384 pbrook
    uint8_t *usb_buf;
48 2e5d83bb pbrook
    uint32_t data_len;
49 a917d384 pbrook
    uint32_t residue;
50 2e5d83bb pbrook
    uint32_t tag;
51 5c6c0e51 Hannes Reinecke
    SCSIRequest *req;
52 ca9c39fa Gerd Hoffmann
    SCSIBus bus;
53 428c149b Christoph Hellwig
    BlockConf conf;
54 2e5d83bb pbrook
    SCSIDevice *scsi_dev;
55 6bb7b867 Stefan Hajnoczi
    uint32_t removable;
56 2e5d83bb pbrook
    int result;
57 4d611c9a pbrook
    /* For async completion.  */
58 4d611c9a pbrook
    USBPacket *packet;
59 2e5d83bb pbrook
} MSDState;
60 2e5d83bb pbrook
61 a917d384 pbrook
struct usb_msd_cbw {
62 a917d384 pbrook
    uint32_t sig;
63 a917d384 pbrook
    uint32_t tag;
64 a917d384 pbrook
    uint32_t data_len;
65 a917d384 pbrook
    uint8_t flags;
66 a917d384 pbrook
    uint8_t lun;
67 a917d384 pbrook
    uint8_t cmd_len;
68 a917d384 pbrook
    uint8_t cmd[16];
69 a917d384 pbrook
};
70 a917d384 pbrook
71 a917d384 pbrook
struct usb_msd_csw {
72 a917d384 pbrook
    uint32_t sig;
73 a917d384 pbrook
    uint32_t tag;
74 a917d384 pbrook
    uint32_t residue;
75 a917d384 pbrook
    uint8_t status;
76 a917d384 pbrook
};
77 a917d384 pbrook
78 81bfd2f2 Gerd Hoffmann
enum {
79 81bfd2f2 Gerd Hoffmann
    STR_MANUFACTURER = 1,
80 81bfd2f2 Gerd Hoffmann
    STR_PRODUCT,
81 81bfd2f2 Gerd Hoffmann
    STR_SERIALNUMBER,
82 ca0c730d Gerd Hoffmann
    STR_CONFIG_FULL,
83 ca0c730d Gerd Hoffmann
    STR_CONFIG_HIGH,
84 2e5d83bb pbrook
};
85 2e5d83bb pbrook
86 81bfd2f2 Gerd Hoffmann
static const USBDescStrings desc_strings = {
87 81bfd2f2 Gerd Hoffmann
    [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
88 81bfd2f2 Gerd Hoffmann
    [STR_PRODUCT]      = "QEMU USB HARDDRIVE",
89 81bfd2f2 Gerd Hoffmann
    [STR_SERIALNUMBER] = "1",
90 ca0c730d Gerd Hoffmann
    [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
91 ca0c730d Gerd Hoffmann
    [STR_CONFIG_HIGH]  = "High speed config (usb 2.0)",
92 81bfd2f2 Gerd Hoffmann
};
93 81bfd2f2 Gerd Hoffmann
94 ca0c730d Gerd Hoffmann
static const USBDescIface desc_iface_full = {
95 81bfd2f2 Gerd Hoffmann
    .bInterfaceNumber              = 0,
96 81bfd2f2 Gerd Hoffmann
    .bNumEndpoints                 = 2,
97 81bfd2f2 Gerd Hoffmann
    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
98 81bfd2f2 Gerd Hoffmann
    .bInterfaceSubClass            = 0x06, /* SCSI */
99 81bfd2f2 Gerd Hoffmann
    .bInterfaceProtocol            = 0x50, /* Bulk */
100 81bfd2f2 Gerd Hoffmann
    .eps = (USBDescEndpoint[]) {
101 81bfd2f2 Gerd Hoffmann
        {
102 81bfd2f2 Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_IN | 0x01,
103 81bfd2f2 Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
104 81bfd2f2 Gerd Hoffmann
            .wMaxPacketSize        = 64,
105 81bfd2f2 Gerd Hoffmann
        },{
106 81bfd2f2 Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_OUT | 0x02,
107 81bfd2f2 Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
108 81bfd2f2 Gerd Hoffmann
            .wMaxPacketSize        = 64,
109 81bfd2f2 Gerd Hoffmann
        },
110 81bfd2f2 Gerd Hoffmann
    }
111 81bfd2f2 Gerd Hoffmann
};
112 81bfd2f2 Gerd Hoffmann
113 ca0c730d Gerd Hoffmann
static const USBDescDevice desc_device_full = {
114 ca0c730d Gerd Hoffmann
    .bcdUSB                        = 0x0200,
115 81bfd2f2 Gerd Hoffmann
    .bMaxPacketSize0               = 8,
116 81bfd2f2 Gerd Hoffmann
    .bNumConfigurations            = 1,
117 81bfd2f2 Gerd Hoffmann
    .confs = (USBDescConfig[]) {
118 81bfd2f2 Gerd Hoffmann
        {
119 81bfd2f2 Gerd Hoffmann
            .bNumInterfaces        = 1,
120 81bfd2f2 Gerd Hoffmann
            .bConfigurationValue   = 1,
121 ca0c730d Gerd Hoffmann
            .iConfiguration        = STR_CONFIG_FULL,
122 81bfd2f2 Gerd Hoffmann
            .bmAttributes          = 0xc0,
123 ca0c730d Gerd Hoffmann
            .ifs = &desc_iface_full,
124 ca0c730d Gerd Hoffmann
        },
125 ca0c730d Gerd Hoffmann
    },
126 ca0c730d Gerd Hoffmann
};
127 ca0c730d Gerd Hoffmann
128 ca0c730d Gerd Hoffmann
static const USBDescIface desc_iface_high = {
129 ca0c730d Gerd Hoffmann
    .bInterfaceNumber              = 0,
130 ca0c730d Gerd Hoffmann
    .bNumEndpoints                 = 2,
131 ca0c730d Gerd Hoffmann
    .bInterfaceClass               = USB_CLASS_MASS_STORAGE,
132 ca0c730d Gerd Hoffmann
    .bInterfaceSubClass            = 0x06, /* SCSI */
133 ca0c730d Gerd Hoffmann
    .bInterfaceProtocol            = 0x50, /* Bulk */
134 ca0c730d Gerd Hoffmann
    .eps = (USBDescEndpoint[]) {
135 ca0c730d Gerd Hoffmann
        {
136 ca0c730d Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_IN | 0x01,
137 ca0c730d Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
138 ca0c730d Gerd Hoffmann
            .wMaxPacketSize        = 512,
139 ca0c730d Gerd Hoffmann
        },{
140 ca0c730d Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_OUT | 0x02,
141 ca0c730d Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_BULK,
142 ca0c730d Gerd Hoffmann
            .wMaxPacketSize        = 512,
143 ca0c730d Gerd Hoffmann
        },
144 ca0c730d Gerd Hoffmann
    }
145 ca0c730d Gerd Hoffmann
};
146 ca0c730d Gerd Hoffmann
147 ca0c730d Gerd Hoffmann
static const USBDescDevice desc_device_high = {
148 ca0c730d Gerd Hoffmann
    .bcdUSB                        = 0x0200,
149 ca0c730d Gerd Hoffmann
    .bMaxPacketSize0               = 64,
150 ca0c730d Gerd Hoffmann
    .bNumConfigurations            = 1,
151 ca0c730d Gerd Hoffmann
    .confs = (USBDescConfig[]) {
152 ca0c730d Gerd Hoffmann
        {
153 ca0c730d Gerd Hoffmann
            .bNumInterfaces        = 1,
154 ca0c730d Gerd Hoffmann
            .bConfigurationValue   = 1,
155 ca0c730d Gerd Hoffmann
            .iConfiguration        = STR_CONFIG_HIGH,
156 ca0c730d Gerd Hoffmann
            .bmAttributes          = 0xc0,
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 81bfd2f2 Gerd Hoffmann
        .idVendor          = 0,
165 81bfd2f2 Gerd Hoffmann
        .idProduct         = 0,
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 a917d384 pbrook
static void usb_msd_copy_data(MSDState *s)
177 a917d384 pbrook
{
178 a917d384 pbrook
    uint32_t len;
179 a917d384 pbrook
    len = s->usb_len;
180 a917d384 pbrook
    if (len > s->scsi_len)
181 a917d384 pbrook
        len = s->scsi_len;
182 a917d384 pbrook
    if (s->mode == USB_MSDM_DATAIN) {
183 a917d384 pbrook
        memcpy(s->usb_buf, s->scsi_buf, len);
184 a917d384 pbrook
    } else {
185 a917d384 pbrook
        memcpy(s->scsi_buf, s->usb_buf, len);
186 a917d384 pbrook
    }
187 a917d384 pbrook
    s->usb_len -= len;
188 a917d384 pbrook
    s->scsi_len -= len;
189 a917d384 pbrook
    s->usb_buf += len;
190 a917d384 pbrook
    s->scsi_buf += len;
191 a917d384 pbrook
    s->data_len -= len;
192 fa7935c1 Gerd Hoffmann
    if (s->scsi_len == 0 || s->data_len == 0) {
193 ad3376cc Paolo Bonzini
        scsi_req_continue(s->req);
194 a917d384 pbrook
    }
195 a917d384 pbrook
}
196 a917d384 pbrook
197 ab4797ad Gerd Hoffmann
static void usb_msd_send_status(MSDState *s, USBPacket *p)
198 a917d384 pbrook
{
199 a917d384 pbrook
    struct usb_msd_csw csw;
200 ab4797ad Gerd Hoffmann
    int len;
201 a917d384 pbrook
202 a917d384 pbrook
    csw.sig = cpu_to_le32(0x53425355);
203 a917d384 pbrook
    csw.tag = cpu_to_le32(s->tag);
204 a917d384 pbrook
    csw.residue = s->residue;
205 a917d384 pbrook
    csw.status = s->result;
206 ab4797ad Gerd Hoffmann
207 ab4797ad Gerd Hoffmann
    len = MIN(sizeof(csw), p->len);
208 ab4797ad Gerd Hoffmann
    memcpy(p->data, &csw, len);
209 a917d384 pbrook
}
210 a917d384 pbrook
211 aba1f023 Paolo Bonzini
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
212 2e5d83bb pbrook
{
213 5c6c0e51 Hannes Reinecke
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
214 a917d384 pbrook
    USBPacket *p = s->packet;
215 4d611c9a pbrook
216 5c6c0e51 Hannes Reinecke
    if (req->tag != s->tag) {
217 5c6c0e51 Hannes Reinecke
        fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
218 a917d384 pbrook
    }
219 c6df7102 Paolo Bonzini
220 ad3376cc Paolo Bonzini
    assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
221 aba1f023 Paolo Bonzini
    s->scsi_len = len;
222 0c34459b Paolo Bonzini
    s->scsi_buf = scsi_req_get_buf(req);
223 a917d384 pbrook
    if (p) {
224 a917d384 pbrook
        usb_msd_copy_data(s);
225 a917d384 pbrook
        if (s->usb_len == 0) {
226 a917d384 pbrook
            /* Set s->packet to NULL before calling usb_packet_complete
227 94843f66 Brad Hards
               because another request may be issued before
228 a917d384 pbrook
               usb_packet_complete returns.  */
229 a917d384 pbrook
            DPRINTF("Packet complete %p\n", p);
230 a917d384 pbrook
            s->packet = NULL;
231 13a9a0d3 Gerd Hoffmann
            usb_packet_complete(&s->dev, p);
232 a917d384 pbrook
        }
233 4d611c9a pbrook
    }
234 2e5d83bb pbrook
}
235 2e5d83bb pbrook
236 aba1f023 Paolo Bonzini
static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
237 c6df7102 Paolo Bonzini
{
238 c6df7102 Paolo Bonzini
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
239 c6df7102 Paolo Bonzini
    USBPacket *p = s->packet;
240 c6df7102 Paolo Bonzini
241 c6df7102 Paolo Bonzini
    if (req->tag != s->tag) {
242 c6df7102 Paolo Bonzini
        fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
243 c6df7102 Paolo Bonzini
    }
244 aba1f023 Paolo Bonzini
    DPRINTF("Command complete %d\n", status);
245 c6df7102 Paolo Bonzini
    s->residue = s->data_len;
246 aba1f023 Paolo Bonzini
    s->result = status != 0;
247 c6df7102 Paolo Bonzini
    if (s->packet) {
248 c6df7102 Paolo Bonzini
        if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
249 c6df7102 Paolo Bonzini
            /* A deferred packet with no write data remaining must be
250 c6df7102 Paolo Bonzini
               the status read packet.  */
251 c6df7102 Paolo Bonzini
            usb_msd_send_status(s, p);
252 c6df7102 Paolo Bonzini
            s->mode = USB_MSDM_CBW;
253 c6df7102 Paolo Bonzini
        } else {
254 c6df7102 Paolo Bonzini
            if (s->data_len) {
255 c6df7102 Paolo Bonzini
                s->data_len -= s->usb_len;
256 c6df7102 Paolo Bonzini
                if (s->mode == USB_MSDM_DATAIN) {
257 c6df7102 Paolo Bonzini
                    memset(s->usb_buf, 0, s->usb_len);
258 c6df7102 Paolo Bonzini
                }
259 c6df7102 Paolo Bonzini
                s->usb_len = 0;
260 c6df7102 Paolo Bonzini
            }
261 c6df7102 Paolo Bonzini
            if (s->data_len == 0) {
262 c6df7102 Paolo Bonzini
                s->mode = USB_MSDM_CSW;
263 c6df7102 Paolo Bonzini
            }
264 c6df7102 Paolo Bonzini
        }
265 c6df7102 Paolo Bonzini
        s->packet = NULL;
266 c6df7102 Paolo Bonzini
        usb_packet_complete(&s->dev, p);
267 c6df7102 Paolo Bonzini
    } else if (s->data_len == 0) {
268 c6df7102 Paolo Bonzini
        s->mode = USB_MSDM_CSW;
269 c6df7102 Paolo Bonzini
    }
270 c6df7102 Paolo Bonzini
    scsi_req_unref(req);
271 c6df7102 Paolo Bonzini
    s->req = NULL;
272 c6df7102 Paolo Bonzini
}
273 c6df7102 Paolo Bonzini
274 94d3f98a Paolo Bonzini
static void usb_msd_request_cancelled(SCSIRequest *req)
275 94d3f98a Paolo Bonzini
{
276 94d3f98a Paolo Bonzini
    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
277 94d3f98a Paolo Bonzini
278 94d3f98a Paolo Bonzini
    if (req == s->req) {
279 94d3f98a Paolo Bonzini
        scsi_req_unref(s->req);
280 94d3f98a Paolo Bonzini
        s->req = NULL;
281 94d3f98a Paolo Bonzini
        s->packet = NULL;
282 94d3f98a Paolo Bonzini
        s->scsi_len = 0;
283 94d3f98a Paolo Bonzini
    }
284 94d3f98a Paolo Bonzini
}
285 94d3f98a Paolo Bonzini
286 059809e4 bellard
static void usb_msd_handle_reset(USBDevice *dev)
287 2e5d83bb pbrook
{
288 2e5d83bb pbrook
    MSDState *s = (MSDState *)dev;
289 2e5d83bb pbrook
290 2e5d83bb pbrook
    DPRINTF("Reset\n");
291 2e5d83bb pbrook
    s->mode = USB_MSDM_CBW;
292 2e5d83bb pbrook
}
293 2e5d83bb pbrook
294 2e5d83bb pbrook
static int usb_msd_handle_control(USBDevice *dev, int request, int value,
295 2e5d83bb pbrook
                                  int index, int length, uint8_t *data)
296 2e5d83bb pbrook
{
297 2e5d83bb pbrook
    MSDState *s = (MSDState *)dev;
298 81bfd2f2 Gerd Hoffmann
    int ret;
299 2e5d83bb pbrook
300 81bfd2f2 Gerd Hoffmann
    ret = usb_desc_handle_control(dev, request, value, index, length, data);
301 81bfd2f2 Gerd Hoffmann
    if (ret >= 0) {
302 81bfd2f2 Gerd Hoffmann
        return ret;
303 81bfd2f2 Gerd Hoffmann
    }
304 81bfd2f2 Gerd Hoffmann
305 81bfd2f2 Gerd Hoffmann
    ret = 0;
306 2e5d83bb pbrook
    switch (request) {
307 2e5d83bb pbrook
    case DeviceRequest | USB_REQ_GET_INTERFACE:
308 2e5d83bb pbrook
        data[0] = 0;
309 2e5d83bb pbrook
        ret = 1;
310 2e5d83bb pbrook
        break;
311 2e5d83bb pbrook
    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
312 2e5d83bb pbrook
        ret = 0;
313 2e5d83bb pbrook
        break;
314 2e5d83bb pbrook
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
315 e5322f76 Arnaud Patard (Rtp)
        ret = 0;
316 e5322f76 Arnaud Patard (Rtp)
        break;
317 e5322f76 Arnaud Patard (Rtp)
    case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
318 2e5d83bb pbrook
        ret = 0;
319 2e5d83bb pbrook
        break;
320 2e5d83bb pbrook
        /* Class specific requests.  */
321 f3571b1a Max Reitz
    case ClassInterfaceOutRequest | MassStorageReset:
322 2e5d83bb pbrook
        /* Reset state ready for the next CBW.  */
323 2e5d83bb pbrook
        s->mode = USB_MSDM_CBW;
324 2e5d83bb pbrook
        ret = 0;
325 2e5d83bb pbrook
        break;
326 f3571b1a Max Reitz
    case ClassInterfaceRequest | GetMaxLun:
327 2e5d83bb pbrook
        data[0] = 0;
328 2e5d83bb pbrook
        ret = 1;
329 2e5d83bb pbrook
        break;
330 2e5d83bb pbrook
    default:
331 2e5d83bb pbrook
        ret = USB_RET_STALL;
332 2e5d83bb pbrook
        break;
333 2e5d83bb pbrook
    }
334 2e5d83bb pbrook
    return ret;
335 2e5d83bb pbrook
}
336 2e5d83bb pbrook
337 4d611c9a pbrook
static void usb_msd_cancel_io(USBPacket *p, void *opaque)
338 4d611c9a pbrook
{
339 4d611c9a pbrook
    MSDState *s = opaque;
340 94d3f98a Paolo Bonzini
    scsi_req_cancel(s->req);
341 4d611c9a pbrook
}
342 4d611c9a pbrook
343 4d611c9a pbrook
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
344 2e5d83bb pbrook
{
345 2e5d83bb pbrook
    MSDState *s = (MSDState *)dev;
346 2e5d83bb pbrook
    int ret = 0;
347 2e5d83bb pbrook
    struct usb_msd_cbw cbw;
348 4d611c9a pbrook
    uint8_t devep = p->devep;
349 4d611c9a pbrook
    uint8_t *data = p->data;
350 4d611c9a pbrook
    int len = p->len;
351 2e5d83bb pbrook
352 4d611c9a pbrook
    switch (p->pid) {
353 2e5d83bb pbrook
    case USB_TOKEN_OUT:
354 2e5d83bb pbrook
        if (devep != 2)
355 2e5d83bb pbrook
            goto fail;
356 2e5d83bb pbrook
357 2e5d83bb pbrook
        switch (s->mode) {
358 2e5d83bb pbrook
        case USB_MSDM_CBW:
359 2e5d83bb pbrook
            if (len != 31) {
360 2e5d83bb pbrook
                fprintf(stderr, "usb-msd: Bad CBW size");
361 2e5d83bb pbrook
                goto fail;
362 2e5d83bb pbrook
            }
363 2e5d83bb pbrook
            memcpy(&cbw, data, 31);
364 2e5d83bb pbrook
            if (le32_to_cpu(cbw.sig) != 0x43425355) {
365 2e5d83bb pbrook
                fprintf(stderr, "usb-msd: Bad signature %08x\n",
366 2e5d83bb pbrook
                        le32_to_cpu(cbw.sig));
367 2e5d83bb pbrook
                goto fail;
368 2e5d83bb pbrook
            }
369 2e5d83bb pbrook
            DPRINTF("Command on LUN %d\n", cbw.lun);
370 2e5d83bb pbrook
            if (cbw.lun != 0) {
371 2e5d83bb pbrook
                fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
372 2e5d83bb pbrook
                goto fail;
373 2e5d83bb pbrook
            }
374 2e5d83bb pbrook
            s->tag = le32_to_cpu(cbw.tag);
375 2e5d83bb pbrook
            s->data_len = le32_to_cpu(cbw.data_len);
376 2e5d83bb pbrook
            if (s->data_len == 0) {
377 2e5d83bb pbrook
                s->mode = USB_MSDM_CSW;
378 2e5d83bb pbrook
            } else if (cbw.flags & 0x80) {
379 2e5d83bb pbrook
                s->mode = USB_MSDM_DATAIN;
380 2e5d83bb pbrook
            } else {
381 2e5d83bb pbrook
                s->mode = USB_MSDM_DATAOUT;
382 2e5d83bb pbrook
            }
383 2e5d83bb pbrook
            DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
384 2e5d83bb pbrook
                    s->tag, cbw.flags, cbw.cmd_len, s->data_len);
385 a917d384 pbrook
            s->residue = 0;
386 ef0bdf77 Gerd Hoffmann
            s->scsi_len = 0;
387 43a2b339 Paolo Bonzini
            s->req = scsi_req_new(s->scsi_dev, s->tag, 0);
388 fc4f0754 Paolo Bonzini
            scsi_req_enqueue(s->req, cbw.cmd);
389 a917d384 pbrook
            /* ??? Should check that USB and SCSI data transfer
390 a917d384 pbrook
               directions match.  */
391 ad3376cc Paolo Bonzini
            if (s->mode != USB_MSDM_CSW && s->residue == 0) {
392 ad3376cc Paolo Bonzini
                scsi_req_continue(s->req);
393 a917d384 pbrook
            }
394 2e5d83bb pbrook
            ret = len;
395 2e5d83bb pbrook
            break;
396 2e5d83bb pbrook
397 2e5d83bb pbrook
        case USB_MSDM_DATAOUT:
398 2e5d83bb pbrook
            DPRINTF("Data out %d/%d\n", len, s->data_len);
399 2e5d83bb pbrook
            if (len > s->data_len)
400 2e5d83bb pbrook
                goto fail;
401 2e5d83bb pbrook
402 a917d384 pbrook
            s->usb_buf = data;
403 a917d384 pbrook
            s->usb_len = len;
404 a917d384 pbrook
            if (s->scsi_len) {
405 a917d384 pbrook
                usb_msd_copy_data(s);
406 a917d384 pbrook
            }
407 a917d384 pbrook
            if (s->residue && s->usb_len) {
408 a917d384 pbrook
                s->data_len -= s->usb_len;
409 a917d384 pbrook
                if (s->data_len == 0)
410 a917d384 pbrook
                    s->mode = USB_MSDM_CSW;
411 a917d384 pbrook
                s->usb_len = 0;
412 a917d384 pbrook
            }
413 a917d384 pbrook
            if (s->usb_len) {
414 4d611c9a pbrook
                DPRINTF("Deferring packet %p\n", p);
415 4d611c9a pbrook
                usb_defer_packet(p, usb_msd_cancel_io, s);
416 4d611c9a pbrook
                s->packet = p;
417 4d611c9a pbrook
                ret = USB_RET_ASYNC;
418 a917d384 pbrook
            } else {
419 a917d384 pbrook
                ret = len;
420 4d611c9a pbrook
            }
421 2e5d83bb pbrook
            break;
422 2e5d83bb pbrook
423 2e5d83bb pbrook
        default:
424 2e5d83bb pbrook
            DPRINTF("Unexpected write (len %d)\n", len);
425 2e5d83bb pbrook
            goto fail;
426 2e5d83bb pbrook
        }
427 2e5d83bb pbrook
        break;
428 2e5d83bb pbrook
429 2e5d83bb pbrook
    case USB_TOKEN_IN:
430 2e5d83bb pbrook
        if (devep != 1)
431 2e5d83bb pbrook
            goto fail;
432 2e5d83bb pbrook
433 2e5d83bb pbrook
        switch (s->mode) {
434 a917d384 pbrook
        case USB_MSDM_DATAOUT:
435 a917d384 pbrook
            if (s->data_len != 0 || len < 13)
436 a917d384 pbrook
                goto fail;
437 a917d384 pbrook
            /* Waiting for SCSI write to complete.  */
438 a917d384 pbrook
            usb_defer_packet(p, usb_msd_cancel_io, s);
439 a917d384 pbrook
            s->packet = p;
440 a917d384 pbrook
            ret = USB_RET_ASYNC;
441 a917d384 pbrook
            break;
442 a917d384 pbrook
443 2e5d83bb pbrook
        case USB_MSDM_CSW:
444 2e5d83bb pbrook
            DPRINTF("Command status %d tag 0x%x, len %d\n",
445 2e5d83bb pbrook
                    s->result, s->tag, len);
446 2e5d83bb pbrook
            if (len < 13)
447 2e5d83bb pbrook
                goto fail;
448 2e5d83bb pbrook
449 ab4797ad Gerd Hoffmann
            usb_msd_send_status(s, p);
450 2e5d83bb pbrook
            s->mode = USB_MSDM_CBW;
451 a917d384 pbrook
            ret = 13;
452 2e5d83bb pbrook
            break;
453 2e5d83bb pbrook
454 2e5d83bb pbrook
        case USB_MSDM_DATAIN:
455 fa7935c1 Gerd Hoffmann
            DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len);
456 2e5d83bb pbrook
            if (len > s->data_len)
457 2e5d83bb pbrook
                len = s->data_len;
458 a917d384 pbrook
            s->usb_buf = data;
459 a917d384 pbrook
            s->usb_len = len;
460 a917d384 pbrook
            if (s->scsi_len) {
461 a917d384 pbrook
                usb_msd_copy_data(s);
462 a917d384 pbrook
            }
463 a917d384 pbrook
            if (s->residue && s->usb_len) {
464 a917d384 pbrook
                s->data_len -= s->usb_len;
465 a917d384 pbrook
                memset(s->usb_buf, 0, s->usb_len);
466 a917d384 pbrook
                if (s->data_len == 0)
467 a917d384 pbrook
                    s->mode = USB_MSDM_CSW;
468 a917d384 pbrook
                s->usb_len = 0;
469 a917d384 pbrook
            }
470 a917d384 pbrook
            if (s->usb_len) {
471 4d611c9a pbrook
                DPRINTF("Deferring packet %p\n", p);
472 4d611c9a pbrook
                usb_defer_packet(p, usb_msd_cancel_io, s);
473 4d611c9a pbrook
                s->packet = p;
474 4d611c9a pbrook
                ret = USB_RET_ASYNC;
475 a917d384 pbrook
            } else {
476 a917d384 pbrook
                ret = len;
477 4d611c9a pbrook
            }
478 2e5d83bb pbrook
            break;
479 2e5d83bb pbrook
480 2e5d83bb pbrook
        default:
481 2e5d83bb pbrook
            DPRINTF("Unexpected read (len %d)\n", len);
482 2e5d83bb pbrook
            goto fail;
483 2e5d83bb pbrook
        }
484 2e5d83bb pbrook
        break;
485 2e5d83bb pbrook
486 2e5d83bb pbrook
    default:
487 2e5d83bb pbrook
        DPRINTF("Bad token\n");
488 2e5d83bb pbrook
    fail:
489 2e5d83bb pbrook
        ret = USB_RET_STALL;
490 2e5d83bb pbrook
        break;
491 2e5d83bb pbrook
    }
492 2e5d83bb pbrook
493 2e5d83bb pbrook
    return ret;
494 2e5d83bb pbrook
}
495 2e5d83bb pbrook
496 b3e461d3 Gerd Hoffmann
static void usb_msd_password_cb(void *opaque, int err)
497 b3e461d3 Gerd Hoffmann
{
498 b3e461d3 Gerd Hoffmann
    MSDState *s = opaque;
499 b3e461d3 Gerd Hoffmann
500 b3e461d3 Gerd Hoffmann
    if (!err)
501 b3e461d3 Gerd Hoffmann
        usb_device_attach(&s->dev);
502 b3e461d3 Gerd Hoffmann
    else
503 b3e461d3 Gerd Hoffmann
        qdev_unplug(&s->dev.qdev);
504 b3e461d3 Gerd Hoffmann
}
505 b3e461d3 Gerd Hoffmann
506 cfdc1bb0 Paolo Bonzini
static const struct SCSIBusOps usb_msd_scsi_ops = {
507 c6df7102 Paolo Bonzini
    .transfer_data = usb_msd_transfer_data,
508 94d3f98a Paolo Bonzini
    .complete = usb_msd_command_complete,
509 94d3f98a Paolo Bonzini
    .cancel = usb_msd_request_cancelled
510 cfdc1bb0 Paolo Bonzini
};
511 cfdc1bb0 Paolo Bonzini
512 806b6024 Gerd Hoffmann
static int usb_msd_initfn(USBDevice *dev)
513 806b6024 Gerd Hoffmann
{
514 806b6024 Gerd Hoffmann
    MSDState *s = DO_UPCAST(MSDState, dev, dev);
515 f8b6cc00 Markus Armbruster
    BlockDriverState *bs = s->conf.bs;
516 4a1e1bc4 Gerd Hoffmann
    DriveInfo *dinfo;
517 806b6024 Gerd Hoffmann
518 f8b6cc00 Markus Armbruster
    if (!bs) {
519 1ecda02b Markus Armbruster
        error_report("usb-msd: drive property not set");
520 7fc2f2c0 Gerd Hoffmann
        return -1;
521 7fc2f2c0 Gerd Hoffmann
    }
522 7fc2f2c0 Gerd Hoffmann
523 14bafc54 Markus Armbruster
    /*
524 14bafc54 Markus Armbruster
     * Hack alert: this pretends to be a block device, but it's really
525 14bafc54 Markus Armbruster
     * a SCSI bus that can serve only a single device, which it
526 18846dee Markus Armbruster
     * creates automatically.  But first it needs to detach from its
527 18846dee Markus Armbruster
     * blockdev, or else scsi_bus_legacy_add_drive() dies when it
528 18846dee Markus Armbruster
     * attaches again.
529 14bafc54 Markus Armbruster
     *
530 14bafc54 Markus Armbruster
     * The hack is probably a bad idea.
531 14bafc54 Markus Armbruster
     */
532 18846dee Markus Armbruster
    bdrv_detach(bs, &s->dev.qdev);
533 f8b6cc00 Markus Armbruster
    s->conf.bs = NULL;
534 14bafc54 Markus Armbruster
535 4a1e1bc4 Gerd Hoffmann
    dinfo = drive_get_by_blockdev(bs);
536 4a1e1bc4 Gerd Hoffmann
    if (dinfo && dinfo->serial) {
537 4a1e1bc4 Gerd Hoffmann
        usb_desc_set_string(dev, STR_SERIALNUMBER, dinfo->serial);
538 4a1e1bc4 Gerd Hoffmann
    }
539 4a1e1bc4 Gerd Hoffmann
540 a980a065 Gerd Hoffmann
    usb_desc_init(dev);
541 cfdc1bb0 Paolo Bonzini
    scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, &usb_msd_scsi_ops);
542 6bb7b867 Stefan Hajnoczi
    s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
543 fa66b909 Markus Armbruster
    if (!s->scsi_dev) {
544 fa66b909 Markus Armbruster
        return -1;
545 fa66b909 Markus Armbruster
    }
546 cb23117b Gerd Hoffmann
    s->bus.qbus.allow_hotplug = 0;
547 7fc2f2c0 Gerd Hoffmann
    usb_msd_handle_reset(dev);
548 b3e461d3 Gerd Hoffmann
549 f8b6cc00 Markus Armbruster
    if (bdrv_key_required(bs)) {
550 a4426488 Markus Armbruster
        if (cur_mon) {
551 f8b6cc00 Markus Armbruster
            monitor_read_bdrv_key_start(cur_mon, bs, usb_msd_password_cb, s);
552 b3e461d3 Gerd Hoffmann
            s->dev.auto_attach = 0;
553 b3e461d3 Gerd Hoffmann
        } else {
554 b3e461d3 Gerd Hoffmann
            autostart = 0;
555 b3e461d3 Gerd Hoffmann
        }
556 b3e461d3 Gerd Hoffmann
    }
557 b3e461d3 Gerd Hoffmann
558 cf8ce30d Gleb Natapov
    add_boot_device_path(s->conf.bootindex, &dev->qdev, "/disk@0,0");
559 806b6024 Gerd Hoffmann
    return 0;
560 806b6024 Gerd Hoffmann
}
561 806b6024 Gerd Hoffmann
562 b3e461d3 Gerd Hoffmann
static USBDevice *usb_msd_init(const char *filename)
563 2e5d83bb pbrook
{
564 7fc2f2c0 Gerd Hoffmann
    static int nr=0;
565 7fc2f2c0 Gerd Hoffmann
    char id[8];
566 7fc2f2c0 Gerd Hoffmann
    QemuOpts *opts;
567 7fc2f2c0 Gerd Hoffmann
    DriveInfo *dinfo;
568 806b6024 Gerd Hoffmann
    USBDevice *dev;
569 334c0241 aurel32
    const char *p1;
570 334c0241 aurel32
    char fmt[32];
571 334c0241 aurel32
572 7fc2f2c0 Gerd Hoffmann
    /* parse -usbdevice disk: syntax into drive opts */
573 7fc2f2c0 Gerd Hoffmann
    snprintf(id, sizeof(id), "usb%d", nr++);
574 3329f07b Gerd Hoffmann
    opts = qemu_opts_create(qemu_find_opts("drive"), id, 0);
575 7fc2f2c0 Gerd Hoffmann
576 334c0241 aurel32
    p1 = strchr(filename, ':');
577 334c0241 aurel32
    if (p1++) {
578 334c0241 aurel32
        const char *p2;
579 334c0241 aurel32
580 334c0241 aurel32
        if (strstart(filename, "format=", &p2)) {
581 334c0241 aurel32
            int len = MIN(p1 - p2, sizeof(fmt));
582 334c0241 aurel32
            pstrcpy(fmt, len, p2);
583 7fc2f2c0 Gerd Hoffmann
            qemu_opt_set(opts, "format", fmt);
584 334c0241 aurel32
        } else if (*filename != ':') {
585 334c0241 aurel32
            printf("unrecognized USB mass-storage option %s\n", filename);
586 334c0241 aurel32
            return NULL;
587 334c0241 aurel32
        }
588 334c0241 aurel32
        filename = p1;
589 334c0241 aurel32
    }
590 334c0241 aurel32
    if (!*filename) {
591 334c0241 aurel32
        printf("block device specification needed\n");
592 334c0241 aurel32
        return NULL;
593 334c0241 aurel32
    }
594 7fc2f2c0 Gerd Hoffmann
    qemu_opt_set(opts, "file", filename);
595 7fc2f2c0 Gerd Hoffmann
    qemu_opt_set(opts, "if", "none");
596 2e5d83bb pbrook
597 7fc2f2c0 Gerd Hoffmann
    /* create host drive */
598 319ae529 Markus Armbruster
    dinfo = drive_init(opts, 0);
599 7fc2f2c0 Gerd Hoffmann
    if (!dinfo) {
600 7fc2f2c0 Gerd Hoffmann
        qemu_opts_del(opts);
601 806b6024 Gerd Hoffmann
        return NULL;
602 7fc2f2c0 Gerd Hoffmann
    }
603 2e5d83bb pbrook
604 7fc2f2c0 Gerd Hoffmann
    /* create guest device */
605 556cd098 Markus Armbruster
    dev = usb_create(NULL /* FIXME */, "usb-storage");
606 d44168ff Paul Brook
    if (!dev) {
607 d44168ff Paul Brook
        return NULL;
608 d44168ff Paul Brook
    }
609 18846dee Markus Armbruster
    if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
610 18846dee Markus Armbruster
        qdev_free(&dev->qdev);
611 18846dee Markus Armbruster
        return NULL;
612 18846dee Markus Armbruster
    }
613 33e66b86 Markus Armbruster
    if (qdev_init(&dev->qdev) < 0)
614 33e66b86 Markus Armbruster
        return NULL;
615 1f6e24e7 bellard
616 7fc2f2c0 Gerd Hoffmann
    return dev;
617 2e5d83bb pbrook
}
618 bb5fc20f aliguori
619 806b6024 Gerd Hoffmann
static struct USBDeviceInfo msd_info = {
620 06384698 Markus Armbruster
    .product_desc   = "QEMU USB MSD",
621 556cd098 Markus Armbruster
    .qdev.name      = "usb-storage",
622 cf8ce30d Gleb Natapov
    .qdev.fw_name      = "storage",
623 806b6024 Gerd Hoffmann
    .qdev.size      = sizeof(MSDState),
624 81bfd2f2 Gerd Hoffmann
    .usb_desc       = &desc,
625 806b6024 Gerd Hoffmann
    .init           = usb_msd_initfn,
626 806b6024 Gerd Hoffmann
    .handle_packet  = usb_generic_handle_packet,
627 ca0c730d Gerd Hoffmann
    .handle_attach  = usb_desc_attach,
628 806b6024 Gerd Hoffmann
    .handle_reset   = usb_msd_handle_reset,
629 806b6024 Gerd Hoffmann
    .handle_control = usb_msd_handle_control,
630 806b6024 Gerd Hoffmann
    .handle_data    = usb_msd_handle_data,
631 b3e461d3 Gerd Hoffmann
    .usbdevice_name = "disk",
632 b3e461d3 Gerd Hoffmann
    .usbdevice_init = usb_msd_init,
633 7fc2f2c0 Gerd Hoffmann
    .qdev.props     = (Property[]) {
634 428c149b Christoph Hellwig
        DEFINE_BLOCK_PROPERTIES(MSDState, conf),
635 6bb7b867 Stefan Hajnoczi
        DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
636 7fc2f2c0 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
637 7fc2f2c0 Gerd Hoffmann
    },
638 806b6024 Gerd Hoffmann
};
639 806b6024 Gerd Hoffmann
640 806b6024 Gerd Hoffmann
static void usb_msd_register_devices(void)
641 806b6024 Gerd Hoffmann
{
642 806b6024 Gerd Hoffmann
    usb_qdev_register(&msd_info);
643 806b6024 Gerd Hoffmann
}
644 806b6024 Gerd Hoffmann
device_init(usb_msd_register_devices)