Writing Device Drivers

Abort and Reset Management

tran_abort(9E)

The tran_abort(9E) entry point for a SCSI HBA driver is called to abort one or all the commands currently in transport for a particular target. This entry point is called when a target driver calls scsi_abort(9E).

The tran_abort(9E) entry point should attempt to abort the command denoted by the pkt parameter. If the pkt parameter is NULL, tran_abort(9E) should attempt to abort all outstanding commands in the transport layer for the particular target or logical unit.

Each command successfully aborted must be marked with pkt_reason CMD_ABORTED and pkt_statistics OR'd with STAT_ABORTED.

tran_reset(9E)

The tran_reset(9E) entry point for a SCSI HBA driver is called to reset either the SCSI bus or a particular SCSI target device. This entry point is called when a target driver calls scsi_reset(9F).

The tran_reset(9E) entry point must reset the SCSI bus if level is RESET_ALL. If level is RESET_TARGET, just the particular target or logical unit must be reset.

Active commands affected by the reset must be marked with pkt_reason CMD_RESET, and with pkt_statistics OR'd with either STAT_BUS_RESET or STAT_DEV_RESET, depending on the type of reset.

Commands in the transport layer, but not yet active on the target, must be marked with pkt_reason CMD_RESET, and with pkt_statistics OR'd with either STAT_ABORTED.

tran_reset_notify(9E)

The tran_reset_notify(9E) entry point for a SCSI HBA driver is called to request that the HBA driver notify the target driver via callback when a SCSI bus reset occurs.


Example 14-14 HBA Driver tran_reset_notify(9E) Entry Point

isp_scsi_reset_notify(
	struct scsi_address								*ap,
	int								flag,
	void								(*callback)(caddr_t),
	caddr_t								arg)
{
	struct isp								*isp;
	struct isp_reset_notify_entry								*p, *beforep;
	int								rval = DDI_FAILURE;

	isp = (struct isp *)ap->a_hba_tran->tran_hba_private;

	mutex_enter(ISP_REQ_MUTEX(isp));

	/*
	 * Try to find an existing entry for this target
	 */
	p = isp->isp_reset_notify_listf;
	beforep = NULL;

	while (p) {
		if (p->ap == ap)
			break;
		beforep = p;
		p = p->next;
	}

	if ((flag & SCSI_RESET_CANCEL) && (p != NULL)) {
		if (beforep == NULL) {
			isp->isp_reset_notify_listf = p->next;
		} else {
			beforep->next = p->next;
		}
		kmem_free((caddr_t)p, sizeof (struct
					isp_reset_notify_entry));
		rval = DDI_SUCCESS;

	} else if ((flag & SCSI_RESET_NOTIFY) && (p == NULL)) {
		p = kmem_zalloc(sizeof (struct isp_reset_notify_entry),
				KM_SLEEP);
		p->ap = ap;
		p->callback = callback;
		p->arg = arg;
		p->next = isp->isp_reset_notify_listf;
		isp->isp_reset_notify_listf = p;
		rval = DDI_SUCCESS;
	}

	mutex_exit(ISP_REQ_MUTEX(isp));

	return (rval);
}