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>