以降のセクションでは、機能管理について説明します。
SCSI HBA ドライバの tran_getcap(9E) エントリポイントは、scsi_ifgetcap(9F) によって呼び出されます。ターゲットドライバは、SCSA 定義機能セットのいずれかの現在の値を調べるために scsi_ifgetcap() を呼び出します。
ターゲットドライバは、whom パラメータをゼロ以外の値に設定することで、特定のターゲットの機能の現在の設定を要求できます。whom 値をゼロに設定することは、SCSI バスまたはアダプタハードウェアの一般的な機能の現在の設定を要求することを意味します。
tran_getcap() エントリポイントは、-1 (機能が未定義の場合) または要求された機能の現在の値を返します。
HBA ドライバは、scsi_hba_lookup_capstr(9F) 関数を使用して、機能文字列を定義済みの標準的な機能セットと比較できます。
使用例 18-10 HBA ドライバの tran_getcap (9E) エントリポイント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);
}
SCSI HBA ドライバの tran_setcap(9E) エントリポイントは、scsi_ifsetcap(9F) によって呼び出されます。ターゲットドライバは、SCSA 定義機能セットのいずれかの現在の値を変更するために scsi_ifsetcap() を呼び出します。
ターゲットドライバは、whom パラメータをゼロ以外の値に設定することで、特定のターゲットに新しい値が設定されるように要求できます。whom 値をゼロに設定することは、一般に SCSI バスまたはアダプタハードウェアの新しい値を設定するよう要求することを意味します。
tran_setcap() は必要に応じて次の値を返します。
-1 (機能が未定義の場合)
0 (HBA ドライバが要求された値に機能を設定できない場合)
1 (HBA ドライバが要求された値に機能を設定できる場合)
HBA ドライバは、scsi_hba_lookup_capstr(9F) 関数を使用して、機能文字列を定義済みの標準的な機能セットと比較できます。
使用例 18-11 HBA ドライバの tran_setcap (9E) エントリポイント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);
}