git: 577f9aa266e3 - main - cam_periph: Add ability to wire units to a serial number

From: Warner Losh <imp_at_FreeBSD.org>
Date: Fri, 05 Nov 2021 15:25:40 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=577f9aa266e3407a2de9d6bd6d836a9ba984e944

commit 577f9aa266e3407a2de9d6bd6d836a9ba984e944
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2021-11-05 14:56:33 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2021-11-05 14:56:33 +0000

    cam_periph: Add ability to wire units to a serial number
    
    For scsi, ata and nvme, at least, we read a serial number from the
    device (if the device supports it, some scsi drives do not) and record
    it during the *_xpt probe device state machine before it posts the
    AC_FOUND_DEVICE async event. For mmc, no serial number is ever
    retrieved, so it's always NULL. Add the ability to match this serial
    number during device wiring.
    
    This mechanism is competely optional, and often times using a label
    and/or some other attribute of the device is easier. However, other
    times wiring a unit to a serial number simplifies management as most
    monitoring tools require the *daX device and having it stable from boot
    to boot helps with data continuity. It can be especially helpful for
    nvme where no other means exists to reliably tie a ndaX device to an
    underlying nvme drive and namespace.
    
    A similar mechanism exists in Linux to mange device unit numbers with
    udev.
    
    Sponsored by:           Netflix
    Differential Revision:  https://reviews.freebsd.org/D32683
---
 sys/cam/cam_periph.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 8fbc2e3926fa..bb4baaf0888f 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -69,7 +69,8 @@ static	u_int		camperiphnextunit(struct periph_driver *p_drv,
 					  lun_id_t lun);
 static	u_int		camperiphunit(struct periph_driver *p_drv,
 				      path_id_t pathid, target_id_t target,
-				      lun_id_t lun); 
+				      lun_id_t lun,
+				      const char *sn);
 static	void		camperiphdone(struct cam_periph *periph, 
 					union ccb *done_ccb);
 static  void		camperiphfree(struct cam_periph *periph);
@@ -273,7 +274,8 @@ cam_periph_alloc(periph_ctor_t *periph_ctor,
 		free(periph, M_CAMPERIPH);
 		return (CAM_REQ_INVALID);
 	}
-	periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id);
+	periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id,
+	    path->device->serial_num);
 	cur_periph = TAILQ_FIRST(&(*p_drv)->units);
 	while (cur_periph != NULL
 	    && cur_periph->unit_number < periph->unit_number)
@@ -582,7 +584,8 @@ camperiphnextunit(struct periph_driver *p_drv, u_int newunit, int wired,
 
 			if (newunit != dunit)
 				continue;
-			if (resource_int_value(dname, dunit, "lun", &val) == 0 ||
+			if (resource_string_value(dname, dunit, "sn", &strval) == 0 ||
+			    resource_int_value(dname, dunit, "lun", &val) == 0 ||
 			    resource_int_value(dname, dunit, "target", &val) == 0 ||
 			    resource_string_value(dname, dunit, "at", &strval) == 0)
 				break;
@@ -595,7 +598,7 @@ camperiphnextunit(struct periph_driver *p_drv, u_int newunit, int wired,
 
 static u_int
 camperiphunit(struct periph_driver *p_drv, path_id_t pathid,
-	      target_id_t target, lun_id_t lun)
+    target_id_t target, lun_id_t lun, const char *sn)
 {
 	u_int	unit;
 	int	wired, i, val, dunit;
@@ -624,6 +627,11 @@ camperiphunit(struct periph_driver *p_drv, path_id_t pathid,
 				continue;
 			wired++;
 		}
+		if (resource_string_value(dname, dunit, "sn", &strval) == 0) {
+			if (sn == NULL || strcmp(strval, sn) != 0)
+				continue;
+			wired++;
+		}
 		if (wired != 0) {
 			unit = dunit;
 			break;