hw/block/nvme: trigger async event during injecting smart warning

During smart critical warning injection by setting property from QMP
command, also try to trigger asynchronous event.

Suggested by Keith, if a event has already been raised, there is no
need to enqueue the duplicate event any more.

Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
[k.jensen: fix typo in commit message]
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
This commit is contained in:
zhenwei pi 2021-01-15 11:27:02 +08:00 committed by Klaus Jensen
parent 4714791b66
commit c62720f137
2 changed files with 42 additions and 7 deletions

View File

@ -980,6 +980,35 @@ static void nvme_enqueue_event(NvmeCtrl *n, uint8_t event_type,
nvme_process_aers(n); nvme_process_aers(n);
} }
static void nvme_smart_event(NvmeCtrl *n, uint8_t event)
{
uint8_t aer_info;
/* Ref SPEC <Asynchronous Event Information 0x2013 SMART / Health Status> */
if (!(NVME_AEC_SMART(n->features.async_config) & event)) {
return;
}
switch (event) {
case NVME_SMART_SPARE:
aer_info = NVME_AER_INFO_SMART_SPARE_THRESH;
break;
case NVME_SMART_TEMPERATURE:
aer_info = NVME_AER_INFO_SMART_TEMP_THRESH;
break;
case NVME_SMART_RELIABILITY:
case NVME_SMART_MEDIA_READ_ONLY:
case NVME_SMART_FAILED_VOLATILE_MEDIA:
case NVME_SMART_PMR_UNRELIABLE:
aer_info = NVME_AER_INFO_SMART_RELIABILITY;
break;
default:
return;
}
nvme_enqueue_event(n, NVME_AER_TYPE_SMART, aer_info, NVME_LOG_SMART_INFO);
}
static void nvme_clear_events(NvmeCtrl *n, uint8_t event_type) static void nvme_clear_events(NvmeCtrl *n, uint8_t event_type)
{ {
n->aer_mask &= ~(1 << event_type); n->aer_mask &= ~(1 << event_type);
@ -3317,12 +3346,9 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
return NVME_INVALID_FIELD | NVME_DNR; return NVME_INVALID_FIELD | NVME_DNR;
} }
if (((n->temperature >= n->features.temp_thresh_hi) || if ((n->temperature >= n->features.temp_thresh_hi) ||
(n->temperature <= n->features.temp_thresh_low)) && (n->temperature <= n->features.temp_thresh_low)) {
NVME_AEC_SMART(n->features.async_config) & NVME_SMART_TEMPERATURE) { nvme_smart_event(n, NVME_AER_INFO_SMART_TEMP_THRESH);
nvme_enqueue_event(n, NVME_AER_TYPE_SMART,
NVME_AER_INFO_SMART_TEMP_THRESH,
NVME_LOG_SMART_INFO);
} }
break; break;
@ -4446,7 +4472,7 @@ static void nvme_set_smart_warning(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp) void *opaque, Error **errp)
{ {
NvmeCtrl *n = NVME(obj); NvmeCtrl *n = NVME(obj);
uint8_t value, cap = 0; uint8_t value, old_value, cap = 0, index, event;
if (!visit_type_uint8(v, name, &value, errp)) { if (!visit_type_uint8(v, name, &value, errp)) {
return; return;
@ -4464,7 +4490,15 @@ static void nvme_set_smart_warning(Object *obj, Visitor *v, const char *name,
return; return;
} }
old_value = n->smart_critical_warning;
n->smart_critical_warning = value; n->smart_critical_warning = value;
/* only inject new bits of smart critical warning */
for (index = 0; index < NVME_SMART_WARN_MAX; index++) {
event = 1 << index;
if (value & ~old_value & event)
nvme_smart_event(n, event);
}
} }
static const VMStateDescription nvme_vmstate = { static const VMStateDescription nvme_vmstate = {

View File

@ -784,6 +784,7 @@ typedef struct QEMU_PACKED NvmeSmartLog {
uint8_t reserved2[320]; uint8_t reserved2[320];
} NvmeSmartLog; } NvmeSmartLog;
#define NVME_SMART_WARN_MAX 6
enum NvmeSmartWarn { enum NvmeSmartWarn {
NVME_SMART_SPARE = 1 << 0, NVME_SMART_SPARE = 1 << 0,
NVME_SMART_TEMPERATURE = 1 << 1, NVME_SMART_TEMPERATURE = 1 << 1,