aboutsummaryrefslogtreecommitdiff
path: root/sys/cam/nvme
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2020-08-13 02:32:46 +0000
committerAlexander Motin <mav@FreeBSD.org>2020-08-13 02:32:46 +0000
commit654f53ab6a9793a931e19ec598b7c496a17f6af8 (patch)
tree14aa3beaf633fcf0c803900ab59789fbef244083 /sys/cam/nvme
parentbceabe277e1286ec694e34c186a73e7bf2c9de4f (diff)
downloadsrc-654f53ab6a9793a931e19ec598b7c496a17f6af8.tar.gz
src-654f53ab6a9793a931e19ec598b7c496a17f6af8.zip
Fill device serial_num and device_id in NVMe XPT.
It allows to report GEOM::lunid for nda(4) same as for nvd(4). Since NVMe now allows multiple LUs (namespaces) with multiple paths unique LU identification is important. The serial_num field is filled same as before with the controller serial number, while device_id is based on namespace GUID and/or EUI64 fields as recommended by "NVM Express: SCSI Translation Reference" and matching nvd(4) at the end. MFC after: 1 week
Notes
Notes: svn path=/head/; revision=364185
Diffstat (limited to 'sys/cam/nvme')
-rw-r--r--sys/cam/nvme/nvme_xpt.c70
1 files changed, 67 insertions, 3 deletions
diff --git a/sys/cam/nvme/nvme_xpt.c b/sys/cam/nvme/nvme_xpt.c
index 687da220325a..fbb9cf19d839 100644
--- a/sys/cam/nvme/nvme_xpt.c
+++ b/sys/cam/nvme/nvme_xpt.c
@@ -310,9 +310,11 @@ nvme_probe_done(struct cam_periph *periph, union ccb *done_ccb)
struct nvme_controller_data *nvme_cdata;
nvme_probe_softc *softc;
struct cam_path *path;
+ struct scsi_vpd_device_id *did;
+ struct scsi_vpd_id_descriptor *idd;
cam_status status;
u_int32_t priority;
- int found = 1;
+ int found = 1, e, g, len;
CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("nvme_probe_done\n"));
@@ -369,6 +371,21 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
bcopy(&softc->cd, nvme_cdata, sizeof(*nvme_cdata));
path->device->nvme_cdata = nvme_cdata;
+ /* Save/update serial number. */
+ if (path->device->serial_num != NULL) {
+ free(path->device->serial_num, M_CAMXPT);
+ path->device->serial_num = NULL;
+ path->device->serial_num_len = 0;
+ }
+ path->device->serial_num = (u_int8_t *)
+ malloc(NVME_SERIAL_NUMBER_LENGTH + 1, M_CAMXPT, M_NOWAIT);
+ if (path->device->serial_num != NULL) {
+ cam_strvis(path->device->serial_num, nvme_cdata->sn,
+ NVME_SERIAL_NUMBER_LENGTH, NVME_SERIAL_NUMBER_LENGTH + 1);
+ path->device->serial_num_len =
+ strlen(path->device->serial_num);
+ }
+
// nvme_find_quirk(path->device);
nvme_device_transport(path);
NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY_NS);
@@ -394,6 +411,53 @@ device_fail: if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
bcopy(&softc->ns, nvme_data, sizeof(*nvme_data));
path->device->nvme_data = nvme_data;
+ /* Save/update device_id based on NGUID and/or EUI64. */
+ if (path->device->device_id != NULL) {
+ free(path->device->device_id, M_CAMXPT);
+ path->device->device_id = NULL;
+ path->device->device_id_len = 0;
+ }
+ len = 0;
+ for (g = 0; g < sizeof(nvme_data->nguid); g++) {
+ if (nvme_data->nguid[g] != 0)
+ break;
+ }
+ if (g < sizeof(nvme_data->nguid))
+ len += sizeof(struct scsi_vpd_id_descriptor) + 16;
+ for (e = 0; e < sizeof(nvme_data->eui64); e++) {
+ if (nvme_data->eui64[e] != 0)
+ break;
+ }
+ if (e < sizeof(nvme_data->eui64))
+ len += sizeof(struct scsi_vpd_id_descriptor) + 8;
+ if (len > 0) {
+ path->device->device_id = (u_int8_t *)
+ malloc(SVPD_DEVICE_ID_HDR_LEN + len,
+ M_CAMXPT, M_NOWAIT);
+ }
+ if (path->device->device_id != NULL) {
+ did = (struct scsi_vpd_device_id *)path->device->device_id;
+ did->device = SID_QUAL_LU_CONNECTED | T_DIRECT;
+ did->page_code = SVPD_DEVICE_ID;
+ scsi_ulto2b(len, did->length);
+ idd = (struct scsi_vpd_id_descriptor *)(did + 1);
+ if (g < sizeof(nvme_data->nguid)) {
+ idd->proto_codeset = SVPD_ID_CODESET_BINARY;
+ idd->id_type = SVPD_ID_ASSOC_LUN | SVPD_ID_TYPE_EUI64;
+ idd->length = 16;
+ bcopy(nvme_data->nguid, idd->identifier, 16);
+ idd = (struct scsi_vpd_id_descriptor *)
+ &idd->identifier[16];
+ }
+ if (e < sizeof(nvme_data->eui64)) {
+ idd->proto_codeset = SVPD_ID_CODESET_BINARY;
+ idd->id_type = SVPD_ID_ASSOC_LUN | SVPD_ID_TYPE_EUI64;
+ idd->length = 8;
+ bcopy(nvme_data->eui64, idd->identifier, 8);
+ }
+ path->device->device_id_len = SVPD_DEVICE_ID_HDR_LEN + len;
+ }
+
if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
path->device->flags &= ~CAM_DEV_UNCONFIGURED;
xpt_acquire_device(path->device);
@@ -546,9 +610,9 @@ nvme_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
device->maxtags = 0;
device->inq_flags = 0;
device->queue_flags = 0;
- device->device_id = NULL; /* XXX Need to set this somewhere */
+ device->device_id = NULL;
device->device_id_len = 0;
- device->serial_num = NULL; /* XXX Need to set this somewhere */
+ device->serial_num = NULL;
device->serial_num_len = 0;
return (device);
}