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 ***
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to