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
This commit is contained in:
parent
7a29e0bf96
commit
53f5ac1310
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=349321
@ -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;
|
||||
}
|
||||
|
@ -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,11 +243,17 @@ enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
|
||||
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);
|
||||
@ -440,7 +449,7 @@ enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag,
|
||||
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;
|
||||
|
@ -120,10 +120,42 @@ 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 */
|
||||
unsigned int elm_idx;
|
||||
|
@ -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. */
|
||||
|
@ -301,21 +301,21 @@ safte_process_config(enc_softc_t *enc, struct enc_fsm_state *state,
|
||||
* 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_state *state,
|
||||
*/
|
||||
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_fsm_state *state,
|
||||
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_fsm_state *state,
|
||||
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 enc_fsm_state *state,
|
||||
} 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 enc_fsm_state *state,
|
||||
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 enc_fsm_state *state,
|
||||
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
|
||||
|
@ -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_element_t *elmpriv;
|
||||
struct ses_addl_status *addl;
|
||||
|
||||
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_state *state,
|
||||
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 *, enc_cache_t *,
|
||||
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 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state,
|
||||
}
|
||||
}
|
||||
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 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state,
|
||||
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 @@ ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state,
|
||||
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_t *enc_cache,
|
||||
}
|
||||
|
||||
#define SES_PRINT_PORTS(p, type) do { \
|
||||
if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) != 0) { \
|
||||
sbuf_printf(sbp, " %s (", type); \
|
||||
if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) == 0) \
|
||||
sbuf_printf(sbp, " None"); \
|
||||
else { \
|
||||
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, " )"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
@ -2214,11 +2247,10 @@ ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *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 sbuf *sbp,
|
||||
|
||||
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 sbuf *sbp,
|
||||
/* 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");
|
||||
@ -2262,33 +2289,17 @@ ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp,
|
||||
}
|
||||
#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 *sesname,
|
||||
|
||||
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 *sesname,
|
||||
}
|
||||
} 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++) {
|
||||
@ -2329,6 +2338,24 @@ ses_print_addl_data_sas_type1(enc_softc_t *enc, char *sesname,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \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.
|
||||
*
|
||||
@ -2360,27 +2387,45 @@ ses_print_addl_data(enc_softc_t *enc, enc_element_t *obj)
|
||||
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_cache_t *enc_cache,
|
||||
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);
|
||||
@ -2593,6 +2638,53 @@ ses_get_elm_addlstatus_sas(enc_softc_t *enc, enc_cache_t *enc_cache,
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
ses_softc_invalidate(enc_softc_t *enc)
|
||||
{
|
||||
|
@ -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
|
||||
@ -2399,6 +2411,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;
|
||||
/*
|
||||
|
@ -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. */
|
||||
|
@ -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 {
|
||||
@ -654,5 +656,11 @@ 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;
|
||||
|
||||
|
@ -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 *ccb)
|
||||
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 *ccb)
|
||||
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 *ccb)
|
||||
/* 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 *ccb)
|
||||
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 *ccb)
|
||||
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 *ccb)
|
||||
/* 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;
|
||||
elmb = (struct ses_elm_ata_hdr *)(elma + 1);
|
||||
scsi_ulto4b(cam_sim_path(ch->sim), elmb->bus);
|
||||
scsi_ulto4b(0, elmb->target);
|
||||
ahci_putch(ch);
|
||||
}
|
||||
ccb->ccb_h.status = CAM_REQ_CMP;
|
||||
goto out;
|
||||
|
Loading…
Reference in New Issue
Block a user