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/scsi/emulation.h"
23 #include "sysemu/block-backend.h"
29 #include "scsi/constants.h"
32 #define MAX_UINT ((unsigned int)-1)
35 typedef struct SCSIGenericReq
{
40 sg_io_hdr_t io_header
;
43 static void scsi_generic_save_request(QEMUFile
*f
, SCSIRequest
*req
)
45 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
47 qemu_put_sbe32s(f
, &r
->buflen
);
48 if (r
->buflen
&& r
->req
.cmd
.mode
== SCSI_XFER_TO_DEV
) {
50 qemu_put_buffer(f
, r
->buf
, r
->req
.cmd
.xfer
);
54 static void scsi_generic_load_request(QEMUFile
*f
, SCSIRequest
*req
)
56 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
58 qemu_get_sbe32s(f
, &r
->buflen
);
59 if (r
->buflen
&& r
->req
.cmd
.mode
== SCSI_XFER_TO_DEV
) {
61 qemu_get_buffer(f
, r
->buf
, r
->req
.cmd
.xfer
);
65 static void scsi_free_request(SCSIRequest
*req
)
67 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
72 /* Helper function for command completion. */
73 static void scsi_command_complete_noio(SCSIGenericReq
*r
, int ret
)
78 assert(r
->req
.aiocb
== NULL
);
80 if (r
->req
.io_canceled
) {
81 scsi_req_cancel_complete(&r
->req
);
84 status
= sg_io_sense_from_errno(-ret
, &r
->io_header
, &sense
);
85 if (status
== CHECK_CONDITION
) {
86 if (r
->io_header
.driver_status
& SG_ERR_DRIVER_SENSE
) {
87 r
->req
.sense_len
= r
->io_header
.sb_len_wr
;
89 scsi_req_build_sense(&r
->req
, sense
);
93 trace_scsi_generic_command_complete_noio(r
, r
->req
.tag
, status
);
95 scsi_req_complete(&r
->req
, status
);
97 scsi_req_unref(&r
->req
);
100 static void scsi_command_complete(void *opaque
, int ret
)
102 SCSIGenericReq
*r
= (SCSIGenericReq
*)opaque
;
103 SCSIDevice
*s
= r
->req
.dev
;
105 assert(r
->req
.aiocb
!= NULL
);
108 aio_context_acquire(blk_get_aio_context(s
->conf
.blk
));
109 scsi_command_complete_noio(r
, ret
);
110 aio_context_release(blk_get_aio_context(s
->conf
.blk
));
113 static int execute_command(BlockBackend
*blk
,
114 SCSIGenericReq
*r
, int direction
,
115 BlockCompletionFunc
*complete
)
117 r
->io_header
.interface_id
= 'S';
118 r
->io_header
.dxfer_direction
= direction
;
119 r
->io_header
.dxferp
= r
->buf
;
120 r
->io_header
.dxfer_len
= r
->buflen
;
121 r
->io_header
.cmdp
= r
->req
.cmd
.buf
;
122 r
->io_header
.cmd_len
= r
->req
.cmd
.len
;
123 r
->io_header
.mx_sb_len
= sizeof(r
->req
.sense
);
124 r
->io_header
.sbp
= r
->req
.sense
;
125 r
->io_header
.timeout
= MAX_UINT
;
126 r
->io_header
.usr_ptr
= r
;
127 r
->io_header
.flags
|= SG_FLAG_DIRECT_IO
;
129 r
->req
.aiocb
= blk_aio_ioctl(blk
, SG_IO
, &r
->io_header
, complete
, r
);
130 if (r
->req
.aiocb
== NULL
) {
137 static void scsi_handle_inquiry_reply(SCSIGenericReq
*r
, SCSIDevice
*s
)
139 uint8_t page
, page_idx
;
142 * EVPD set to zero returns the standard INQUIRY data.
144 * Check if scsi_version is unset (-1) to avoid re-defining it
145 * each time an INQUIRY with standard data is received.
146 * scsi_version is initialized with -1 in scsi_generic_reset
147 * and scsi_disk_reset, making sure that we'll set the
148 * scsi_version after a reset. If the version field of the
149 * INQUIRY response somehow changes after a guest reboot,
150 * we'll be able to keep track of it.
152 * On SCSI-2 and older, first 3 bits of byte 2 is the
153 * ANSI-approved version, while on later versions the
154 * whole byte 2 contains the version. Check if we're dealing
155 * with a newer version and, in that case, assign the
158 if (s
->scsi_version
== -1 && !(r
->req
.cmd
.buf
[1] & 0x01)) {
159 s
->scsi_version
= r
->buf
[2] & 0x07;
160 if (s
->scsi_version
> 2) {
161 s
->scsi_version
= r
->buf
[2];
165 if ((s
->type
== TYPE_DISK
|| s
->type
== TYPE_ZBC
) &&
166 (r
->req
.cmd
.buf
[1] & 0x01)) {
167 page
= r
->req
.cmd
.buf
[2];
169 uint32_t max_transfer
=
170 blk_get_max_transfer(s
->conf
.blk
) / s
->blocksize
;
172 assert(max_transfer
);
173 stl_be_p(&r
->buf
[8], max_transfer
);
174 /* Also take care of the opt xfer len. */
175 stl_be_p(&r
->buf
[12],
176 MIN_NON_ZERO(max_transfer
, ldl_be_p(&r
->buf
[12])));
177 } else if (s
->needs_vpd_bl_emulation
&& page
== 0x00 && r
->buflen
>= 4) {
179 * Now we're capable of supplying the VPD Block Limits
180 * response if the hardware can't. Add it in the INQUIRY
181 * Supported VPD pages response in case we are using the
182 * emulation for this device.
184 * This way, the guest kernel will be aware of the support
185 * and will use it to proper setup the SCSI device.
187 * VPD page numbers must be sorted, so insert 0xb0 at the
188 * right place with an in-place insert. When the while loop
189 * begins the device response is at r[0] to r[page_idx - 1].
191 page_idx
= lduw_be_p(r
->buf
+ 2) + 4;
192 page_idx
= MIN(page_idx
, r
->buflen
);
193 while (page_idx
> 4 && r
->buf
[page_idx
- 1] >= 0xb0) {
194 if (page_idx
< r
->buflen
) {
195 r
->buf
[page_idx
] = r
->buf
[page_idx
- 1];
199 if (page_idx
< r
->buflen
) {
200 r
->buf
[page_idx
] = 0xb0;
202 stw_be_p(r
->buf
+ 2, lduw_be_p(r
->buf
+ 2) + 1);
207 static int scsi_generic_emulate_block_limits(SCSIGenericReq
*r
, SCSIDevice
*s
)
212 SCSIBlockLimits bl
= {
213 .max_io_sectors
= blk_get_max_transfer(s
->conf
.blk
) / s
->blocksize
216 memset(r
->buf
, 0, r
->buflen
);
218 stb_p(buf
+ 1, 0xb0);
219 len
= scsi_emulate_block_limits(buf
+ 4, &bl
);
220 assert(len
<= sizeof(buf
) - 4);
221 stw_be_p(buf
+ 2, len
);
223 memcpy(r
->buf
, buf
, MIN(r
->buflen
, len
+ 4));
225 r
->io_header
.sb_len_wr
= 0;
228 * We have valid contents in the reply buffer but the
229 * io_header can report a sense error coming from
230 * the hardware in scsi_command_complete_noio. Clean
231 * up the io_header to avoid reporting it.
233 r
->io_header
.driver_status
= 0;
234 r
->io_header
.status
= 0;
239 static void scsi_read_complete(void * opaque
, int ret
)
241 SCSIGenericReq
*r
= (SCSIGenericReq
*)opaque
;
242 SCSIDevice
*s
= r
->req
.dev
;
245 assert(r
->req
.aiocb
!= NULL
);
248 aio_context_acquire(blk_get_aio_context(s
->conf
.blk
));
250 if (ret
|| r
->req
.io_canceled
) {
251 scsi_command_complete_noio(r
, ret
);
255 len
= r
->io_header
.dxfer_len
- r
->io_header
.resid
;
256 trace_scsi_generic_read_complete(r
->req
.tag
, len
);
260 if (r
->io_header
.driver_status
& SG_ERR_DRIVER_SENSE
) {
262 scsi_parse_sense_buf(r
->req
.sense
, r
->io_header
.sb_len_wr
);
265 * Check if this is a VPD Block Limits request that
266 * resulted in sense error but would need emulation.
267 * In this case, emulate a valid VPD response.
269 if (sense
.key
== ILLEGAL_REQUEST
&&
270 s
->needs_vpd_bl_emulation
&&
271 r
->req
.cmd
.buf
[0] == INQUIRY
&&
272 (r
->req
.cmd
.buf
[1] & 0x01) &&
273 r
->req
.cmd
.buf
[2] == 0xb0) {
274 len
= scsi_generic_emulate_block_limits(r
, s
);
276 * It's okay to jup to req_complete: no need to
277 * let scsi_handle_inquiry_reply handle an
278 * INQUIRY VPD BL request we created manually.
287 scsi_command_complete_noio(r
, 0);
291 /* Snoop READ CAPACITY output to set the blocksize. */
292 if (r
->req
.cmd
.buf
[0] == READ_CAPACITY_10
&&
293 (ldl_be_p(&r
->buf
[0]) != 0xffffffffU
|| s
->max_lba
== 0)) {
294 s
->blocksize
= ldl_be_p(&r
->buf
[4]);
295 s
->max_lba
= ldl_be_p(&r
->buf
[0]) & 0xffffffffULL
;
296 } else if (r
->req
.cmd
.buf
[0] == SERVICE_ACTION_IN_16
&&
297 (r
->req
.cmd
.buf
[1] & 31) == SAI_READ_CAPACITY_16
) {
298 s
->blocksize
= ldl_be_p(&r
->buf
[8]);
299 s
->max_lba
= ldq_be_p(&r
->buf
[0]);
301 blk_set_guest_block_size(s
->conf
.blk
, s
->blocksize
);
304 * Patch MODE SENSE device specific parameters if the BDS is opened
307 if ((s
->type
== TYPE_DISK
|| s
->type
== TYPE_TAPE
|| s
->type
== TYPE_ZBC
) &&
308 blk_is_read_only(s
->conf
.blk
) &&
309 (r
->req
.cmd
.buf
[0] == MODE_SENSE
||
310 r
->req
.cmd
.buf
[0] == MODE_SENSE_10
) &&
311 (r
->req
.cmd
.buf
[1] & 0x8) == 0) {
312 if (r
->req
.cmd
.buf
[0] == MODE_SENSE
) {
318 if (r
->req
.cmd
.buf
[0] == INQUIRY
) {
319 scsi_handle_inquiry_reply(r
, s
);
323 scsi_req_data(&r
->req
, len
);
324 scsi_req_unref(&r
->req
);
327 aio_context_release(blk_get_aio_context(s
->conf
.blk
));
330 /* Read more data from scsi device into buffer. */
331 static void scsi_read_data(SCSIRequest
*req
)
333 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
334 SCSIDevice
*s
= r
->req
.dev
;
337 trace_scsi_generic_read_data(req
->tag
);
339 /* The request is used as the AIO opaque value, so add a ref. */
340 scsi_req_ref(&r
->req
);
342 scsi_command_complete_noio(r
, 0);
346 ret
= execute_command(s
->conf
.blk
, r
, SG_DXFER_FROM_DEV
,
349 scsi_command_complete_noio(r
, ret
);
353 static void scsi_write_complete(void * opaque
, int ret
)
355 SCSIGenericReq
*r
= (SCSIGenericReq
*)opaque
;
356 SCSIDevice
*s
= r
->req
.dev
;
358 trace_scsi_generic_write_complete(ret
);
360 assert(r
->req
.aiocb
!= NULL
);
363 aio_context_acquire(blk_get_aio_context(s
->conf
.blk
));
365 if (ret
|| r
->req
.io_canceled
) {
366 scsi_command_complete_noio(r
, ret
);
370 if (r
->req
.cmd
.buf
[0] == MODE_SELECT
&& r
->req
.cmd
.buf
[4] == 12 &&
371 s
->type
== TYPE_TAPE
) {
372 s
->blocksize
= (r
->buf
[9] << 16) | (r
->buf
[10] << 8) | r
->buf
[11];
373 trace_scsi_generic_write_complete_blocksize(s
->blocksize
);
376 scsi_command_complete_noio(r
, ret
);
379 aio_context_release(blk_get_aio_context(s
->conf
.blk
));
382 /* Write data to a scsi device. Returns nonzero on failure.
383 The transfer may complete asynchronously. */
384 static void scsi_write_data(SCSIRequest
*req
)
386 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
387 SCSIDevice
*s
= r
->req
.dev
;
390 trace_scsi_generic_write_data(req
->tag
);
393 scsi_req_data(&r
->req
, r
->len
);
397 /* The request is used as the AIO opaque value, so add a ref. */
398 scsi_req_ref(&r
->req
);
399 ret
= execute_command(s
->conf
.blk
, r
, SG_DXFER_TO_DEV
, scsi_write_complete
);
401 scsi_command_complete_noio(r
, ret
);
405 /* Return a pointer to the data buffer. */
406 static uint8_t *scsi_get_buf(SCSIRequest
*req
)
408 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
413 static void scsi_generic_command_dump(uint8_t *cmd
, int len
)
416 char *line_buffer
, *p
;
418 line_buffer
= g_malloc(len
* 5 + 1);
420 for (i
= 0, p
= line_buffer
; i
< len
; i
++) {
421 p
+= sprintf(p
, " 0x%02x", cmd
[i
]);
423 trace_scsi_generic_send_command(line_buffer
);
428 /* Execute a scsi command. Returns the length of the data expected by the
429 command. This will be Positive for data transfers from the device
430 (eg. disk reads), negative for transfers to the device (eg. disk writes),
431 and zero if the command does not transfer any data. */
433 static int32_t scsi_send_command(SCSIRequest
*req
, uint8_t *cmd
)
435 SCSIGenericReq
*r
= DO_UPCAST(SCSIGenericReq
, req
, req
);
436 SCSIDevice
*s
= r
->req
.dev
;
439 if (trace_event_get_state_backends(TRACE_SCSI_GENERIC_SEND_COMMAND
)) {
440 scsi_generic_command_dump(cmd
, r
->req
.cmd
.len
);
443 if (r
->req
.cmd
.xfer
== 0) {
447 /* The request is used as the AIO opaque value, so add a ref. */
448 scsi_req_ref(&r
->req
);
449 ret
= execute_command(s
->conf
.blk
, r
, SG_DXFER_NONE
,
450 scsi_command_complete
);
452 scsi_command_complete_noio(r
, ret
);
458 if (r
->buflen
!= r
->req
.cmd
.xfer
) {
460 r
->buf
= g_malloc(r
->req
.cmd
.xfer
);
461 r
->buflen
= r
->req
.cmd
.xfer
;
464 memset(r
->buf
, 0, r
->buflen
);
465 r
->len
= r
->req
.cmd
.xfer
;
466 if (r
->req
.cmd
.mode
== SCSI_XFER_TO_DEV
) {
468 return -r
->req
.cmd
.xfer
;
470 return r
->req
.cmd
.xfer
;
474 static int read_naa_id(const uint8_t *p
, uint64_t *p_wwn
)
478 if ((p
[1] & 0xF) == 3) {
479 /* NAA designator type */
483 *p_wwn
= ldq_be_p(p
+ 4);
487 if ((p
[1] & 0xF) == 8) {
488 /* SCSI name string designator type */
489 if (p
[3] < 20 || memcmp(&p
[4], "naa.", 4)) {
492 if (p
[3] > 20 && p
[24] != ',') {
496 for (i
= 8; i
< 24; i
++) {
497 char c
= qemu_toupper(p
[i
]);
498 c
-= (c
>= '0' && c
<= '9' ? '0' : 'A' - 10);
499 *p_wwn
= (*p_wwn
<< 4) | c
;
507 int scsi_SG_IO_FROM_DEV(BlockBackend
*blk
, uint8_t *cmd
, uint8_t cmd_size
,
508 uint8_t *buf
, uint8_t buf_size
)
510 sg_io_hdr_t io_header
;
514 memset(&io_header
, 0, sizeof(io_header
));
515 io_header
.interface_id
= 'S';
516 io_header
.dxfer_direction
= SG_DXFER_FROM_DEV
;
517 io_header
.dxfer_len
= buf_size
;
518 io_header
.dxferp
= buf
;
519 io_header
.cmdp
= cmd
;
520 io_header
.cmd_len
= cmd_size
;
521 io_header
.mx_sb_len
= sizeof(sensebuf
);
522 io_header
.sbp
= sensebuf
;
523 io_header
.timeout
= 6000; /* XXX */
525 ret
= blk_ioctl(blk
, SG_IO
, &io_header
);
526 if (ret
< 0 || io_header
.driver_status
|| io_header
.host_status
) {
533 * Executes an INQUIRY request with EVPD set to retrieve the
534 * available VPD pages of the device. If the device does
535 * not support the Block Limits page (page 0xb0), set
536 * the needs_vpd_bl_emulation flag for future use.
538 static void scsi_generic_set_vpd_bl_emulation(SCSIDevice
*s
)
545 memset(cmd
, 0, sizeof(cmd
));
546 memset(buf
, 0, sizeof(buf
));
550 cmd
[4] = sizeof(buf
);
552 ret
= scsi_SG_IO_FROM_DEV(s
->conf
.blk
, cmd
, sizeof(cmd
),
556 * Do not assume anything if we can't retrieve the
557 * INQUIRY response to assert the VPD Block Limits
560 s
->needs_vpd_bl_emulation
= false;
565 for (i
= 4; i
< MIN(sizeof(buf
), page_len
+ 4); i
++) {
566 if (buf
[i
] == 0xb0) {
567 s
->needs_vpd_bl_emulation
= false;
571 s
->needs_vpd_bl_emulation
= true;
574 static void scsi_generic_read_device_identification(SCSIDevice
*s
)
581 memset(cmd
, 0, sizeof(cmd
));
582 memset(buf
, 0, sizeof(buf
));
586 cmd
[4] = sizeof(buf
);
588 ret
= scsi_SG_IO_FROM_DEV(s
->conf
.blk
, cmd
, sizeof(cmd
),
594 len
= MIN((buf
[2] << 8) | buf
[3], sizeof(buf
) - 4);
595 for (i
= 0; i
+ 3 <= len
; ) {
596 const uint8_t *p
= &buf
[i
+ 4];
599 if (i
+ (p
[3] + 4) > len
) {
603 if ((p
[1] & 0x10) == 0) {
604 /* Associated with the logical unit */
605 if (read_naa_id(p
, &wwn
) == 0) {
608 } else if ((p
[1] & 0x10) == 0x10) {
609 /* Associated with the target port */
610 if (read_naa_id(p
, &wwn
) == 0) {
619 void scsi_generic_read_device_inquiry(SCSIDevice
*s
)
621 scsi_generic_read_device_identification(s
);
622 if (s
->type
== TYPE_DISK
|| s
->type
== TYPE_ZBC
) {
623 scsi_generic_set_vpd_bl_emulation(s
);
625 s
->needs_vpd_bl_emulation
= false;
629 static int get_stream_blocksize(BlockBackend
*blk
)
635 memset(cmd
, 0, sizeof(cmd
));
636 memset(buf
, 0, sizeof(buf
));
638 cmd
[4] = sizeof(buf
);
640 ret
= scsi_SG_IO_FROM_DEV(blk
, cmd
, sizeof(cmd
), buf
, sizeof(buf
));
645 return (buf
[9] << 16) | (buf
[10] << 8) | buf
[11];
648 static void scsi_generic_reset(DeviceState
*dev
)
650 SCSIDevice
*s
= SCSI_DEVICE(dev
);
652 s
->scsi_version
= s
->default_scsi_version
;
653 scsi_device_purge_requests(s
, SENSE_CODE(RESET
));
656 static void scsi_generic_realize(SCSIDevice
*s
, Error
**errp
)
660 struct sg_scsi_id scsiid
;
663 error_setg(errp
, "drive property not set");
667 if (blk_get_on_error(s
->conf
.blk
, 0) != BLOCKDEV_ON_ERROR_ENOSPC
) {
668 error_setg(errp
, "Device doesn't support drive option werror");
671 if (blk_get_on_error(s
->conf
.blk
, 1) != BLOCKDEV_ON_ERROR_REPORT
) {
672 error_setg(errp
, "Device doesn't support drive option rerror");
676 /* check we are using a driver managing SG_IO (version 3 and after */
677 rc
= blk_ioctl(s
->conf
.blk
, SG_GET_VERSION_NUM
, &sg_version
);
679 error_setg_errno(errp
, -rc
, "cannot get SG_IO version number");
681 error_append_hint(errp
, "Is this a SCSI device?\n");
685 if (sg_version
< 30000) {
686 error_setg(errp
, "scsi generic interface too old");
690 /* get LUN of the /dev/sg? */
691 if (blk_ioctl(s
->conf
.blk
, SG_GET_SCSI_ID
, &scsiid
)) {
692 error_setg(errp
, "SG_GET_SCSI_ID ioctl failed");
695 if (!blkconf_apply_backend_options(&s
->conf
,
696 blk_is_read_only(s
->conf
.blk
),
701 /* define device state */
702 s
->type
= scsiid
.scsi_type
;
703 trace_scsi_generic_realize_type(s
->type
);
707 s
->blocksize
= get_stream_blocksize(s
->conf
.blk
);
708 if (s
->blocksize
== -1) {
713 /* Make a guess for block devices, we'll fix it when the guest sends.
714 * READ CAPACITY. If they don't, they likely would assume these sizes
715 * anyway. (TODO: they could also send MODE SENSE).
726 trace_scsi_generic_realize_blocksize(s
->blocksize
);
728 /* Only used by scsi-block, but initialize it nevertheless to be clean. */
729 s
->default_scsi_version
= -1;
730 scsi_generic_read_device_inquiry(s
);
733 const SCSIReqOps scsi_generic_req_ops
= {
734 .size
= sizeof(SCSIGenericReq
),
735 .free_req
= scsi_free_request
,
736 .send_command
= scsi_send_command
,
737 .read_data
= scsi_read_data
,
738 .write_data
= scsi_write_data
,
739 .get_buf
= scsi_get_buf
,
740 .load_request
= scsi_generic_load_request
,
741 .save_request
= scsi_generic_save_request
,
744 static SCSIRequest
*scsi_new_request(SCSIDevice
*d
, uint32_t tag
, uint32_t lun
,
745 uint8_t *buf
, void *hba_private
)
747 return scsi_req_alloc(&scsi_generic_req_ops
, d
, tag
, lun
, hba_private
);
750 static Property scsi_generic_properties
[] = {
751 DEFINE_PROP_DRIVE("drive", SCSIDevice
, conf
.blk
),
752 DEFINE_PROP_BOOL("share-rw", SCSIDevice
, conf
.share_rw
, false),
753 DEFINE_PROP_END_OF_LIST(),
756 static int scsi_generic_parse_cdb(SCSIDevice
*dev
, SCSICommand
*cmd
,
757 uint8_t *buf
, void *hba_private
)
759 return scsi_bus_parse_cdb(dev
, cmd
, buf
, hba_private
);
762 static void scsi_generic_class_initfn(ObjectClass
*klass
, void *data
)
764 DeviceClass
*dc
= DEVICE_CLASS(klass
);
765 SCSIDeviceClass
*sc
= SCSI_DEVICE_CLASS(klass
);
767 sc
->realize
= scsi_generic_realize
;
768 sc
->alloc_req
= scsi_new_request
;
769 sc
->parse_cdb
= scsi_generic_parse_cdb
;
770 dc
->fw_name
= "disk";
771 dc
->desc
= "pass through generic scsi device (/dev/sg*)";
772 dc
->reset
= scsi_generic_reset
;
773 device_class_set_props(dc
, scsi_generic_properties
);
774 dc
->vmsd
= &vmstate_scsi_device
;
777 static const TypeInfo scsi_generic_info
= {
778 .name
= "scsi-generic",
779 .parent
= TYPE_SCSI_DEVICE
,
780 .instance_size
= sizeof(SCSIDevice
),
781 .class_init
= scsi_generic_class_initfn
,
784 static void scsi_generic_register_types(void)
786 type_register_static(&scsi_generic_info
);
789 type_init(scsi_generic_register_types
)
791 #endif /* __linux__ */