diff options
Diffstat (limited to 'hw/scsi')
-rw-r--r-- | hw/scsi/scsi-bus.c | 16 | ||||
-rw-r--r-- | hw/scsi/scsi-disk.c | 52 | ||||
-rw-r--r-- | hw/scsi/scsi-generic.c | 2 | ||||
-rw-r--r-- | hw/scsi/vhost-scsi.c | 45 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 63 |
5 files changed, 114 insertions, 64 deletions
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 3e5e31da8f..50b89ad4aa 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -469,6 +469,8 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) r->req.dev->sense_is_ua = false; } break; + case TEST_UNIT_READY: + break; default: scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED)); scsi_req_complete(req, CHECK_CONDITION); @@ -886,7 +888,6 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case RELEASE: case ERASE: case ALLOW_MEDIUM_REMOVAL: - case VERIFY_10: case SEEK_10: case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: @@ -903,6 +904,16 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case ALLOW_OVERWRITE: cmd->xfer = 0; break; + case VERIFY_10: + case VERIFY_12: + case VERIFY_16: + if ((buf[1] & 2) == 0) { + cmd->xfer = 0; + } else if ((buf[1] & 4) == 1) { + cmd->xfer = 1; + } + cmd->xfer *= dev->blocksize; + break; case MODE_SENSE: break; case WRITE_SAME_10: @@ -1100,6 +1111,9 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) case WRITE_VERIFY_12: case WRITE_16: case WRITE_VERIFY_16: + case VERIFY_10: + case VERIFY_12: + case VERIFY_16: case COPY: case COPY_VERIFY: case COMPARE: diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index efadfc023f..a8d0f15ebe 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -47,6 +47,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define SCSI_MAX_MODE_LEN 256 #define DEFAULT_DISCARD_GRANULARITY 4096 +#define DEFAULT_MAX_UNMAP_SIZE (1 << 30) /* 1 GB */ typedef struct SCSIDiskState SCSIDiskState; @@ -74,6 +75,7 @@ struct SCSIDiskState bool media_event; bool eject_request; uint64_t wwn; + uint64_t max_unmap_size; QEMUBH *bh; char *version; char *serial; @@ -625,6 +627,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) s->qdev.conf.min_io_size / s->qdev.blocksize; unsigned int opt_io_size = s->qdev.conf.opt_io_size / s->qdev.blocksize; + unsigned int max_unmap_sectors = + s->max_unmap_size / s->qdev.blocksize; if (s->qdev.type == TYPE_ROM) { DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n", @@ -647,6 +651,18 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) outbuf[14] = (opt_io_size >> 8) & 0xff; outbuf[15] = opt_io_size & 0xff; + /* max unmap LBA count, default is 1GB */ + outbuf[20] = (max_unmap_sectors >> 24) & 0xff; + outbuf[21] = (max_unmap_sectors >> 16) & 0xff; + outbuf[22] = (max_unmap_sectors >> 8) & 0xff; + outbuf[23] = max_unmap_sectors & 0xff; + + /* max unmap descriptors, 255 fit in 4 kb with an 8-byte header. */ + outbuf[24] = 0; + outbuf[25] = 0; + outbuf[26] = 0; + outbuf[27] = 255; + /* optimal unmap granularity */ outbuf[28] = (unmap_sectors >> 24) & 0xff; outbuf[29] = (unmap_sectors >> 16) & 0xff; @@ -1626,7 +1642,7 @@ static void scsi_write_same_complete(void *opaque, int ret) bdrv_acct_start(s->qdev.conf.bs, &r->acct, data->iov.iov_len, BDRV_ACCT_WRITE); r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, data->sector, &data->qiov, data->iov.iov_len / 512, - scsi_write_same_complete, r); + scsi_write_same_complete, data); return; } @@ -1720,10 +1736,19 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req) scsi_disk_emulate_unmap(r, r->iov.iov_base); break; + case VERIFY_10: + case VERIFY_12: + case VERIFY_16: + if (r->req.status == -1) { + scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); + } + break; + case WRITE_SAME_10: case WRITE_SAME_16: scsi_disk_emulate_write_same(r, r->iov.iov_base); break; + default: abort(); } @@ -1964,6 +1989,14 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) case UNMAP: DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer); break; + case VERIFY_10: + case VERIFY_12: + case VERIFY_16: + DPRINTF("Verify (bytchk %lu)\n", (r->req.buf[1] >> 1) & 3); + if (req->cmd.buf[1] & 6) { + goto illegal_request; + } + break; case WRITE_SAME_10: case WRITE_SAME_16: DPRINTF("WRITE SAME %d (len %lu)\n", @@ -2044,10 +2077,6 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); return 0; } - /* fallthrough */ - case VERIFY_10: - case VERIFY_12: - case VERIFY_16: DPRINTF("Write %s(sector %" PRId64 ", count %u)\n", (command & 0xe) == 0xe ? "And Verify " : "", r->req.cmd.lba, len); @@ -2225,7 +2254,7 @@ static int scsi_initfn(SCSIDevice *dev) } else { bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_block_ops, s); } - bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize); + bdrv_set_guest_block_size(s->qdev.conf.bs, s->qdev.blocksize); bdrv_iostatus_enable(s->qdev.conf.bs); add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, NULL); @@ -2277,6 +2306,7 @@ static const SCSIReqOps scsi_disk_emulate_reqops = { .send_command = scsi_disk_emulate_command, .read_data = scsi_disk_emulate_read_data, .write_data = scsi_disk_emulate_write_data, + .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, }; @@ -2315,14 +2345,14 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = { [UNMAP] = &scsi_disk_emulate_reqops, [WRITE_SAME_10] = &scsi_disk_emulate_reqops, [WRITE_SAME_16] = &scsi_disk_emulate_reqops, + [VERIFY_10] = &scsi_disk_emulate_reqops, + [VERIFY_12] = &scsi_disk_emulate_reqops, + [VERIFY_16] = &scsi_disk_emulate_reqops, [READ_6] = &scsi_disk_dma_reqops, [READ_10] = &scsi_disk_dma_reqops, [READ_12] = &scsi_disk_dma_reqops, [READ_16] = &scsi_disk_dma_reqops, - [VERIFY_10] = &scsi_disk_dma_reqops, - [VERIFY_12] = &scsi_disk_dma_reqops, - [VERIFY_16] = &scsi_disk_dma_reqops, [WRITE_6] = &scsi_disk_dma_reqops, [WRITE_10] = &scsi_disk_dma_reqops, [WRITE_12] = &scsi_disk_dma_reqops, @@ -2506,6 +2536,8 @@ static Property scsi_hd_properties[] = { DEFINE_PROP_BIT("dpofua", SCSIDiskState, features, SCSI_DISK_F_DPOFUA, false), DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0), + DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size, + DEFAULT_MAX_UNMAP_SIZE), DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf), DEFINE_PROP_END_OF_LIST(), }; @@ -2615,6 +2647,8 @@ static Property scsi_disk_properties[] = { DEFINE_PROP_BIT("dpofua", SCSIDiskState, features, SCSI_DISK_F_DPOFUA, false), DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0), + DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size, + DEFAULT_MAX_UNMAP_SIZE), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 8f195bec00..f08b64e177 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -210,7 +210,7 @@ static void scsi_read_complete(void * opaque, int ret) s->blocksize = ldl_be_p(&r->buf[8]); s->max_lba = ldq_be_p(&r->buf[0]); } - bdrv_set_buffer_alignment(s->conf.bs, s->blocksize); + bdrv_set_guest_block_size(s->conf.bs, s->blocksize); scsi_req_data(&r->req, len); if (!r->req.io_canceled) { diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 9e770fba98..3983a5b464 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -196,29 +196,31 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) } } -static int vhost_scsi_init(VirtIODevice *vdev) +static void vhost_scsi_realize(DeviceState *dev, Error **errp) { - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - VHostSCSI *s = VHOST_SCSI(vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + VHostSCSI *s = VHOST_SCSI(dev); + Error *err = NULL; int vhostfd = -1; int ret; if (!vs->conf.wwpn) { - error_report("vhost-scsi: missing wwpn\n"); - return -EINVAL; + error_setg(errp, "vhost-scsi: missing wwpn"); + return; } if (vs->conf.vhostfd) { vhostfd = monitor_handle_fd_param(cur_mon, vs->conf.vhostfd); if (vhostfd == -1) { - error_report("vhost-scsi: unable to parse vhostfd\n"); - return -EINVAL; + error_setg(errp, "vhost-scsi: unable to parse vhostfd"); + return; } } - ret = virtio_scsi_common_init(vs); - if (ret < 0) { - return ret; + virtio_scsi_common_realize(dev, &err); + if (err != NULL) { + error_propagate(errp, err); + return; } s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; @@ -227,24 +229,21 @@ static int vhost_scsi_init(VirtIODevice *vdev) ret = vhost_dev_init(&s->dev, vhostfd, "/dev/vhost-scsi", true); if (ret < 0) { - error_report("vhost-scsi: vhost initialization failed: %s\n", - strerror(-ret)); - return ret; + error_setg(errp, "vhost-scsi: vhost initialization failed: %s", + strerror(-ret)); + return; } s->dev.backend_features = 0; error_setg(&s->migration_blocker, "vhost-scsi does not support migration"); migrate_add_blocker(s->migration_blocker); - - return 0; } -static int vhost_scsi_exit(DeviceState *qdev) +static void vhost_scsi_unrealize(DeviceState *dev, Error **errp) { - VirtIODevice *vdev = VIRTIO_DEVICE(qdev); - VHostSCSI *s = VHOST_SCSI(qdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostSCSI *s = VHOST_SCSI(dev); migrate_del_blocker(s->migration_blocker); error_free(s->migration_blocker); @@ -253,7 +252,8 @@ static int vhost_scsi_exit(DeviceState *qdev) vhost_scsi_set_status(vdev, 0); g_free(s->dev.vqs); - return virtio_scsi_common_exit(vs); + + virtio_scsi_common_unrealize(dev, errp); } static Property vhost_scsi_properties[] = { @@ -265,10 +265,11 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - dc->exit = vhost_scsi_exit; + dc->props = vhost_scsi_properties; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - vdc->init = vhost_scsi_init; + vdc->realize = vhost_scsi_realize; + vdc->unrealize = vhost_scsi_unrealize; vdc->get_features = vhost_scsi_get_features; vdc->set_config = vhost_scsi_set_config; vdc->set_status = vhost_scsi_set_status; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 26d95a14ec..6610b3aab3 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -306,6 +306,10 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, VirtIOSCSIReq *req = r->hba_private; uint32_t sense_len; + if (r->io_canceled) { + return; + } + req->resp.cmd->response = VIRTIO_SCSI_S_OK; req->resp.cmd->status = status; if (req->resp.cmd->status == GOOD) { @@ -516,7 +520,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, evt->event = event; evt->reason = reason; if (!dev) { - assert(event == VIRTIO_SCSI_T_NO_EVENT); + assert(event == VIRTIO_SCSI_T_EVENTS_MISSED); } else { evt->lun[0] = 1; evt->lun[1] = dev->id; @@ -589,12 +593,13 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = { .load_request = virtio_scsi_load_request, }; -int virtio_scsi_common_init(VirtIOSCSICommon *s) +void virtio_scsi_common_realize(DeviceState *dev, Error **errp) { - VirtIODevice *vdev = VIRTIO_DEVICE(s); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev); int i; - virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI, + virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI, sizeof(VirtIOSCSIConfig)); s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *)); @@ -609,57 +614,52 @@ int virtio_scsi_common_init(VirtIOSCSICommon *s) s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, virtio_scsi_handle_cmd); } - - return 0; } -static int virtio_scsi_device_init(VirtIODevice *vdev) +static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) { - DeviceState *qdev = DEVICE(vdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - VirtIOSCSI *s = VIRTIO_SCSI(vdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSCSI *s = VIRTIO_SCSI(dev); static int virtio_scsi_id; Error *err = NULL; - int ret; - ret = virtio_scsi_common_init(vs); - if (ret < 0) { - return ret; + virtio_scsi_common_realize(dev, &err); + if (err != NULL) { + error_propagate(errp, err); + return; } - scsi_bus_new(&s->bus, sizeof(s->bus), qdev, + scsi_bus_new(&s->bus, sizeof(s->bus), dev, &virtio_scsi_scsi_info, vdev->bus_name); - if (!qdev->hotplugged) { + if (!dev->hotplugged) { scsi_bus_legacy_handle_cmdline(&s->bus, &err); if (err != NULL) { - error_free(err); - return -1; + error_propagate(errp, err); + return; } } - register_savevm(qdev, "virtio-scsi", virtio_scsi_id++, 1, + register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, virtio_scsi_save, virtio_scsi_load, s); - - return 0; } -int virtio_scsi_common_exit(VirtIOSCSICommon *vs) +void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp) { - VirtIODevice *vdev = VIRTIO_DEVICE(vs); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); g_free(vs->cmd_vqs); virtio_cleanup(vdev); - return 0; } -static int virtio_scsi_device_exit(DeviceState *qdev) +static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) { - VirtIOSCSI *s = VIRTIO_SCSI(qdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev); + VirtIOSCSI *s = VIRTIO_SCSI(dev); - unregister_savevm(qdev, "virtio-scsi", s); - return virtio_scsi_common_exit(vs); + unregister_savevm(dev, "virtio-scsi", s); + + virtio_scsi_common_unrealize(dev, errp); } static Property virtio_scsi_properties[] = { @@ -680,10 +680,11 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - dc->exit = virtio_scsi_device_exit; + dc->props = virtio_scsi_properties; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - vdc->init = virtio_scsi_device_init; + vdc->realize = virtio_scsi_device_realize; + vdc->unrealize = virtio_scsi_device_unrealize; vdc->set_config = virtio_scsi_set_config; vdc->get_features = virtio_scsi_get_features; vdc->reset = virtio_scsi_reset; |