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/ctype.h"
17 #include "qemu/error-report.h"
18 #include "qemu/module.h"
19 #include "hw/scsi/scsi.h"
20 #include "migration/qemu-file-types.h"
21 #include "hw/qdev-properties.h"
22 #include "hw/qdev-properties-system.h"
23 #include "hw/scsi/emulation.h"
24 #include "sysemu/block-backend.h"
30 #include "scsi/constants.h"
33 #define MAX_UINT ((unsigned int)-1)
36 typedef struct SCSIGenericReq
{
41 sg_io_hdr_t io_header
;
44 static void scsi_generic_save_request(QEMUFile
*f
, SCSIRequest
*req
)
46 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
48 qemu_put_sbe32s(f
, &r
->buflen
);
49 if (r
->buflen
&& r
->req
.cmd
.mode
== SCSI_XFER_TO_DEV
) {
51 qemu_put_buffer(f
, r
->buf
, r
->req
.cmd
.xfer
);
55 static void scsi_generic_load_request(QEMUFile
*f
, SCSIRequest
*req
)
57 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
59 qemu_get_sbe32s(f
, &r
->buflen
);
60 if (r
->buflen
&& r
->req
.cmd
.mode
== SCSI_XFER_TO_DEV
) {
62 qemu_get_buffer(f
, r
->buf
, r
->req
.cmd
.xfer
);
66 static void scsi_free_request(SCSIRequest
*req
)
68 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
73 /* Helper function for command completion. */
74 static void scsi_command_complete_noio(SCSIGenericReq
*r
, int ret
)
79 assert(r
->req
.aiocb
== NULL
);
81 if (r
->req
.io_canceled
) {
82 scsi_req_cancel_complete(&r
->req
);
85 status
= sg_io_sense_from_errno(-ret
, &r
->io_header
, &sense
);
86 if (status
== CHECK_CONDITION
) {
87 if (r
->io_header
.driver_status
& SG_ERR_DRIVER_SENSE
) {
88 r
->req
.sense_len
= r
->io_header
.sb_len_wr
;
90 scsi_req_build_sense(&r
->req
, sense
);
94 trace_scsi_generic_command_complete_noio(r
, r
->req
.tag
, status
);
96 scsi_req_complete(&r
->req
, status
);
98 scsi_req_unref(&r
->req
);
101 static void scsi_command_complete(void *opaque
, int ret
)
103 SCSIGenericReq
*r
= (SCSIGenericReq
*)opaque
;
104 SCSIDevice
*s
= r
->req
.dev
;
106 assert(r
->req
.aiocb
!= NULL
);
109 aio_context_acquire(blk_get_aio_context(s
->conf
.blk
));
110 scsi_command_complete_noio(r
, ret
);
111 aio_context_release(blk_get_aio_context(s
->conf
.blk
));
114 static int execute_command(BlockBackend
*blk
,
115 SCSIGenericReq
*r
, int direction
,
116 BlockCompletionFunc
*complete
)
118 SCSIDevice
*s
= r
->req
.dev
;
120 r
->io_header
.interface_id
= 'S';
121 r
->io_header
.dxfer_direction
= direction
;
122 r
->io_header
.dxferp
= r
->buf
;
123 r
->io_header
.dxfer_len
= r
->buflen
;
124 r
->io_header
.cmdp
= r
->req
.cmd
.buf
;
125 r
->io_header
.cmd_len
= r
->req
.cmd
.len
;
126 r
->io_header
.mx_sb_len
= sizeof(r
->req
.sense
);
127 r
->io_header
.sbp
= r
->req
.sense
;
128 r
->io_header
.timeout
= s
->io_timeout
* 1000;
129 r
->io_header
.usr_ptr
= r
;
130 r
->io_header
.flags
|= SG_FLAG_DIRECT_IO
;
132 r
->req
.aiocb
= blk_aio_ioctl(blk
, SG_IO
, &r
->io_header
, complete
, r
);
133 if (r
->req
.aiocb
== NULL
) {
140 static void scsi_handle_inquiry_reply(SCSIGenericReq
*r
, SCSIDevice
*s
)
142 uint8_t page
, page_idx
;
145 * EVPD set to zero returns the standard INQUIRY data.
147 * Check if scsi_version is unset (-1) to avoid re-defining it
148 * each time an INQUIRY with standard data is received.
149 * scsi_version is initialized with -1 in scsi_generic_reset
150 * and scsi_disk_reset, making sure that we'll set the
151 * scsi_version after a reset. If the version field of the
152 * INQUIRY response somehow changes after a guest reboot,
153 * we'll be able to keep track of it.
155 * On SCSI-2 and older, first 3 bits of byte 2 is the
156 * ANSI-approved version, while on later versions the
157 * whole byte 2 contains the version. Check if we're dealing
158 * with a newer version and, in that case, assign the
161 if (s
->scsi_version
== -1 && !(r
->req
.cmd
.buf
[1] & 0x01)) {
162 s
->scsi_version
= r
->buf
[2] & 0x07;
163 if (s
->scsi_version
> 2) {
164 s
->scsi_version
= r
->buf
[2];
168 if ((s
->type
== TYPE_DISK
|| s
->type
== TYPE_ZBC
) &&
169 (r
->req
.cmd
.buf
[1] & 0x01)) {
170 page
= r
->req
.cmd
.buf
[2];
172 uint32_t max_transfer
=
173 blk_get_max_transfer(s
->conf
.blk
) / s
->blocksize
;
175 assert(max_transfer
);
176 stl_be_p(&r
->buf
[8], max_transfer
);
177 /* Also take care of the opt xfer len. */
178 stl_be_p(&r
->buf
[12],
179 MIN_NON_ZERO(max_transfer
, ldl_be_p(&r
->buf
[12])));
180 } else if (s
->needs_vpd_bl_emulation
&& page
== 0x00 && r
->buflen
>= 4) {
182 * Now we're capable of supplying the VPD Block Limits
183 * response if the hardware can't. Add it in the INQUIRY
184 * Supported VPD pages response in case we are using the
185 * emulation for this device.
187 * This way, the guest kernel will be aware of the support
188 * and will use it to proper setup the SCSI device.
190 * VPD page numbers must be sorted, so insert 0xb0 at the
191 * right place with an in-place insert. When the while loop
192 * begins the device response is at r[0] to r[page_idx - 1].
194 page_idx
= lduw_be_p(r
->buf
+ 2) + 4;
195 page_idx
= MIN(page_idx
, r
->buflen
);
196 while (page_idx
> 4 && r
->buf
[page_idx
- 1] >= 0xb0) {
197 if (page_idx
< r
->buflen
) {
198 r
->buf
[page_idx
] = r
->buf
[page_idx
- 1];
202 if (page_idx
< r
->buflen
) {
203 r
->buf
[page_idx
] = 0xb0;
205 stw_be_p(r
->buf
+ 2, lduw_be_p(r
->buf
+ 2) + 1);
210 static int scsi_generic_emulate_block_limits(SCSIGenericReq
*r
, SCSIDevice
*s
)
215 SCSIBlockLimits bl
= {
216 .max_io_sectors
= blk_get_max_transfer(s
->conf
.blk
) / s
->blocksize
219 memset(r
->buf
, 0, r
->buflen
);
221 stb_p(buf
+ 1, 0xb0);
222 len
= scsi_emulate_block_limits(buf
+ 4, &bl
);
223 assert(len
<= sizeof(buf
) - 4);
224 stw_be_p(buf
+ 2, len
);
226 memcpy(r
->buf
, buf
, MIN(r
->buflen
, len
+ 4));
228 r
->io_header
.sb_len_wr
= 0;
231 * We have valid contents in the reply buffer but the
232 * io_header can report a sense error coming from
233 * the hardware in scsi_command_complete_noio. Clean
234 * up the io_header to avoid reporting it.
236 r
->io_header
.driver_status
= 0;
237 r
->io_header
.status
= 0;
242 static void scsi_read_complete(void * opaque
, int ret
)
244 SCSIGenericReq
*r
= (SCSIGenericReq
*)opaque
;
245 SCSIDevice
*s
= r
->req
.dev
;
248 assert(r
->req
.aiocb
!= NULL
);
251 aio_context_acquire(blk_get_aio_context(s
->conf
.blk
));
253 if (ret
|| r
->req
.io_canceled
) {
254 scsi_command_complete_noio(r
, ret
);
258 len
= r
->io_header
.dxfer_len
- r
->io_header
.resid
;
259 trace_scsi_generic_read_complete(r
->req
.tag
, len
);
263 if (r
->io_header
.driver_status
& SG_ERR_DRIVER_SENSE
) {
265 scsi_parse_sense_buf(r
->req
.sense
, r
->io_header
.sb_len_wr
);
268 * Check if this is a VPD Block Limits request that
269 * resulted in sense error but would need emulation.
270 * In this case, emulate a valid VPD response.
272 if (sense
.key
== ILLEGAL_REQUEST
&&
273 s
->needs_vpd_bl_emulation
&&
274 r
->req
.cmd
.buf
[0] == INQUIRY
&&
275 (r
->req
.cmd
.buf
[1] & 0x01) &&
276 r
->req
.cmd
.buf
[2] == 0xb0) {
277 len
= scsi_generic_emulate_block_limits(r
, s
);
279 * It's okay to jup to req_complete: no need to
280 * let scsi_handle_inquiry_reply handle an
281 * INQUIRY VPD BL request we created manually.
290 scsi_command_complete_noio(r
, 0);
294 /* Snoop READ CAPACITY output to set the blocksize. */
295 if (r
->req
.cmd
.buf
[0] == READ_CAPACITY_10
&&
296 (ldl_be_p(&r
->buf
[0]) != 0xffffffffU
|| s
->max_lba
== 0)) {
297 s
->blocksize
= ldl_be_p(&r
->buf
[4]);
298 s
->max_lba
= ldl_be_p(&r
->buf
[0]) & 0xffffffffULL
;
299 } else if (r
->req
.cmd
.buf
[0] == SERVICE_ACTION_IN_16
&&
300 (r
->req
.cmd
.buf
[1] & 31) == SAI_READ_CAPACITY_16
) {
301 s
->blocksize
= ldl_be_p(&r
->buf
[8]);
302 s
->max_lba
= ldq_be_p(&r
->buf
[0]);
304 blk_set_guest_block_size(s
->conf
.blk
, s
->blocksize
);
307 * Patch MODE SENSE device specific parameters if the BDS is opened
310 if ((s
->type
== TYPE_DISK
|| s
->type
== TYPE_TAPE
|| s
->type
== TYPE_ZBC
) &&
311 !blk_is_writable(s
->conf
.blk
) &&
312 (r
->req
.cmd
.buf
[0] == MODE_SENSE
||
313 r
->req
.cmd
.buf
[0] == MODE_SENSE_10
) &&
314 (r
->req
.cmd
.buf
[1] & 0x8) == 0) {
315 if (r
->req
.cmd
.buf
[0] == MODE_SENSE
) {
321 if (r
->req
.cmd
.buf
[0] == INQUIRY
) {
322 scsi_handle_inquiry_reply(r
, s
);
326 scsi_req_data(&r
->req
, len
);
327 scsi_req_unref(&r
->req
);
330 aio_context_release(blk_get_aio_context(s
->conf
.blk
));
333 /* Read more data from scsi device into buffer. */
334 static void scsi_read_data(SCSIRequest
*req
)
336 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
337 SCSIDevice
*s
= r
->req
.dev
;
340 trace_scsi_generic_read_data(req
->tag
);
342 /* The request is used as the AIO opaque value, so add a ref. */
343 scsi_req_ref(&r
->req
);
345 scsi_command_complete_noio(r
, 0);
349 ret
= execute_command(s
->conf
.blk
, r
, SG_DXFER_FROM_DEV
,
352 scsi_command_complete_noio(r
, ret
);
356 static void scsi_write_complete(void * opaque
, int ret
)
358 SCSIGenericReq
*r
= (SCSIGenericReq
*)opaque
;
359 SCSIDevice
*s
= r
->req
.dev
;
361 trace_scsi_generic_write_complete(ret
);
363 assert(r
->req
.aiocb
!= NULL
);
366 aio_context_acquire(blk_get_aio_context(s
->conf
.blk
));
368 if (ret
|| r
->req
.io_canceled
) {
369 scsi_command_complete_noio(r
, ret
);
373 if (r
->req
.cmd
.buf
[0] == MODE_SELECT
&& r
->req
.cmd
.buf
[4] == 12 &&
374 s
->type
== TYPE_TAPE
) {
375 s
->blocksize
= (r
->buf
[9] << 16) | (r
->buf
[10] << 8) | r
->buf
[11];
376 trace_scsi_generic_write_complete_blocksize(s
->blocksize
);
379 scsi_command_complete_noio(r
, ret
);
382 aio_context_release(blk_get_aio_context(s
->conf
.blk
));
385 /* Write data to a scsi device. Returns nonzero on failure.
386 The transfer may complete asynchronously. */
387 static void scsi_write_data(SCSIRequest
*req
)
389 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
390 SCSIDevice
*s
= r
->req
.dev
;
393 trace_scsi_generic_write_data(req
->tag
);
396 scsi_req_data(&r
->req
, r
->len
);
400 /* The request is used as the AIO opaque value, so add a ref. */
401 scsi_req_ref(&r
->req
);
402 ret
= execute_command(s
->conf
.blk
, r
, SG_DXFER_TO_DEV
, scsi_write_complete
);
404 scsi_command_complete_noio(r
, ret
);
408 /* Return a pointer to the data buffer. */
409 static uint8_t *scsi_get_buf(SCSIRequest
*req
)
411 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
416 static void scsi_generic_command_dump(uint8_t *cmd
, int len
)
419 char *line_buffer
, *p
;
421 line_buffer
= g_malloc(len
* 5 + 1);
423 for (i
= 0, p
= line_buffer
; i
< len
; i
++) {
424 p
+= sprintf(p
, " 0x%02x", cmd
[i
]);
426 trace_scsi_generic_send_command(line_buffer
);
431 /* Execute a scsi command. Returns the length of the data expected by the
432 command. This will be Positive for data transfers from the device
433 (eg. disk reads), negative for transfers to the device (eg. disk writes),
434 and zero if the command does not transfer any data. */
436 static int32_t scsi_send_command(SCSIRequest
*req
, uint8_t *cmd
)
438 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
439 SCSIDevice
*s
= r
->req
.dev
;
442 if (trace_event_get_state_backends(TRACE_SCSI_GENERIC_SEND_COMMAND
)) {
443 scsi_generic_command_dump(cmd
, r
->req
.cmd
.len
);
446 if (r
->req
.cmd
.xfer
== 0) {
450 /* The request is used as the AIO opaque value, so add a ref. */
451 scsi_req_ref(&r
->req
);
452 ret
= execute_command(s
->conf
.blk
, r
, SG_DXFER_NONE
,
453 scsi_command_complete
);
455 scsi_command_complete_noio(r
, ret
);
461 if (r
->buflen
!= r
->req
.cmd
.xfer
) {
463 r
->buf
= g_malloc(r
->req
.cmd
.xfer
);
464 r
->buflen
= r
->req
.cmd
.xfer
;
467 memset(r
->buf
, 0, r
->buflen
);
468 r
->len
= r
->req
.cmd
.xfer
;
469 if (r
->req
.cmd
.mode
== SCSI_XFER_TO_DEV
) {
471 return -r
->req
.cmd
.xfer
;
473 return r
->req
.cmd
.xfer
;
477 static int read_naa_id(const uint8_t *p
, uint64_t *p_wwn
)
481 if ((p
[1] & 0xF) == 3) {
482 /* NAA designator type */
486 *p_wwn
= ldq_be_p(p
+ 4);
490 if ((p
[1] & 0xF) == 8) {
491 /* SCSI name string designator type */
492 if (p
[3] < 20 || memcmp(&p
[4], "naa.", 4)) {
495 if (p
[3] > 20 && p
[24] != ',') {
499 for (i
= 8; i
< 24; i
++) {
500 char c
= qemu_toupper(p
[i
]);
501 c
-= (c
>= '0' && c
<= '9' ? '0' : 'A' - 10);
502 *p_wwn
= (*p_wwn
<< 4) | c
;
510 int scsi_SG_IO_FROM_DEV(BlockBackend
*blk
, uint8_t *cmd
, uint8_t cmd_size
,
511 uint8_t *buf
, uint8_t buf_size
, uint32_t timeout
)
513 sg_io_hdr_t io_header
;
517 memset(&io_header
, 0, sizeof(io_header
));
518 io_header
.interface_id
= 'S';
519 io_header
.dxfer_direction
= SG_DXFER_FROM_DEV
;
520 io_header
.dxfer_len
= buf_size
;
521 io_header
.dxferp
= buf
;
522 io_header
.cmdp
= cmd
;
523 io_header
.cmd_len
= cmd_size
;
524 io_header
.mx_sb_len
= sizeof(sensebuf
);
525 io_header
.sbp
= sensebuf
;
526 io_header
.timeout
= timeout
* 1000;
528 ret
= blk_ioctl(blk
, SG_IO
, &io_header
);
529 if (ret
< 0 || io_header
.driver_status
|| io_header
.host_status
) {
536 * Executes an INQUIRY request with EVPD set to retrieve the
537 * available VPD pages of the device. If the device does
538 * not support the Block Limits page (page 0xb0), set
539 * the needs_vpd_bl_emulation flag for future use.
541 static void scsi_generic_set_vpd_bl_emulation(SCSIDevice
*s
)
548 memset(cmd
, 0, sizeof(cmd
));
549 memset(buf
, 0, sizeof(buf
));
553 cmd
[4] = sizeof(buf
);
555 ret
= scsi_SG_IO_FROM_DEV(s
->conf
.blk
, cmd
, sizeof(cmd
),
556 buf
, sizeof(buf
), s
->io_timeout
);
559 * Do not assume anything if we can't retrieve the
560 * INQUIRY response to assert the VPD Block Limits
563 s
->needs_vpd_bl_emulation
= false;
568 for (i
= 4; i
< MIN(sizeof(buf
), page_len
+ 4); i
++) {
569 if (buf
[i
] == 0xb0) {
570 s
->needs_vpd_bl_emulation
= false;
574 s
->needs_vpd_bl_emulation
= true;
577 static void scsi_generic_read_device_identification(SCSIDevice
*s
)
584 memset(cmd
, 0, sizeof(cmd
));
585 memset(buf
, 0, sizeof(buf
));
589 cmd
[4] = sizeof(buf
);
591 ret
= scsi_SG_IO_FROM_DEV(s
->conf
.blk
, cmd
, sizeof(cmd
),
592 buf
, sizeof(buf
), s
->io_timeout
);
597 len
= MIN((buf
[2] << 8) | buf
[3], sizeof(buf
) - 4);
598 for (i
= 0; i
+ 3 <= len
; ) {
599 const uint8_t *p
= &buf
[i
+ 4];
602 if (i
+ (p
[3] + 4) > len
) {
606 if ((p
[1] & 0x10) == 0) {
607 /* Associated with the logical unit */
608 if (read_naa_id(p
, &wwn
) == 0) {
611 } else if ((p
[1] & 0x10) == 0x10) {
612 /* Associated with the target port */
613 if (read_naa_id(p
, &wwn
) == 0) {
622 void scsi_generic_read_device_inquiry(SCSIDevice
*s
)
624 scsi_generic_read_device_identification(s
);
625 if (s
->type
== TYPE_DISK
|| s
->type
== TYPE_ZBC
) {
626 scsi_generic_set_vpd_bl_emulation(s
);
628 s
->needs_vpd_bl_emulation
= false;
632 static int get_stream_blocksize(BlockBackend
*blk
)
638 memset(cmd
, 0, sizeof(cmd
));
639 memset(buf
, 0, sizeof(buf
));
641 cmd
[4] = sizeof(buf
);
643 ret
= scsi_SG_IO_FROM_DEV(blk
, cmd
, sizeof(cmd
), buf
, sizeof(buf
), 6);
648 return (buf
[9] << 16) | (buf
[10] << 8) | buf
[11];
651 static void scsi_generic_reset(DeviceState
*dev
)
653 SCSIDevice
*s
= SCSI_DEVICE(dev
);
655 s
->scsi_version
= s
->default_scsi_version
;
656 scsi_device_purge_requests(s
, SENSE_CODE(RESET
));
659 static void scsi_generic_realize(SCSIDevice
*s
, Error
**errp
)
663 struct sg_scsi_id scsiid
;
666 error_setg(errp
, "drive property not set");
670 if (blk_get_on_error(s
->conf
.blk
, 0) != BLOCKDEV_ON_ERROR_ENOSPC
) {
671 error_setg(errp
, "Device doesn't support drive option werror");
674 if (blk_get_on_error(s
->conf
.blk
, 1) != BLOCKDEV_ON_ERROR_REPORT
) {
675 error_setg(errp
, "Device doesn't support drive option rerror");
679 /* check we are using a driver managing SG_IO (version 3 and after */
680 rc
= blk_ioctl(s
->conf
.blk
, SG_GET_VERSION_NUM
, &sg_version
);
682 error_setg_errno(errp
, -rc
, "cannot get SG_IO version number");
684 error_append_hint(errp
, "Is this a SCSI device?\n");
688 if (sg_version
< 30000) {
689 error_setg(errp
, "scsi generic interface too old");
693 /* get LUN of the /dev/sg? */
694 if (blk_ioctl(s
->conf
.blk
, SG_GET_SCSI_ID
, &scsiid
)) {
695 error_setg(errp
, "SG_GET_SCSI_ID ioctl failed");
698 if (!blkconf_apply_backend_options(&s
->conf
,
699 !blk_supports_write_perm(s
->conf
.blk
),
704 /* define device state */
705 s
->type
= scsiid
.scsi_type
;
706 trace_scsi_generic_realize_type(s
->type
);
710 s
->blocksize
= get_stream_blocksize(s
->conf
.blk
);
711 if (s
->blocksize
== -1) {
716 /* Make a guess for block devices, we'll fix it when the guest sends.
717 * READ CAPACITY. If they don't, they likely would assume these sizes
718 * anyway. (TODO: they could also send MODE SENSE).
729 trace_scsi_generic_realize_blocksize(s
->blocksize
);
731 /* Only used by scsi-block, but initialize it nevertheless to be clean. */
732 s
->default_scsi_version
= -1;
733 s
->io_timeout
= DEFAULT_IO_TIMEOUT
;
734 scsi_generic_read_device_inquiry(s
);
737 const SCSIReqOps scsi_generic_req_ops
= {
738 .size
= sizeof(SCSIGenericReq
),
739 .free_req
= scsi_free_request
,
740 .send_command
= scsi_send_command
,
741 .read_data
= scsi_read_data
,
742 .write_data
= scsi_write_data
,
743 .get_buf
= scsi_get_buf
,
744 .load_request
= scsi_generic_load_request
,
745 .save_request
= scsi_generic_save_request
,
748 static SCSIRequest
*scsi_new_request(SCSIDevice
*d
, uint32_t tag
, uint32_t lun
,
749 uint8_t *buf
, void *hba_private
)
751 return scsi_req_alloc(&scsi_generic_req_ops
, d
, tag
, lun
, hba_private
);
754 static Property scsi_generic_properties
[] = {
755 DEFINE_PROP_DRIVE("drive", SCSIDevice
, conf
.blk
),
756 DEFINE_PROP_BOOL("share-rw", SCSIDevice
, conf
.share_rw
, false),
757 DEFINE_PROP_UINT32("io_timeout", SCSIDevice
, io_timeout
,
759 DEFINE_PROP_END_OF_LIST(),
762 static int scsi_generic_parse_cdb(SCSIDevice
*dev
, SCSICommand
*cmd
,
763 uint8_t *buf
, void *hba_private
)
765 return scsi_bus_parse_cdb(dev
, cmd
, buf
, hba_private
);
768 static void scsi_generic_class_initfn(ObjectClass
*klass
, void *data
)
770 DeviceClass
*dc
= DEVICE_CLASS(klass
);
771 SCSIDeviceClass
*sc
= SCSI_DEVICE_CLASS(klass
);
773 sc
->realize
= scsi_generic_realize
;
774 sc
->alloc_req
= scsi_new_request
;
775 sc
->parse_cdb
= scsi_generic_parse_cdb
;
776 dc
->fw_name
= "disk";
777 dc
->desc
= "pass through generic scsi device (/dev/sg*)";
778 dc
->reset
= scsi_generic_reset
;
779 device_class_set_props(dc
, scsi_generic_properties
);
780 dc
->vmsd
= &vmstate_scsi_device
;
783 static const TypeInfo scsi_generic_info
= {
784 .name
= "scsi-generic",
785 .parent
= TYPE_SCSI_DEVICE
,
786 .instance_size
= sizeof(SCSIDevice
),
787 .class_init
= scsi_generic_class_initfn
,
790 static void scsi_generic_register_types(void)
792 type_register_static(&scsi_generic_info
);
795 type_init(scsi_generic_register_types
)
797 #endif /* __linux__ */