Index: sbin/camcontrol/camcontrol.c =================================================================== --- sbin/camcontrol/camcontrol.c (revision 222339) +++ sbin/camcontrol/camcontrol.c (working copy) @@ -456,7 +456,7 @@ case DEV_MATCH_DEVICE: { struct device_match_result *dev_result; char vendor[16], product[48], revision[16]; - char tmpstr[256]; + char fw[5], tmpstr[256]; dev_result = &ccb.cdm.matches[i].result.device_result; @@ -495,6 +495,21 @@ sizeof(revision)); sprintf(tmpstr, "<%s %s>", product, revision); + } else if (dev_result->protocol == PROTO_SEMB) { + cam_strvis(vendor, + ((uint8_t *)&dev_result->ident_data) + 10, + 8, sizeof(vendor)); + cam_strvis(product, + ((uint8_t *)&dev_result->ident_data) + 18, + 16, sizeof(product)); + cam_strvis(revision, + ((uint8_t *)&dev_result->ident_data) + 34, + 4, sizeof(revision)); + cam_strvis(fw, + ((uint8_t *)&dev_result->ident_data) + 39, + 4, sizeof(fw)); + sprintf(tmpstr, "<%s %s %s %s>", + vendor, product, revision, fw); } else { sprintf(tmpstr, "<>"); } Index: sys/cam/cam_ccb.h =================================================================== --- sys/cam/cam_ccb.h (revision 222339) +++ sys/cam/cam_ccb.h (working copy) @@ -242,6 +242,7 @@ PROTO_ATA, /* AT Attachment */ PROTO_ATAPI, /* AT Attachment Packetized Interface */ PROTO_SATAPM, /* SATA Port Multiplier */ + PROTO_SEMB, /* SATA Enclosure Management Bridge */ } cam_proto; typedef enum { Index: sys/cam/scsi/scsi_ses.c =================================================================== --- sys/cam/scsi/scsi_ses.c (revision 222339) +++ sys/cam/scsi/scsi_ses.c (working copy) @@ -63,7 +63,9 @@ SES_SES, SES_SES_PASSTHROUGH, SES_SEN, - SES_SAFT + SES_SAFT, + SES_SEMB_SES, + SES_SEMB_SAFT } enctyp; struct ses_softc; @@ -92,6 +94,7 @@ #define SEN_ID_LEN 24 +static enctyp semb_type(void *, int); static enctyp ses_type(void *, int); @@ -251,25 +254,35 @@ break; } - if (cgd->protocol != PROTO_SCSI) - break; + if (cgd->protocol == PROTO_SCSI) { + inq_len = cgd->inq_data.additional_length + 4; - inq_len = cgd->inq_data.additional_length + 4; + /* + * PROBLEM: WE NEED TO LOOK AT BYTES 48-53 TO SEE + * PROBLEM: IF THIS IS IS A SAF-TE DEVICE. + */ + switch (ses_type(&cgd->inq_data, inq_len)) { + case SES_SES: + case SES_SES_SCSI2: + case SES_SES_PASSTHROUGH: + case SES_SEN: + case SES_SAFT: + break; + default: + return; + } + } else if (cgd->protocol == PROTO_SEMB) { + inq_len = ((uint8_t *)&cgd->ident_data)[0]; - /* - * PROBLEM: WE NEED TO LOOK AT BYTES 48-53 TO SEE IF THIS IS - * PROBLEM: IS A SAF-TE DEVICE. - */ - switch (ses_type(&cgd->inq_data, inq_len)) { - case SES_SES: - case SES_SES_SCSI2: - case SES_SES_PASSTHROUGH: - case SES_SEN: - case SES_SAFT: - break; - default: + switch (semb_type(&cgd->ident_data, inq_len)) { + case SES_SEMB_SES: + case SES_SEMB_SAFT: + break; + default: + return; + } + } else return; - } status = cam_periph_alloc(sesregister, sesoninvalidate, sescleanup, sesstart, "ses", CAM_PERIPH_BIO, @@ -315,12 +328,19 @@ periph->softc = softc; softc->periph = periph; - softc->ses_type = ses_type(&cgd->inq_data, sizeof (cgd->inq_data)); + if (cgd->protocol == PROTO_SCSI) { + softc->ses_type = + ses_type(&cgd->inq_data, sizeof(cgd->inq_data)); + } else { + softc->ses_type = + semb_type(&cgd->ident_data, sizeof(cgd->ident_data)); + } switch (softc->ses_type) { case SES_SES: case SES_SES_SCSI2: - case SES_SES_PASSTHROUGH: + case SES_SES_PASSTHROUGH: + case SES_SEMB_SES: softc->ses_vec.softc_init = ses_softc_init; softc->ses_vec.init_enc = ses_init_enc; softc->ses_vec.get_encstat = ses_get_encstat; @@ -328,7 +348,8 @@ softc->ses_vec.get_objstat = ses_get_objstat; softc->ses_vec.set_objstat = ses_set_objstat; break; - case SES_SAFT: + case SES_SAFT: + case SES_SEMB_SAFT: softc->ses_vec.softc_init = safte_softc_init; softc->ses_vec.init_enc = safte_init_enc; softc->ses_vec.get_encstat = safte_get_encstat; @@ -336,7 +357,7 @@ softc->ses_vec.get_objstat = safte_get_objstat; softc->ses_vec.set_objstat = safte_set_objstat; break; - case SES_SEN: + case SES_SEN: break; case SES_NONE: default: @@ -368,15 +389,21 @@ case SES_SES: tname = "SCSI-3 SES Device"; break; - case SES_SES_PASSTHROUGH: + case SES_SES_PASSTHROUGH: tname = "SES Passthrough Device"; break; - case SES_SEN: + case SES_SEN: tname = "UNISYS SEN Device (NOT HANDLED YET)"; break; - case SES_SAFT: + case SES_SAFT: tname = "SAF-TE Compliant Device"; break; + case SES_SEMB_SES: + tname = "SEMB SES Device"; + break; + case SES_SEMB_SAFT: + tname = "SEMB SAF-TE Device"; + break; } xpt_announce_periph(periph, tname); return (CAM_REQ_CMP); @@ -653,7 +680,7 @@ static int ses_runcmd(struct ses_softc *ssc, char *cdb, int cdbl, char *dptr, int *dlenp) { - int error, dlen; + int error, dlen, tdlen; ccb_flags ddf; union ccb *ccb; @@ -674,9 +701,32 @@ } ccb = cam_periph_getccb(ssc->periph, 1); - cam_fill_csio(&ccb->csio, 0, sesdone, ddf, MSG_SIMPLE_Q_TAG, dptr, - dlen, sizeof (struct scsi_sense_data), cdbl, 60 * 1000); - bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl); + if (ssc->ses_type == SES_SEMB_SES || ssc->ses_type == SES_SEMB_SAFT) { + tdlen = min(dlen, 1020); + tdlen = (tdlen + 3) & ~3; + cam_fill_ataio(&ccb->ataio, 0, sesdone, ddf, 0, dptr, tdlen, + 30 * 1000); + if (cdb[0] == RECEIVE_DIAGNOSTIC) + ata_28bit_cmd(&ccb->ataio, + ATA_SEP_ATTN, cdb[2], 0x02, tdlen / 4); + else if (cdb[0] == SEND_DIAGNOSTIC) + ata_28bit_cmd(&ccb->ataio, + ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0, + 0x82, tdlen / 4); + else if (cdb[0] == READ_BUFFER) + ata_28bit_cmd(&ccb->ataio, + ATA_SEP_ATTN, cdb[2], 0x00, tdlen / 4); + else + ata_28bit_cmd(&ccb->ataio, + ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0, + 0x80, tdlen / 4); + } else { + tdlen = dlen; + cam_fill_csio(&ccb->csio, 0, sesdone, ddf, MSG_SIMPLE_Q_TAG, + dptr, dlen, sizeof (struct scsi_sense_data), cdbl, + 60 * 1000); + bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl); + } error = cam_periph_runccb(ccb, seserror, SES_CFLAGS, SES_FLAGS, NULL); if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) @@ -687,7 +737,11 @@ } } else { if (dptr) { - *dlenp = ccb->csio.resid; + if (ccb->ccb_h.func_code == XPT_ATA_IO) + *dlenp = ccb->ataio.resid; + else + *dlenp = ccb->csio.resid; + *dlenp += tdlen - dlen; } } xpt_release_ccb(ccb); @@ -712,6 +766,25 @@ */ /* + * Identify SES and SAF-TE SEMB devices. + */ + +static enctyp +semb_type(void *buf, int buflen) +{ + char *iqd = buf; + + if (buflen < 49) + return (SES_NONE); + + if (STRNCMP(iqd + 43, "S-E-S", 5) == 0) + return (SES_SEMB_SES); + else if (STRNCMP(iqd + 43, "SAF-TE", 6) == 0) + return (SES_SEMB_SAFT); + return (SES_NONE); +} + +/* * Is this a device that supports enclosure services? * * It's a a pretty simple ruleset- if it is device type 0x0D (13), it's Index: sys/cam/ata/ata_xpt.c =================================================================== --- sys/cam/ata/ata_xpt.c (revision 222339) +++ sys/cam/ata/ata_xpt.c (working copy) @@ -93,6 +93,7 @@ PROBE_FULL_INQUIRY, PROBE_PM_PID, PROBE_PM_PRV, + PROBE_IDENTIFY_SEP, PROBE_INVALID } probe_action; @@ -110,6 +111,7 @@ "PROBE_FULL_INQUIRY", "PROBE_PM_PID", "PROBE_PM_PRV", + "PROBE_IDENTIFY_SEP", "PROBE_INVALID" }; @@ -260,7 +262,8 @@ ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) || - periph->path->device->protocol == PROTO_SATAPM) + periph->path->device->protocol == PROTO_SATAPM || + periph->path->device->protocol == PROTO_SEMB) PROBE_SET_ACTION(softc, PROBE_RESET); else PROBE_SET_ACTION(softc, PROBE_IDENTIFY); @@ -294,7 +297,8 @@ if (softc->restart) { softc->restart = 0; if ((path->device->flags & CAM_DEV_UNCONFIGURED) || - path->device->protocol == PROTO_SATAPM) + path->device->protocol == PROTO_SATAPM || + path->device->protocol == PROTO_SEMB) softc->action = PROBE_RESET; else softc->action = PROBE_IDENTIFY; @@ -609,6 +613,18 @@ 10 * 1000); ata_pm_read_cmd(ataio, 1, 15); break; + case PROBE_IDENTIFY_SEP: + cam_fill_ataio(ataio, + 1, + probedone, + /*flags*/CAM_DIR_IN, + 0, + /*data_ptr*/(u_int8_t *)&softc->ident_data, + /*dxfer_len*/sizeof(softc->ident_data), + 30 * 1000); + ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x02, + sizeof(softc->ident_data) / 4); + break; case PROBE_INVALID: CAM_DEBUG(path, CAM_DEBUG_INFO, ("probestart: invalid action state\n")); @@ -750,7 +766,7 @@ cam_status status; u_int32_t priority; u_int caps; - int found = 1; + int changed = 1, found = 1; CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); @@ -849,6 +865,10 @@ xpt_action((union ccb *)&cts); path->device->protocol = PROTO_SATAPM; PROBE_SET_ACTION(softc, PROBE_PM_PID); + } else if (sign == 0xc33c && + done_ccb->ccb_h.target_id != 15) { + path->device->protocol = PROTO_SEMB; + PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SEP); } else if (sign == 0xeb14 && done_ccb->ccb_h.target_id != 15) { path->device->protocol = PROTO_SCSI; @@ -868,7 +888,6 @@ { struct ccb_pathinq cpi; int16_t *ptr; - int changed = 1; ident_buf = &softc->ident_data; for (ptr = (int16_t *)ident_buf; @@ -1187,6 +1206,47 @@ xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb); } break; + case PROBE_IDENTIFY_SEP: + if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { + /* Check that it is the same device. */ + if (bcmp(&softc->ident_data, ident_buf, 53)) { + /* Device changed. */ + xpt_async(AC_LOST_DEVICE, path, NULL); + } else { + bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params)); + changed = 0; + } + } + if (changed) { + bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params)); + /* Clean up from previous instance of this device */ + if (path->device->serial_num != NULL) { + free(path->device->serial_num, M_CAMXPT); + path->device->serial_num = NULL; + path->device->serial_num_len = 0; + } + path->device->serial_num = + (u_int8_t *)malloc(8 + 1, M_CAMXPT, M_NOWAIT); + if (path->device->serial_num != NULL) { + bcopy(((uint8_t*)ident_buf) + 2, + path->device->serial_num, 8); + path->device->serial_num[8] = '\0'; + path->device->serial_num_len = + strlen(path->device->serial_num); + } + + path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID; + } + + if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { + path->device->flags &= ~CAM_DEV_UNCONFIGURED; + xpt_acquire_device(path->device); + done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action(done_ccb); + xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, + done_ccb); + } + break; case PROBE_INVALID: CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO, ("probedone: invalid action state\n")); Index: sys/cam/ata/ata_pmp.c =================================================================== --- sys/cam/ata/ata_pmp.c (revision 222339) +++ sys/cam/ata/ata_pmp.c (working copy) @@ -586,8 +586,8 @@ /* This PMP declares 6 ports, while only 5 of them are real. * Port 5 is enclosure management bridge port, which has implementation * problems, causing probe faults. Hide it for now. */ - if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) - softc->pm_ports = 5; +// if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) +// softc->pm_ports = 5; /* This PMP declares 7 ports, while only 5 of them are real. * Port 5 is some fake "Config Disk" with 640 sectors size, * port 6 is enclosure management bridge port. Index: sys/cam/ata/ata_all.h =================================================================== --- sys/cam/ata/ata_all.h (revision 222339) +++ sys/cam/ata/ata_all.h (working copy) @@ -93,6 +93,7 @@ int ata_res_sbuf(struct ccb_ataio *ataio, struct sbuf *sb); void ata_print_ident(struct ata_params *ident_data); +void semb_print_ident(struct ata_params *ident_data); uint32_t ata_logical_sector_size(struct ata_params *ident_data); uint64_t ata_physical_sector_size(struct ata_params *ident_data); Index: sys/cam/ata/ata_all.c =================================================================== --- sys/cam/ata/ata_all.c (revision 222339) +++ sys/cam/ata/ata_all.c (working copy) @@ -108,6 +108,7 @@ case 0x51: return ("CONFIGURE_STREAM"); case 0x60: return ("READ_FPDMA_QUEUED"); case 0x61: return ("WRITE_FPDMA_QUEUED"); + case 0x67: return ("SEP_ATTN"); case 0x70: return ("SEEK"); case 0x87: return ("CFA_TRANSLATE_SECTOR"); case 0x90: return ("EXECUTE_DEVICE_DIAGNOSTIC"); @@ -285,6 +286,21 @@ printf(" device\n"); } +void +semb_print_ident(struct ata_params *ident_data) +{ + char vendor[9], product[17], revision[5], fw[5], in[7], ins[5]; + + cam_strvis(vendor, ((uint8_t *)ident_data) + 10, 8, sizeof(vendor)); + cam_strvis(product, ((uint8_t *)ident_data) + 18, 16, sizeof(product)); + cam_strvis(revision, ((uint8_t *)ident_data) + 34, 4, sizeof(revision)); + cam_strvis(fw, ((uint8_t *)ident_data) + 39, 4, sizeof(fw)); + cam_strvis(in, ((uint8_t *)ident_data) + 43, 6, sizeof(in)); + cam_strvis(ins, ((uint8_t *)ident_data) + 49, 4, sizeof(ins)); + printf("<%s %s %s %s> SEMB %s %s device\n", + vendor, product, revision, fw, in, ins); +} + uint32_t ata_logical_sector_size(struct ata_params *ident_data) { Index: sys/cam/cam_xpt.c =================================================================== --- sys/cam/cam_xpt.c (revision 222339) +++ sys/cam/cam_xpt.c (working copy) @@ -1084,6 +1084,8 @@ else if (path->device->protocol == PROTO_ATA || path->device->protocol == PROTO_SATAPM) ata_print_ident(&path->device->ident_data); + else if (path->device->protocol == PROTO_SEMB) + semb_print_ident(&path->device->ident_data); else printf("Unknown protocol device\n"); if (bootverbose && path->device->serial_num_len > 0) { Index: sys/sys/ata.h =================================================================== --- sys/sys/ata.h (revision 222339) +++ sys/sys/ata.h (working copy) @@ -318,6 +318,7 @@ #define ATA_READ_VERIFY48 0x42 #define ATA_READ_FPDMA_QUEUED 0x60 /* read DMA NCQ */ #define ATA_WRITE_FPDMA_QUEUED 0x61 /* write DMA NCQ */ +#define ATA_SEP_ATTN 0x67 /* SEP request */ #define ATA_SEEK 0x70 /* seek */ #define ATA_PACKET_CMD 0xa0 /* packet command */ #define ATA_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/