git: 2e19fae49fd4 - main - sesutil: Avoid setting reserved bits.

From: Alexander Motin <mav_at_FreeBSD.org>
Date: Thu, 13 Jan 2022 18:57:41 UTC
The branch main has been updated by mav:

URL: https://cgit.FreeBSD.org/src/commit/?id=2e19fae49fd4ab2360971463cee99a62198973b1

commit 2e19fae49fd4ab2360971463cee99a62198973b1
Author:     Alexander Motin <mav@FreeBSD.org>
AuthorDate: 2022-01-13 18:45:28 +0000
Commit:     Alexander Motin <mav@FreeBSD.org>
CommitDate: 2022-01-13 18:57:35 +0000

    sesutil: Avoid setting reserved bits.
    
    Weird side of SES specification is that some bits have different
    meaning or semantics in status and control pages.  This patch fixes
    non-zero writes into reserved fields, that caused errors on some
    enclosures when trying to control locate/fault LEDs, keeping other
    bits unchanged.
    
    MFC after:      2 weeks
    Sposonred by:   iXsystems, Inc.
---
 sys/cam/scsi/scsi_ses.h    | 44 ++++++++++++++++++++++++++++++++++++++++++++
 usr.sbin/sesutil/sesutil.c |  3 ++-
 2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/sys/cam/scsi/scsi_ses.h b/sys/cam/scsi/scsi_ses.h
index 86cc88ad27f1..8a1c7118f99a 100644
--- a/sys/cam/scsi/scsi_ses.h
+++ b/sys/cam/scsi/scsi_ses.h
@@ -2058,6 +2058,50 @@ union ses_status_element {
 	uint8_t				    bytes[4];
 };
 
+/*
+ * Convert element status into control as much as possible.
+ * Some bits have different meaning in status and control,
+ * while others have the same and should be preserved.
+ */
+static inline void
+ses_status_to_ctrl(uint8_t type, uint8_t *bytes)
+{
+	/* Updated to SES4r5. */
+	static const uint8_t mask[][4] = {
+	    { 0x60, 0x00, 0x00, 0x00 },	/* UNSPECIFIED */
+	    { 0x60, 0x00, 0x4e, 0x3c },	/* DEVICE */
+	    { 0x60, 0xc0, 0x00, 0x60 },	/* POWER */
+	    { 0x60, 0xc0, 0x00, 0x60 },	/* COOLING/FAN */
+	    { 0x60, 0xc0, 0x00, 0x80 },	/* THERM */
+	    { 0x60, 0xc0, 0x00, 0x01 },	/* DOORLOCK */
+	    { 0x60, 0xc0, 0x00, 0x5f },	/* ALARM */
+	    { 0x60, 0xf0, 0x01, 0x00 },	/* ESSC */
+	    { 0x60, 0xc0, 0x00, 0x00 },	/* SCC */
+	    { 0x60, 0xc0, 0x00, 0x00 },	/* NVRAM */
+	    { 0x60, 0x00, 0x00, 0x00 },	/* INV_OP_REASON */
+	    { 0x60, 0x00, 0x00, 0xe0 },	/* UPS */
+	    { 0x60, 0xc0, 0xff, 0xff },	/* DISPLAY */
+	    { 0x60, 0xc0, 0x00, 0x00 },	/* KEYPAD */
+	    { 0x60, 0x80, 0x00, 0xff },	/* ENCLOSURE */
+	    { 0x60, 0xc0, 0x00, 0x10 },	/* SCSIXVR */
+	    { 0x60, 0x80, 0xff, 0xff },	/* LANGUAGE */
+	    { 0x60, 0xc0, 0x00, 0x01 },	/* COMPORT */
+	    { 0x60, 0xc0, 0x00, 0x00 },	/* VOM */
+	    { 0x60, 0xc0, 0x00, 0x00 },	/* AMMETER */
+	    { 0x60, 0xc0, 0x00, 0x01 },	/* SCSI_TGT */
+	    { 0x60, 0xc0, 0x00, 0x01 },	/* SCSI_INI*/
+	    { 0x60, 0xc0, 0x00, 0x00 },	/* SUBENC */
+	    { 0x60, 0xff, 0x4e, 0x3c },	/* ARRAY_DEV */
+	    { 0x60, 0xc0, 0x00, 0x00 },	/* SAS_EXP */
+	    { 0x60, 0x80, 0x00, 0x40 },	/* SAS_CONN */
+	};
+
+	if (type >= sizeof(mask) / sizeof(mask[0]))
+		type = 0;
+	for (int i = 0; i < 4; i++)
+		bytes[i] &= mask[type][i];
+}
+
 /*===================== SCSI SES Status Diagnostic Page =====================*/
 struct ses_status_page {
 	struct ses_page_hdr  hdr;
diff --git a/usr.sbin/sesutil/sesutil.c b/usr.sbin/sesutil/sesutil.c
index 9e6098e1da35..d78a9172e454 100644
--- a/usr.sbin/sesutil/sesutil.c
+++ b/usr.sbin/sesutil/sesutil.c
@@ -138,10 +138,11 @@ do_led(int fd, unsigned int idx, elm_type_t type, bool onoff, bool setfault)
 		close(fd);
 		xo_err(EXIT_FAILURE, "ENCIOC_GETELMSTAT");
 	}
-	slot = (struct ses_ctrl_dev_slot *) &o.cstat[0];
+	ses_status_to_ctrl(type, &o.cstat[0]);
 	switch (type) {
 	case ELMTYP_DEVICE:
 	case ELMTYP_ARRAY_DEV:
+		slot = (struct ses_ctrl_dev_slot *) &o.cstat[0];
 		ses_ctrl_common_set_select(&slot->common, 1);
 		if (setfault)
 			ses_ctrl_dev_slot_set_rqst_fault(slot, state);