Make multi-namespace nvme drives more robust.

Fix assumptions about name spaces in NVME driver. First, it assumes
cdata.nn is the number of configured devices. However, it is the
number of supported name spaces. Second, it assumes that there will
never be more than 16 name spaces supported, but a certain drive I'm
testing reports 1024. It assumes that name spaces are a tightly packed
namespace, but the standard seems to indicate otherwise. Finally, it
assumes that an error would be generated when quearying an
unconfigured namespace. Instead, it succeeds but the identify data is
all zeros.

Fix these by limiting the number of name spaces we probe to 16. Remove
aborting when we find one in error. When the size of the name space is
zero, ignore it.

This is admittedly a bandaide. The long term fix will be to
participate in the enumeration and name space change protocols
definfed in the NVNe standard.

Sponsored by: Netflix
This commit is contained in:
Warner Losh 2017-03-07 21:47:54 +00:00
parent 397ebc5b80
commit a8a18dd590
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=314884
3 changed files with 16 additions and 7 deletions

View File

@ -327,8 +327,10 @@ nvme_notify(struct nvme_consumer *cons,
*/
return;
}
for (ns_idx = 0; ns_idx < ctrlr->cdata.nn; ns_idx++) {
for (ns_idx = 0; ns_idx < min(ctrlr->cdata.nn, NVME_MAX_NAMESPACES); ns_idx++) {
ns = &ctrlr->ns[ns_idx];
if (ns->data.nsze == 0)
continue;
if (cons->ns_fn != NULL)
ns->cons_cookie[cons->id] =
(*cons->ns_fn)(ns, ctrlr_cookie);

View File

@ -458,13 +458,11 @@ static int
nvme_ctrlr_construct_namespaces(struct nvme_controller *ctrlr)
{
struct nvme_namespace *ns;
int i, status;
int i;
for (i = 0; i < ctrlr->cdata.nn; i++) {
for (i = 0; i < min(ctrlr->cdata.nn, NVME_MAX_NAMESPACES); i++) {
ns = &ctrlr->ns[i];
status = nvme_ns_construct(ns, i+1, ctrlr);
if (status != 0)
return (status);
nvme_ns_construct(ns, i+1, ctrlr);
}
return (0);

View File

@ -511,6 +511,15 @@ nvme_ns_construct(struct nvme_namespace *ns, uint16_t id,
return (ENXIO);
}
/*
* If the size of is zero, chances are this isn't a valid
* namespace (eg one that's not been configured yet). The
* standard says the entire id will be zeros, so this is a
* cheap way to test for that.
*/
if (ns->data.nsze == 0)
return (ENXIO);
/*
* Note: format is a 0-based value, so > is appropriate here,
* not >=.
@ -518,7 +527,7 @@ nvme_ns_construct(struct nvme_namespace *ns, uint16_t id,
if (ns->data.flbas.format > ns->data.nlbaf) {
printf("lba format %d exceeds number supported (%d)\n",
ns->data.flbas.format, ns->data.nlbaf+1);
return (1);
return (ENXIO);
}
if (ctrlr->cdata.oncs.dsm)