git: 9aba757e92aa - main - ahci(4): Allow enclosure emulation without hardware.

From: Alexander Motin <mav_at_FreeBSD.org>
Date: Fri, 17 Dec 2021 20:34:54 UTC
The branch main has been updated by mav:

URL: https://cgit.FreeBSD.org/src/commit/?id=9aba757e92aaf0751c83c0ce3f18f65f864f1811

commit 9aba757e92aaf0751c83c0ce3f18f65f864f1811
Author:     Alexander Motin <mav@FreeBSD.org>
AuthorDate: 2021-12-17 20:24:56 +0000
Commit:     Alexander Motin <mav@FreeBSD.org>
CommitDate: 2021-12-17 20:34:43 +0000

    ahci(4): Allow enclosure emulation without hardware.
    
    After 53f5ac1310e allowed SATA device mapping to enclosure slots,
    it may have sense to provide enclosure device emulation even without
    real hardware interface like SGPIO just for purposes of physical
    device location tracking (still assuming straight cabling).
    
    MFC after:      1 week
    Sponsored by:   iXsystems, Inc.
---
 share/man/man4/ahci.4 |  6 +++++-
 sys/dev/ahci/ahci.c   |  7 ++++++-
 sys/dev/ahci/ahciem.c | 36 ++++++++++++++++++++++--------------
 3 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/share/man/man4/ahci.4 b/share/man/man4/ahci.4
index a7a70c6dd5bc..58b9fea7c838 100644
--- a/share/man/man4/ahci.4
+++ b/share/man/man4/ahci.4
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd August 21, 2019
+.Dd December 17, 2021
 .Dt AHCI 4
 .Os
 .Sh NAME
@@ -73,6 +73,10 @@ controls whether the driver should use direct command completion from
 interrupt thread(s), or queue them to CAM completion threads.
 Default value depends on number of MSI interrupts supported and number of
 implemented SATA ports.
+.It Va hint.ahci. Ns Ar X Ns Va .em
+controls whether the driver should implement virtual enclosure management
+device on top of SGPIO or other interface.
+Default value depends on controller capabilities.
 .It Va hint.ahcich. Ns Ar X Ns Va .pm_level
 controls SATA interface Power Management for the specified channel,
 allowing some power to be saved at the cost of additional command
diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c
index 4b13ae3068d5..12e6ee8102da 100644
--- a/sys/dev/ahci/ahci.c
+++ b/sys/dev/ahci/ahci.c
@@ -376,7 +376,10 @@ ahci_attach(device_t dev)
 		device_set_ivars(child, (void *)(intptr_t)(unit | AHCI_REMAPPED_UNIT));
 	}
 
-	if (ctlr->caps & AHCI_CAP_EMS) {
+	int em = (ctlr->caps & AHCI_CAP_EMS) != 0;
+	resource_int_value(device_get_name(dev), device_get_unit(dev),
+	    "em", &em);
+	if (em) {
 		child = device_add_child(dev, "ahciem", -1);
 		if (child == NULL)
 			device_printf(dev, "failed to add enclosure device\n");
@@ -602,6 +605,8 @@ ahci_alloc_resource(device_t dev, device_t child, int type, int *rid,
 		} else if (!is_em) {
 			offset = AHCI_OFFSET + (unit << 7);
 			size = 128;
+		} else if ((ctlr->caps & AHCI_CAP_EMS) == 0) {
+			break;
 		} else if (*rid == 0) {
 			offset = AHCI_EM_CTL;
 			size = 4;
diff --git a/sys/dev/ahci/ahciem.c b/sys/dev/ahci/ahciem.c
index b1c3fbf1fdd4..20b36830ce9a 100644
--- a/sys/dev/ahci/ahciem.c
+++ b/sys/dev/ahci/ahciem.c
@@ -86,17 +86,18 @@ ahci_em_attach(device_t dev)
 	enc->ichannels = ctlr->ichannels;
 	mtx_init(&enc->mtx, "AHCI enclosure lock", NULL, MTX_DEF);
 	rid = 0;
-	if (!(enc->r_memc = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
-	    &rid, RF_ACTIVE))) {
-		mtx_destroy(&enc->mtx);
-		return (ENXIO);
-	}
-	enc->capsem = ATA_INL(enc->r_memc, 0);
-	rid = 1;
-	if (!(enc->r_memt = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
-	    &rid, RF_ACTIVE))) {
-		error = ENXIO;
-		goto err0;
+	if ((enc->r_memc = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+	    &rid, RF_ACTIVE)) != NULL) {
+		enc->capsem = ATA_INL(enc->r_memc, 0);
+		rid = 1;
+		if (!(enc->r_memt = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+		    &rid, RF_ACTIVE))) {
+			error = ENXIO;
+			goto err0;
+		}
+	} else {
+		enc->capsem = AHCI_EM_XMT | AHCI_EM_SMB | AHCI_EM_LED;
+		enc->r_memt = NULL;
 	}
 	if ((enc->capsem & (AHCI_EM_XMT | AHCI_EM_SMB)) == 0) {
 		rid = 2;
@@ -194,7 +195,8 @@ err1:
 err0:
 	if (enc->r_memt)
 		bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
-	bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
+	if (enc->r_memc)
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
 	mtx_destroy(&enc->mtx);
 	return (error);
 }
@@ -216,8 +218,10 @@ ahci_em_detach(device_t dev)
 	cam_sim_free(enc->sim, /*free_devq*/TRUE);
 	mtx_unlock(&enc->mtx);
 
-	bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
-	bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
+	if (enc->r_memc)
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
+	if (enc->r_memt)
+		bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
 	if (enc->r_memr)
 		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
 	mtx_destroy(&enc->mtx);
@@ -231,6 +235,8 @@ ahci_em_reset(device_t dev)
 	int i, timeout;
 
 	enc = device_get_softc(dev);
+	if (enc->r_memc == NULL)
+		return (0);
 	ATA_OUTL(enc->r_memc, 0, AHCI_EM_RST);
 	timeout = 1000;
 	while ((ATA_INL(enc->r_memc, 0) & AHCI_EM_RST) &&
@@ -292,6 +298,8 @@ ahci_em_setleds(device_t dev, int c)
 	int16_t val;
 
 	enc = device_get_softc(dev);
+	if (enc->r_memc == NULL)
+		return;
 
 	val = 0;
 	if (enc->status[c][2] & SESCTL_RQSACT)		/* Activity */