Writing Device Drivers

tran_getcap(9E)

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 may 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(9E) should return -1 for undefined capabilities or the current value of the requested capability.

The HBA driver may use the function scsi_hba_lookup_capstr(9F) to compare the capability string against the canonical set of defined capabilities.


Example 14-12 HBA Driver tran_getcap(9E) Entry Point

static int
isp_scsi_setcap(
	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);
}