scsi: notify the device when unit attention is reported
Reporting media change events via unit attention sense codes requires a small state machine: first report "NO MEDIUM", then report "MEDIUM MAY HAVE CHANGED". Unfortunately there is no good hooking point for the device to notice that its pending unit attention condition has been reported. This patch reworks the generic machinery to add one. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
af0e1ea2d3
commit
3653d8c40e
@ -295,6 +295,13 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
|
|||||||
r->len = scsi_device_get_sense(r->req.dev, r->buf,
|
r->len = scsi_device_get_sense(r->req.dev, r->buf,
|
||||||
MIN(req->cmd.xfer, sizeof r->buf),
|
MIN(req->cmd.xfer, sizeof r->buf),
|
||||||
(req->cmd.buf[1] & 1) == 0);
|
(req->cmd.buf[1] & 1) == 0);
|
||||||
|
if (r->req.dev->sense_is_ua) {
|
||||||
|
if (r->req.dev->info->unit_attention_reported) {
|
||||||
|
r->req.dev->info->unit_attention_reported(req->dev);
|
||||||
|
}
|
||||||
|
r->req.dev->sense_len = 0;
|
||||||
|
r->req.dev->sense_is_ua = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
|
scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
|
||||||
@ -383,7 +390,13 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
|||||||
(buf[0] != INQUIRY &&
|
(buf[0] != INQUIRY &&
|
||||||
buf[0] != REPORT_LUNS &&
|
buf[0] != REPORT_LUNS &&
|
||||||
buf[0] != GET_CONFIGURATION &&
|
buf[0] != GET_CONFIGURATION &&
|
||||||
buf[0] != GET_EVENT_STATUS_NOTIFICATION)) {
|
buf[0] != GET_EVENT_STATUS_NOTIFICATION &&
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we already have a pending unit attention condition,
|
||||||
|
* report this one before triggering another one.
|
||||||
|
*/
|
||||||
|
!(buf[0] == REQUEST_SENSE && d->sense_is_ua))) {
|
||||||
req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun,
|
req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun,
|
||||||
hba_private);
|
hba_private);
|
||||||
} else if (lun != d->lun ||
|
} else if (lun != d->lun ||
|
||||||
@ -479,10 +492,15 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
|
|||||||
*
|
*
|
||||||
* We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
|
* 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).
|
* 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
|
* Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
|
||||||
* after moving them to the device's sense buffer.
|
|
||||||
*/
|
*/
|
||||||
scsi_clear_unit_attention(req);
|
if (req->dev->sense_is_ua) {
|
||||||
|
if (req->dev->info->unit_attention_reported) {
|
||||||
|
req->dev->info->unit_attention_reported(req->dev);
|
||||||
|
}
|
||||||
|
req->dev->sense_len = 0;
|
||||||
|
req->dev->sense_is_ua = false;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1082,8 +1100,12 @@ void scsi_req_complete(SCSIRequest *req, int status)
|
|||||||
|
|
||||||
if (req->sense_len) {
|
if (req->sense_len) {
|
||||||
memcpy(req->dev->sense, req->sense, req->sense_len);
|
memcpy(req->dev->sense, req->sense, req->sense_len);
|
||||||
|
req->dev->sense_len = req->sense_len;
|
||||||
|
req->dev->sense_is_ua = (req->ops == &reqops_unit_attention);
|
||||||
|
} else {
|
||||||
|
req->dev->sense_len = 0;
|
||||||
|
req->dev->sense_is_ua = false;
|
||||||
}
|
}
|
||||||
req->dev->sense_len = req->sense_len;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unit attention state is now stored in the device's sense buffer
|
* Unit attention state is now stored in the device's sense buffer
|
||||||
|
@ -62,6 +62,7 @@ struct SCSIDevice
|
|||||||
BlockConf conf;
|
BlockConf conf;
|
||||||
SCSIDeviceInfo *info;
|
SCSIDeviceInfo *info;
|
||||||
SCSISense unit_attention;
|
SCSISense unit_attention;
|
||||||
|
bool sense_is_ua;
|
||||||
uint8_t sense[SCSI_SENSE_BUF_SIZE];
|
uint8_t sense[SCSI_SENSE_BUF_SIZE];
|
||||||
uint32_t sense_len;
|
uint32_t sense_len;
|
||||||
QTAILQ_HEAD(, SCSIRequest) requests;
|
QTAILQ_HEAD(, SCSIRequest) requests;
|
||||||
@ -92,6 +93,7 @@ struct SCSIDeviceInfo {
|
|||||||
void (*destroy)(SCSIDevice *s);
|
void (*destroy)(SCSIDevice *s);
|
||||||
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
|
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
|
||||||
void *hba_private);
|
void *hba_private);
|
||||||
|
void (*unit_attention_reported)(SCSIDevice *s);
|
||||||
SCSIReqOps reqops;
|
SCSIReqOps reqops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user