SCSI HBA 驱动程序的 tran_setcap(9E) 入口点通过 scsi_ifsetcap(9F) 进行调用。目标驱动程序调用 scsi_ifsetcap() 可更改 SCSA 定义的一组功能中其中一个的当前值。
目标驱动程序可能会通过将 whom 参数设置为非零值来请求为特定目标设置新值。whom 值为零通常表明请求为 SCSI 总线或适配器硬件设置新值。
tran_setcap() 应相应地返回以下值:
-1,如果功能未定义
0,如果 HBA 驱动程序无法将功能设置为请求值
1,如果 HBA 驱动程序可以将功能设置为请求值
HBA 驱动程序可以使用函数 scsi_hba_lookup_capstr(9F) 来比较功能字符串和已定义功能的标准集。
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 through
* 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);
}