summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2018-01-03 15:17:18 +0200
committerRichard Lowe <richlowe@richlowe.net>2018-02-14 19:02:41 +0000
commit081391626072035c77f552902b50d1f7c1359700 (patch)
tree04c587f729b795da619125a482f4dc093252f4b7 /usr/src
parent351128add6ee764cb0082bcf82bde86a83696801 (diff)
downloadillumos-joyent-081391626072035c77f552902b50d1f7c1359700.tar.gz
8945 nvme panics when async events are not supported
Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Reviewed by: Yuri Pankov <yuripv@yuripv.net> Reviewed by: Michal Nowak <mnowak@startmail.com> Approved by: Richard Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/nvme/nvme.c35
-rw-r--r--usr/src/uts/common/io/nvme/nvme_var.h1
2 files changed, 30 insertions, 6 deletions
diff --git a/usr/src/uts/common/io/nvme/nvme.c b/usr/src/uts/common/io/nvme/nvme.c
index 42a320dff0..2046d38a07 100644
--- a/usr/src/uts/common/io/nvme/nvme.c
+++ b/usr/src/uts/common/io/nvme/nvme.c
@@ -1060,9 +1060,11 @@ nvme_check_generic_cmd_status(nvme_cmd_t *cmd)
*/
case NVME_CQE_SC_GEN_INV_OPC:
/* Invalid Command Opcode */
- dev_err(cmd->nc_nvme->n_dip, CE_PANIC, "programming error: "
- "invalid opcode in cmd %p", (void *)cmd);
- return (0);
+ if (!cmd->nc_dontpanic)
+ dev_err(cmd->nc_nvme->n_dip, CE_PANIC,
+ "programming error: invalid opcode in cmd %p",
+ (void *)cmd);
+ return (EINVAL);
case NVME_CQE_SC_GEN_INV_FLD:
/* Invalid Field in Command */
@@ -1431,7 +1433,12 @@ nvme_async_event_task(void *arg)
* Other possible errors are various scenarios where the async request
* was aborted, or internal errors in the device. Internal errors are
* reported to FMA, the command aborts need no special handling here.
+ *
+ * And finally, at least qemu nvme does not support async events,
+ * and will return NVME_CQE_SC_GEN_INV_OPC | DNR. If so, we
+ * will avoid posting async events.
*/
+
if (nvme_check_cmd_status(cmd) != 0) {
dev_err(cmd->nc_nvme->n_dip, CE_WARN,
"!async event request returned failure, sct = %x, "
@@ -1445,6 +1452,13 @@ nvme_async_event_task(void *arg)
ddi_fm_service_impact(cmd->nc_nvme->n_dip,
DDI_SERVICE_LOST);
}
+
+ if (cmd->nc_cqe.cqe_sf.sf_sct == NVME_CQE_SCT_GENERIC &&
+ cmd->nc_cqe.cqe_sf.sf_sc == NVME_CQE_SC_GEN_INV_OPC &&
+ cmd->nc_cqe.cqe_sf.sf_dnr == 1) {
+ nvme->n_async_event_supported = B_FALSE;
+ }
+
nvme_free_cmd(cmd);
return;
}
@@ -1576,11 +1590,13 @@ nvme_admin_cmd(nvme_cmd_t *cmd, int sec)
static void
nvme_async_event(nvme_t *nvme)
{
- nvme_cmd_t *cmd = nvme_alloc_cmd(nvme, KM_SLEEP);
+ nvme_cmd_t *cmd;
+ cmd = nvme_alloc_cmd(nvme, KM_SLEEP);
cmd->nc_sqid = 0;
cmd->nc_sqe.sqe_opc = NVME_OPC_ASYNC_EVENT;
cmd->nc_callback = nvme_async_event_task;
+ cmd->nc_dontpanic = B_TRUE;
nvme_submit_admin_cmd(nvme->n_adminq, cmd);
}
@@ -2376,7 +2392,12 @@ nvme_init(nvme_t *nvme)
/*
* Post an asynchronous event command to catch errors.
+ * We assume the asynchronous events are supported as required by
+ * specification (Figure 40 in section 5 of NVMe 1.2).
+ * However, since at least qemu does not follow the specification,
+ * we need a mechanism to protect ourselves.
*/
+ nvme->n_async_event_supported = B_TRUE;
nvme_async_event(nvme);
/*
@@ -2604,8 +2625,10 @@ nvme_init(nvme_t *nvme)
* Post more asynchronous events commands to reduce event reporting
* latency as suggested by the spec.
*/
- for (i = 1; i != nvme->n_async_event_limit; i++)
- nvme_async_event(nvme);
+ if (nvme->n_async_event_supported) {
+ for (i = 1; i != nvme->n_async_event_limit; i++)
+ nvme_async_event(nvme);
+ }
return (DDI_SUCCESS);
diff --git a/usr/src/uts/common/io/nvme/nvme_var.h b/usr/src/uts/common/io/nvme/nvme_var.h
index dca8c57e7c..b60febeabb 100644
--- a/usr/src/uts/common/io/nvme/nvme_var.h
+++ b/usr/src/uts/common/io/nvme/nvme_var.h
@@ -152,6 +152,7 @@ struct nvme {
int n_error_log_len;
boolean_t n_lba_range_supported;
boolean_t n_auto_pst_supported;
+ boolean_t n_async_event_supported;
int n_nssr_supported;
int n_doorbell_stride;