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.
This commit is contained in:
Alexander Motin 2022-01-13 13:45:28 -05:00
parent 1d41a49404
commit 2e19fae49f
2 changed files with 46 additions and 1 deletions

View File

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

View File

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