Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 23 Jun 2019 19:05:01 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r349321 - in head/sys: cam/scsi dev/ahci
Message-ID:  <201906231905.x5NJ51Fl054396@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sun Jun 23 19:05:01 2019
New Revision: 349321
URL: https://svnweb.freebsd.org/changeset/base/349321

Log:
  Improve AHCI Enclosure Management and SES interoperation.
  
  Since SES specs do not define mechanism to map enclosure slots to SATA
  disks, AHCI EM code I written many years ago appeared quite useless,
  that always bugged me.  I was thinking whether it was a good idea, but
  if LSI HBAs do that, why I shouldn't?
  
  This change introduces simple non-standard mechanism for the mapping
  into both AHCI EM and SES code, that makes AHCI EM on capable controllers
  (most of Intel's) a first-class SES citizen, allowing it to report disk
  physical path to GEOM, show devices inserted into each enclosure slot in
  `sesutil map` and `getencstat`, control locate and fault LEDs for specific
  devices with `sesutil locate adaX on` and `sesutil fault adaX on`, etc.
  
  I've successfully tested this on Supermicro X10DRH-i motherboard connected
  with sideband cable of its S-SATA Mini-SAS connector to SAS815TQ backplane.
  It can indicate with LEDs Locate, Fault and Rebuild/Remap SES statuses for
  each disk identical to real SES of Supermicro SAS2 backplanes.
  
  MFC after:	2 weeks

Modified:
  head/sys/cam/scsi/scsi_all.c
  head/sys/cam/scsi/scsi_enc.c
  head/sys/cam/scsi/scsi_enc.h
  head/sys/cam/scsi/scsi_enc_internal.h
  head/sys/cam/scsi/scsi_enc_safte.c
  head/sys/cam/scsi/scsi_enc_ses.c
  head/sys/cam/scsi/scsi_ses.h
  head/sys/dev/ahci/ahci.c
  head/sys/dev/ahci/ahci.h
  head/sys/dev/ahci/ahciem.c

Modified: head/sys/cam/scsi/scsi_all.c
==============================================================================
--- head/sys/cam/scsi/scsi_all.c	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/cam/scsi/scsi_all.c	Sun Jun 23 19:05:01 2019	(r349321)
@@ -5574,6 +5574,7 @@ scsi_devid_is_naa_ieee_reg(uint8_t *bufp)
 {
 	struct scsi_vpd_id_descriptor *descr;
 	struct scsi_vpd_id_naa_basic *naa;
+	int n;
 
 	descr = (struct scsi_vpd_id_descriptor *)bufp;
 	naa = (struct scsi_vpd_id_naa_basic *)descr->identifier;
@@ -5581,7 +5582,8 @@ scsi_devid_is_naa_ieee_reg(uint8_t *bufp)
 		return 0;
 	if (descr->length < sizeof(struct scsi_vpd_id_naa_ieee_reg))
 		return 0;
-	if ((naa->naa >> SVPD_ID_NAA_NAA_SHIFT) != SVPD_ID_NAA_IEEE_REG)
+	n = naa->naa >> SVPD_ID_NAA_NAA_SHIFT;
+	if (n != SVPD_ID_NAA_LOCAL_REG && n != SVPD_ID_NAA_IEEE_REG)
 		return 0;
 	return 1;
 }

Modified: head/sys/cam/scsi/scsi_enc.c
==============================================================================
--- head/sys/cam/scsi/scsi_enc.c	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/cam/scsi/scsi_enc.c	Sun Jun 23 19:05:01 2019	(r349321)
@@ -89,6 +89,9 @@ int enc_verbose = 0;
 SYSCTL_INT(_kern_cam_enc, OID_AUTO, verbose, CTLFLAG_RWTUN,
            &enc_verbose, 0, "Enable verbose logging");
 
+const char *elm_type_names[] = ELM_TYPE_NAMES;
+CTASSERT(nitems(elm_type_names) - 1 == ELMTYP_LAST);
+
 static struct periph_driver encdriver = {
 	enc_init, "ses",
 	TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0
@@ -240,13 +243,19 @@ enc_async(void *callback_arg, uint32_t code, struct ca
 				struct enc_softc *softc;
 
 				softc = (struct enc_softc *)periph->softc;
-				if (xpt_path_path_id(periph->path) != path_id
-				 || softc == NULL
-				 || (softc->enc_flags & ENC_FLAG_INITIALIZED)
-				  == 0
-				 || softc->enc_vec.device_found == NULL)
+
+				/* Check this SEP is ready. */
+				if (softc == NULL || (softc->enc_flags &
+				     ENC_FLAG_INITIALIZED) == 0 ||
+				    softc->enc_vec.device_found == NULL)
 					continue;
 
+				/* Check this SEP may manage this device. */
+				if (xpt_path_path_id(periph->path) != path_id &&
+				    (softc->enc_type != ENC_SEMB_SES ||
+				     cgd->protocol != PROTO_ATA))
+					continue;
+
 				softc->enc_vec.device_found(softc);
 			}
 			xpt_unlock_buses();
@@ -440,7 +449,7 @@ enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_ad
 			encioc_element_t kelm;
 			kelm.elm_idx = i;
 			kelm.elm_subenc_id = cache->elm_map[i].subenclosure;
-			kelm.elm_type = cache->elm_map[i].enctype;
+			kelm.elm_type = cache->elm_map[i].elm_type;
 			error = copyout(&kelm, &uelm[i], sizeof(kelm));
 			if (error)
 				break;

Modified: head/sys/cam/scsi/scsi_enc.h
==============================================================================
--- head/sys/cam/scsi/scsi_enc.h	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/cam/scsi/scsi_enc.h	Sun Jun 23 19:05:01 2019	(r349321)
@@ -120,9 +120,41 @@ typedef enum {
 	ELMTYP_SCSI_INI		= 0x15,
 	ELMTYP_SUBENC		= 0x16,
 	ELMTYP_ARRAY_DEV	= 0x17,
-	ELMTYP_SAS_EXP		= 0x18, /* SAS expander */
-	ELMTYP_SAS_CONN		= 0x19  /* SAS connector */
+	ELMTYP_SAS_EXP		= 0x18,	/* SAS Expander */
+	ELMTYP_SAS_CONN		= 0x19,	/* SAS Connector */
+	ELMTYP_LAST		= ELMTYP_SAS_CONN
 } elm_type_t;
+
+#define	ELM_TYPE_NAMES	{				\
+	"Unspecified",					\
+	"Device Slot",					\
+	"Power Supply",					\
+	"Cooling",					\
+	"Temperature Sensors",				\
+	"Door",						\
+	"Audible alarm",				\
+	"Enclosure Services Controller Electronics",	\
+	"SCC Controller Electronics",			\
+	"Nonvolatile Cache",				\
+	"Invalid Operation Reason",			\
+	"Uninterruptible Power Supply",			\
+	"Display",					\
+	"Key Pad Entry",				\
+	"Enclosure",					\
+	"SCSI Port/Transceiver",			\
+	"Language",					\
+	"Communication Port",				\
+	"Voltage Sensor",				\
+	"Current Sensor",				\
+	"SCSI Target Port",				\
+	"SCSI Initiator Port",				\
+	"Simple Subenclosure",				\
+	"Array Device Slot",				\
+	"SAS Expander",					\
+	"SAS Connector"					\
+}
+
+extern const char *elm_type_names[];
 
 typedef struct encioc_element {
 	/* Element Index */

Modified: head/sys/cam/scsi/scsi_enc_internal.h
==============================================================================
--- head/sys/cam/scsi/scsi_enc_internal.h	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/cam/scsi/scsi_enc_internal.h	Sun Jun 23 19:05:01 2019	(r349321)
@@ -39,16 +39,12 @@
 #include <sys/sysctl.h>
 
 typedef struct enc_element {
-	uint32_t
-		 enctype	: 8,	/* enclosure type */
-		 subenclosure : 8,	/* subenclosure id */
-		 svalid	: 1,		/* enclosure information valid */
-		 overall_status_elem: 1,/*
-					 * This object represents generic
-					 * status about all objects of this
-					 * type.
-					 */
-		 priv	: 14;		/* private data, per object */
+	uint8_t	 elm_idx;		/* index of element */
+	uint8_t	 elm_type;		/* element type */
+	uint8_t	 subenclosure;		/* subenclosure id */
+	uint8_t	 type_elm_idx;		/* index of element within type */
+	uint8_t	 svalid;		/* enclosure information valid */
+	uint16_t priv;			/* private data, per object */
 	uint8_t	 encstat[4];		/* state && stats */
 	uint8_t *physical_path;		/* Device physical path data. */
 	u_int    physical_path_len;	/* Length of device path data. */

Modified: head/sys/cam/scsi/scsi_enc_safte.c
==============================================================================
--- head/sys/cam/scsi/scsi_enc_safte.c	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/cam/scsi/scsi_enc_safte.c	Sun Jun 23 19:05:01 2019	(r349321)
@@ -301,21 +301,21 @@ safte_process_config(enc_softc_t *enc, struct enc_fsm_
 	 * in later fetches of status.
 	 */
 	for (i = 0; i < cfg->Nfans; i++)
-		enc->enc_cache.elm_map[r++].enctype = ELMTYP_FAN;
+		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_FAN;
 	cfg->pwroff = (uint8_t) r;
 	for (i = 0; i < cfg->Npwr; i++)
-		enc->enc_cache.elm_map[r++].enctype = ELMTYP_POWER;
+		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_POWER;
 	for (i = 0; i < cfg->DoorLock; i++)
-		enc->enc_cache.elm_map[r++].enctype = ELMTYP_DOORLOCK;
+		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_DOORLOCK;
 	if (cfg->Nspkrs > 0)
-		enc->enc_cache.elm_map[r++].enctype = ELMTYP_ALARM;
+		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_ALARM;
 	for (i = 0; i < cfg->Ntherm; i++)
-		enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM;
+		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM;
 	for (i = 0; i <= cfg->Ntstats; i++)
-		enc->enc_cache.elm_map[r++].enctype = ELMTYP_THERM;
+		enc->enc_cache.elm_map[r++].elm_type = ELMTYP_THERM;
 	cfg->slotoff = (uint8_t) r;
 	for (i = 0; i < cfg->Nslots; i++)
-		enc->enc_cache.elm_map[r++].enctype =
+		enc->enc_cache.elm_map[r++].elm_type =
 		    emulate_array_devices ? ELMTYP_ARRAY_DEV :
 		     ELMTYP_DEVICE;
 
@@ -505,7 +505,7 @@ safte_process_status(enc_softc_t *enc, struct enc_fsm_
 	 */
 	for (i = 0; i < cfg->Nslots; i++) {
 		SAFT_BAIL(r, xfer_len);
-		if (cache->elm_map[cfg->slotoff + i].enctype == ELMTYP_DEVICE)
+		if (cache->elm_map[cfg->slotoff + i].elm_type == ELMTYP_DEVICE)
 			cache->elm_map[cfg->slotoff + i].encstat[1] = buf[r];
 		r++;
 	}
@@ -678,7 +678,7 @@ safte_process_slotstatus(enc_softc_t *enc, struct enc_
 	oid = cfg->slotoff;
 	for (r = i = 0; i < cfg->Nslots; i++, r += 4) {
 		SAFT_BAIL(r+3, xfer_len);
-		if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV)
+		if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV)
 			cache->elm_map[oid].encstat[1] = 0;
 		cache->elm_map[oid].encstat[2] &= SESCTL_RQSID;
 		cache->elm_map[oid].encstat[3] = 0;
@@ -705,7 +705,7 @@ safte_process_slotstatus(enc_softc_t *enc, struct enc_
 			cache->elm_map[oid].encstat[3] |= SESCTL_RQSFLT;
 		if (buf[r+0] & 0x40)
 			cache->elm_map[oid].encstat[0] |= SESCTL_PRDFAIL;
-		if (cache->elm_map[oid].enctype == ELMTYP_ARRAY_DEV) {
+		if (cache->elm_map[oid].elm_type == ELMTYP_ARRAY_DEV) {
 			if (buf[r+0] & 0x01)
 				cache->elm_map[oid].encstat[1] |= 0x80;
 			if (buf[r+0] & 0x04)
@@ -771,7 +771,7 @@ safte_fill_control_request(enc_softc_t *enc, struct en
 	} else {
 		ep = &enc->enc_cache.elm_map[idx];
 
-		switch (ep->enctype) {
+		switch (ep->elm_type) {
 		case ELMTYP_DEVICE:
 		case ELMTYP_ARRAY_DEV:
 			switch (cfg->current_request_stage) {
@@ -781,7 +781,7 @@ safte_fill_control_request(enc_softc_t *enc, struct en
 					ep->priv |= 0x40;
 				if (req->elm_stat[3] & SESCTL_RQSFLT)
 					ep->priv |= 0x02;
-				if (ep->enctype == ELMTYP_ARRAY_DEV) {
+				if (ep->elm_type == ELMTYP_ARRAY_DEV) {
 					if (req->elm_stat[1] & 0x01)
 						ep->priv |= 0x200;
 					if (req->elm_stat[1] & 0x02)
@@ -970,7 +970,7 @@ safte_process_control_request(enc_softc_t *enc, struct
 		if (idx == SES_SETSTATUS_ENC_IDX)
 			type = -1;
 		else
-			type = enc->enc_cache.elm_map[idx].enctype;
+			type = enc->enc_cache.elm_map[idx].elm_type;
 		if (type == ELMTYP_DEVICE || type == ELMTYP_ARRAY_DEV)
 			enc_update_request(enc, SAFTE_UPDATE_READSLOTSTATUS);
 		else

Modified: head/sys/cam/scsi/scsi_enc_ses.c
==============================================================================
--- head/sys/cam/scsi/scsi_enc_ses.c	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/cam/scsi/scsi_enc_ses.c	Sun Jun 23 19:05:01 2019	(r349321)
@@ -102,6 +102,7 @@ typedef struct ses_addl_status {
 	union {
 		union ses_fcobj_hdr *fc;
 		union ses_elm_sas_hdr *sas;
+		struct ses_elm_ata_hdr *ata;
 	} proto_hdr;
 	union ses_addl_data proto_data;	/* array sizes stored in header */
 } ses_add_status_t;
@@ -825,14 +826,6 @@ ses_devids_iter(enc_softc_t *enc, enc_element_t *elm,
 	elmpriv = elm->elm_private;
 	addl = &(elmpriv->addl);
 
-	/*
-	 * Don't assume this object has additional status information, or
-	 * that it is a SAS device, or that it is a device slot device.
-	 */
-	if (addl->hdr == NULL || addl->proto_hdr.sas == NULL
-	 || addl->proto_data.sasdev_phys == NULL)
-		return;
-
 	devid_record_size = SVPD_DEVICE_ID_DESC_HDR_LEN
 			  + sizeof(struct scsi_vpd_id_naa_ieee_reg);
 	for (i = 0; i < addl->proto_hdr.sas->base_hdr.num_phys; i++) {
@@ -950,11 +943,40 @@ static void
 ses_paths_iter(enc_softc_t *enc, enc_element_t *elm,
 	       ses_path_callback_t *callback, void *callback_arg)
 {
-	ses_path_iter_args_t args;
+	ses_element_t *elmpriv;
+	struct ses_addl_status *addl;
 
-	args.callback     = callback;
-	args.callback_arg = callback_arg;
-	ses_devids_iter(enc, elm, ses_path_iter_devid_callback, &args);
+	elmpriv = elm->elm_private;
+	addl = &(elmpriv->addl);
+
+	if (addl->hdr == NULL)
+		return;
+
+	if (addl->proto_hdr.sas != NULL &&
+	    addl->proto_data.sasdev_phys != NULL) {
+		ses_path_iter_args_t args;
+
+		args.callback     = callback;
+		args.callback_arg = callback_arg;
+		ses_devids_iter(enc, elm, ses_path_iter_devid_callback, &args);
+	} else if (addl->proto_hdr.ata != NULL) {
+		struct cam_path *path;
+		struct ccb_getdev cgd;
+
+		if (xpt_create_path(&path, /*periph*/NULL,
+		    scsi_4btoul(addl->proto_hdr.ata->bus),
+		    scsi_4btoul(addl->proto_hdr.ata->target), 0)
+		     != CAM_REQ_CMP)
+			return;
+
+		xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL);
+		cgd.ccb_h.func_code = XPT_GDEV_TYPE;
+		xpt_action((union ccb *)&cgd);
+		if (cgd.ccb_h.status == CAM_REQ_CMP)
+			callback(enc, elm, path, callback_arg);
+
+		xpt_free_path(path);
+	}
 }
 
 /**
@@ -1059,6 +1081,10 @@ ses_set_physpath(enc_softc_t *enc, enc_element_t *elm,
 	ret = EIO;
 	devid = NULL;
 
+	elmpriv = elm->elm_private;
+	if (elmpriv->addl.hdr == NULL)
+		goto out;
+
 	/*
 	 * Assemble the components of the physical path starting with
 	 * the device ID of the enclosure itself.
@@ -1091,7 +1117,6 @@ ses_set_physpath(enc_softc_t *enc, enc_element_t *elm,
 	    scsi_8btou64(idd->identifier), iter->type_index,
 	    iter->type_element_index);
 	/* Append the element descriptor if one exists */
-	elmpriv = elm->elm_private;
 	if (elmpriv->descr != NULL && elmpriv->descr_len > 0) {
 		sbuf_cat(&sb, "/elmdesc@");
 		for (i = 0, c = elmpriv->descr; i < elmpriv->descr_len;
@@ -1457,9 +1482,10 @@ ses_process_config(enc_softc_t *enc, struct enc_fsm_st
 		    iter.global_element_index, iter.type_index, nelm,
 		    iter.type_element_index);
 		thdr = ses_cache->ses_types[iter.type_index].hdr;
+		element->elm_idx = iter.global_element_index;
+		element->elm_type = thdr->etype_elm_type;
 		element->subenclosure = thdr->etype_subenc;
-		element->enctype = thdr->etype_elm_type;
-		element->overall_status_elem = iter.type_element_index == 0;
+		element->type_elm_idx = iter.type_element_index;
 		element->elm_private = malloc(sizeof(ses_element_t),
 		    M_SCSIENC, M_WAITOK|M_ZERO);
 		ENC_DLOG(enc, "%s: creating elmpriv %d(%d,%d) subenc %d "
@@ -1663,6 +1689,8 @@ static int ses_get_elm_addlstatus_fc(enc_softc_t *, en
 				     uint8_t *, int);
 static int ses_get_elm_addlstatus_sas(enc_softc_t *, enc_cache_t *, uint8_t *,
 				      int, int, int, int);
+static int ses_get_elm_addlstatus_ata(enc_softc_t *, enc_cache_t *, uint8_t *,
+				      int, int, int, int);
 
 /**
  * \brief Parse the additional status element data for each object.
@@ -1818,7 +1846,6 @@ badindex:
 			}
 		}
 		elmpriv = element->elm_private;
-		elmpriv->addl.hdr = elm_hdr;
 		ENC_DLOG(enc, "%s: global element index=%d, type index=%d "
 		    "type element index=%d, offset=0x%x, "
 		    "byte0=0x%x, length=0x%x\n", __func__,
@@ -1842,6 +1869,7 @@ badindex:
 			offset += elm_hdr->length;
 			continue;
 		}
+		elmpriv->addl.hdr = elm_hdr;
 
 		/* Advance to the protocol data, skipping eip bytes if needed */
 		offset += (eip * SES_EIP_HDR_EXTRA_LEN);
@@ -1865,6 +1893,13 @@ badindex:
 						   eip, iter.type_index,
 						   iter.global_element_index);
 			break;
+		case SPSP_PROTO_ATA:
+			ses_get_elm_addlstatus_ata(enc, enc_cache,
+						   &buf[offset],
+						   proto_info_len,
+						   eip, iter.type_index,
+						   iter.global_element_index);
+			break;
 		default:
 			ENC_VLOG(enc, "Element %d: Unknown Additional Element "
 			    "Protocol 0x%x\n", iter.global_element_index,
@@ -2193,18 +2228,16 @@ ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_
 }
 
 #define	SES_PRINT_PORTS(p, type) do {					\
-	sbuf_printf(sbp, " %s(", type);					\
-	if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) == 0)			\
-		sbuf_printf(sbp, " None");				\
-	else {								\
+	if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) != 0) {		\
+		sbuf_printf(sbp, " %s (", type);			\
 		if ((p) & SES_SASOBJ_DEV_PHY_SMP)			\
 			sbuf_printf(sbp, " SMP");			\
 		if ((p) & SES_SASOBJ_DEV_PHY_STP)			\
 			sbuf_printf(sbp, " STP");			\
 		if ((p) & SES_SASOBJ_DEV_PHY_SSP)			\
 			sbuf_printf(sbp, " SSP");			\
+		sbuf_printf(sbp, " )");					\
 	}								\
-	sbuf_printf(sbp, " )");						\
 } while(0)
 
 /**
@@ -2214,11 +2247,10 @@ ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_
  * \param sesname	SES device name associated with the object.
  * \param sbp		Sbuf to print to.
  * \param obj		The object to print the data for.
- * \param periph_name	Peripheral string associated with the object.
  */
 static void
 ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp,
-			      enc_element_t *obj, char *periph_name)
+			      enc_element_t *obj)
 {
 	int i;
 	ses_element_t *elmpriv;
@@ -2227,16 +2259,12 @@ ses_print_addl_data_sas_type0(char *sesname, struct sb
 
 	elmpriv = obj->elm_private;
 	addl = &(elmpriv->addl);
-	if (addl->proto_hdr.sas == NULL)
-		return;
-	sbuf_printf(sbp, "%s: %s: SAS Device Slot Element:",
-	    sesname, periph_name);
-	sbuf_printf(sbp, " %d Phys", addl->proto_hdr.sas->base_hdr.num_phys);
+	sbuf_printf(sbp, ", SAS Slot: %d%s phys",
+	    addl->proto_hdr.sas->base_hdr.num_phys,
+	    ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas) ? "+" : "");
 	if (ses_elm_addlstatus_eip(addl->hdr))
-		sbuf_printf(sbp, " at Slot %d",
+		sbuf_printf(sbp, " at slot %d",
 		    addl->proto_hdr.sas->type0_eip.dev_slot_num);
-	if (ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas))
-		sbuf_printf(sbp, ", Not All Phys");
 	sbuf_printf(sbp, "\n");
 	if (addl->proto_data.sasdev_phys == NULL)
 		return;
@@ -2247,9 +2275,8 @@ ses_print_addl_data_sas_type0(char *sesname, struct sb
 			/* Spec says all other fields are specific values */
 			sbuf_printf(sbp, " SATA device\n");
 		else {
-			sbuf_printf(sbp, " SAS device type %d id %d\n",
+			sbuf_printf(sbp, " SAS device type %d phy %d",
 			    ses_elm_sas_dev_phy_dev_type(phy), phy->phy_id);
-			sbuf_printf(sbp, "%s:  phy %d: protocols:", sesname, i);
 			SES_PRINT_PORTS(phy->initiator_ports, "Initiator");
 			SES_PRINT_PORTS(phy->target_ports, "Target");
 			sbuf_printf(sbp, "\n");
@@ -2263,32 +2290,16 @@ ses_print_addl_data_sas_type0(char *sesname, struct sb
 #undef SES_PRINT_PORTS
 
 /**
- * \brief Report whether a given enclosure object is an expander.
- *
- * \param enc	SES softc associated with object.
- * \param obj	Enclosure object to report for.
- *
- * \return	1 if true, 0 otherwise.
- */
-static int
-ses_obj_is_expander(enc_softc_t *enc, enc_element_t *obj)
-{
-	return (obj->enctype == ELMTYP_SAS_EXP);
-}
-
-/**
  * \brief Print the additional element status data for this object, for SAS
  *	  type 1 objects.  See SES2 r20 Sections 6.1.13.3.3 and 6.1.13.3.4.
  *
- * \param enc		SES enclosure, needed for type identification.
  * \param sesname	SES device name associated with the object.
  * \param sbp		Sbuf to print to.
  * \param obj		The object to print the data for.
- * \param periph_name	Peripheral string associated with the object.
  */
 static void
-ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname,
-    struct sbuf *sbp, enc_element_t *obj, char *periph_name)
+ses_print_addl_data_sas_type1(char *sesname, struct sbuf *sbp,
+			      enc_element_t *obj)
 {
 	int i, num_phys;
 	ses_element_t *elmpriv;
@@ -2298,12 +2309,10 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *
 
 	elmpriv = obj->elm_private;
 	addl = &(elmpriv->addl);
-	if (addl->proto_hdr.sas == NULL)
-		return;
-	sbuf_printf(sbp, "%s: %s: SAS ", sesname, periph_name);
-	if (ses_obj_is_expander(enc, obj)) {
+	sbuf_printf(sbp, ", SAS ");
+	if (obj->elm_type == ELMTYP_SAS_EXP) {
 		num_phys = addl->proto_hdr.sas->base_hdr.num_phys;
-		sbuf_printf(sbp, "Expander: %d Phys", num_phys);
+		sbuf_printf(sbp, "Expander: %d phys", num_phys);
 		if (addl->proto_data.sasexp_phys == NULL)
 			return;
 		for (i = 0;i < num_phys;i++) {
@@ -2314,7 +2323,7 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *
 		}
 	} else {
 		num_phys = addl->proto_hdr.sas->base_hdr.num_phys;
-		sbuf_printf(sbp, "Port: %d Phys", num_phys);
+		sbuf_printf(sbp, "Port: %d phys", num_phys);
 		if (addl->proto_data.sasport_phys == NULL)
 			return;
 		for (i = 0;i < num_phys;i++) {
@@ -2330,6 +2339,24 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *
 }
 
 /**
+ * \brief Print the additional element status data for this object, for
+ *	  ATA objects.
+ *
+ * \param sbp		Sbuf to print to.
+ * \param obj		The object to print the data for.
+ */
+static void
+ses_print_addl_data_ata(struct sbuf *sbp, enc_element_t *obj)
+{
+	ses_element_t *elmpriv = obj->elm_private;
+	struct ses_addl_status *addl = &elmpriv->addl;
+	struct ses_elm_ata_hdr *ata = addl->proto_hdr.ata;
+
+	sbuf_printf(sbp, ", SATA Slot: scbus%d target %d\n",
+	    scsi_4btoul(ata->bus), scsi_4btoul(ata->target));
+}
+
+/**
  * \brief Print the additional element status data for this object.
  *
  * \param enc		SES softc associated with the object.
@@ -2360,27 +2387,45 @@ ses_print_addl_data(enc_softc_t *enc, enc_element_t *o
 	sbuf_printf(&sesname, "%s%d", enc->periph->periph_name,
 	    enc->periph->unit_number);
 	sbuf_finish(&sesname);
+	sbuf_printf(&out, "%s: %s in ", sbuf_data(&sesname), sbuf_data(&name));
 	if (elmpriv->descr != NULL)
-		sbuf_printf(&out, "%s: %s: Element descriptor: '%s'\n",
-		    sbuf_data(&sesname), sbuf_data(&name), elmpriv->descr);
+		sbuf_printf(&out, "'%s'", elmpriv->descr);
+	else {
+		if (obj->elm_type <= ELMTYP_LAST)
+			sbuf_cat(&out, elm_type_names[obj->elm_type]);
+		else
+			sbuf_printf(&out, "<Type 0x%02x>", obj->elm_type);
+		sbuf_printf(&out, " %d", obj->type_elm_idx);
+		if (obj->subenclosure != 0)
+			sbuf_printf(&out, " of subenc %d", obj->subenclosure);
+	}
 	switch(ses_elm_addlstatus_proto(addl->hdr)) {
+	case SPSP_PROTO_FC:
+		goto noaddl;	/* stubbed for now */
 	case SPSP_PROTO_SAS:
+		if (addl->proto_hdr.sas == NULL)
+			goto noaddl;
 		switch(ses_elm_sas_descr_type(addl->proto_hdr.sas)) {
 		case SES_SASOBJ_TYPE_SLOT:
 			ses_print_addl_data_sas_type0(sbuf_data(&sesname),
-			    &out, obj, sbuf_data(&name));
+			    &out, obj);
 			break;
 		case SES_SASOBJ_TYPE_OTHER:
-			ses_print_addl_data_sas_type1(enc, sbuf_data(&sesname),
-			    &out, obj, sbuf_data(&name));
+			ses_print_addl_data_sas_type1(sbuf_data(&sesname),
+			    &out, obj);
 			break;
 		default:
-			break;
+			goto noaddl;
 		}
 		break;
-	case SPSP_PROTO_FC:	/* stubbed for now */
+	case SPSP_PROTO_ATA:
+		if (addl->proto_hdr.ata == NULL)
+			goto noaddl;
+		ses_print_addl_data_ata(&out, obj);
 		break;
 	default:
+noaddl:
+		sbuf_cat(&out, "\n");
 		break;
 	}
 	sbuf_finish(&out);
@@ -2485,7 +2530,7 @@ ses_get_elm_addlstatus_sas_type1(enc_softc_t *enc, enc
 		goto out;
 
 	/* Process expanders differently from other type1 cases */
-	if (ses_obj_is_expander(enc, obj)) {
+	if (obj->elm_type == ELMTYP_SAS_EXP) {
 		offset += sizeof(struct ses_elm_sas_type1_expander_hdr);
 		physz = addl->proto_hdr.sas->base_hdr.num_phys *
 		    sizeof(struct ses_elm_sas_expander_phy);
@@ -2588,6 +2633,53 @@ ses_get_elm_addlstatus_sas(enc_softc_t *enc, enc_cache
 		err = ENODEV;
 		break;
 	}
+
+out:
+	return (err);
+}
+
+/**
+ * \brief Update the softc with the additional element status data for this
+ * 	  object, for ATA objects.
+ *
+ * \param enc		SES softc to be updated.
+ * \param buf		The additional element status response buffer.
+ * \param bufsiz	Size of the response buffer.
+ * \param eip		The EIP bit value.
+ * \param tidx		Type index for this object.
+ * \param nobj		Number of objects attached to the SES softc.
+ * 
+ * \return		0 on success, errno otherwise.
+ */
+static int
+ses_get_elm_addlstatus_ata(enc_softc_t *enc, enc_cache_t *enc_cache,
+			   uint8_t *buf, int bufsiz, int eip, int tidx,
+			   int nobj)
+{
+	int err;
+	ses_cache_t *ses_cache;
+
+	if (bufsiz < sizeof(struct ses_elm_ata_hdr)) {
+		err = EIO;
+		goto out;
+	}
+
+	ses_cache = enc_cache->private;
+	switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) {
+	case ELMTYP_DEVICE:
+	case ELMTYP_ARRAY_DEV:
+		break;
+	default:
+		ENC_VLOG(enc, "Element %d has Additional Status, "
+		    "invalid for SES element type 0x%x\n", nobj,
+		    ses_cache->ses_types[tidx].hdr->etype_elm_type);
+		err = ENODEV;
+		goto out;
+	}
+
+	((ses_element_t *)enc_cache->elm_map[nobj].elm_private)
+	    ->addl.proto_hdr.ata = (struct ses_elm_ata_hdr *)buf;
+	err = 0;
 
 out:
 	return (err);

Modified: head/sys/cam/scsi/scsi_ses.h
==============================================================================
--- head/sys/cam/scsi/scsi_ses.h	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/cam/scsi/scsi_ses.h	Sun Jun 23 19:05:01 2019	(r349321)
@@ -2181,15 +2181,27 @@ struct ses_status_page_hdr {
 #define	SESCTL_DISABLE		0x20
 #define	SESCTL_RSTSWAP		0x10
 
-
-/* Control bits, Device Elements, byte 2 */
-#define	SESCTL_DRVLCK	0x40	/* "DO NOT REMOVE" */
+/* Control bits, Array Device Slot Elements, byte 1 */
+#define	SESCTL_RQSOK	0x80	/* RQST OK */
+#define	SESCTL_RQSRSV	0x40	/* RQST RSVD DEVICE */
+#define	SESCTL_RQSSPR	0x20	/* RQST HOT SPARE */
+#define	SESCTL_RQSCCH	0x10	/* RQST CONS CHECK */
+#define	SESCTL_RQSCRA	0x08	/* RQST IN CRIT ARRAY */
+#define	SESCTL_RQSFAA	0x04	/* RQST IN FAILED ARRAY */
+#define	SESCTL_RQSRR	0x02	/* RQST REBUI/REMAP */
+#define	SESCTL_RQSRRA	0x01	/* RQST R/R ABORT */
+/* Control bits, [Array] Device Slot Elements, byte 2 */
+#define	SESCTL_RQSACT	0x80	/* RQST ACTIVE */
+#define	SESCTL_DRVLCK	0x40	/* DO NOT REMOVE */
+#define	SESCTL_RQSMSN	0x10	/* RQST MISSING */
 #define	SESCTL_RQSINS	0x08	/* RQST INSERT */
 #define	SESCTL_RQSRMV	0x04	/* RQST REMOVE */
 #define	SESCTL_RQSID	0x02	/* RQST IDENT */
-/* Control bits, Device Elements, byte 3 */
+/* Control bits, [Array] Device Slot Elements, byte 3 */
 #define	SESCTL_RQSFLT	0x20	/* RQST FAULT */
 #define	SESCTL_DEVOFF	0x10	/* DEVICE OFF */
+#define	SESCTL_ENBYPA	0x08	/* ENABLE BYP A */
+#define	SESCTL_ENBYPB	0x04	/* ENABLE BYP B */
 
 /* Control bits, Generic, byte 3 */
 #define	SESCTL_RQSTFAIL	0x40
@@ -2398,6 +2410,17 @@ union ses_elm_sas_hdr {
 };
 int ses_elm_sas_type0_not_all_phys(union ses_elm_sas_hdr *);
 int ses_elm_sas_descr_type(union ses_elm_sas_hdr *);
+
+/*
+ * This structure for SPSP_PROTO_ATA is not defined by SES specs,
+ * but purely my own design to make AHCI EM interoperate with SES.
+ * Since no other software I know can talk to SEMB, and we do not
+ * expose this this outside, it should be safe to do what we want.
+ */
+struct ses_elm_ata_hdr {
+	uint8_t bus[4];
+	uint8_t target[4];
+};
 
 struct ses_elm_addlstatus_base_hdr {
 	uint8_t byte0;

Modified: head/sys/dev/ahci/ahci.c
==============================================================================
--- head/sys/dev/ahci/ahci.c	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/dev/ahci/ahci.c	Sun Jun 23 19:05:01 2019	(r349321)
@@ -186,6 +186,7 @@ ahci_attach(device_t dev)
 	ctlr->ccc = 0;
 	resource_int_value(device_get_name(dev),
 	    device_get_unit(dev), "ccc", &ctlr->ccc);
+	mtx_init(&ctlr->ch_mtx, "AHCI channels lock", NULL, MTX_DEF);
 
 	/* Setup our own memory management for channels. */
 	ctlr->sc_iomem.rm_start = rman_get_start(ctlr->r_mem);
@@ -379,6 +380,7 @@ ahci_detach(device_t dev)
 	/* Free memory. */
 	rman_fini(&ctlr->sc_iomem);
 	ahci_free_mem(dev);
+	mtx_destroy(&ctlr->ch_mtx);
 	return (0);
 }
 
@@ -666,6 +668,50 @@ ahci_get_dma_tag(device_t dev, device_t child)
 	return (ctlr->dma_tag);
 }
 
+void
+ahci_attached(device_t dev, struct ahci_channel *ch)
+{
+	struct ahci_controller *ctlr = device_get_softc(dev);
+
+	mtx_lock(&ctlr->ch_mtx);
+	ctlr->ch[ch->unit] = ch;
+	mtx_unlock(&ctlr->ch_mtx);
+}
+
+void
+ahci_detached(device_t dev, struct ahci_channel *ch)
+{
+	struct ahci_controller *ctlr = device_get_softc(dev);
+
+	mtx_lock(&ctlr->ch_mtx);
+	mtx_lock(&ch->mtx);
+	ctlr->ch[ch->unit] = NULL;
+	mtx_unlock(&ch->mtx);
+	mtx_unlock(&ctlr->ch_mtx);
+}
+
+struct ahci_channel *
+ahci_getch(device_t dev, int n)
+{
+	struct ahci_controller *ctlr = device_get_softc(dev);
+	struct ahci_channel *ch;
+
+	KASSERT(n >= 0 && n < AHCI_MAX_PORTS, ("Bad channel number %d", n));
+	mtx_lock(&ctlr->ch_mtx);
+	ch = ctlr->ch[n];
+	if (ch != NULL)
+		mtx_lock(&ch->mtx);
+	mtx_unlock(&ctlr->ch_mtx);
+	return (ch);
+}
+
+void
+ahci_putch(struct ahci_channel *ch)
+{
+
+	mtx_unlock(&ch->mtx);
+}
+
 static int
 ahci_ch_probe(device_t dev)
 {
@@ -824,6 +870,7 @@ ahci_ch_attach(device_t dev)
 		    ahci_ch_pm, ch);
 	}
 	mtx_unlock(&ch->mtx);
+	ahci_attached(device_get_parent(dev), ch);
 	ctx = device_get_sysctl_ctx(dev);
 	tree = device_get_sysctl_tree(dev);
 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "disable_phy",
@@ -849,6 +896,7 @@ ahci_ch_detach(device_t dev)
 {
 	struct ahci_channel *ch = device_get_softc(dev);
 
+	ahci_detached(device_get_parent(dev), ch);
 	mtx_lock(&ch->mtx);
 	xpt_async(AC_LOST_DEVICE, ch->path, NULL);
 	/* Forget about reset. */

Modified: head/sys/dev/ahci/ahci.h
==============================================================================
--- head/sys/dev/ahci/ahci.h	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/dev/ahci/ahci.h	Sun Jun 23 19:05:01 2019	(r349321)
@@ -524,6 +524,8 @@ struct ahci_controller {
 	} interrupt[AHCI_MAX_PORTS];
 	void			(*ch_start)(struct ahci_channel *);
 	int			dma_coherent;	/* DMA is cache-coherent */
+	struct mtx		ch_mtx;		/* Lock for attached channels */
+	struct ahci_channel	*ch[AHCI_MAX_PORTS];	/* Attached channels */
 };
 
 enum ahci_err_type {
@@ -653,6 +655,12 @@ bus_dma_tag_t ahci_get_dma_tag(device_t dev, device_t 
 int ahci_ctlr_reset(device_t dev);
 int ahci_ctlr_setup(device_t dev);
 void ahci_free_mem(device_t dev);
+
+/* Functions to allow AHCI EM to access other channels. */
+void ahci_attached(device_t dev, struct ahci_channel *ch);
+void ahci_detached(device_t dev, struct ahci_channel *ch);
+struct ahci_channel * ahci_getch(device_t dev, int n);
+void ahci_putch(struct ahci_channel *ch);
 
 extern devclass_t ahci_devclass;
 

Modified: head/sys/dev/ahci/ahciem.c
==============================================================================
--- head/sys/dev/ahci/ahciem.c	Sun Jun 23 18:35:11 2019	(r349320)
+++ head/sys/dev/ahci/ahciem.c	Sun Jun 23 19:05:01 2019	(r349321)
@@ -294,14 +294,14 @@ ahci_em_setleds(device_t dev, int c)
 	enc = device_get_softc(dev);
 
 	val = 0;
-	if (enc->status[c][2] & 0x80)		/* Activity */
+	if (enc->status[c][2] & SESCTL_RQSACT)		/* Activity */
 		val |= (1 << 0);
-	if (enc->status[c][2] & SESCTL_RQSID)	/* Identification */
+	if (enc->status[c][1] & SESCTL_RQSRR)		/* Rebuild */
+		val |= (1 << 6) | (1 << 3);
+	else if (enc->status[c][2] & SESCTL_RQSID)	/* Identification */
 		val |= (1 << 3);
 	else if (enc->status[c][3] & SESCTL_RQSFLT)	/* Fault */
 		val |= (1 << 6);
-	else if (enc->status[c][1] & 0x02)		/* Rebuild */
-		val |= (1 << 6) | (1 << 3);
 
 	timeout = 10000;
 	while (ATA_INL(enc->r_memc, 0) & (AHCI_EM_TM | AHCI_EM_RST) &&
@@ -366,9 +366,12 @@ static void
 ahci_em_emulate_ses_on_led(device_t dev, union ccb *ccb)
 {
 	struct ahci_enclosure *enc;
+	struct ahci_channel *ch;
 	struct ses_status_page *page;
 	struct ses_status_array_dev_slot *ads, *ads0;
 	struct ses_elm_desc_hdr *elmd;
+	struct ses_elm_addlstatus_eip_hdr *elma;
+	struct ses_elm_ata_hdr *elmb;
 	uint8_t *buf;
 	int i;
 
@@ -391,7 +394,7 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *cc
 		strncpy(&buf[3], device_get_nameunit(dev), 7);
 		strncpy(&buf[10], "AHCI    ", SID_VENDOR_SIZE);
 		strncpy(&buf[18], "SGPIO Enclosure ", SID_PRODUCT_SIZE);
-		strncpy(&buf[34], "1.00", SID_REVISION_SIZE);
+		strncpy(&buf[34], "2.00", SID_REVISION_SIZE);
 		strncpy(&buf[39], "0001", 4);
 		strncpy(&buf[43], "S-E-S ", 6);
 		strncpy(&buf[49], "2.00", 4);
@@ -403,14 +406,15 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *cc
 	page = (struct ses_status_page *)buf;
 	if (ccb->ataio.cmd.lba_low == 0x02 &&
 	    ccb->ataio.cmd.features == 0x00 &&
-	    ccb->ataio.cmd.sector_count >= 2) {
+	    ccb->ataio.cmd.sector_count >= 3) {
 		bzero(buf, ccb->ataio.dxfer_len);
 		page->hdr.page_code = 0;
-		scsi_ulto2b(4, page->hdr.length);
-		buf[4] = 0;
-		buf[5] = 1;
-		buf[6] = 2;
-		buf[7] = 7;
+		scsi_ulto2b(5, page->hdr.length);
+		buf[4] = 0x00;
+		buf[5] = 0x01;
+		buf[6] = 0x02;
+		buf[7] = 0x07;
+		buf[8] = 0x0a;
 		ccb->ccb_h.status = CAM_REQ_CMP;
 		goto out;
 	}
@@ -418,26 +422,30 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *cc
 	/* SEMB RECEIVE DIAGNOSTIC RESULT (1) */
 	if (ccb->ataio.cmd.lba_low == 0x02 &&
 	    ccb->ataio.cmd.features == 0x01 &&
-	    ccb->ataio.cmd.sector_count >= 13) {
+	    ccb->ataio.cmd.sector_count >= 16) {
 		struct ses_enc_desc *ed;
 		struct ses_elm_type_desc *td;
 
 		bzero(buf, ccb->ataio.dxfer_len);
 		page->hdr.page_code = 0x01;
-		scsi_ulto2b(4 + 4 + 36 + 4, page->hdr.length);
+		scsi_ulto2b(4 + sizeof(*ed) + sizeof(*td) + 11,
+		    page->hdr.length);
 		ed = (struct ses_enc_desc *)&buf[8];
 		ed->byte0 = 0x11;
 		ed->subenc_id = 0;
 		ed->num_types = 1;
 		ed->length = 36;
+		ed->logical_id[0] = 0x30;	/* NAA Locally Assigned. */
+		strncpy(&ed->logical_id[1], device_get_nameunit(dev), 7);
 		strncpy(ed->vendor_id, "AHCI    ", SID_VENDOR_SIZE);
 		strncpy(ed->product_id, "SGPIO Enclosure ", SID_PRODUCT_SIZE);
-		strncpy(ed->product_rev, "    ", SID_REVISION_SIZE);
+		strncpy(ed->product_rev, "2.00", SID_REVISION_SIZE);
 		td = (struct ses_elm_type_desc *)ses_enc_desc_next(ed);
 		td->etype_elm_type = 0x17;
 		td->etype_maxelt = enc->channels;
 		td->etype_subenc = 0;
-		td->etype_txt_len = 0;
+		td->etype_txt_len = 11;
+		snprintf((char *)(td + 1), 12, "Drive Slots");
 		ccb->ccb_h.status = CAM_REQ_CMP;
 		goto out;
 	}
@@ -453,10 +461,22 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *cc
 		for (i = 0; i < enc->channels; i++) {
 			ads = &page->elements[i + 1].array_dev_slot;
 			memcpy(ads, enc->status[i], 4);
-			ads->common.bytes[0] |=
-			    (enc->ichannels & (1 << i)) ?
-			     SES_OBJSTAT_UNKNOWN :
-			     SES_OBJSTAT_NOTINSTALLED;
+			ch = ahci_getch(device_get_parent(dev), i);
+			if (ch == NULL) {
+				ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN;
+				continue;
+			}
+			if (ch->pm_present)
+				ads->common.bytes[0] |= SES_OBJSTAT_UNKNOWN;
+			else if (ch->devices)
+				ads->common.bytes[0] |= SES_OBJSTAT_OK;
+			else if (ch->disablephy)
+				ads->common.bytes[0] |= SES_OBJSTAT_NOTAVAIL;
+			else
+				ads->common.bytes[0] |= SES_OBJSTAT_NOTINSTALLED;
+			if (ch->disablephy)
+				ads->common.bytes[3] |= SESCTL_DEVOFF;
+			ahci_putch(ch);
 		}
 		ccb->ccb_h.status = CAM_REQ_CMP;
 		goto out;
@@ -471,21 +491,21 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *cc
 			ads = &page->elements[i + 1].array_dev_slot;
 			if (ads->common.bytes[0] & SESCTL_CSEL) {
 				enc->status[i][0] = 0;
-				enc->status[i][1] = 
-				    ads->bytes[0] & 0x02;
-				enc->status[i][2] =
-				    ads->bytes[1] & (0x80 | SESCTL_RQSID);
-				enc->status[i][3] =
-				    ads->bytes[2] & SESCTL_RQSFLT;
+				enc->status[i][1] = ads->bytes[0] &
+				    SESCTL_RQSRR;
+				enc->status[i][2] = ads->bytes[1] &
+				    (SESCTL_RQSACT | SESCTL_RQSID);
+				enc->status[i][3] = ads->bytes[2] &
+				    SESCTL_RQSFLT;
 				ahci_em_setleds(dev, i);
 			} else if (ads0->common.bytes[0] & SESCTL_CSEL) {
 				enc->status[i][0] = 0;
-				enc->status[i][1] = 
-				    ads0->bytes[0] & 0x02;
-				enc->status[i][2] =
-				    ads0->bytes[1] & (0x80 | SESCTL_RQSID);
-				enc->status[i][3] =
-				    ads0->bytes[2] & SESCTL_RQSFLT;
+				enc->status[i][1] = ads0->bytes[0] &
+				    SESCTL_RQSRR;
+				enc->status[i][2] = ads0->bytes[1] &
+				    (SESCTL_RQSACT | SESCTL_RQSID);
+				enc->status[i][3] = ads0->bytes[2] &
+				    SESCTL_RQSFLT;
 				ahci_em_setleds(dev, i);
 			}
 		}
@@ -496,15 +516,48 @@ ahci_em_emulate_ses_on_led(device_t dev, union ccb *cc
 	/* SEMB RECEIVE DIAGNOSTIC RESULT (7) */
 	if (ccb->ataio.cmd.lba_low == 0x02 &&
 	    ccb->ataio.cmd.features == 0x07 &&
-	    ccb->ataio.cmd.sector_count >= (3 + 3 * enc->channels)) {
+	    ccb->ataio.cmd.sector_count >= (6 + 3 * enc->channels)) {
 		bzero(buf, ccb->ataio.dxfer_len);
 		page->hdr.page_code = 0x07;
-		scsi_ulto2b(4 + 4 + 12 * enc->channels,
+		scsi_ulto2b(4 + 15 + 11 * enc->channels, page->hdr.length);
+		elmd = (struct ses_elm_desc_hdr *)&buf[8];
+		scsi_ulto2b(11, elmd->length);
+		snprintf((char *)(elmd + 1), 12, "Drive Slots");
+		for (i = 0; i < enc->channels; i++) {
+			elmd = (struct ses_elm_desc_hdr *)&buf[8 + 15 + 11 * i];
+			scsi_ulto2b(7, elmd->length);
+			snprintf((char *)(elmd + 1), 8, "Slot %02d", i);
+		}
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		goto out;
+	}
+
+	/* SEMB RECEIVE DIAGNOSTIC RESULT (a) */
+	if (ccb->ataio.cmd.lba_low == 0x02 &&
+	    ccb->ataio.cmd.features == 0x0a &&
+	    ccb->ataio.cmd.sector_count >= (2 + 3 * enc->channels)) {
+		bzero(buf, ccb->ataio.dxfer_len);
+		page->hdr.page_code = 0x0a;
+		scsi_ulto2b(4 + (sizeof(*elma) + sizeof(*elmb)) * enc->channels,
 		    page->hdr.length);
 		for (i = 0; i < enc->channels; i++) {
-			elmd = (struct ses_elm_desc_hdr *)&buf[8 + 4 + 12 * i];
-			scsi_ulto2b(8, elmd->length);
-			snprintf((char *)(elmd + 1), 9, "SLOT %03d", i);
+			elma = (struct ses_elm_addlstatus_eip_hdr *)&buf[
+			    8 + (sizeof(*elma) + sizeof(*elmb)) * i];
+			elma->base.byte0 = 0x10 | SPSP_PROTO_ATA;
+			elma->base.length = 2 + sizeof(*elmb);
+			elma->byte2 = 0x01;
+			elma->element_index = 1 + i;
+			ch = ahci_getch(device_get_parent(dev), i);
+			if (ch == NULL) {
+				elma->base.byte0 |= 0x80;
+				continue;
+			}
+			if (ch->devices == 0 || ch->pm_present)
+				elma->base.byte0 |= 0x80;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201906231905.x5NJ51Fl054396>