hw/block/nvme: support changed namespace asynchronous event
If namespace inventory is changed due to some reasons (e.g., namespace attachment/detachment), controller can send out event notifier to the host to manage namespaces. This patch sends out the AEN to the host after either attach or detach namespaces from controllers. To support clear of the event from the controller, this patch also implemented Get Log Page command for Changed Namespace List log type. To return namespace id list through the command, when namespace inventory is updated, id is added to the per-controller list (changed_ns_list). To indicate the support of this async event, this patch set OAES(Optional Asynchronous Events Supported) in Identify Controller data structure. Signed-off-by: Minwoo Im <minwoo.im.dev@gmail.com> Reviewed-by: Keith Busch <kbusch@kernel.org> Reviewed-by: Klaus Jensen <k.jensen@samsung.com> Tested-by: Klaus Jensen <k.jensen@samsung.com> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
This commit is contained in:
parent
645ce1a70c
commit
f432fdfa12
@ -53,6 +53,7 @@ typedef struct NvmeNamespace {
|
||||
uint8_t csi;
|
||||
|
||||
NvmeSubsystem *subsys;
|
||||
QTAILQ_ENTRY(NvmeNamespace) entry;
|
||||
|
||||
NvmeIdNsZoned *id_ns_zoned;
|
||||
NvmeZone *zone_array;
|
||||
|
@ -3015,6 +3015,48 @@ static uint16_t nvme_error_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
|
||||
return nvme_c2h(n, (uint8_t *)&errlog, trans_len, req);
|
||||
}
|
||||
|
||||
static uint16_t nvme_changed_nslist(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
|
||||
uint64_t off, NvmeRequest *req)
|
||||
{
|
||||
uint32_t nslist[1024];
|
||||
uint32_t trans_len;
|
||||
int i = 0;
|
||||
uint32_t nsid;
|
||||
|
||||
memset(nslist, 0x0, sizeof(nslist));
|
||||
trans_len = MIN(sizeof(nslist) - off, buf_len);
|
||||
|
||||
while ((nsid = find_first_bit(n->changed_nsids, NVME_CHANGED_NSID_SIZE)) !=
|
||||
NVME_CHANGED_NSID_SIZE) {
|
||||
/*
|
||||
* If more than 1024 namespaces, the first entry in the log page should
|
||||
* be set to 0xffffffff and the others to 0 as spec.
|
||||
*/
|
||||
if (i == ARRAY_SIZE(nslist)) {
|
||||
memset(nslist, 0x0, sizeof(nslist));
|
||||
nslist[0] = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
|
||||
nslist[i++] = nsid;
|
||||
clear_bit(nsid, n->changed_nsids);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove all the remaining list entries in case returns directly due to
|
||||
* more than 1024 namespaces.
|
||||
*/
|
||||
if (nslist[0] == 0xffffffff) {
|
||||
bitmap_zero(n->changed_nsids, NVME_CHANGED_NSID_SIZE);
|
||||
}
|
||||
|
||||
if (!rae) {
|
||||
nvme_clear_events(n, NVME_AER_TYPE_NOTICE);
|
||||
}
|
||||
|
||||
return nvme_c2h(n, ((uint8_t *)nslist) + off, trans_len, req);
|
||||
}
|
||||
|
||||
static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
|
||||
uint64_t off, NvmeRequest *req)
|
||||
{
|
||||
@ -3098,6 +3140,8 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req)
|
||||
return nvme_smart_info(n, rae, len, off, req);
|
||||
case NVME_LOG_FW_SLOT_INFO:
|
||||
return nvme_fw_log_info(n, len, off, req);
|
||||
case NVME_LOG_CHANGED_NSLIST:
|
||||
return nvme_changed_nslist(n, rae, len, off, req);
|
||||
case NVME_LOG_CMD_EFFECTS:
|
||||
return nvme_cmd_effects(n, csi, len, off, req);
|
||||
default:
|
||||
@ -3956,6 +4000,16 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
|
||||
|
||||
nvme_ns_detach(ctrl, ns);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add namespace id to the changed namespace id list for event clearing
|
||||
* via Get Log Page command.
|
||||
*/
|
||||
if (!test_and_set_bit(nsid, ctrl->changed_nsids)) {
|
||||
nvme_enqueue_event(ctrl, NVME_AER_TYPE_NOTICE,
|
||||
NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED,
|
||||
NVME_LOG_CHANGED_NSLIST);
|
||||
}
|
||||
}
|
||||
|
||||
return NVME_SUCCESS;
|
||||
@ -4954,6 +5008,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
|
||||
|
||||
id->cntlid = cpu_to_le16(n->cntlid);
|
||||
|
||||
id->oaes = cpu_to_le32(NVME_OAES_NS_ATTR);
|
||||
|
||||
id->rab = 6;
|
||||
|
||||
if (n->params.use_intel_id) {
|
||||
|
@ -192,6 +192,10 @@ typedef struct NvmeCtrl {
|
||||
|
||||
uint32_t dmrsl;
|
||||
|
||||
/* Namespace ID is started with 1 so bitmap should be 1-based */
|
||||
#define NVME_CHANGED_NSID_SIZE (NVME_MAX_NAMESPACES + 1)
|
||||
DECLARE_BITMAP(changed_nsids, NVME_CHANGED_NSID_SIZE);
|
||||
|
||||
NvmeSubsystem *subsys;
|
||||
|
||||
NvmeNamespace namespace;
|
||||
|
@ -760,6 +760,7 @@ typedef struct QEMU_PACKED NvmeCopySourceRange {
|
||||
enum NvmeAsyncEventRequest {
|
||||
NVME_AER_TYPE_ERROR = 0,
|
||||
NVME_AER_TYPE_SMART = 1,
|
||||
NVME_AER_TYPE_NOTICE = 2,
|
||||
NVME_AER_TYPE_IO_SPECIFIC = 6,
|
||||
NVME_AER_TYPE_VENDOR_SPECIFIC = 7,
|
||||
NVME_AER_INFO_ERR_INVALID_DB_REGISTER = 0,
|
||||
@ -771,6 +772,7 @@ enum NvmeAsyncEventRequest {
|
||||
NVME_AER_INFO_SMART_RELIABILITY = 0,
|
||||
NVME_AER_INFO_SMART_TEMP_THRESH = 1,
|
||||
NVME_AER_INFO_SMART_SPARE_THRESH = 2,
|
||||
NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED = 0,
|
||||
};
|
||||
|
||||
typedef struct QEMU_PACKED NvmeAerResult {
|
||||
@ -940,6 +942,7 @@ enum NvmeLogIdentifier {
|
||||
NVME_LOG_ERROR_INFO = 0x01,
|
||||
NVME_LOG_SMART_INFO = 0x02,
|
||||
NVME_LOG_FW_SLOT_INFO = 0x03,
|
||||
NVME_LOG_CHANGED_NSLIST = 0x04,
|
||||
NVME_LOG_CMD_EFFECTS = 0x05,
|
||||
};
|
||||
|
||||
@ -1056,6 +1059,10 @@ typedef struct NvmeIdCtrlNvm {
|
||||
uint8_t rsvd16[4080];
|
||||
} NvmeIdCtrlNvm;
|
||||
|
||||
enum NvmeIdCtrlOaes {
|
||||
NVME_OAES_NS_ATTR = 1 << 8,
|
||||
};
|
||||
|
||||
enum NvmeIdCtrlOacs {
|
||||
NVME_OACS_SECURITY = 1 << 0,
|
||||
NVME_OACS_FORMAT = 1 << 1,
|
||||
|
Loading…
Reference in New Issue
Block a user