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
This commit is contained in:
Warner Losh 2021-11-05 08:56:33 -06:00
parent 710a519ebb
commit 577f9aa266

View File

@ -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;