forked from mirrors/linux
		
	libnvdimm: handle locked label storage areas
Per the latest version of the "NVDIMM DSM Interface Example" [1], the label data retrieval routine can report a "locked" status. In this case all regions associated with that DIMM are disabled until the label area is unlocked. Provide generic libnvdimm enabling for NVDIMMs with label data area locking capabilities. [1]: http://pmem.io/documents/ Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
		
							parent
							
								
									8f078b38dd
								
							
						
					
					
						commit
						9d62ed9651
					
				
					 5 changed files with 39 additions and 10 deletions
				
			
		| 
						 | 
					@ -184,14 +184,29 @@ static int xlat_bus_status(void *buf, unsigned int cmd, u32 status)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int xlat_nvdimm_status(void *buf, unsigned int cmd, u32 status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (cmd) {
 | 
				
			||||||
 | 
						case ND_CMD_GET_CONFIG_SIZE:
 | 
				
			||||||
 | 
							if (status >> 16 & ND_CONFIG_LOCKED)
 | 
				
			||||||
 | 
								return -EACCES;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* all other non-zero status results in an error */
 | 
				
			||||||
 | 
						if (status)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int xlat_status(struct nvdimm *nvdimm, void *buf, unsigned int cmd,
 | 
					static int xlat_status(struct nvdimm *nvdimm, void *buf, unsigned int cmd,
 | 
				
			||||||
		u32 status)
 | 
							u32 status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!nvdimm)
 | 
						if (!nvdimm)
 | 
				
			||||||
		return xlat_bus_status(buf, cmd, status);
 | 
							return xlat_bus_status(buf, cmd, status);
 | 
				
			||||||
	if (status)
 | 
						return xlat_nvdimm_status(buf, cmd, status);
 | 
				
			||||||
		return -EIO;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
 | 
					int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,6 +49,8 @@ static int nvdimm_probe(struct device *dev)
 | 
				
			||||||
	kref_init(&ndd->kref);
 | 
						kref_init(&ndd->kref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = nvdimm_init_nsarea(ndd);
 | 
						rc = nvdimm_init_nsarea(ndd);
 | 
				
			||||||
 | 
						if (rc == -EACCES)
 | 
				
			||||||
 | 
							nvdimm_set_locked(dev);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,6 +67,7 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
 | 
				
			||||||
	struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
 | 
						struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(ndd->dev);
 | 
				
			||||||
	struct nvdimm_bus_descriptor *nd_desc;
 | 
						struct nvdimm_bus_descriptor *nd_desc;
 | 
				
			||||||
	int rc = validate_dimm(ndd);
 | 
						int rc = validate_dimm(ndd);
 | 
				
			||||||
 | 
						int cmd_rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
| 
						 | 
					@ -76,8 +77,11 @@ int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(cmd, 0, sizeof(*cmd));
 | 
						memset(cmd, 0, sizeof(*cmd));
 | 
				
			||||||
	nd_desc = nvdimm_bus->nd_desc;
 | 
						nd_desc = nvdimm_bus->nd_desc;
 | 
				
			||||||
	return nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
 | 
						rc = nd_desc->ndctl(nd_desc, to_nvdimm(ndd->dev),
 | 
				
			||||||
			ND_CMD_GET_CONFIG_SIZE, cmd, sizeof(*cmd), NULL);
 | 
								ND_CMD_GET_CONFIG_SIZE, cmd, sizeof(*cmd), &cmd_rc);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						return cmd_rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
 | 
					int nvdimm_init_config_data(struct nvdimm_drvdata *ndd)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2236,14 +2236,21 @@ static int init_active_labels(struct nd_region *nd_region)
 | 
				
			||||||
		int count, j;
 | 
							int count, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * If the dimm is disabled then prevent the region from
 | 
							 * If the dimm is disabled then we may need to prevent
 | 
				
			||||||
		 * being activated if it aliases DPA.
 | 
							 * the region from being activated.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (!ndd) {
 | 
							if (!ndd) {
 | 
				
			||||||
			if (!test_bit(NDD_ALIASING, &nvdimm->flags))
 | 
								if (test_bit(NDD_LOCKED, &nvdimm->flags))
 | 
				
			||||||
 | 
									/* fail, label data may be unreadable */;
 | 
				
			||||||
 | 
								else if (test_bit(NDD_ALIASING, &nvdimm->flags))
 | 
				
			||||||
 | 
									/* fail, labels needed to disambiguate dpa */;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
				return 0;
 | 
									return 0;
 | 
				
			||||||
			dev_dbg(&nd_region->dev, "%s: is disabled, failing probe\n",
 | 
					
 | 
				
			||||||
					dev_name(&nd_mapping->nvdimm->dev));
 | 
								dev_err(&nd_region->dev, "%s: is %s, failing probe\n",
 | 
				
			||||||
 | 
										dev_name(&nd_mapping->nvdimm->dev),
 | 
				
			||||||
 | 
										test_bit(NDD_LOCKED, &nvdimm->flags)
 | 
				
			||||||
 | 
										? "locked" : "disabled");
 | 
				
			||||||
			return -ENXIO;
 | 
								return -ENXIO;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		nd_mapping->ndd = ndd;
 | 
							nd_mapping->ndd = ndd;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,6 +169,7 @@ enum {
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	ND_ARS_VOLATILE = 1,
 | 
						ND_ARS_VOLATILE = 1,
 | 
				
			||||||
	ND_ARS_PERSISTENT = 2,
 | 
						ND_ARS_PERSISTENT = 2,
 | 
				
			||||||
 | 
						ND_CONFIG_LOCKED = 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline const char *nvdimm_bus_cmd_name(unsigned cmd)
 | 
					static inline const char *nvdimm_bus_cmd_name(unsigned cmd)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue