#include <sys/scsi/adapters/smrt/smrt.h>
#define SMRT_SATA_INQ83_LEN 256
int
smrt_sata_determine_wwn(smrt_t *smrt, PhysDevAddr_t *addr, uint64_t *wwnp,
uint16_t timeout)
{
smrt_command_t *smcm;
int r;
uint8_t *inq;
uint64_t wwn;
size_t resid;
VERIFY3P(wwnp, !=, NULL);
if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
KM_NOSLEEP)) == NULL || smrt_command_attach_internal(smrt, smcm,
SMRT_SATA_INQ83_LEN, KM_NOSLEEP) != 0) {
if (smcm != NULL) {
smrt_command_free(smcm);
}
return (ENOMEM);
}
smcm->smcm_va_cmd->Header.LUN.PhysDev = *addr;
smcm->smcm_va_cmd->Request.CDBLen = CDB_GROUP0;
smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout);
smcm->smcm_va_cmd->Request.CDB[0] = SCMD_INQUIRY;
smcm->smcm_va_cmd->Request.CDB[1] = 1;
smcm->smcm_va_cmd->Request.CDB[2] = 0x83;
smcm->smcm_va_cmd->Request.CDB[3] = (SMRT_SATA_INQ83_LEN & 0xff00) >> 8;
smcm->smcm_va_cmd->Request.CDB[4] = SMRT_SATA_INQ83_LEN & 0x00ff;
smcm->smcm_va_cmd->Request.CDB[5] = 0;
mutex_enter(&smrt->smrt_mutex);
smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
if ((r = smrt_submit(smrt, smcm)) != 0) {
mutex_exit(&smrt->smrt_mutex);
smrt_command_free(smcm);
return (r);
}
if ((r = smrt_poll_for(smrt, smcm)) != 0) {
VERIFY3S(r, ==, ETIMEDOUT);
VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
mutex_exit(&smrt->smrt_mutex);
return (r);
}
if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
mutex_exit(&smrt->smrt_mutex);
smrt_command_free(smcm);
return (EIO);
}
if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
ErrorInfo_t *ei = smcm->smcm_va_err;
if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
dev_err(smrt->smrt_dip, CE_WARN, "physical target "
"SATA WWN error: status 0x%x", ei->CommandStatus);
mutex_exit(&smrt->smrt_mutex);
smrt_command_free(smcm);
return (EIO);
}
resid = ei->ResidualCnt;
} else {
resid = 0;
}
mutex_exit(&smrt->smrt_mutex);
if (SMRT_SATA_INQ83_LEN - resid < 16) {
smrt_command_free(smcm);
return (EINVAL);
}
inq = smcm->smcm_internal->smcmi_va;
if (inq[1] != 0x83) {
smrt_command_free(smcm);
return (EINVAL);
}
if ((inq[5] & 0x30) != 0 || (inq[5] & 0x0f) != 3 || inq[7] != 8) {
smrt_command_free(smcm);
return (ENOTSUP);
}
bcopy(&inq[8], &wwn, sizeof (uint64_t));
*wwnp = BE_64(wwn);
smrt_command_free(smcm);
return (0);
}