diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 686d59d818..ae16a2d6f7 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -156,6 +156,15 @@ uint8_t *scsi_req_get_buf(SCSIRequest *req) return req->dev->info->get_buf(req); } +int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) +{ + if (req->dev->info->get_sense) { + return req->dev->info->get_sense(req, buf, len); + } else { + return 0; + } +} + int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf) { int32_t rc; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index adee8feb91..9567c7c0c8 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -340,6 +340,14 @@ static uint8_t *scsi_get_buf(SCSIRequest *req) 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); @@ -1257,6 +1265,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { .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), @@ -1277,6 +1286,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { .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(), @@ -1296,6 +1306,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { .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), diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 90f2a4af1b..fc015e0755 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -79,6 +79,23 @@ static void scsi_clear_sense(SCSIGenericState *s) s->driver_status = 0; } +static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len) +{ + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev); + int size = SCSI_SENSE_BUF_SIZE; + + if (!(s->driver_status & SG_ERR_DRIVER_SENSE)) { + size = scsi_build_sense(SENSE_CODE(NO_SENSE), s->sensebuf, + SCSI_SENSE_BUF_SIZE, 0); + } + if (size > len) { + size = len; + } + memcpy(outbuf, s->sensebuf, size); + + return size; +} + static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) { SCSIRequest *req; @@ -535,6 +552,7 @@ static SCSIDeviceInfo scsi_generic_info = { .write_data = scsi_write_data, .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, + .get_sense = scsi_get_sense, .qdev.props = (Property[]) { DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/scsi.h b/hw/scsi.h index edf68283c1..5730faa553 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -80,6 +80,7 @@ struct SCSIDeviceInfo { int (*write_data)(SCSIRequest *req); void (*cancel_io)(SCSIRequest *req); uint8_t *(*get_buf)(SCSIRequest *req); + int (*get_sense)(SCSIRequest *req, uint8_t *buf, int len); }; struct SCSIBusOps { @@ -155,6 +156,7 @@ void scsi_req_continue(SCSIRequest *req); void scsi_req_data(SCSIRequest *req, int len); void scsi_req_complete(SCSIRequest *req); uint8_t *scsi_req_get_buf(SCSIRequest *req); +int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len); void scsi_req_abort(SCSIRequest *req, int status); void scsi_req_cancel(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 762a22ec4a..bae670a377 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -450,6 +450,15 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) uint8_t *cdb = req->iu.srp.cmd.cdb; int n; + n = scsi_req_get_sense(req->sreq, req->sense, sizeof(req->sense)); + if (n) { + req->senselen = n; + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + vscsi_put_req(s, req); + return; + } + + dprintf("VSCSI: Got CHECK_CONDITION, requesting sense...\n"); cdb[0] = 3; cdb[1] = 0; cdb[2] = 0; @@ -522,7 +531,6 @@ static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) } vscsi_send_rsp(s, req, 0, res_in, res_out); } else if (arg == CHECK_CONDITION) { - dprintf("VSCSI: Got CHECK_CONDITION, requesting sense...\n"); vscsi_send_request_sense(s, req); return; } else {