From 577f9aa266e3407a2de9d6bd6d836a9ba984e944 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 5 Nov 2021 08:56:33 -0600 Subject: [PATCH] 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;