2 * Generic SCSI Device support
4 * Copyright (c) 2007 Bull S.A.S.
5 * Based on code by Paul Brook
6 * Based on code by Fabrice Bellard
8 * Written by Laurent Vivier <Laurent.Vivier@bull.net>
10 * This code is licensed under the LGPL.
14 #include "qemu/osdep.h"
15 #include "qapi/error.h"
16 #include "qemu-common.h"
17 #include "qemu/error-report.h"
18 #include "hw/scsi/scsi.h"
19 #include "sysemu/block-backend.h"
20 #include "sysemu/blockdev.h"
27 #define DPRINTF(fmt, ...) \
28 do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
30 #define DPRINTF(fmt, ...) do {} while(0)
33 #define BADF(fmt, ...) \
34 do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
37 #include "block/scsi.h"
39 #define SG_ERR_DRIVER_TIMEOUT 0x06
40 #define SG_ERR_DRIVER_SENSE 0x08
42 #define SG_ERR_DID_OK 0x00
43 #define SG_ERR_DID_NO_CONNECT 0x01
44 #define SG_ERR_DID_BUS_BUSY 0x02
45 #define SG_ERR_DID_TIME_OUT 0x03
48 #define MAX_UINT ((unsigned int)-1)
51 typedef struct SCSIGenericReq
{
56 sg_io_hdr_t io_header
;
59 static void scsi_generic_save_request(QEMUFile
*f
, SCSIRequest
*req
)
61 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
63 qemu_put_sbe32s(f
, &r
->buflen
);
64 if (r
->buflen
&& r
->req
.cmd
.mode
== SCSI_XFER_TO_DEV
) {
66 qemu_put_buffer(f
, r
->buf
, r
->req
.cmd
.xfer
);
70 static void scsi_generic_load_request(QEMUFile
*f
, SCSIRequest
*req
)
72 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
74 qemu_get_sbe32s(f
, &r
->buflen
);
75 if (r
->buflen
&& r
->req
.cmd
.mode
== SCSI_XFER_TO_DEV
) {
77 qemu_get_buffer(f
, r
->buf
, r
->req
.cmd
.xfer
);
81 static void scsi_free_request(SCSIRequest
*req
)
83 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
88 /* Helper function for command completion. */
89 static void scsi_command_complete_noio(SCSIGenericReq
*r
, int ret
)
93 assert(r
->req
.aiocb
== NULL
);
95 if (r
->req
.io_canceled
) {
96 scsi_req_cancel_complete(&r
->req
);
99 if (r
->io_header
.driver_status
& SG_ERR_DRIVER_SENSE
) {
100 r
->req
.sense_len
= r
->io_header
.sb_len_wr
;
106 status
= TASK_SET_FULL
;
109 status
= CHECK_CONDITION
;
110 scsi_req_build_sense(&r
->req
, SENSE_CODE(TARGET_FAILURE
));
113 status
= CHECK_CONDITION
;
114 scsi_req_build_sense(&r
->req
, SENSE_CODE(IO_ERROR
));
118 if (r
->io_header
.host_status
== SG_ERR_DID_NO_CONNECT
||
119 r
->io_header
.host_status
== SG_ERR_DID_BUS_BUSY
||
120 r
->io_header
.host_status
== SG_ERR_DID_TIME_OUT
||
121 (r
->io_header
.driver_status
& SG_ERR_DRIVER_TIMEOUT
)) {
123 BADF("Driver Timeout\n");
124 } else if (r
->io_header
.host_status
) {
125 status
= CHECK_CONDITION
;
126 scsi_req_build_sense(&r
->req
, SENSE_CODE(I_T_NEXUS_LOSS
));
127 } else if (r
->io_header
.status
) {
128 status
= r
->io_header
.status
;
129 } else if (r
->io_header
.driver_status
& SG_ERR_DRIVER_SENSE
) {
130 status
= CHECK_CONDITION
;
135 DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
136 r
, r
->req
.tag
, status
);
138 scsi_req_complete(&r
->req
, status
);
140 scsi_req_unref(&r
->req
);
143 static void scsi_command_complete(void *opaque
, int ret
)
145 SCSIGenericReq
*r
= (SCSIGenericReq
*)opaque
;
147 assert(r
->req
.aiocb
!= NULL
);
149 scsi_command_complete_noio(r
, ret
);
152 static int execute_command(BlockBackend
*blk
,
153 SCSIGenericReq
*r
, int direction
,
154 BlockCompletionFunc
*complete
)
156 r
->io_header
.interface_id
= 'S';
157 r
->io_header
.dxfer_direction
= direction
;
158 r
->io_header
.dxferp
= r
->buf
;
159 r
->io_header
.dxfer_len
= r
->buflen
;
160 r
->io_header
.cmdp
= r
->req
.cmd
.buf
;
161 r
->io_header
.cmd_len
= r
->req
.cmd
.len
;
162 r
->io_header
.mx_sb_len
= sizeof(r
->req
.sense
);
163 r
->io_header
.sbp
= r
->req
.sense
;
164 r
->io_header
.timeout
= MAX_UINT
;
165 r
->io_header
.usr_ptr
= r
;
166 r
->io_header
.flags
|= SG_FLAG_DIRECT_IO
;
168 r
->req
.aiocb
= blk_aio_ioctl(blk
, SG_IO
, &r
->io_header
, complete
, r
);
169 if (r
->req
.aiocb
== NULL
) {
176 static void scsi_read_complete(void * opaque
, int ret
)
178 SCSIGenericReq
*r
= (SCSIGenericReq
*)opaque
;
179 SCSIDevice
*s
= r
->req
.dev
;
182 assert(r
->req
.aiocb
!= NULL
);
185 if (ret
|| r
->req
.io_canceled
) {
186 scsi_command_complete_noio(r
, ret
);
190 len
= r
->io_header
.dxfer_len
- r
->io_header
.resid
;
191 DPRINTF("Data ready tag=0x%x len=%d\n", r
->req
.tag
, len
);
195 scsi_command_complete_noio(r
, 0);
199 /* Snoop READ CAPACITY output to set the blocksize. */
200 if (r
->req
.cmd
.buf
[0] == READ_CAPACITY_10
&&
201 (ldl_be_p(&r
->buf
[0]) != 0xffffffffU
|| s
->max_lba
== 0)) {
202 s
->blocksize
= ldl_be_p(&r
->buf
[4]);
203 s
->max_lba
= ldl_be_p(&r
->buf
[0]) & 0xffffffffULL
;
204 } else if (r
->req
.cmd
.buf
[0] == SERVICE_ACTION_IN_16
&&
205 (r
->req
.cmd
.buf
[1] & 31) == SAI_READ_CAPACITY_16
) {
206 s
->blocksize
= ldl_be_p(&r
->buf
[8]);
207 s
->max_lba
= ldq_be_p(&r
->buf
[0]);
209 blk_set_guest_block_size(s
->conf
.blk
, s
->blocksize
);
211 /* Patch MODE SENSE device specific parameters if the BDS is opened
214 if ((s
->type
== TYPE_DISK
|| s
->type
== TYPE_TAPE
) &&
215 blk_is_read_only(s
->conf
.blk
) &&
216 (r
->req
.cmd
.buf
[0] == MODE_SENSE
||
217 r
->req
.cmd
.buf
[0] == MODE_SENSE_10
) &&
218 (r
->req
.cmd
.buf
[1] & 0x8) == 0) {
219 if (r
->req
.cmd
.buf
[0] == MODE_SENSE
) {
225 if (s
->type
== TYPE_DISK
&&
226 r
->req
.cmd
.buf
[0] == INQUIRY
&&
227 r
->req
.cmd
.buf
[2] == 0xb0) {
228 uint32_t max_xfer_len
= blk_get_max_transfer_length(s
->conf
.blk
);
230 stl_be_p(&r
->buf
[8], max_xfer_len
);
231 /* Also take care of the opt xfer len. */
232 if (ldl_be_p(&r
->buf
[12]) > max_xfer_len
) {
233 stl_be_p(&r
->buf
[12], max_xfer_len
);
237 scsi_req_data(&r
->req
, len
);
238 scsi_req_unref(&r
->req
);
241 /* Read more data from scsi device into buffer. */
242 static void scsi_read_data(SCSIRequest
*req
)
244 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
245 SCSIDevice
*s
= r
->req
.dev
;
248 DPRINTF("scsi_read_data 0x%x\n", req
->tag
);
250 /* The request is used as the AIO opaque value, so add a ref. */
251 scsi_req_ref(&r
->req
);
253 scsi_command_complete_noio(r
, 0);
257 ret
= execute_command(s
->conf
.blk
, r
, SG_DXFER_FROM_DEV
,
260 scsi_command_complete_noio(r
, ret
);
264 static void scsi_write_complete(void * opaque
, int ret
)
266 SCSIGenericReq
*r
= (SCSIGenericReq
*)opaque
;
267 SCSIDevice
*s
= r
->req
.dev
;
269 DPRINTF("scsi_write_complete() ret = %d\n", ret
);
271 assert(r
->req
.aiocb
!= NULL
);
274 if (ret
|| r
->req
.io_canceled
) {
275 scsi_command_complete_noio(r
, ret
);
279 if (r
->req
.cmd
.buf
[0] == MODE_SELECT
&& r
->req
.cmd
.buf
[4] == 12 &&
280 s
->type
== TYPE_TAPE
) {
281 s
->blocksize
= (r
->buf
[9] << 16) | (r
->buf
[10] << 8) | r
->buf
[11];
282 DPRINTF("block size %d\n", s
->blocksize
);
285 scsi_command_complete_noio(r
, ret
);
288 /* Write data to a scsi device. Returns nonzero on failure.
289 The transfer may complete asynchronously. */
290 static void scsi_write_data(SCSIRequest
*req
)
292 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
293 SCSIDevice
*s
= r
->req
.dev
;
296 DPRINTF("scsi_write_data 0x%x\n", req
->tag
);
299 scsi_req_data(&r
->req
, r
->len
);
303 /* The request is used as the AIO opaque value, so add a ref. */
304 scsi_req_ref(&r
->req
);
305 ret
= execute_command(s
->conf
.blk
, r
, SG_DXFER_TO_DEV
, scsi_write_complete
);
307 scsi_command_complete_noio(r
, ret
);
311 /* Return a pointer to the data buffer. */
312 static uint8_t *scsi_get_buf(SCSIRequest
*req
)
314 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
319 /* Execute a scsi command. Returns the length of the data expected by the
320 command. This will be Positive for data transfers from the device
321 (eg. disk reads), negative for transfers to the device (eg. disk writes),
322 and zero if the command does not transfer any data. */
324 static int32_t scsi_send_command(SCSIRequest
*req
, uint8_t *cmd
)
326 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
327 SCSIDevice
*s
= r
->req
.dev
;
333 for (i
= 1; i
< r
->req
.cmd
.len
; i
++) {
334 printf(" 0x%02x", cmd
[i
]);
340 if (r
->req
.cmd
.xfer
== 0) {
344 /* The request is used as the AIO opaque value, so add a ref. */
345 scsi_req_ref(&r
->req
);
346 ret
= execute_command(s
->conf
.blk
, r
, SG_DXFER_NONE
,
347 scsi_command_complete
);
349 scsi_command_complete_noio(r
, ret
);
355 if (r
->buflen
!= r
->req
.cmd
.xfer
) {
357 r
->buf
= g_malloc(r
->req
.cmd
.xfer
);
358 r
->buflen
= r
->req
.cmd
.xfer
;
361 memset(r
->buf
, 0, r
->buflen
);
362 r
->len
= r
->req
.cmd
.xfer
;
363 if (r
->req
.cmd
.mode
== SCSI_XFER_TO_DEV
) {
365 return -r
->req
.cmd
.xfer
;
367 return r
->req
.cmd
.xfer
;
371 static int read_naa_id(const uint8_t *p
, uint64_t *p_wwn
)
375 if ((p
[1] & 0xF) == 3) {
376 /* NAA designator type */
380 *p_wwn
= ldq_be_p(p
+ 4);
384 if ((p
[1] & 0xF) == 8) {
385 /* SCSI name string designator type */
386 if (p
[3] < 20 || memcmp(&p
[4], "naa.", 4)) {
389 if (p
[3] > 20 && p
[24] != ',') {
393 for (i
= 8; i
< 24; i
++) {
394 char c
= toupper(p
[i
]);
395 c
-= (c
>= '0' && c
<= '9' ? '0' : 'A' - 10);
396 *p_wwn
= (*p_wwn
<< 4) | c
;
404 void scsi_generic_read_device_identification(SCSIDevice
*s
)
409 sg_io_hdr_t io_header
;
413 memset(cmd
, 0, sizeof(cmd
));
414 memset(buf
, 0, sizeof(buf
));
418 cmd
[4] = sizeof(buf
);
420 memset(&io_header
, 0, sizeof(io_header
));
421 io_header
.interface_id
= 'S';
422 io_header
.dxfer_direction
= SG_DXFER_FROM_DEV
;
423 io_header
.dxfer_len
= sizeof(buf
);
424 io_header
.dxferp
= buf
;
425 io_header
.cmdp
= cmd
;
426 io_header
.cmd_len
= sizeof(cmd
);
427 io_header
.mx_sb_len
= sizeof(sensebuf
);
428 io_header
.sbp
= sensebuf
;
429 io_header
.timeout
= 6000; /* XXX */
431 ret
= blk_ioctl(s
->conf
.blk
, SG_IO
, &io_header
);
432 if (ret
< 0 || io_header
.driver_status
|| io_header
.host_status
) {
436 len
= MIN((buf
[2] << 8) | buf
[3], sizeof(buf
) - 4);
437 for (i
= 0; i
+ 3 <= len
; ) {
438 const uint8_t *p
= &buf
[i
+ 4];
441 if (i
+ (p
[3] + 4) > len
) {
445 if ((p
[1] & 0x10) == 0) {
446 /* Associated with the logical unit */
447 if (read_naa_id(p
, &wwn
) == 0) {
450 } else if ((p
[1] & 0x10) == 0x10) {
451 /* Associated with the target port */
452 if (read_naa_id(p
, &wwn
) == 0) {
461 static int get_stream_blocksize(BlockBackend
*blk
)
466 sg_io_hdr_t io_header
;
469 memset(cmd
, 0, sizeof(cmd
));
470 memset(buf
, 0, sizeof(buf
));
472 cmd
[4] = sizeof(buf
);
474 memset(&io_header
, 0, sizeof(io_header
));
475 io_header
.interface_id
= 'S';
476 io_header
.dxfer_direction
= SG_DXFER_FROM_DEV
;
477 io_header
.dxfer_len
= sizeof(buf
);
478 io_header
.dxferp
= buf
;
479 io_header
.cmdp
= cmd
;
480 io_header
.cmd_len
= sizeof(cmd
);
481 io_header
.mx_sb_len
= sizeof(sensebuf
);
482 io_header
.sbp
= sensebuf
;
483 io_header
.timeout
= 6000; /* XXX */
485 ret
= blk_ioctl(blk
, SG_IO
, &io_header
);
486 if (ret
< 0 || io_header
.driver_status
|| io_header
.host_status
) {
489 return (buf
[9] << 16) | (buf
[10] << 8) | buf
[11];
492 static void scsi_generic_reset(DeviceState
*dev
)
494 SCSIDevice
*s
= SCSI_DEVICE(dev
);
496 scsi_device_purge_requests(s
, SENSE_CODE(RESET
));
499 static void scsi_generic_realize(SCSIDevice
*s
, Error
**errp
)
503 struct sg_scsi_id scsiid
;
506 error_setg(errp
, "drive property not set");
510 if (blk_get_on_error(s
->conf
.blk
, 0) != BLOCKDEV_ON_ERROR_ENOSPC
) {
511 error_setg(errp
, "Device doesn't support drive option werror");
514 if (blk_get_on_error(s
->conf
.blk
, 1) != BLOCKDEV_ON_ERROR_REPORT
) {
515 error_setg(errp
, "Device doesn't support drive option rerror");
519 /* check we are using a driver managing SG_IO (version 3 and after */
520 rc
= blk_ioctl(s
->conf
.blk
, SG_GET_VERSION_NUM
, &sg_version
);
522 error_setg(errp
, "cannot get SG_IO version number: %s. "
523 "Is this a SCSI device?",
527 if (sg_version
< 30000) {
528 error_setg(errp
, "scsi generic interface too old");
532 /* get LUN of the /dev/sg? */
533 if (blk_ioctl(s
->conf
.blk
, SG_GET_SCSI_ID
, &scsiid
)) {
534 error_setg(errp
, "SG_GET_SCSI_ID ioctl failed");
538 /* define device state */
539 s
->type
= scsiid
.scsi_type
;
540 DPRINTF("device type %d\n", s
->type
);
544 s
->blocksize
= get_stream_blocksize(s
->conf
.blk
);
545 if (s
->blocksize
== -1) {
550 /* Make a guess for block devices, we'll fix it when the guest sends.
551 * READ CAPACITY. If they don't, they likely would assume these sizes
552 * anyway. (TODO: they could also send MODE SENSE).
563 DPRINTF("block size %d\n", s
->blocksize
);
565 scsi_generic_read_device_identification(s
);
568 const SCSIReqOps scsi_generic_req_ops
= {
569 .size
= sizeof(SCSIGenericReq
),
570 .free_req
= scsi_free_request
,
571 .send_command
= scsi_send_command
,
572 .read_data
= scsi_read_data
,
573 .write_data
= scsi_write_data
,
574 .get_buf
= scsi_get_buf
,
575 .load_request
= scsi_generic_load_request
,
576 .save_request
= scsi_generic_save_request
,
579 static SCSIRequest
*scsi_new_request(SCSIDevice
*d
, uint32_t tag
, uint32_t lun
,
580 uint8_t *buf
, void *hba_private
)
584 req
= scsi_req_alloc(&scsi_generic_req_ops
, d
, tag
, lun
, hba_private
);
588 static Property scsi_generic_properties
[] = {
589 DEFINE_PROP_DRIVE("drive", SCSIDevice
, conf
.blk
),
590 DEFINE_PROP_END_OF_LIST(),
593 static int scsi_generic_parse_cdb(SCSIDevice
*dev
, SCSICommand
*cmd
,
594 uint8_t *buf
, void *hba_private
)
596 return scsi_bus_parse_cdb(dev
, cmd
, buf
, hba_private
);
599 static void scsi_generic_class_initfn(ObjectClass
*klass
, void *data
)
601 DeviceClass
*dc
= DEVICE_CLASS(klass
);
602 SCSIDeviceClass
*sc
= SCSI_DEVICE_CLASS(klass
);
604 sc
->realize
= scsi_generic_realize
;
605 sc
->alloc_req
= scsi_new_request
;
606 sc
->parse_cdb
= scsi_generic_parse_cdb
;
607 dc
->fw_name
= "disk";
608 dc
->desc
= "pass through generic scsi device (/dev/sg*)";
609 dc
->reset
= scsi_generic_reset
;
610 dc
->props
= scsi_generic_properties
;
611 dc
->vmsd
= &vmstate_scsi_device
;
614 static const TypeInfo scsi_generic_info
= {
615 .name
= "scsi-generic",
616 .parent
= TYPE_SCSI_DEVICE
,
617 .instance_size
= sizeof(SCSIDevice
),
618 .class_init
= scsi_generic_class_initfn
,
621 static void scsi_generic_register_types(void)
623 type_register_static(&scsi_generic_info
);
626 type_init(scsi_generic_register_types
)
628 #endif /* __linux__ */