tran_setcap() Entry Point
The tran_setcap(9E) entry point for a SCSI HBA driver is called when a target driver calls scsi_ifsetcap(9F) to change the current one of a set of SCSA-defined capabilities.
The target driver might request that the new value be set for a particular target by setting the whom parameter to nonzero. A whom value of 0 means the request is to set the new value for the SCSI bus or for adapter hardware in general.
tran_setcap() should return -1 for undefined capabilities, 0 if the HBA driver cannot set the capability to the requested value, or 1 if the HBA driver is able to set the capability to the requested value.
The HBA driver can use the function scsi_hba_lookup_capstr(9F) to compare the capability string against the canonical set of
defined capabilities.
Example 15-11 HBA Driver tran_setcap(9E) Entry Point
static int
isp_scsi_setcap(
struct scsi_address *ap,
char *cap,
int value,
int whom)
{
struct isp *isp;
int rval = 0;
u_char tgt = ap->a_target;
int update_isp = 0;
/*
* We don't allow setting 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:
case SCSI_CAP_MSG_OUT:
case SCSI_CAP_PARITY:
case SCSI_CAP_UNTAGGED_QING:
case SCSI_CAP_LINKED_CMDS:
case SCSI_CAP_RESET_NOTIFICATION:
/*
* None of these are settable via
* the capability interface.
*/
break;
case SCSI_CAP_DISCONNECT:
if ((isp->isp_target_scsi_options[tgt] &
SCSI_OPTIONS_DR) == 0) {
break;
} else {
if (value) {
isp->isp_cap[tgt] |= ISP_CAP_DISCONNECT;
} else {
isp->isp_cap[tgt] &= ~ISP_CAP_DISCONNECT;
}
}
rval = 1;
break;
case SCSI_CAP_SYNCHRONOUS:
if ((isp->isp_target_scsi_options[tgt] &
SCSI_OPTIONS_SYNC) == 0) {
break;
} else {
if (value) {
isp->isp_cap[tgt] |= ISP_CAP_SYNC;
} else {
isp->isp_cap[tgt] &= ~ISP_CAP_SYNC;
}
}
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 (value) {
isp->isp_cap[tgt] |= ISP_CAP_TAG;
} else {
isp->isp_cap[tgt] &= ~ISP_CAP_TAG;
}
}
rval = 1;
break;
case SCSI_CAP_WIDE_XFER:
if ((isp->isp_target_scsi_options[tgt] &
SCSI_OPTIONS_WIDE) == 0) {
break;
} else {
if (value) {
isp->isp_cap[tgt] |= ISP_CAP_WIDE;
} else {
isp->isp_cap[tgt] &= ~ISP_CAP_WIDE;
}
}
rval = 1;
break;
case SCSI_CAP_INITIATOR_ID:
if (value < N_ISP_TARGETS_WIDE) {
struct isp_mbox_cmd mbox_cmd;
isp->isp_initiator_id = (u_short) value;
/*
* set Initiator SCSI ID
*/
isp_i_mbox_cmd_init(isp, &mbox_cmd, 2, 2,
ISP_MBOX_CMD_SET_SCSI_ID,
isp->isp_initiator_id,
0, 0, 0, 0);
if (isp_i_mbox_cmd_start(isp, &mbox_cmd) == 0) {
rval = 1;
}
}
break;
case SCSI_CAP_ARQ:
if (value) {
isp->isp_cap[tgt] |= ISP_CAP_AUTOSENSE;
} else {
isp->isp_cap[tgt] &= ~ISP_CAP_AUTOSENSE;
}
rval = 1;
break;
default:
rval = -1;
break;
}
ISP_MUTEX_EXIT(isp);
return (rval);
}
|