From 0c0e3a894b68fd380552879c5c60c16889415ba7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Feb 2012 14:11:33 +0100 Subject: [PATCH 017/109] scsi: add support for unit attention conditions RH-Author: Paolo Bonzini Message-id: <1329919979-20948-17-git-send-email-pbonzini@redhat.com> Patchwork-id: 37492 O-Subject: [RHEL 6.3 qemu-kvm PATCH v2 016/102] scsi: add support for unit attention conditions Bugzilla: 782029 RH-Acked-by: Gerd Hoffmann RH-Acked-by: Laszlo Ersek RH-Acked-by: Orit Wasserman Unit attention conditions override any sense data the device already has. Their signaling and clearing is handled entirely by the SCSIBus code, and they are completely transparent to the SCSIDevices. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori (cherry picked from 6dc06f08b3d6c0347df00ac68d9f30e2b233a749) --- hw/scsi-bus.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/scsi-defs.h | 1 + hw/scsi.h | 2 + 3 files changed, 94 insertions(+), 2 deletions(-) Signed-off-by: Michal Novotny --- hw/scsi-bus.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- hw/scsi-defs.h | 1 + hw/scsi.h | 2 + 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 257e0a3..56d5046 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -149,6 +149,24 @@ struct SCSIReqOps reqops_invalid_opcode = { .send_command = scsi_invalid_command }; +/* SCSIReqOps implementation for unit attention conditions. */ + +static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf) +{ + if (req->dev && req->dev->unit_attention.key == UNIT_ATTENTION) { + scsi_req_build_sense(req, req->dev->unit_attention); + } else if (req->bus->unit_attention.key == UNIT_ATTENTION) { + scsi_req_build_sense(req, req->bus->unit_attention); + } + scsi_req_complete(req, CHECK_CONDITION); + return 0; +} + +struct SCSIReqOps reqops_unit_attention = { + .size = sizeof(SCSIRequest), + .send_command = scsi_unit_attention +}; + /* SCSIReqOps implementation for REPORT LUNS and for commands sent to an invalid LUN. */ @@ -345,6 +363,7 @@ SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag, SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, void *hba_private) { + SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); SCSIRequest *req; SCSICommand cmd; @@ -359,7 +378,15 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, cmd.lba); } - if (lun != d->lun || + if ((d->unit_attention.key == UNIT_ATTENTION || + bus->unit_attention.key == UNIT_ATTENTION) && + (buf[0] != INQUIRY && + buf[0] != REPORT_LUNS && + buf[0] != GET_CONFIGURATION && + buf[0] != GET_EVENT_STATUS_NOTIFICATION)) { + req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun, + hba_private); + } else if (lun != d->lun || buf[0] == REPORT_LUNS || buf[0] == REQUEST_SENSE) { req = scsi_req_alloc(&reqops_target_command, d, tag, lun, @@ -378,13 +405,68 @@ uint8_t *scsi_req_get_buf(SCSIRequest *req) return req->ops->get_buf(req); } +static void scsi_clear_unit_attention(SCSIRequest *req) +{ + SCSISense *ua; + if (req->dev->unit_attention.key != UNIT_ATTENTION && + req->bus->unit_attention.key != UNIT_ATTENTION) { + return; + } + + /* + * If an INQUIRY command enters the enabled command state, + * the device server shall [not] clear any unit attention condition; + * See also MMC-6, paragraphs 6.5 and 6.6.2. + */ + if (req->cmd.buf[0] == INQUIRY || + req->cmd.buf[0] == GET_CONFIGURATION || + req->cmd.buf[0] == GET_EVENT_STATUS_NOTIFICATION) { + return; + } + + if (req->dev->unit_attention.key == UNIT_ATTENTION) { + ua = &req->dev->unit_attention; + } else { + ua = &req->bus->unit_attention; + } + + /* + * If a REPORT LUNS command enters the enabled command state, [...] + * the device server shall clear any pending unit attention condition + * with an additional sense code of REPORTED LUNS DATA HAS CHANGED. + */ + if (req->cmd.buf[0] == REPORT_LUNS && + !(ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED).asc && + ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED).ascq)) { + return; + } + + *ua = SENSE_CODE(NO_SENSE); +} + int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) { + int ret; + assert(len >= 14); if (!req->sense_len) { return 0; } - return scsi_build_sense(req->sense, req->sense_len, buf, len, true); + + ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true); + + /* + * FIXME: clearing unit attention conditions upon autosense should be done + * only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b + * (SAM-5, 5.14). + * + * We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and + * 10b for HBAs that do not support it (do not call scsi_req_get_sense). + * In the latter case, scsi_req_complete clears unit attention conditions + * after moving them to the device's sense buffer. + */ + scsi_clear_unit_attention(req); + return ret; } int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed) @@ -995,6 +1077,13 @@ void scsi_req_complete(SCSIRequest *req, int status) } req->dev->sense_len = req->sense_len; + /* + * Unit attention state is now stored in the device's sense buffer + * if the HBA didn't do autosense. Clear the pending unit attention + * flags. + */ + scsi_clear_unit_attention(req); + scsi_req_ref(req); scsi_req_dequeue(req); req->bus->ops->complete(req, req->status); diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index 977c38b..ea288fa 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -78,6 +78,7 @@ #define READ_TOC 0x43 #define REPORT_DENSITY_SUPPORT 0x44 #define GET_CONFIGURATION 0x46 +#define GET_EVENT_STATUS_NOTIFICATION 0x4a #define LOG_SELECT 0x4c #define LOG_SENSE 0x4d #define MODE_SELECT_10 0x55 diff --git a/hw/scsi.h b/hw/scsi.h index e38c171..532fd1e 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -62,6 +62,7 @@ struct SCSIDevice uint32_t id; BlockConf conf; SCSIDeviceInfo *info; + SCSISense unit_attention; uint8_t sense[SCSI_SENSE_BUF_SIZE]; uint32_t sense_len; QTAILQ_HEAD(, SCSIRequest) requests; @@ -105,6 +106,7 @@ struct SCSIBus { BusState qbus; int busnr; + SCSISense unit_attention; int tcq, ndev; const SCSIBusOps *ops; -- 1.7.7.6