Section 5.6.6.3 of VirtIO specification states, "Events will also be reported via sense codes..." However, no sense data is sent when VIRTIO_SCSI_EVT_RESET_RESCAN or VIRTIO_SCSI_EVT_RESET_REMOVED events are reported (when disk hotplug/hotunplug events occur). SCSI layer on Solaris depends on this sense data, and hence does not handle disk hotplug/hotunplug events.
When disk inventory changes, return a CHECK_CONDITION status with sense data of 0x06/0x3F/0x0E (sense code REPORTED_LUNS_CHANGED), as per the specifications in Section 5.14 (h) of SAM-4. Signed-off-by: Venu Busireddy <venu.busire...@oracle.com> v2 -> v3: - Implement the suggestion from Paolo Bonzini <pbonz...@redhat.com>. v1 -> v2: - Send the sense data for VIRTIO_SCSI_EVT_RESET_REMOVED event too. --- hw/scsi/scsi-bus.c | 1 + hw/scsi/virtio-scsi.c | 16 ++++++++++++++++ include/hw/scsi/scsi.h | 6 ++++++ include/hw/virtio/virtio-scsi.h | 1 + 4 files changed, 24 insertions(+) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 4403717c4aaf..b7cb249f2eab 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -730,6 +730,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, */ !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) { ops = &reqops_unit_attention; + d->clear_reported_luns_changed = true; } else if (lun != d->lun || buf[0] == REPORT_LUNS || (buf[0] == REQUEST_SENSE && d->sense_len)) { diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 41f2a5630173..b7f66d366fcb 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -695,9 +695,23 @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) return -ENOENT; } virtio_scsi_ctx_check(s, d); + + if (s->reported_luns_changed) { + scsi_device_set_ua(d, SENSE_CODE(REPORTED_LUNS_CHANGED)); + } + + /* + * set d->clear_reported_luns_changed. + * scsi_req_new() will clear it if the required conditions are met. + */ + d->clear_reported_luns_changed = false; req->sreq = scsi_req_new(d, req->req.cmd.tag, virtio_scsi_get_lun(req->req.cmd.lun), req->req.cmd.cdb, vs->cdb_size, req); + if (d->clear_reported_luns_changed) { + s->reported_luns_changed = false; + d->clear_reported_luns_changed = false; + } if (req->sreq->cmd.mode != SCSI_XFER_NONE && (req->sreq->cmd.mode != req->mode || @@ -956,6 +970,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_RESCAN); + s->reported_luns_changed = true; virtio_scsi_release(s); } } @@ -973,6 +988,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_REMOVED); + s->reported_luns_changed = true; virtio_scsi_release(s); } diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 001103488c23..ea81c6f89e74 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -89,6 +89,12 @@ struct SCSIDevice uint32_t io_timeout; bool needs_vpd_bl_emulation; bool hba_supports_iothread; + /* + * clear_reported_luns_changed is used, if the required + * conditions are met, to inform the virtio-scsi layer that + * any pending REPORTED_LUNS_CHANGED condition can be cleared. + */ + bool clear_reported_luns_changed; }; extern const VMStateDescription vmstate_scsi_device; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index a36aad9c8695..efbcf9ba069a 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -81,6 +81,7 @@ struct VirtIOSCSI { SCSIBus bus; int resetting; bool events_dropped; + bool reported_luns_changed; /* Fields for dataplane below */ AioContext *ctx; /* one iothread per virtio-scsi-pci for now */