struct iovec iov;
QEMUIOVector qiov;
uint32_t status;
+ BlockAcctCookie acct;
} SCSIDiskReq;
struct SCSIDiskState
QEMUBH *bh;
char *version;
char *serial;
- SCSISense sense;
+ bool tray_open;
};
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
- uint32_t lun, void *hba_private)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
- SCSIRequest *req;
- SCSIDiskReq *r;
-
- req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun, hba_private);
- r = DO_UPCAST(SCSIDiskReq, req, req);
- r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
- return req;
-}
-
static void scsi_free_request(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
qemu_vfree(r->iov.iov_base);
}
-static void scsi_disk_clear_sense(SCSIDiskState *s)
-{
- memset(&s->sense, 0, sizeof(s->sense));
-}
-
-static void scsi_req_set_status(SCSIDiskReq *r, int status, SCSISense sense)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
- r->req.status = status;
- s->sense = sense;
-}
-
-/* Helper function for command completion. */
-static void scsi_command_complete(SCSIDiskReq *r, int status, SCSISense sense)
+/* Helper function for command completion with sense. */
+static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense)
{
- DPRINTF("Command complete tag=0x%x status=%d sense=%d/%d/%d\n",
- r->req.tag, status, sense.key, sense.asc, sense.ascq);
- scsi_req_set_status(r, status, sense);
- scsi_req_complete(&r->req);
+ DPRINTF("Command complete tag=0x%x sense=%d/%d/%d\n",
+ r->req.tag, sense.key, sense.asc, sense.ascq);
+ scsi_req_build_sense(&r->req, sense);
+ scsi_req_complete(&r->req, CHECK_CONDITION);
}
/* Cancel a pending data transfer. */
static void scsi_read_complete(void * opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
int n;
- r->req.aiocb = NULL;
+ if (r->req.aiocb != NULL) {
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->bs, &r->acct);
+ }
if (ret) {
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
scsi_req_data(&r->req, r->iov.iov_len);
}
+static void scsi_flush_complete(void * opaque, int ret)
+{
+ SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ if (r->req.aiocb != NULL) {
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->bs, &r->acct);
+ }
+
+ if (ret < 0) {
+ if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
+ return;
+ }
+ }
+
+ scsi_req_complete(&r->req, GOOD);
+}
/* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIRequest *req)
}
DPRINTF("Read sector_count=%d\n", r->sector_count);
if (r->sector_count == 0) {
- scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
+ /* This also clears the sense buffer for REQUEST SENSE. */
+ scsi_req_complete(&r->req, GOOD);
return;
}
if (n > SCSI_DMA_BUF_SIZE / 512)
n = SCSI_DMA_BUF_SIZE / 512;
+ if (s->tray_open) {
+ scsi_read_complete(r, -ENOMEDIUM);
+ }
r->iov.iov_len = n * 512;
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+
+ bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
scsi_read_complete, r);
if (r->req.aiocb == NULL) {
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(VMSTOP_DISKFULL);
} else {
- if (type == SCSI_REQ_STATUS_RETRY_READ) {
- scsi_req_data(&r->req, 0);
- }
switch (error) {
case ENOMEM:
- scsi_command_complete(r, CHECK_CONDITION,
- SENSE_CODE(TARGET_FAILURE));
+ scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE));
break;
case EINVAL:
- scsi_command_complete(r, CHECK_CONDITION,
- SENSE_CODE(INVALID_FIELD));
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
break;
default:
- scsi_command_complete(r, CHECK_CONDITION,
- SENSE_CODE(IO_ERROR));
+ scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
}
bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
static void scsi_write_complete(void * opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t len;
uint32_t n;
- r->req.aiocb = NULL;
+ if (r->req.aiocb != NULL) {
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->bs, &r->acct);
+ }
if (ret) {
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
r->sector += n;
r->sector_count -= n;
if (r->sector_count == 0) {
- scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
+ scsi_req_complete(&r->req, GOOD);
} else {
len = r->sector_count * 512;
if (len > SCSI_DMA_BUF_SIZE) {
n = r->iov.iov_len / 512;
if (n) {
+ if (s->tray_open) {
+ scsi_write_complete(r, -ENOMEDIUM);
+ }
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+
+ bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
scsi_write_complete, r);
if (r->req.aiocb == NULL) {
case SCSI_REQ_STATUS_RETRY_FLUSH:
ret = scsi_disk_emulate_command(r, r->iov.iov_base);
if (ret == 0) {
- scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
+ scsi_req_complete(&r->req, GOOD);
}
}
}
return (uint8_t *)r->iov.iov_base;
}
-/* Copy sense information into the provided buffer */
-static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len)
-{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
-
- return scsi_build_sense(s->sense, outbuf, len, len > 14);
-}
-
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
memset(outbuf, 0, buflen);
- if (req->lun) {
- outbuf[0] = 0x7f; /* LUN not supported */
- return buflen;
- }
-
outbuf[0] = s->qdev.type & 0x1f;
if (s->qdev.type == TYPE_ROM) {
outbuf[1] = 0x80;
return buflen;
}
-static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
+static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
int page_control)
{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
BlockDriverState *bdrv = s->bs;
int cylinders, heads, secs;
+ uint8_t *p = *p_outbuf;
/*
* If Changeable Values are requested, a mask denoting those mode parameters
*/
switch (page) {
case 4: /* Rigid disk device geometry page. */
+ if (s->qdev.type == TYPE_ROM) {
+ return -1;
+ }
p[0] = 4;
p[1] = 0x16;
if (page_control == 1) { /* Changeable Values */
- return p[1] + 2;
+ break;
}
/* if a geometry hint is available, use it */
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
/* Medium rotation rate [rpm], 5400 rpm */
p[20] = (5400 >> 8) & 0xff;
p[21] = 5400 & 0xff;
- return p[1] + 2;
+ break;
case 5: /* Flexible disk device geometry page. */
+ if (s->qdev.type == TYPE_ROM) {
+ return -1;
+ }
p[0] = 5;
p[1] = 0x1e;
if (page_control == 1) { /* Changeable Values */
- return p[1] + 2;
+ break;
}
/* Transfer rate [kbit/s], 5Mbit/s */
p[2] = 5000 >> 8;
/* Medium rotation rate [rpm], 5400 rpm */
p[28] = (5400 >> 8) & 0xff;
p[29] = 5400 & 0xff;
- return p[1] + 2;
+ break;
case 8: /* Caching page. */
p[0] = 8;
p[1] = 0x12;
if (page_control == 1) { /* Changeable Values */
- return p[1] + 2;
+ break;
}
if (bdrv_enable_write_cache(s->bs)) {
p[2] = 4; /* WCE */
}
- return p[1] + 2;
+ break;
case 0x2a: /* CD Capabilities and Mechanical Status page. */
- if (s->qdev.type != TYPE_ROM)
- return 0;
+ if (s->qdev.type != TYPE_ROM) {
+ return -1;
+ }
p[0] = 0x2a;
p[1] = 0x14;
if (page_control == 1) { /* Changeable Values */
- return p[1] + 2;
+ break;
}
p[2] = 3; // CD-R & CD-RW read
p[3] = 0; // Writing not supported
p[19] = (16 * 176) & 0xff;
p[20] = (16 * 176) >> 8; // 16x write speed current
p[21] = (16 * 176) & 0xff;
- return p[1] + 2;
+ break;
default:
- return 0;
+ return -1;
}
+
+ *p_outbuf += p[1] + 2;
+ return p[1] + 2;
}
-static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
+static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
{
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint64_t nb_sectors;
- int page, dbd, buflen, page_control;
+ int page, dbd, buflen, ret, page_control;
uint8_t *p;
uint8_t dev_specific_param;
- dbd = req->cmd.buf[1] & 0x8;
- page = req->cmd.buf[2] & 0x3f;
- page_control = (req->cmd.buf[2] & 0xc0) >> 6;
+ dbd = r->req.cmd.buf[1] & 0x8;
+ page = r->req.cmd.buf[2] & 0x3f;
+ page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
- (req->cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, req->cmd.xfer, page_control);
- memset(outbuf, 0, req->cmd.xfer);
+ (r->req.cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, r->req.cmd.xfer, page_control);
+ memset(outbuf, 0, r->req.cmd.xfer);
p = outbuf;
if (bdrv_is_read_only(s->bs)) {
dev_specific_param = 0x00;
}
- if (req->cmd.buf[0] == MODE_SENSE) {
+ if (r->req.cmd.buf[0] == MODE_SENSE) {
p[1] = 0; /* Default media type. */
p[2] = dev_specific_param;
p[3] = 0; /* Block descriptor length. */
bdrv_get_geometry(s->bs, &nb_sectors);
if (!dbd && nb_sectors) {
- if (req->cmd.buf[0] == MODE_SENSE) {
+ if (r->req.cmd.buf[0] == MODE_SENSE) {
outbuf[3] = 8; /* Block descriptor length */
} else { /* MODE_SENSE_10 */
outbuf[7] = 8; /* Block descriptor length */
p += 8;
}
- if (page_control == 3) { /* Saved Values */
- return -1; /* ILLEGAL_REQUEST */
+ if (page_control == 3) {
+ /* Saved Values */
+ scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
+ return -1;
}
- switch (page) {
- case 0x04:
- case 0x05:
- case 0x08:
- case 0x2a:
- p += mode_sense_page(req, page, p, page_control);
- break;
- case 0x3f:
- p += mode_sense_page(req, 0x08, p, page_control);
- p += mode_sense_page(req, 0x2a, p, page_control);
- break;
- default:
- return -1; /* ILLEGAL_REQUEST */
+ if (page == 0x3f) {
+ for (page = 0; page <= 0x3e; page++) {
+ mode_sense_page(s, page, &p, page_control);
+ }
+ } else {
+ ret = mode_sense_page(s, page, &p, page_control);
+ if (ret == -1) {
+ return -1;
+ }
}
buflen = p - outbuf;
* following data that is available to be transferred. The mode data
* length does not include itself.
*/
- if (req->cmd.buf[0] == MODE_SENSE) {
+ if (r->req.cmd.buf[0] == MODE_SENSE) {
outbuf[0] = buflen - 1;
} else { /* MODE_SENSE_10 */
outbuf[0] = ((buflen - 2) >> 8) & 0xff;
outbuf[1] = (buflen - 2) & 0xff;
}
- if (buflen > req->cmd.xfer)
- buflen = req->cmd.xfer;
+ if (buflen > r->req.cmd.xfer)
+ buflen = r->req.cmd.xfer;
return buflen;
}
return toclen;
}
+static void scsi_disk_emulate_start_stop(SCSIDiskReq *r)
+{
+ SCSIRequest *req = &r->req;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+ bool start = req->cmd.buf[4] & 1;
+ bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
+
+ if (s->qdev.type == TYPE_ROM && loej) {
+ bdrv_eject(s->bs, !start);
+ s->tray_open = !start;
+ }
+}
+
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
{
SCSIRequest *req = &r->req;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
uint64_t nb_sectors;
int buflen = 0;
- int ret;
switch (req->cmd.buf[0]) {
case TEST_UNIT_READY:
- if (!bdrv_is_inserted(s->bs))
+ if (s->tray_open || !bdrv_is_inserted(s->bs))
goto not_ready;
break;
- case REQUEST_SENSE:
- if (req->cmd.xfer < 4)
- goto illegal_request;
- buflen = scsi_build_sense(s->sense, outbuf, req->cmd.xfer,
- req->cmd.xfer > 13);
- scsi_disk_clear_sense(s);
- break;
case INQUIRY:
buflen = scsi_disk_emulate_inquiry(req, outbuf);
if (buflen < 0)
break;
case MODE_SENSE:
case MODE_SENSE_10:
- buflen = scsi_disk_emulate_mode_sense(req, outbuf);
+ buflen = scsi_disk_emulate_mode_sense(r, outbuf);
if (buflen < 0)
goto illegal_request;
break;
goto illegal_request;
break;
case START_STOP:
- if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) {
- /* load/eject medium */
- bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));
- }
+ scsi_disk_emulate_start_stop(r);
break;
case ALLOW_MEDIUM_REMOVAL:
bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
outbuf[7] = 0;
buflen = 8;
break;
- case SYNCHRONIZE_CACHE:
- ret = bdrv_flush(s->bs);
- if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
- return -1;
- }
- }
- break;
case GET_CONFIGURATION:
memset(outbuf, 0, 8);
/* ??? This should probably return much more information. For now
outbuf[7] = 8; // CD-ROM
buflen = 8;
break;
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
/* Service Action In subcommands. */
- if ((req->cmd.buf[1] & 31) == 0x10) {
+ if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
DPRINTF("SAI READ CAPACITY(16)\n");
memset(outbuf, 0, req->cmd.xfer);
bdrv_get_geometry(s->bs, &nb_sectors);
}
DPRINTF("Unsupported Service Action In\n");
goto illegal_request;
- case REPORT_LUNS:
- if (req->cmd.xfer < 16)
- goto illegal_request;
- memset(outbuf, 0, 16);
- outbuf[3] = 8;
- buflen = 16;
- break;
case VERIFY_10:
break;
default:
- scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
+ scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
return -1;
}
- scsi_req_set_status(r, GOOD, SENSE_CODE(NO_SENSE));
return buflen;
not_ready:
- if (!bdrv_is_inserted(s->bs)) {
- scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(NO_MEDIUM));
+ if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+ scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
} else {
- scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LUN_NOT_READY));
+ scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
}
return -1;
illegal_request:
- scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
+ if (r->req.status == -1) {
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+ }
return -1;
}
outbuf = (uint8_t *)r->iov.iov_base;
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
- if (scsi_req_parse(&r->req, buf) != 0) {
- BADF("Unsupported command length, command %x\n", command);
- scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
- return 0;
- }
#ifdef DEBUG_SCSI
{
int i;
}
#endif
- if (req->lun) {
- /* Only LUN 0 supported. */
- DPRINTF("Unimplemented LUN %d\n", req->lun);
- if (command != REQUEST_SENSE && command != INQUIRY) {
- scsi_command_complete(r, CHECK_CONDITION,
- SENSE_CODE(LUN_NOT_SUPPORTED));
- return 0;
- }
- }
switch (command) {
case TEST_UNIT_READY:
- case REQUEST_SENSE:
case INQUIRY:
case MODE_SENSE:
case MODE_SENSE_10:
case START_STOP:
case ALLOW_MEDIUM_REMOVAL:
case READ_CAPACITY_10:
- case SYNCHRONIZE_CACHE:
case READ_TOC:
case GET_CONFIGURATION:
- case SERVICE_ACTION_IN:
- case REPORT_LUNS:
+ case SERVICE_ACTION_IN_16:
case VERIFY_10:
rc = scsi_disk_emulate_command(r, outbuf);
if (rc < 0) {
r->iov.iov_len = rc;
break;
+ case SYNCHRONIZE_CACHE:
+ bdrv_acct_start(s->bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+ r->req.aiocb = bdrv_aio_flush(s->bs, scsi_flush_complete, r);
+ if (r->req.aiocb == NULL) {
+ scsi_flush_complete(r, -EIO);
+ }
+ return 0;
case READ_6:
case READ_10:
case READ_12:
}
break;
+ case REQUEST_SENSE:
+ abort();
default:
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
- scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
+ scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
return 0;
fail:
- scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_FIELD));
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
return 0;
illegal_lba:
- scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(LBA_OUT_OF_RANGE));
+ scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
return 0;
}
if (r->sector_count == 0 && r->iov.iov_len == 0) {
- scsi_command_complete(r, GOOD, SENSE_CODE(NO_SENSE));
+ scsi_req_complete(&r->req, GOOD);
}
len = r->sector_count * 512 + r->iov.iov_len;
if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
uint64_t nb_sectors;
- scsi_device_purge_requests(&s->qdev);
+ scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
bdrv_get_geometry(s->bs, &nb_sectors);
nb_sectors /= s->cluster_size;
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
- scsi_device_purge_requests(&s->qdev);
+ scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
blockdev_mark_auto_del(s->qdev.conf.bs);
}
/* try to fall back to value set with legacy -drive serial=... */
dinfo = drive_get_by_blockdev(s->bs);
if (*dinfo->serial) {
- s->serial = qemu_strdup(dinfo->serial);
+ s->serial = g_strdup(dinfo->serial);
}
}
if (!s->version) {
- s->version = qemu_strdup(QEMU_VERSION);
+ s->version = g_strdup(QEMU_VERSION);
}
if (bdrv_is_sg(s->bs)) {
return scsi_initfn(dev, scsi_type);
}
+static SCSIReqOps scsi_disk_reqops = {
+ .size = sizeof(SCSIDiskReq),
+ .free_req = scsi_free_request,
+ .send_command = scsi_send_command,
+ .read_data = scsi_read_data,
+ .write_data = scsi_write_data,
+ .cancel_io = scsi_cancel_io,
+ .get_buf = scsi_get_buf,
+};
+
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
+ uint32_t lun, void *hba_private)
+{
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+ SCSIRequest *req;
+ SCSIDiskReq *r;
+
+ req = scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, hba_private);
+ r = DO_UPCAST(SCSIDiskReq, req, req);
+ r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
+ return req;
+}
+
#define DEFINE_SCSI_DISK_PROPERTIES() \
DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \
DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
.init = scsi_hd_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
- .free_req = scsi_free_request,
- .send_command = scsi_send_command,
- .read_data = scsi_read_data,
- .write_data = scsi_write_data,
- .cancel_io = scsi_cancel_io,
- .get_buf = scsi_get_buf,
- .get_sense = scsi_get_sense,
.qdev.props = (Property[]) {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
.init = scsi_cd_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
- .free_req = scsi_free_request,
- .send_command = scsi_send_command,
- .read_data = scsi_read_data,
- .write_data = scsi_write_data,
- .cancel_io = scsi_cancel_io,
- .get_buf = scsi_get_buf,
- .get_sense = scsi_get_sense,
.qdev.props = (Property[]) {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_END_OF_LIST(),
.init = scsi_disk_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
- .free_req = scsi_free_request,
- .send_command = scsi_send_command,
- .read_data = scsi_read_data,
- .write_data = scsi_write_data,
- .cancel_io = scsi_cancel_io,
- .get_buf = scsi_get_buf,
- .get_sense = scsi_get_sense,
.qdev.props = (Property[]) {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),