Skip to content

Commit

Permalink
8945 nvme panics when async events are not supported
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
tsoome authored and richlowe committed Feb 14, 2018
1 parent 351128a commit 0813916
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 6 deletions.
35 changes: 29 additions & 6 deletions usr/src/uts/common/io/nvme/nvme.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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, "
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);

/*
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions usr/src/uts/common/io/nvme/nvme_var.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 0813916

Please sign in to comment.