The tran_getcap(9E) entry point for a SCSI HBA driver is called when a target driver calls scsi_ifgetcap(9F) to determine the current value of one of a set of SCSA-defined capabilities.
The target driver can request the current setting of the capability for a particular target by setting the whom parameter to nonzero. A whom value of 0 means the request is for the current setting of the capability for the SCSI bus or for adapter hardware in general.
tran_getcap() should return -1 for undefined capabilities or the current value of the requested capability.
The HBA driver can use the function scsi_hba_lookup_capstr(9F) to compare the capability string against the canonical set of defined capabilities.
static int
isp_scsi_getcap(
struct scsi_address *ap,
char *cap,
int whom)
{
struct isp *isp;
int rval = 0;
u_char tgt = ap->a_target;
/*
* We don't allow getting capabilities for other targets
*/
if (cap == NULL || whom == 0) {
return (-1);
}
isp = (struct isp *)ap->a_hba_tran->tran_hba_private;
ISP_MUTEX_ENTER(isp);
switch (scsi_hba_lookup_capstr(cap)) {
case SCSI_CAP_DMA_MAX:
rval = 1 << 24; /* Limit to 16MB max transfer */
break;
case SCSI_CAP_MSG_OUT:
rval = 1;
break;
case SCSI_CAP_DISCONNECT:
if ((isp->isp_target_scsi_options[tgt] &
SCSI_OPTIONS_DR) == 0) {
break;
} else if (
(isp->isp_cap[tgt] & ISP_CAP_DISCONNECT) == 0) {
break;
}
rval = 1;
break;
case SCSI_CAP_SYNCHRONOUS:
if ((isp->isp_target_scsi_options[tgt] &
SCSI_OPTIONS_SYNC) == 0) {
break;
} else if (
(isp->isp_cap[tgt] & ISP_CAP_SYNC) == 0) {
break;
}
rval = 1;
break;
case SCSI_CAP_WIDE_XFER:
if ((isp->isp_target_scsi_options[tgt] &
SCSI_OPTIONS_WIDE) == 0) {
break;
} else if (
(isp->isp_cap[tgt] & ISP_CAP_WIDE) == 0) {
break;
}
rval = 1;
break;
case SCSI_CAP_TAGGED_QING:
if ((isp->isp_target_scsi_options[tgt] &
SCSI_OPTIONS_DR) == 0 ||
(isp->isp_target_scsi_options[tgt] &
SCSI_OPTIONS_TAG) == 0) {
break;
} else if (
(isp->isp_cap[tgt] & ISP_CAP_TAG) == 0) {
break;
}
rval = 1;
break;
case SCSI_CAP_UNTAGGED_QING:
rval = 1;
break;
case SCSI_CAP_PARITY:
if (isp->isp_target_scsi_options[tgt] &
SCSI_OPTIONS_PARITY) {
rval = 1;
}
break;
case SCSI_CAP_INITIATOR_ID:
rval = isp->isp_initiator_id;
break;
case SCSI_CAP_ARQ:
if (isp->isp_cap[tgt] & ISP_CAP_AUTOSENSE) {
rval = 1;
}
break;
case SCSI_CAP_LINKED_CMDS:
break;
case SCSI_CAP_RESET_NOTIFICATION:
rval = 1;
break;
case SCSI_CAP_GEOMETRY:
rval = (64 << 16) | 32;
break;
default:
rval = -1;
break;
}
ISP_MUTEX_EXIT(isp);
return (rval);
}