]> Git Repo - qemu.git/blame - hw/usb/dev-uas.c
Include migration/vmstate.h less
[qemu.git] / hw / usb / dev-uas.c
CommitLineData
0f58f68b
GH
1/*
2 * UAS (USB Attached SCSI) emulation
3 *
4 * Copyright Red Hat, Inc. 2012
5 *
6 * Author: Gerd Hoffmann <[email protected]>
7 *
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
10 */
11
e532b2e0 12#include "qemu/osdep.h"
1de7afc9
PB
13#include "qemu/option.h"
14#include "qemu/config-file.h"
0f58f68b 15#include "trace.h"
6b7afb7f 16#include "qemu/error-report.h"
0b8fa32f 17#include "qemu/module.h"
0f58f68b
GH
18
19#include "hw/usb.h"
d6454270 20#include "migration/vmstate.h"
463581a8 21#include "desc.h"
0d09e41a 22#include "hw/scsi/scsi.h"
08e2c9f1 23#include "scsi/constants.h"
0f58f68b
GH
24
25/* --------------------------------------------------------------------- */
26
27#define UAS_UI_COMMAND 0x01
28#define UAS_UI_SENSE 0x03
29#define UAS_UI_RESPONSE 0x04
30#define UAS_UI_TASK_MGMT 0x05
31#define UAS_UI_READ_READY 0x06
32#define UAS_UI_WRITE_READY 0x07
33
34#define UAS_RC_TMF_COMPLETE 0x00
35#define UAS_RC_INVALID_INFO_UNIT 0x02
36#define UAS_RC_TMF_NOT_SUPPORTED 0x04
37#define UAS_RC_TMF_FAILED 0x05
38#define UAS_RC_TMF_SUCCEEDED 0x08
39#define UAS_RC_INCORRECT_LUN 0x09
40#define UAS_RC_OVERLAPPED_TAG 0x0a
41
42#define UAS_TMF_ABORT_TASK 0x01
43#define UAS_TMF_ABORT_TASK_SET 0x02
44#define UAS_TMF_CLEAR_TASK_SET 0x04
45#define UAS_TMF_LOGICAL_UNIT_RESET 0x08
46#define UAS_TMF_I_T_NEXUS_RESET 0x10
47#define UAS_TMF_CLEAR_ACA 0x40
48#define UAS_TMF_QUERY_TASK 0x80
49#define UAS_TMF_QUERY_TASK_SET 0x81
50#define UAS_TMF_QUERY_ASYNC_EVENT 0x82
51
52#define UAS_PIPE_ID_COMMAND 0x01
53#define UAS_PIPE_ID_STATUS 0x02
54#define UAS_PIPE_ID_DATA_IN 0x03
55#define UAS_PIPE_ID_DATA_OUT 0x04
56
57typedef struct {
58 uint8_t id;
59 uint8_t reserved;
60 uint16_t tag;
5007c940 61} QEMU_PACKED uas_iu_header;
0f58f68b
GH
62
63typedef struct {
64 uint8_t prio_taskattr; /* 6:3 priority, 2:0 task attribute */
65 uint8_t reserved_1;
66 uint8_t add_cdb_length; /* 7:2 additional adb length (dwords) */
67 uint8_t reserved_2;
68 uint64_t lun;
69 uint8_t cdb[16];
70 uint8_t add_cdb[];
5007c940 71} QEMU_PACKED uas_iu_command;
0f58f68b
GH
72
73typedef struct {
74 uint16_t status_qualifier;
75 uint8_t status;
76 uint8_t reserved[7];
77 uint16_t sense_length;
78 uint8_t sense_data[18];
5007c940 79} QEMU_PACKED uas_iu_sense;
0f58f68b
GH
80
81typedef struct {
49cfa2fd 82 uint8_t add_response_info[3];
0f58f68b 83 uint8_t response_code;
5007c940 84} QEMU_PACKED uas_iu_response;
0f58f68b
GH
85
86typedef struct {
87 uint8_t function;
88 uint8_t reserved;
89 uint16_t task_tag;
90 uint64_t lun;
5007c940 91} QEMU_PACKED uas_iu_task_mgmt;
0f58f68b
GH
92
93typedef struct {
5007c940 94 uas_iu_header hdr;
0f58f68b 95 union {
5007c940
HG
96 uas_iu_command command;
97 uas_iu_sense sense;
98 uas_iu_task_mgmt task;
99 uas_iu_response response;
0f58f68b 100 };
5007c940 101} QEMU_PACKED uas_iu;
0f58f68b
GH
102
103/* --------------------------------------------------------------------- */
104
89a453d4
GH
105#define UAS_STREAM_BM_ATTR 4
106#define UAS_MAX_STREAMS (1 << UAS_STREAM_BM_ATTR)
107
0f58f68b
GH
108typedef struct UASDevice UASDevice;
109typedef struct UASRequest UASRequest;
110typedef struct UASStatus UASStatus;
111
112struct UASDevice {
113 USBDevice dev;
114 SCSIBus bus;
0f58f68b
GH
115 QEMUBH *status_bh;
116 QTAILQ_HEAD(, UASStatus) results;
117 QTAILQ_HEAD(, UASRequest) requests;
89a453d4 118
1556a8fc
GH
119 /* properties */
120 uint32_t requestlog;
121
89a453d4
GH
122 /* usb 2.0 only */
123 USBPacket *status2;
124 UASRequest *datain2;
125 UASRequest *dataout2;
126
127 /* usb 3.0 only */
0478661e
HG
128 USBPacket *data3[UAS_MAX_STREAMS + 1];
129 USBPacket *status3[UAS_MAX_STREAMS + 1];
0f58f68b
GH
130};
131
0b06d099
GA
132#define TYPE_USB_UAS "usb-uas"
133#define USB_UAS(obj) OBJECT_CHECK(UASDevice, (obj), TYPE_USB_UAS)
134
0f58f68b
GH
135struct UASRequest {
136 uint16_t tag;
137 uint64_t lun;
138 UASDevice *uas;
139 SCSIDevice *dev;
140 SCSIRequest *req;
141 USBPacket *data;
142 bool data_async;
143 bool active;
144 bool complete;
145 uint32_t buf_off;
146 uint32_t buf_size;
147 uint32_t data_off;
148 uint32_t data_size;
149 QTAILQ_ENTRY(UASRequest) next;
150};
151
152struct UASStatus {
89a453d4 153 uint32_t stream;
5007c940 154 uas_iu status;
0f58f68b
GH
155 uint32_t length;
156 QTAILQ_ENTRY(UASStatus) next;
157};
158
159/* --------------------------------------------------------------------- */
160
161enum {
162 STR_MANUFACTURER = 1,
163 STR_PRODUCT,
164 STR_SERIALNUMBER,
165 STR_CONFIG_HIGH,
89a453d4 166 STR_CONFIG_SUPER,
0f58f68b
GH
167};
168
169static const USBDescStrings desc_strings = {
170 [STR_MANUFACTURER] = "QEMU",
171 [STR_PRODUCT] = "USB Attached SCSI HBA",
172 [STR_SERIALNUMBER] = "27842",
173 [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
89a453d4 174 [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
0f58f68b
GH
175};
176
177static const USBDescIface desc_iface_high = {
178 .bInterfaceNumber = 0,
179 .bNumEndpoints = 4,
180 .bInterfaceClass = USB_CLASS_MASS_STORAGE,
181 .bInterfaceSubClass = 0x06, /* SCSI */
182 .bInterfaceProtocol = 0x62, /* UAS */
183 .eps = (USBDescEndpoint[]) {
184 {
185 .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
186 .bmAttributes = USB_ENDPOINT_XFER_BULK,
187 .wMaxPacketSize = 512,
188 .extra = (uint8_t[]) {
189 0x04, /* u8 bLength */
190 0x24, /* u8 bDescriptorType */
191 UAS_PIPE_ID_COMMAND,
192 0x00, /* u8 bReserved */
193 },
194 },{
195 .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_STATUS,
196 .bmAttributes = USB_ENDPOINT_XFER_BULK,
197 .wMaxPacketSize = 512,
198 .extra = (uint8_t[]) {
199 0x04, /* u8 bLength */
200 0x24, /* u8 bDescriptorType */
201 UAS_PIPE_ID_STATUS,
202 0x00, /* u8 bReserved */
203 },
204 },{
205 .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
206 .bmAttributes = USB_ENDPOINT_XFER_BULK,
207 .wMaxPacketSize = 512,
208 .extra = (uint8_t[]) {
209 0x04, /* u8 bLength */
210 0x24, /* u8 bDescriptorType */
211 UAS_PIPE_ID_DATA_IN,
212 0x00, /* u8 bReserved */
213 },
214 },{
215 .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
216 .bmAttributes = USB_ENDPOINT_XFER_BULK,
217 .wMaxPacketSize = 512,
218 .extra = (uint8_t[]) {
219 0x04, /* u8 bLength */
220 0x24, /* u8 bDescriptorType */
221 UAS_PIPE_ID_DATA_OUT,
222 0x00, /* u8 bReserved */
223 },
224 },
225 }
226};
227
89a453d4
GH
228static const USBDescIface desc_iface_super = {
229 .bInterfaceNumber = 0,
230 .bNumEndpoints = 4,
231 .bInterfaceClass = USB_CLASS_MASS_STORAGE,
232 .bInterfaceSubClass = 0x06, /* SCSI */
233 .bInterfaceProtocol = 0x62, /* UAS */
234 .eps = (USBDescEndpoint[]) {
235 {
236 .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_COMMAND,
237 .bmAttributes = USB_ENDPOINT_XFER_BULK,
238 .wMaxPacketSize = 1024,
239 .bMaxBurst = 15,
240 .extra = (uint8_t[]) {
241 0x04, /* u8 bLength */
242 0x24, /* u8 bDescriptorType */
243 UAS_PIPE_ID_COMMAND,
244 0x00, /* u8 bReserved */
245 },
246 },{
247 .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_STATUS,
248 .bmAttributes = USB_ENDPOINT_XFER_BULK,
249 .wMaxPacketSize = 1024,
250 .bMaxBurst = 15,
251 .bmAttributes_super = UAS_STREAM_BM_ATTR,
252 .extra = (uint8_t[]) {
253 0x04, /* u8 bLength */
254 0x24, /* u8 bDescriptorType */
255 UAS_PIPE_ID_STATUS,
256 0x00, /* u8 bReserved */
257 },
258 },{
259 .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_DATA_IN,
260 .bmAttributes = USB_ENDPOINT_XFER_BULK,
261 .wMaxPacketSize = 1024,
262 .bMaxBurst = 15,
263 .bmAttributes_super = UAS_STREAM_BM_ATTR,
264 .extra = (uint8_t[]) {
265 0x04, /* u8 bLength */
266 0x24, /* u8 bDescriptorType */
267 UAS_PIPE_ID_DATA_IN,
268 0x00, /* u8 bReserved */
269 },
270 },{
271 .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT,
272 .bmAttributes = USB_ENDPOINT_XFER_BULK,
273 .wMaxPacketSize = 1024,
274 .bMaxBurst = 15,
275 .bmAttributes_super = UAS_STREAM_BM_ATTR,
276 .extra = (uint8_t[]) {
277 0x04, /* u8 bLength */
278 0x24, /* u8 bDescriptorType */
279 UAS_PIPE_ID_DATA_OUT,
280 0x00, /* u8 bReserved */
281 },
282 },
283 }
284};
285
0f58f68b
GH
286static const USBDescDevice desc_device_high = {
287 .bcdUSB = 0x0200,
288 .bMaxPacketSize0 = 64,
289 .bNumConfigurations = 1,
290 .confs = (USBDescConfig[]) {
291 {
292 .bNumInterfaces = 1,
293 .bConfigurationValue = 1,
294 .iConfiguration = STR_CONFIG_HIGH,
bd93976a 295 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
0f58f68b
GH
296 .nif = 1,
297 .ifs = &desc_iface_high,
298 },
299 },
300};
301
89a453d4
GH
302static const USBDescDevice desc_device_super = {
303 .bcdUSB = 0x0300,
304 .bMaxPacketSize0 = 64,
305 .bNumConfigurations = 1,
306 .confs = (USBDescConfig[]) {
307 {
308 .bNumInterfaces = 1,
309 .bConfigurationValue = 1,
310 .iConfiguration = STR_CONFIG_SUPER,
bd93976a 311 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_SELFPOWER,
89a453d4
GH
312 .nif = 1,
313 .ifs = &desc_iface_super,
314 },
315 },
316};
317
0f58f68b
GH
318static const USBDesc desc = {
319 .id = {
320 .idVendor = 0x46f4, /* CRC16() of "QEMU" */
0daf5304 321 .idProduct = 0x0003,
0f58f68b
GH
322 .bcdDevice = 0,
323 .iManufacturer = STR_MANUFACTURER,
324 .iProduct = STR_PRODUCT,
325 .iSerialNumber = STR_SERIALNUMBER,
326 },
89a453d4
GH
327 .high = &desc_device_high,
328 .super = &desc_device_super,
329 .str = desc_strings,
0f58f68b
GH
330};
331
332/* --------------------------------------------------------------------- */
333
89a453d4
GH
334static bool uas_using_streams(UASDevice *uas)
335{
336 return uas->dev.speed == USB_SPEED_SUPER;
337}
338
339/* --------------------------------------------------------------------- */
340
341static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag)
0f58f68b
GH
342{
343 UASStatus *st = g_new0(UASStatus, 1);
344
345 st->status.hdr.id = id;
346 st->status.hdr.tag = cpu_to_be16(tag);
5007c940 347 st->length = sizeof(uas_iu_header);
89a453d4
GH
348 if (uas_using_streams(uas)) {
349 st->stream = tag;
350 }
0f58f68b
GH
351 return st;
352}
353
354static void usb_uas_send_status_bh(void *opaque)
355{
356 UASDevice *uas = opaque;
89a453d4
GH
357 UASStatus *st;
358 USBPacket *p;
0f58f68b 359
89a453d4
GH
360 while ((st = QTAILQ_FIRST(&uas->results)) != NULL) {
361 if (uas_using_streams(uas)) {
362 p = uas->status3[st->stream];
363 uas->status3[st->stream] = NULL;
364 } else {
365 p = uas->status2;
366 uas->status2 = NULL;
367 }
368 if (p == NULL) {
369 break;
370 }
0f58f68b 371
89a453d4
GH
372 usb_packet_copy(p, &st->status, st->length);
373 QTAILQ_REMOVE(&uas->results, st, next);
374 g_free(st);
0f58f68b 375
89a453d4
GH
376 p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
377 usb_packet_complete(&uas->dev, p);
378 }
0f58f68b
GH
379}
380
381static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length)
382{
89a453d4
GH
383 USBPacket *p = uas_using_streams(uas) ?
384 uas->status3[st->stream] : uas->status2;
385
0f58f68b
GH
386 st->length += length;
387 QTAILQ_INSERT_TAIL(&uas->results, st, next);
89a453d4 388 if (p) {
0f58f68b
GH
389 /*
390 * Just schedule bh make sure any in-flight data transaction
391 * is finished before completing (sending) the status packet.
392 */
393 qemu_bh_schedule(uas->status_bh);
394 } else {
395 USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN,
396 UAS_PIPE_ID_STATUS);
89a453d4 397 usb_wakeup(ep, st->stream);
0f58f68b
GH
398 }
399}
400
49cfa2fd 401static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, uint8_t code)
0f58f68b 402{
89a453d4 403 UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag);
0f58f68b
GH
404
405 trace_usb_uas_response(uas->dev.addr, tag, code);
406 st->status.response.response_code = code;
5007c940 407 usb_uas_queue_status(uas, st, sizeof(uas_iu_response));
0f58f68b
GH
408}
409
410static void usb_uas_queue_sense(UASRequest *req, uint8_t status)
411{
89a453d4 412 UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_SENSE, req->tag);
0f58f68b
GH
413 int len, slen = 0;
414
415 trace_usb_uas_sense(req->uas->dev.addr, req->tag, status);
416 st->status.sense.status = status;
417 st->status.sense.status_qualifier = cpu_to_be16(0);
418 if (status != GOOD) {
419 slen = scsi_req_get_sense(req->req, st->status.sense.sense_data,
420 sizeof(st->status.sense.sense_data));
421 st->status.sense.sense_length = cpu_to_be16(slen);
422 }
5007c940 423 len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
0f58f68b
GH
424 usb_uas_queue_status(req->uas, st, len);
425}
426
d4bfc7b9
HG
427static void usb_uas_queue_fake_sense(UASDevice *uas, uint16_t tag,
428 struct SCSISense sense)
429{
430 UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_SENSE, tag);
431 int len, slen = 0;
432
433 st->status.sense.status = CHECK_CONDITION;
434 st->status.sense.status_qualifier = cpu_to_be16(0);
435 st->status.sense.sense_data[0] = 0x70;
436 st->status.sense.sense_data[2] = sense.key;
437 st->status.sense.sense_data[7] = 10;
438 st->status.sense.sense_data[12] = sense.asc;
439 st->status.sense.sense_data[13] = sense.ascq;
440 slen = 18;
5007c940 441 len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen;
d4bfc7b9
HG
442 usb_uas_queue_status(uas, st, len);
443}
444
0f58f68b
GH
445static void usb_uas_queue_read_ready(UASRequest *req)
446{
89a453d4
GH
447 UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY,
448 req->tag);
0f58f68b
GH
449
450 trace_usb_uas_read_ready(req->uas->dev.addr, req->tag);
451 usb_uas_queue_status(req->uas, st, 0);
452}
453
454static void usb_uas_queue_write_ready(UASRequest *req)
455{
89a453d4
GH
456 UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_WRITE_READY,
457 req->tag);
0f58f68b
GH
458
459 trace_usb_uas_write_ready(req->uas->dev.addr, req->tag);
460 usb_uas_queue_status(req->uas, st, 0);
461}
462
463/* --------------------------------------------------------------------- */
464
465static int usb_uas_get_lun(uint64_t lun64)
466{
467 return (lun64 >> 48) & 0xff;
468}
469
470static SCSIDevice *usb_uas_get_dev(UASDevice *uas, uint64_t lun64)
471{
472 if ((lun64 >> 56) != 0x00) {
473 return NULL;
474 }
475 return scsi_device_find(&uas->bus, 0, 0, usb_uas_get_lun(lun64));
476}
477
478static void usb_uas_complete_data_packet(UASRequest *req)
479{
480 USBPacket *p;
481
482 if (!req->data_async) {
483 return;
484 }
485 p = req->data;
486 req->data = NULL;
487 req->data_async = false;
9a77a0f5 488 p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
0f58f68b
GH
489 usb_packet_complete(&req->uas->dev, p);
490}
491
492static void usb_uas_copy_data(UASRequest *req)
493{
494 uint32_t length;
495
496 length = MIN(req->buf_size - req->buf_off,
9a77a0f5 497 req->data->iov.size - req->data->actual_length);
0f58f68b 498 trace_usb_uas_xfer_data(req->uas->dev.addr, req->tag, length,
9a77a0f5 499 req->data->actual_length, req->data->iov.size,
0f58f68b
GH
500 req->buf_off, req->buf_size);
501 usb_packet_copy(req->data, scsi_req_get_buf(req->req) + req->buf_off,
502 length);
503 req->buf_off += length;
504 req->data_off += length;
505
9a77a0f5 506 if (req->data->actual_length == req->data->iov.size) {
0f58f68b
GH
507 usb_uas_complete_data_packet(req);
508 }
509 if (req->buf_size && req->buf_off == req->buf_size) {
510 req->buf_off = 0;
511 req->buf_size = 0;
512 scsi_req_continue(req->req);
513 }
514}
515
516static void usb_uas_start_next_transfer(UASDevice *uas)
517{
518 UASRequest *req;
519
89a453d4
GH
520 if (uas_using_streams(uas)) {
521 return;
522 }
523
0f58f68b
GH
524 QTAILQ_FOREACH(req, &uas->requests, next) {
525 if (req->active || req->complete) {
526 continue;
527 }
89a453d4
GH
528 if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain2 == NULL) {
529 uas->datain2 = req;
0f58f68b
GH
530 usb_uas_queue_read_ready(req);
531 req->active = true;
532 return;
533 }
89a453d4
GH
534 if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout2 == NULL) {
535 uas->dataout2 = req;
0f58f68b
GH
536 usb_uas_queue_write_ready(req);
537 req->active = true;
538 return;
539 }
540 }
541}
542
5007c940 543static UASRequest *usb_uas_alloc_request(UASDevice *uas, uas_iu *iu)
0f58f68b
GH
544{
545 UASRequest *req;
546
547 req = g_new0(UASRequest, 1);
548 req->uas = uas;
5007c940
HG
549 req->tag = be16_to_cpu(iu->hdr.tag);
550 req->lun = be64_to_cpu(iu->command.lun);
0f58f68b
GH
551 req->dev = usb_uas_get_dev(req->uas, req->lun);
552 return req;
553}
554
555static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv)
556{
557 UASRequest *req = priv;
558 UASDevice *uas = req->uas;
559
89a453d4
GH
560 if (req == uas->datain2) {
561 uas->datain2 = NULL;
0f58f68b 562 }
89a453d4
GH
563 if (req == uas->dataout2) {
564 uas->dataout2 = NULL;
0f58f68b
GH
565 }
566 QTAILQ_REMOVE(&uas->requests, req, next);
567 g_free(req);
347e40ff 568 usb_uas_start_next_transfer(uas);
0f58f68b
GH
569}
570
571static UASRequest *usb_uas_find_request(UASDevice *uas, uint16_t tag)
572{
573 UASRequest *req;
574
575 QTAILQ_FOREACH(req, &uas->requests, next) {
576 if (req->tag == tag) {
577 return req;
578 }
579 }
580 return NULL;
581}
582
583static void usb_uas_scsi_transfer_data(SCSIRequest *r, uint32_t len)
584{
585 UASRequest *req = r->hba_private;
586
587 trace_usb_uas_scsi_data(req->uas->dev.addr, req->tag, len);
588 req->buf_off = 0;
589 req->buf_size = len;
590 if (req->data) {
591 usb_uas_copy_data(req);
592 } else {
593 usb_uas_start_next_transfer(req->uas);
594 }
595}
596
597static void usb_uas_scsi_command_complete(SCSIRequest *r,
598 uint32_t status, size_t resid)
599{
600 UASRequest *req = r->hba_private;
0f58f68b
GH
601
602 trace_usb_uas_scsi_complete(req->uas->dev.addr, req->tag, status, resid);
603 req->complete = true;
604 if (req->data) {
605 usb_uas_complete_data_packet(req);
606 }
607 usb_uas_queue_sense(req, status);
608 scsi_req_unref(req->req);
0f58f68b
GH
609}
610
611static void usb_uas_scsi_request_cancelled(SCSIRequest *r)
612{
613 UASRequest *req = r->hba_private;
614
615 /* FIXME: queue notification to status pipe? */
616 scsi_req_unref(req->req);
617}
618
619static const struct SCSIBusInfo usb_uas_scsi_info = {
620 .tcq = true,
621 .max_target = 0,
622 .max_lun = 255,
623
624 .transfer_data = usb_uas_scsi_transfer_data,
625 .complete = usb_uas_scsi_command_complete,
626 .cancel = usb_uas_scsi_request_cancelled,
627 .free_request = usb_uas_scsi_free_request,
628};
629
630/* --------------------------------------------------------------------- */
631
632static void usb_uas_handle_reset(USBDevice *dev)
633{
0b06d099 634 UASDevice *uas = USB_UAS(dev);
0f58f68b
GH
635 UASRequest *req, *nreq;
636 UASStatus *st, *nst;
637
638 trace_usb_uas_reset(dev->addr);
639 QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
640 scsi_req_cancel(req->req);
641 }
642 QTAILQ_FOREACH_SAFE(st, &uas->results, next, nst) {
643 QTAILQ_REMOVE(&uas->results, st, next);
644 g_free(st);
645 }
646}
647
9a77a0f5 648static void usb_uas_handle_control(USBDevice *dev, USBPacket *p,
0f58f68b
GH
649 int request, int value, int index, int length, uint8_t *data)
650{
651 int ret;
652
653 ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
654 if (ret >= 0) {
9a77a0f5 655 return;
0f58f68b 656 }
e306b2fd
GH
657 error_report("%s: unhandled control request (req 0x%x, val 0x%x, idx 0x%x",
658 __func__, request, value, index);
9a77a0f5 659 p->status = USB_RET_STALL;
0f58f68b
GH
660}
661
662static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p)
663{
0b06d099 664 UASDevice *uas = USB_UAS(dev);
0f58f68b 665 UASRequest *req, *nreq;
89a453d4 666 int i;
0f58f68b 667
89a453d4
GH
668 if (uas->status2 == p) {
669 uas->status2 = NULL;
0f58f68b
GH
670 qemu_bh_cancel(uas->status_bh);
671 return;
672 }
89a453d4 673 if (uas_using_streams(uas)) {
0478661e 674 for (i = 0; i <= UAS_MAX_STREAMS; i++) {
89a453d4
GH
675 if (uas->status3[i] == p) {
676 uas->status3[i] = NULL;
677 return;
678 }
679 if (uas->data3[i] == p) {
680 uas->data3[i] = NULL;
681 return;
682 }
683 }
684 }
0f58f68b
GH
685 QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) {
686 if (req->data == p) {
687 req->data = NULL;
688 return;
689 }
690 }
691 assert(!"canceled usb packet not found");
692}
693
5007c940 694static void usb_uas_command(UASDevice *uas, uas_iu *iu)
0f58f68b
GH
695{
696 UASRequest *req;
697 uint32_t len;
5007c940 698 uint16_t tag = be16_to_cpu(iu->hdr.tag);
0f58f68b 699
3453f9a0
HG
700 if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
701 goto invalid_tag;
702 }
d4bfc7b9 703 req = usb_uas_find_request(uas, tag);
0f58f68b
GH
704 if (req) {
705 goto overlapped_tag;
706 }
5007c940 707 req = usb_uas_alloc_request(uas, iu);
0f58f68b
GH
708 if (req->dev == NULL) {
709 goto bad_target;
710 }
711
712 trace_usb_uas_command(uas->dev.addr, req->tag,
713 usb_uas_get_lun(req->lun),
714 req->lun >> 32, req->lun & 0xffffffff);
715 QTAILQ_INSERT_TAIL(&uas->requests, req, next);
89a453d4
GH
716 if (uas_using_streams(uas) && uas->data3[req->tag] != NULL) {
717 req->data = uas->data3[req->tag];
718 req->data_async = true;
719 uas->data3[req->tag] = NULL;
720 }
721
0f58f68b
GH
722 req->req = scsi_req_new(req->dev, req->tag,
723 usb_uas_get_lun(req->lun),
5007c940 724 iu->command.cdb, req);
1556a8fc
GH
725 if (uas->requestlog) {
726 scsi_req_print(req->req);
727 }
0f58f68b
GH
728 len = scsi_req_enqueue(req->req);
729 if (len) {
730 req->data_size = len;
731 scsi_req_continue(req->req);
732 }
733 return;
734
3453f9a0
HG
735invalid_tag:
736 usb_uas_queue_fake_sense(uas, tag, sense_code_INVALID_TAG);
737 return;
738
0f58f68b 739overlapped_tag:
d4bfc7b9 740 usb_uas_queue_fake_sense(uas, tag, sense_code_OVERLAPPED_COMMANDS);
0f58f68b
GH
741 return;
742
743bad_target:
d4bfc7b9 744 usb_uas_queue_fake_sense(uas, tag, sense_code_LUN_NOT_SUPPORTED);
0f58f68b 745 g_free(req);
0f58f68b
GH
746}
747
5007c940 748static void usb_uas_task(UASDevice *uas, uas_iu *iu)
0f58f68b 749{
5007c940
HG
750 uint16_t tag = be16_to_cpu(iu->hdr.tag);
751 uint64_t lun64 = be64_to_cpu(iu->task.lun);
0f58f68b
GH
752 SCSIDevice *dev = usb_uas_get_dev(uas, lun64);
753 int lun = usb_uas_get_lun(lun64);
754 UASRequest *req;
755 uint16_t task_tag;
756
3453f9a0
HG
757 if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) {
758 goto invalid_tag;
759 }
5007c940 760 req = usb_uas_find_request(uas, be16_to_cpu(iu->hdr.tag));
0f58f68b
GH
761 if (req) {
762 goto overlapped_tag;
763 }
5eb6d9e3
HG
764 if (dev == NULL) {
765 goto incorrect_lun;
766 }
0f58f68b 767
5007c940 768 switch (iu->task.function) {
0f58f68b 769 case UAS_TMF_ABORT_TASK:
5007c940 770 task_tag = be16_to_cpu(iu->task.task_tag);
0f58f68b 771 trace_usb_uas_tmf_abort_task(uas->dev.addr, tag, task_tag);
0f58f68b
GH
772 req = usb_uas_find_request(uas, task_tag);
773 if (req && req->dev == dev) {
774 scsi_req_cancel(req->req);
775 }
49cfa2fd 776 usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
0f58f68b
GH
777 break;
778
779 case UAS_TMF_LOGICAL_UNIT_RESET:
780 trace_usb_uas_tmf_logical_unit_reset(uas->dev.addr, tag, lun);
0f58f68b 781 qdev_reset_all(&dev->qdev);
49cfa2fd 782 usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE);
0f58f68b
GH
783 break;
784
785 default:
5007c940 786 trace_usb_uas_tmf_unsupported(uas->dev.addr, tag, iu->task.function);
49cfa2fd 787 usb_uas_queue_response(uas, tag, UAS_RC_TMF_NOT_SUPPORTED);
0f58f68b
GH
788 break;
789 }
790 return;
791
3453f9a0 792invalid_tag:
49cfa2fd 793 usb_uas_queue_response(uas, tag, UAS_RC_INVALID_INFO_UNIT);
3453f9a0
HG
794 return;
795
0f58f68b 796overlapped_tag:
49cfa2fd 797 usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG);
0f58f68b
GH
798 return;
799
0f58f68b 800incorrect_lun:
49cfa2fd 801 usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN);
0f58f68b
GH
802}
803
9a77a0f5 804static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
0f58f68b 805{
0b06d099 806 UASDevice *uas = USB_UAS(dev);
5007c940 807 uas_iu iu;
0f58f68b
GH
808 UASStatus *st;
809 UASRequest *req;
9a77a0f5 810 int length;
0f58f68b
GH
811
812 switch (p->ep->nr) {
813 case UAS_PIPE_ID_COMMAND:
5007c940
HG
814 length = MIN(sizeof(iu), p->iov.size);
815 usb_packet_copy(p, &iu, length);
816 switch (iu.hdr.id) {
0f58f68b 817 case UAS_UI_COMMAND:
5007c940 818 usb_uas_command(uas, &iu);
0f58f68b
GH
819 break;
820 case UAS_UI_TASK_MGMT:
5007c940 821 usb_uas_task(uas, &iu);
0f58f68b
GH
822 break;
823 default:
6b7afb7f
GA
824 error_report("%s: unknown command iu: id 0x%x",
825 __func__, iu.hdr.id);
9a77a0f5 826 p->status = USB_RET_STALL;
0f58f68b
GH
827 break;
828 }
829 break;
830 case UAS_PIPE_ID_STATUS:
89a453d4
GH
831 if (p->stream) {
832 QTAILQ_FOREACH(st, &uas->results, next) {
833 if (st->stream == p->stream) {
834 break;
835 }
836 }
837 if (st == NULL) {
838 assert(uas->status3[p->stream] == NULL);
839 uas->status3[p->stream] = p;
840 p->status = USB_RET_ASYNC;
841 break;
842 }
843 } else {
844 st = QTAILQ_FIRST(&uas->results);
845 if (st == NULL) {
846 assert(uas->status2 == NULL);
847 uas->status2 = p;
848 p->status = USB_RET_ASYNC;
849 break;
850 }
0f58f68b
GH
851 }
852 usb_packet_copy(p, &st->status, st->length);
0f58f68b
GH
853 QTAILQ_REMOVE(&uas->results, st, next);
854 g_free(st);
855 break;
856 case UAS_PIPE_ID_DATA_IN:
857 case UAS_PIPE_ID_DATA_OUT:
89a453d4
GH
858 if (p->stream) {
859 req = usb_uas_find_request(uas, p->stream);
860 } else {
861 req = (p->ep->nr == UAS_PIPE_ID_DATA_IN)
862 ? uas->datain2 : uas->dataout2;
863 }
0f58f68b 864 if (req == NULL) {
89a453d4
GH
865 if (p->stream) {
866 assert(uas->data3[p->stream] == NULL);
867 uas->data3[p->stream] = p;
868 p->status = USB_RET_ASYNC;
869 break;
870 } else {
6b7afb7f 871 error_report("%s: no inflight request", __func__);
89a453d4
GH
872 p->status = USB_RET_STALL;
873 break;
874 }
0f58f68b
GH
875 }
876 scsi_req_ref(req->req);
877 req->data = p;
878 usb_uas_copy_data(req);
9a77a0f5 879 if (p->actual_length == p->iov.size || req->complete) {
0f58f68b 880 req->data = NULL;
0f58f68b
GH
881 } else {
882 req->data_async = true;
9a77a0f5 883 p->status = USB_RET_ASYNC;
0f58f68b
GH
884 }
885 scsi_req_unref(req->req);
886 usb_uas_start_next_transfer(uas);
887 break;
888 default:
6b7afb7f 889 error_report("%s: invalid endpoint %d", __func__, p->ep->nr);
9a77a0f5 890 p->status = USB_RET_STALL;
0f58f68b
GH
891 break;
892 }
0f58f68b
GH
893}
894
c4fe9700 895static void usb_uas_unrealize(USBDevice *dev, Error **errp)
0f58f68b 896{
0b06d099 897 UASDevice *uas = USB_UAS(dev);
0f58f68b
GH
898
899 qemu_bh_delete(uas->status_bh);
900}
901
b89dc7e3 902static void usb_uas_realize(USBDevice *dev, Error **errp)
0f58f68b 903{
0b06d099 904 UASDevice *uas = USB_UAS(dev);
0d4cf3e7 905 DeviceState *d = DEVICE(dev);
0f58f68b
GH
906
907 usb_desc_create_serial(dev);
908 usb_desc_init(dev);
0d4cf3e7
GH
909 if (d->hotplugged) {
910 uas->dev.auto_attach = 0;
911 }
0f58f68b
GH
912
913 QTAILQ_INIT(&uas->results);
914 QTAILQ_INIT(&uas->requests);
915 uas->status_bh = qemu_bh_new(usb_uas_send_status_bh, uas);
916
b1187b51
AF
917 scsi_bus_new(&uas->bus, sizeof(uas->bus), DEVICE(dev),
918 &usb_uas_scsi_info, NULL);
0f58f68b
GH
919}
920
921static const VMStateDescription vmstate_usb_uas = {
922 .name = "usb-uas",
923 .unmigratable = 1,
924 .fields = (VMStateField[]) {
925 VMSTATE_USB_DEVICE(dev, UASDevice),
926 VMSTATE_END_OF_LIST()
927 }
928};
929
1556a8fc
GH
930static Property uas_properties[] = {
931 DEFINE_PROP_UINT32("log-scsi-req", UASDevice, requestlog, 0),
932 DEFINE_PROP_END_OF_LIST(),
933};
934
0f58f68b
GH
935static void usb_uas_class_initfn(ObjectClass *klass, void *data)
936{
937 DeviceClass *dc = DEVICE_CLASS(klass);
938 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
939
b89dc7e3 940 uc->realize = usb_uas_realize;
0f58f68b
GH
941 uc->product_desc = desc_strings[STR_PRODUCT];
942 uc->usb_desc = &desc;
943 uc->cancel_packet = usb_uas_cancel_io;
944 uc->handle_attach = usb_desc_attach;
945 uc->handle_reset = usb_uas_handle_reset;
946 uc->handle_control = usb_uas_handle_control;
947 uc->handle_data = usb_uas_handle_data;
c4fe9700 948 uc->unrealize = usb_uas_unrealize;
0d4cf3e7 949 uc->attached_settable = true;
125ee0ed 950 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
0f58f68b
GH
951 dc->fw_name = "storage";
952 dc->vmsd = &vmstate_usb_uas;
1556a8fc 953 dc->props = uas_properties;
0f58f68b
GH
954}
955
8c43a6f0 956static const TypeInfo uas_info = {
0b06d099 957 .name = TYPE_USB_UAS,
0f58f68b
GH
958 .parent = TYPE_USB_DEVICE,
959 .instance_size = sizeof(UASDevice),
960 .class_init = usb_uas_class_initfn,
961};
962
963static void usb_uas_register_types(void)
964{
965 type_register_static(&uas_info);
966}
967
968type_init(usb_uas_register_types)
This page took 0.531328 seconds and 4 git commands to generate.