isp_target.c revision 154704
1139749Simp/*-
255373Smjacob * Machine and OS Independent Target Mode Code for the Qlogic SCSI/FC adapters.
355373Smjacob *
4154704Smjacob * Copyright (c) 1997-2006 by Matthew Jacob
555373Smjacob * All rights reserved.
655373Smjacob *
755373Smjacob * Redistribution and use in source and binary forms, with or without
855373Smjacob * modification, are permitted provided that the following conditions
955373Smjacob * are met:
1055373Smjacob * 1. Redistributions of source code must retain the above copyright
1155373Smjacob *    notice immediately at the beginning of the file, without modification,
1255373Smjacob *    this list of conditions, and the following disclaimer.
1366189Smjacob * 2. The name of the author may not be used to endorse or promote products
1455373Smjacob *    derived from this software without specific prior written permission.
1555373Smjacob *
1655373Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1755373Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1855373Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1955373Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2055373Smjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2155373Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2255373Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2355373Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2455373Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2555373Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2655373Smjacob * SUCH DAMAGE.
2755373Smjacob */
2855373Smjacob
2955373Smjacob/*
3090224Smjacob * Bug fixes gratefully acknowledged from:
3190224Smjacob *	Oded Kedem <oded@kashya.com>
3290224Smjacob */
3390224Smjacob/*
3455373Smjacob * Include header file appropriate for platform we're building on.
3555373Smjacob */
3655373Smjacob
3755373Smjacob#ifdef	__NetBSD__
3855373Smjacob#include <dev/ic/isp_netbsd.h>
3955373Smjacob#endif
4055373Smjacob#ifdef	__FreeBSD__
41154704Smjacob#include <sys/cdefs.h>
42154704Smjacob__FBSDID("$FreeBSD: head/sys/dev/isp/isp_target.c 154704 2006-01-23 06:23:37Z mjacob $");
43154704Smjacob
4455373Smjacob#include <dev/isp/isp_freebsd.h>
4555373Smjacob#endif
4655373Smjacob#ifdef	__OpenBSD__
4755373Smjacob#include <dev/ic/isp_openbsd.h>
4855373Smjacob#endif
4955373Smjacob#ifdef	__linux__
5055373Smjacob#include "isp_linux.h"
5155373Smjacob#endif
5255373Smjacob
5355373Smjacob#ifdef	ISP_TARGET_MODE
5475196Smjacobstatic const char atiocope[] =
5583027Smjacob    "ATIO returned for lun %d because it was in the middle of Bus Device Reset "
5683027Smjacob    "on bus %d";
5775196Smjacobstatic const char atior[] =
5883027Smjacob    "ATIO returned on for lun %d on from IID %d because a Bus Reset occurred "
5983027Smjacob    "on bus %d";
6055373Smjacob
61154704Smjacobstatic void isp_got_msg(struct ispsoftc *, in_entry_t *);
62154704Smjacobstatic void isp_got_msg_fc(struct ispsoftc *, in_fcentry_t *);
6355373Smjacobstatic void isp_handle_atio(struct ispsoftc *, at_entry_t *);
6455373Smjacobstatic void isp_handle_atio2(struct ispsoftc *, at2_entry_t *);
6555373Smjacobstatic void isp_handle_ctio(struct ispsoftc *, ct_entry_t *);
6655373Smjacobstatic void isp_handle_ctio2(struct ispsoftc *, ct2_entry_t *);
6755373Smjacob
6855373Smjacob/*
6955373Smjacob * The Qlogic driver gets an interrupt to look at response queue entries.
7055373Smjacob * Some of these are status completions for initiatior mode commands, but
7155373Smjacob * if target mode is enabled, we get a whole wad of response queue entries
7255373Smjacob * to be handled here.
7355373Smjacob *
7455373Smjacob * Basically the split into 3 main groups: Lun Enable/Modification responses,
7555373Smjacob * SCSI Command processing, and Immediate Notification events.
7655373Smjacob *
7755373Smjacob * You start by writing a request queue entry to enable target mode (and
7855373Smjacob * establish some resource limitations which you can modify later).
7955373Smjacob * The f/w responds with a LUN ENABLE or LUN MODIFY response with
8055373Smjacob * the status of this action. If the enable was successful, you can expect...
8155373Smjacob *
8255373Smjacob * Response queue entries with SCSI commands encapsulate show up in an ATIO
8355373Smjacob * (Accept Target IO) type- sometimes with enough info to stop the command at
8455373Smjacob * this level. Ultimately the driver has to feed back to the f/w's request
8555373Smjacob * queue a sequence of CTIOs (continue target I/O) that describe data to
8655373Smjacob * be moved and/or status to be sent) and finally finishing with sending
8755373Smjacob * to the f/w's response queue an ATIO which then completes the handshake
8855373Smjacob * with the f/w for that command. There's a lot of variations on this theme,
8955373Smjacob * including flags you can set in the CTIO for the Qlogic 2X00 fibre channel
9055373Smjacob * cards that 'auto-replenish' the f/w's ATIO count, but this is the basic
9155373Smjacob * gist of it.
9255373Smjacob *
9355373Smjacob * The third group that can show up in the response queue are Immediate
9455373Smjacob * Notification events. These include things like notifications of SCSI bus
9555373Smjacob * resets, or Bus Device Reset messages or other messages received. This
9672082Sasmodai * a classic oddbins area. It can get  a little weird because you then turn
9755373Smjacob * around and acknowledge the Immediate Notify by writing an entry onto the
9855373Smjacob * request queue and then the f/w turns around and gives you an acknowledgement
9955373Smjacob * to *your* acknowledgement on the response queue (the idea being to let
10055373Smjacob * the f/w tell you when the event is *really* over I guess).
10155373Smjacob *
10255373Smjacob */
10355373Smjacob
10455373Smjacob
10555373Smjacob/*
10655373Smjacob * A new response queue entry has arrived. The interrupt service code
10755373Smjacob * has already swizzled it into the platform dependent from canonical form.
10855373Smjacob *
10955373Smjacob * Because of the way this driver is designed, unfortunately most of the
11055373Smjacob * actual synchronization work has to be done in the platform specific
11155373Smjacob * code- we have no synchroniation primitives in the common code.
11255373Smjacob */
11355373Smjacob
11455373Smjacobint
11575196Smjacobisp_target_notify(struct ispsoftc *isp, void *vptr, u_int16_t *optrp)
11655373Smjacob{
11755373Smjacob	u_int16_t status, seqid;
11855373Smjacob	union {
11955373Smjacob		at_entry_t	*atiop;
12055373Smjacob		at2_entry_t	*at2iop;
121154704Smjacob		at2e_entry_t	*at2eiop;
12255373Smjacob		ct_entry_t	*ctiop;
12355373Smjacob		ct2_entry_t	*ct2iop;
124154704Smjacob		ct2e_entry_t	*ct2eiop;
12555373Smjacob		lun_entry_t	*lunenp;
12655373Smjacob		in_entry_t	*inotp;
12755373Smjacob		in_fcentry_t	*inot_fcp;
128154704Smjacob		in_fcentry_e_t	*inote_fcp;
12955373Smjacob		na_entry_t	*nackp;
13055373Smjacob		na_fcentry_t	*nack_fcp;
131154704Smjacob		na_fcentry_e_t	*nacke_fcp;
13255373Smjacob		isphdr_t	*hp;
13355373Smjacob		void *		*vp;
13455373Smjacob#define	atiop		unp.atiop
13555373Smjacob#define	at2iop		unp.at2iop
136154704Smjacob#define	at2eiop		unp.at2eiop
13755373Smjacob#define	ctiop		unp.ctiop
13855373Smjacob#define	ct2iop		unp.ct2iop
139154704Smjacob#define	ct2eiop		unp.ct2eiop
14055373Smjacob#define	lunenp		unp.lunenp
14155373Smjacob#define	inotp		unp.inotp
14255373Smjacob#define	inot_fcp	unp.inot_fcp
143154704Smjacob#define	inote_fcp	unp.inote_fcp
14455373Smjacob#define	nackp		unp.nackp
14555373Smjacob#define	nack_fcp	unp.nack_fcp
146154704Smjacob#define	nacke_fcp	unp.nacke_fcp
14755373Smjacob#define	hdrp		unp.hp
14855373Smjacob	} unp;
14987635Smjacob	u_int8_t local[QENTRY_LEN];
15098284Smjacob	int bus, type, rval = 1;
15155373Smjacob
15287635Smjacob	type = isp_get_response_type(isp, (isphdr_t *)vptr);
15355373Smjacob	unp.vp = vptr;
15455373Smjacob
15555373Smjacob	ISP_TDQE(isp, "isp_target_notify", (int) *optrp, vptr);
15655373Smjacob
15787635Smjacob	switch(type) {
15855373Smjacob	case RQSTYPE_ATIO:
15987635Smjacob		isp_get_atio(isp, atiop, (at_entry_t *) local);
16087635Smjacob		isp_handle_atio(isp, (at_entry_t *) local);
16155373Smjacob		break;
16255373Smjacob	case RQSTYPE_CTIO:
16387635Smjacob		isp_get_ctio(isp, ctiop, (ct_entry_t *) local);
16487635Smjacob		isp_handle_ctio(isp, (ct_entry_t *) local);
16555373Smjacob		break;
16655373Smjacob	case RQSTYPE_ATIO2:
167154704Smjacob		if (IS_2KLOGIN(isp))
168154704Smjacob			isp_get_atio2e(isp, at2eiop, (at2e_entry_t *) local);
169154704Smjacob		else
170154704Smjacob			isp_get_atio2(isp, at2iop, (at2_entry_t *) local);
17187635Smjacob		isp_handle_atio2(isp, (at2_entry_t *) local);
17255373Smjacob		break;
173125187Smjacob	case RQSTYPE_CTIO3:
17455373Smjacob	case RQSTYPE_CTIO2:
175154704Smjacob		if (IS_2KLOGIN(isp))
176154704Smjacob			isp_get_ctio2e(isp, ct2eiop, (ct2e_entry_t *) local);
177154704Smjacob		else
178154704Smjacob			isp_get_ctio2(isp, ct2iop, (ct2_entry_t *) local);
17987635Smjacob		isp_handle_ctio2(isp, (ct2_entry_t *) local);
18055373Smjacob		break;
18155373Smjacob	case RQSTYPE_ENABLE_LUN:
18255373Smjacob	case RQSTYPE_MODIFY_LUN:
18387635Smjacob		isp_get_enable_lun(isp, lunenp, (lun_entry_t *) local);
18487635Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, local);
18555373Smjacob		break;
18655373Smjacob
18755373Smjacob	case RQSTYPE_NOTIFY:
18855373Smjacob		/*
18955373Smjacob		 * Either the ISP received a SCSI message it can't
19055373Smjacob		 * handle, or it's returning an Immed. Notify entry
19155373Smjacob		 * we sent. We can send Immed. Notify entries to
19255373Smjacob		 * increment the firmware's resource count for them
19355373Smjacob		 * (we set this initially in the Enable Lun entry).
19455373Smjacob		 */
19557216Smjacob		bus = 0;
19655373Smjacob		if (IS_FC(isp)) {
197154704Smjacob			if (IS_2KLOGIN(isp))
198154704Smjacob				isp_get_notify_fc_e(isp, inote_fcp, (in_fcentry_e_t *)local);
199154704Smjacob				isp_get_notify_fc(isp, inot_fcp, (in_fcentry_t *)local);
20087635Smjacob			inot_fcp = (in_fcentry_t *) local;
20155373Smjacob			status = inot_fcp->in_status;
20255373Smjacob			seqid = inot_fcp->in_seqid;
20355373Smjacob		} else {
20487635Smjacob			isp_get_notify(isp, inotp, (in_entry_t *)local);
20587635Smjacob			inotp = (in_entry_t *) local;
20655373Smjacob			status = inotp->in_status & 0xff;
20755373Smjacob			seqid = inotp->in_seqid;
20857216Smjacob			if (IS_DUALBUS(isp)) {
20983027Smjacob				bus = GET_BUS_VAL(inotp->in_iid);
21083027Smjacob				SET_BUS_VAL(inotp->in_iid, 0);
21157216Smjacob			}
21255373Smjacob		}
21383027Smjacob		isp_prt(isp, ISP_LOGTDEBUG0,
21483027Smjacob		    "Immediate Notify On Bus %d, status=0x%x seqid=0x%x",
21583027Smjacob		    bus, status, seqid);
21683027Smjacob
21755373Smjacob		switch (status) {
21855373Smjacob		case IN_MSG_RECEIVED:
21955373Smjacob		case IN_IDE_RECEIVED:
22055373Smjacob			if (IS_FC(isp)) {
221154704Smjacob				isp_got_msg_fc(isp, (in_fcentry_t *)local);
22255373Smjacob			} else {
223154704Smjacob				isp_got_msg(isp, (in_entry_t *)local);
22455373Smjacob			}
22555373Smjacob			break;
22655373Smjacob		case IN_RSRC_UNAVAIL:
22764090Smjacob			isp_prt(isp, ISP_LOGWARN, "Firmware out of ATIOs");
228154704Smjacob			isp_notify_ack(isp, local);
22955373Smjacob			break;
230154704Smjacob		case IN_RESET:
231154704Smjacob			isp_target_async(isp, 0, ASYNC_BUS_RESET);
232154704Smjacob			break;
23398284Smjacob		case IN_PORT_LOGOUT:
23455373Smjacob		case IN_ABORT_TASK:
23555373Smjacob		case IN_PORT_CHANGED:
23655373Smjacob		case IN_GLOBAL_LOGO:
23798284Smjacob			(void) isp_async(isp, ISPASYNC_TARGET_ACTION, &local);
23855373Smjacob			break;
23955373Smjacob		default:
24064090Smjacob			isp_prt(isp, ISP_LOGERR,
24164090Smjacob			    "bad status (0x%x) in isp_target_notify", status);
242154704Smjacob			isp_notify_ack(isp, local);
24355373Smjacob			break;
24455373Smjacob		}
24555373Smjacob		break;
24655373Smjacob
24755373Smjacob	case RQSTYPE_NOTIFY_ACK:
24855373Smjacob		/*
24955373Smjacob		 * The ISP is acknowledging our acknowledgement of an
25055373Smjacob		 * Immediate Notify entry for some asynchronous event.
25155373Smjacob		 */
25255373Smjacob		if (IS_FC(isp)) {
253154704Smjacob			if (IS_2KLOGIN(isp))
254154704Smjacob				isp_get_notify_ack_fc_e(isp, nacke_fcp,
255154704Smjacob				    (na_fcentry_e_t *)local);
256154704Smjacob			else
257154704Smjacob				isp_get_notify_ack_fc(isp, nack_fcp,
258154704Smjacob				    (na_fcentry_t *)local);
25987635Smjacob			nack_fcp = (na_fcentry_t *)local;
26064090Smjacob			isp_prt(isp, ISP_LOGTDEBUG1,
26164090Smjacob			    "Notify Ack status=0x%x seqid 0x%x",
26264090Smjacob			    nack_fcp->na_status, nack_fcp->na_seqid);
26355373Smjacob		} else {
26487635Smjacob			isp_get_notify_ack(isp, nackp, (na_entry_t *)local);
26587635Smjacob			nackp = (na_entry_t *)local;
26664090Smjacob			isp_prt(isp, ISP_LOGTDEBUG1,
26764090Smjacob			    "Notify Ack event 0x%x status=0x%x seqid 0x%x",
26864090Smjacob			    nackp->na_event, nackp->na_status, nackp->na_seqid);
26955373Smjacob		}
27055373Smjacob		break;
27155373Smjacob	default:
27264090Smjacob		isp_prt(isp, ISP_LOGERR,
27387635Smjacob		    "Unknown entry type 0x%x in isp_target_notify", type);
27498284Smjacob		rval = 0;
27555373Smjacob		break;
27655373Smjacob	}
27755373Smjacob#undef	atiop
27855373Smjacob#undef	at2iop
279154704Smjacob#undef	at2eiop
28055373Smjacob#undef	ctiop
28155373Smjacob#undef	ct2iop
282154704Smjacob#undef	ct2eiop
28355373Smjacob#undef	lunenp
28455373Smjacob#undef	inotp
28555373Smjacob#undef	inot_fcp
286154704Smjacob#undef	inote_fcp
28755373Smjacob#undef	nackp
28855373Smjacob#undef	nack_fcp
289154704Smjacob#undef	nacke_fcp
29055373Smjacob#undef	hdrp
29155373Smjacob	return (rval);
29255373Smjacob}
29355373Smjacob
29455373Smjacob
29555373Smjacob/*
29655373Smjacob * Toggle (on/off) target mode for bus/target/lun
29755373Smjacob *
29855373Smjacob * The caller has checked for overlap and legality.
29955373Smjacob *
30055373Smjacob * Note that not all of bus, target or lun can be paid attention to.
30155373Smjacob * Note also that this action will not be complete until the f/w writes
30255373Smjacob * response entry. The caller is responsible for synchronizing this.
30355373Smjacob */
30455373Smjacobint
30575196Smjacobisp_lun_cmd(struct ispsoftc *isp, int cmd, int bus, int tgt, int lun,
30677365Smjacob    int cmd_cnt, int inot_cnt, u_int32_t opaque)
30755373Smjacob{
30855373Smjacob	lun_entry_t el;
30987635Smjacob	u_int16_t nxti, optr;
31055373Smjacob	void *outp;
31155373Smjacob
31255373Smjacob
31355373Smjacob	MEMZERO(&el, sizeof (el));
31457216Smjacob	if (IS_DUALBUS(isp)) {
31557216Smjacob		el.le_rsvd = (bus & 0x1) << 7;
31657216Smjacob	}
31777365Smjacob	el.le_cmd_count = cmd_cnt;
31877365Smjacob	el.le_in_count = inot_cnt;
31955373Smjacob	if (cmd == RQSTYPE_ENABLE_LUN) {
32055373Smjacob		if (IS_SCSI(isp)) {
32161774Smjacob			el.le_flags = LUN_TQAE|LUN_DISAD;
32255373Smjacob			el.le_cdb6len = 12;
32355373Smjacob			el.le_cdb7len = 12;
32455373Smjacob		}
32555373Smjacob	} else if (cmd == -RQSTYPE_ENABLE_LUN) {
32655373Smjacob		cmd = RQSTYPE_ENABLE_LUN;
32755373Smjacob		el.le_cmd_count = 0;
32855373Smjacob		el.le_in_count = 0;
32955373Smjacob	} else if (cmd == -RQSTYPE_MODIFY_LUN) {
33055373Smjacob		cmd = RQSTYPE_MODIFY_LUN;
33155373Smjacob		el.le_ops = LUN_CCDECR | LUN_INDECR;
33255373Smjacob	} else {
33355373Smjacob		el.le_ops = LUN_CCINCR | LUN_ININCR;
33455373Smjacob	}
33555373Smjacob	el.le_header.rqs_entry_type = cmd;
33655373Smjacob	el.le_header.rqs_entry_count = 1;
33755373Smjacob	el.le_reserved = opaque;
33855373Smjacob	if (IS_SCSI(isp)) {
33955373Smjacob		el.le_tgt = tgt;
34055373Smjacob		el.le_lun = lun;
34183027Smjacob	} else if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) {
34255373Smjacob		el.le_lun = lun;
34355373Smjacob	}
34475196Smjacob	el.le_timeout = 2;
34555373Smjacob
34687635Smjacob	if (isp_getrqentry(isp, &nxti, &optr, &outp)) {
34787635Smjacob		isp_prt(isp, ISP_LOGERR,
34864090Smjacob		    "Request Queue Overflow in isp_lun_cmd");
34955373Smjacob		return (-1);
35055373Smjacob	}
35155373Smjacob	ISP_TDQE(isp, "isp_lun_cmd", (int) optr, &el);
35287635Smjacob	isp_put_enable_lun(isp, &el, outp);
35387635Smjacob	ISP_ADD_REQUEST(isp, nxti);
35455373Smjacob	return (0);
35555373Smjacob}
35655373Smjacob
35755373Smjacob
35855373Smjacobint
35975196Smjacobisp_target_put_entry(struct ispsoftc *isp, void *ap)
36055373Smjacob{
36155373Smjacob	void *outp;
36287635Smjacob	u_int16_t nxti, optr;
36355373Smjacob	u_int8_t etype = ((isphdr_t *) ap)->rqs_entry_type;
36455373Smjacob
36587635Smjacob	if (isp_getrqentry(isp, &nxti, &optr, &outp)) {
36664090Smjacob		isp_prt(isp, ISP_LOGWARN,
36764090Smjacob		    "Request Queue Overflow in isp_target_put_entry");
36855373Smjacob		return (-1);
36955373Smjacob	}
37055373Smjacob	switch (etype) {
37155373Smjacob	case RQSTYPE_ATIO:
37287635Smjacob		isp_put_atio(isp, (at_entry_t *) ap, (at_entry_t *) outp);
37355373Smjacob		break;
37455373Smjacob	case RQSTYPE_ATIO2:
37587635Smjacob		isp_put_atio2(isp, (at2_entry_t *) ap, (at2_entry_t *) outp);
37655373Smjacob		break;
37755373Smjacob	case RQSTYPE_CTIO:
37887635Smjacob		isp_put_ctio(isp, (ct_entry_t *) ap, (ct_entry_t *) outp);
37955373Smjacob		break;
38055373Smjacob	case RQSTYPE_CTIO2:
38187635Smjacob		isp_put_ctio2(isp, (ct2_entry_t *) ap, (ct2_entry_t *) outp);
38255373Smjacob		break;
38355373Smjacob	default:
38464090Smjacob		isp_prt(isp, ISP_LOGERR,
38564090Smjacob		    "Unknown type 0x%x in isp_put_entry", etype);
38655373Smjacob		return (-1);
38755373Smjacob	}
38855373Smjacob
389120016Smjacob	ISP_TDQE(isp, "isp_target_put_entry", (int) optr, ap);
39087635Smjacob	ISP_ADD_REQUEST(isp, nxti);
39155373Smjacob	return (0);
39255373Smjacob}
39355373Smjacob
39455373Smjacobint
39575196Smjacobisp_target_put_atio(struct ispsoftc *isp, void *arg)
39655373Smjacob{
39755373Smjacob	union {
39855373Smjacob		at_entry_t _atio;
39955373Smjacob		at2_entry_t _atio2;
400154704Smjacob		at2e_entry_t _atio2e;
40155373Smjacob	} atun;
40255373Smjacob
40355373Smjacob	MEMZERO(&atun, sizeof atun);
40455373Smjacob	if (IS_FC(isp)) {
40575196Smjacob		at2_entry_t *aep = arg;
40655373Smjacob		atun._atio2.at_header.rqs_entry_type = RQSTYPE_ATIO2;
40755373Smjacob		atun._atio2.at_header.rqs_entry_count = 1;
40882843Smjacob		if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {
40975196Smjacob			atun._atio2.at_scclun = (u_int16_t) aep->at_scclun;
41061774Smjacob		} else {
41182843Smjacob			atun._atio2.at_lun = (u_int8_t) aep->at_lun;
41261774Smjacob		}
413154704Smjacob		if (IS_2KLOGIN(isp)) {
414154704Smjacob			atun._atio2e.at_iid = ((at2e_entry_t *)aep)->at_iid;
415154704Smjacob		} else {
416154704Smjacob			atun._atio2.at_iid = aep->at_iid;
417154704Smjacob		}
418111004Smjacob		atun._atio2.at_rxid = aep->at_rxid;
41955373Smjacob		atun._atio2.at_status = CT_OK;
42055373Smjacob	} else {
42175196Smjacob		at_entry_t *aep = arg;
42255373Smjacob		atun._atio.at_header.rqs_entry_type = RQSTYPE_ATIO;
42355373Smjacob		atun._atio.at_header.rqs_entry_count = 1;
42475196Smjacob		atun._atio.at_handle = aep->at_handle;
42575196Smjacob		atun._atio.at_iid = aep->at_iid;
42675196Smjacob		atun._atio.at_tgt = aep->at_tgt;
42775196Smjacob		atun._atio.at_lun = aep->at_lun;
42875196Smjacob		atun._atio.at_tag_type = aep->at_tag_type;
42975196Smjacob		atun._atio.at_tag_val = aep->at_tag_val;
43075196Smjacob		atun._atio.at_status = (aep->at_flags & AT_TQAE);
43175196Smjacob		atun._atio.at_status |= CT_OK;
43255373Smjacob	}
43355373Smjacob	return (isp_target_put_entry(isp, &atun));
43455373Smjacob}
43555373Smjacob
43655373Smjacob/*
43755373Smjacob * Command completion- both for handling cases of no resources or
43855373Smjacob * no blackhole driver, or other cases where we have to, inline,
43955373Smjacob * finish the command sanely, or for normal command completion.
44055373Smjacob *
44155373Smjacob * The 'completion' code value has the scsi status byte in the low 8 bits.
44255373Smjacob * If status is a CHECK CONDITION and bit 8 is nonzero, then bits 12..15 have
44355373Smjacob * the sense key and  bits 16..23 have the ASCQ and bits 24..31 have the ASC
44455373Smjacob * values.
44555373Smjacob *
44655373Smjacob * NB: the key, asc, ascq, cannot be used for parallel SCSI as it doesn't
44775196Smjacob * NB: inline SCSI sense reporting. As such, we lose this information. XXX.
44855373Smjacob *
44955373Smjacob * For both parallel && fibre channel, we use the feature that does
45055373Smjacob * an automatic resource autoreplenish so we don't have then later do
45155373Smjacob * put of an atio to replenish the f/w's resource count.
45255373Smjacob */
45355373Smjacob
45455373Smjacobint
45573319Smjacobisp_endcmd(struct ispsoftc *isp, void *arg, u_int32_t code, u_int16_t hdl)
45655373Smjacob{
45755373Smjacob	int sts;
45855373Smjacob	union {
45955373Smjacob		ct_entry_t _ctio;
46055373Smjacob		ct2_entry_t _ctio2;
461154704Smjacob		ct2e_entry_t _ctio2e;
46255373Smjacob	} un;
46355373Smjacob
46455373Smjacob	MEMZERO(&un, sizeof un);
46555373Smjacob	sts = code & 0xff;
46655373Smjacob
46755373Smjacob	if (IS_FC(isp)) {
46855373Smjacob		at2_entry_t *aep = arg;
46955373Smjacob		ct2_entry_t *cto = &un._ctio2;
47055373Smjacob
47155373Smjacob		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
47255373Smjacob		cto->ct_header.rqs_entry_count = 1;
47383027Smjacob		if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) {
47461774Smjacob			cto->ct_lun = aep->at_lun;
47561774Smjacob		}
476154704Smjacob		if (IS_2KLOGIN(isp)) {
477154704Smjacob			un._ctio2e.ct_iid = ((at2e_entry_t *)aep)->at_iid;
478154704Smjacob		} else {
479154704Smjacob			cto->ct_iid = aep->at_iid;
480154704Smjacob		}
48155373Smjacob		cto->ct_rxid = aep->at_rxid;
482125189Smjacob		cto->rsp.m1.ct_scsi_status = sts;
48355373Smjacob		cto->ct_flags = CT2_SENDSTATUS | CT2_NO_DATA | CT2_FLAG_MODE1;
48455373Smjacob		if (hdl == 0) {
48555373Smjacob			cto->ct_flags |= CT2_CCINCR;
48655373Smjacob		}
48755373Smjacob		if (aep->at_datalen) {
48855373Smjacob			cto->ct_resid = aep->at_datalen;
48977365Smjacob			cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER;
49055373Smjacob		}
491125189Smjacob		if (sts == SCSI_CHECK && (code & ECMD_SVALID)) {
49255373Smjacob			cto->rsp.m1.ct_resp[0] = 0xf0;
49355373Smjacob			cto->rsp.m1.ct_resp[2] = (code >> 12) & 0xf;
49455373Smjacob			cto->rsp.m1.ct_resp[7] = 8;
49555373Smjacob			cto->rsp.m1.ct_resp[12] = (code >> 24) & 0xff;
49655373Smjacob			cto->rsp.m1.ct_resp[13] = (code >> 16) & 0xff;
49755373Smjacob			cto->rsp.m1.ct_senselen = 16;
49877365Smjacob			cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
49955373Smjacob		}
50074232Smjacob		cto->ct_syshandle = hdl;
50155373Smjacob	} else {
50255373Smjacob		at_entry_t *aep = arg;
50355373Smjacob		ct_entry_t *cto = &un._ctio;
50455373Smjacob
50555373Smjacob		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
50655373Smjacob		cto->ct_header.rqs_entry_count = 1;
50773319Smjacob		cto->ct_fwhandle = aep->at_handle;
50855373Smjacob		cto->ct_iid = aep->at_iid;
50955373Smjacob		cto->ct_tgt = aep->at_tgt;
51055373Smjacob		cto->ct_lun = aep->at_lun;
51155373Smjacob		cto->ct_tag_type = aep->at_tag_type;
51255373Smjacob		cto->ct_tag_val = aep->at_tag_val;
51375196Smjacob		if (aep->at_flags & AT_TQAE) {
51475196Smjacob			cto->ct_flags |= CT_TQAE;
51575196Smjacob		}
51655373Smjacob		cto->ct_flags = CT_SENDSTATUS | CT_NO_DATA;
51755373Smjacob		if (hdl == 0) {
51855373Smjacob			cto->ct_flags |= CT_CCINCR;
51955373Smjacob		}
52055373Smjacob		cto->ct_scsi_status = sts;
52174232Smjacob		cto->ct_syshandle = hdl;
52255373Smjacob	}
52355373Smjacob	return (isp_target_put_entry(isp, &un));
52455373Smjacob}
52555373Smjacob
52698284Smjacobint
52775196Smjacobisp_target_async(struct ispsoftc *isp, int bus, int event)
52855373Smjacob{
529154704Smjacob	tmd_notify_t notify;
53055373Smjacob
531154704Smjacob	MEMZERO(&notify, sizeof (tmd_notify_t));
532154704Smjacob	notify.nt_hba = isp;
533154704Smjacob	/* nt_str set in outer layers */
534154704Smjacob	notify.nt_iid = INI_ANY;
535154704Smjacob	/* nt_tgt set in outer layers */
536154704Smjacob	notify.nt_lun = LUN_ANY;
537154704Smjacob	notify.nt_tagval = TAG_ANY;
538154704Smjacob
539154704Smjacob	if (IS_SCSI(isp)) {
540154704Smjacob		TAG_INSERT_BUS(notify.nt_tagval, bus);
541154704Smjacob	}
542154704Smjacob
54355373Smjacob	switch (event) {
544154704Smjacob	case ASYNC_LOOP_UP:
545154704Smjacob	case ASYNC_PTPMODE:
546154704Smjacob		notify.nt_ncode = NT_LINK_UP;
547154704Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &notify);
548154704Smjacob		break;
549154704Smjacob	case ASYNC_LOOP_DOWN:
550154704Smjacob		notify.nt_ncode = NT_LINK_DOWN;
551154704Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &notify);
552154704Smjacob		break;
55383027Smjacob	case ASYNC_LIP_F8:
55455373Smjacob	case ASYNC_LIP_OCCURRED:
55583027Smjacob	case ASYNC_LOOP_RESET:
556154704Smjacob		notify.nt_ncode = NT_LIP_RESET;
557154704Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &notify);
558154704Smjacob		break;
55955373Smjacob	case ASYNC_BUS_RESET:
560154704Smjacob	case ASYNC_TIMEOUT_RESET:	/* XXX: where does this come from ? */
561154704Smjacob		notify.nt_ncode = NT_BUS_RESET;
562154704Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &notify);
56355373Smjacob		break;
56455373Smjacob	case ASYNC_DEVICE_RESET:
565154704Smjacob		notify.nt_ncode = NT_TARGET_RESET;
566154704Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &notify);
567154704Smjacob		break;
568154704Smjacob	case ASYNC_CTIO_DONE:
569154704Smjacob	{
570154704Smjacob		uint8_t storage[QENTRY_LEN];
571154704Smjacob		memset(storage, 0, QENTRY_LEN);
57255373Smjacob		if (IS_FC(isp)) {
573154704Smjacob			ct2_entry_t *ct = (ct2_entry_t *) storage;
574154704Smjacob			ct->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
575154704Smjacob			ct->ct_status = CT_OK;
576154704Smjacob			ct->ct_syshandle = bus;
577154704Smjacob			ct->ct_flags = CT2_SENDSTATUS|CT2_FASTPOST;
57855373Smjacob		} else {
579154704Smjacob			ct_entry_t *ct = (ct_entry_t *) storage;
580154704Smjacob			ct->ct_header.rqs_entry_type = RQSTYPE_CTIO;
581154704Smjacob			ct->ct_status = CT_OK;
582154704Smjacob			ct->ct_fwhandle = bus;
583154704Smjacob			ct->ct_flags = CT_SENDSTATUS;
58455373Smjacob		}
585154704Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, storage);
586120016Smjacob		return (0);
587154704Smjacob	}
58855373Smjacob	default:
58964090Smjacob		isp_prt(isp, ISP_LOGERR,
59064090Smjacob		    "isp_target_async: unknown event 0x%x", event);
591154704Smjacob		if (isp->isp_state == ISP_RUNSTATE) {
592154704Smjacob			isp_notify_ack(isp, NULL);
593154704Smjacob		}
59455373Smjacob		break;
59555373Smjacob	}
596154704Smjacob	return (0);
59755373Smjacob}
59855373Smjacob
59955373Smjacob
60055373Smjacob/*
60155373Smjacob * Process a received message.
60255373Smjacob * The ISP firmware can handle most messages, there are only
60355373Smjacob * a few that we need to deal with:
60455373Smjacob * - abort: clean up the current command
60555373Smjacob * - abort tag and clear queue
60655373Smjacob */
60755373Smjacob
60855373Smjacobstatic void
609154704Smjacobisp_got_msg(struct ispsoftc *isp, in_entry_t *inp)
61055373Smjacob{
611154704Smjacob	tmd_notify_t nt;
61255373Smjacob	u_int8_t status = inp->in_status & ~QLTM_SVALID;
61355373Smjacob
614154704Smjacob	MEMZERO(&nt, sizeof (nt));
615154704Smjacob	nt.nt_hba = isp;
616154704Smjacob	/* nt_str set in outer layers */
617154704Smjacob	nt.nt_iid = GET_IID_VAL(inp->in_iid);
618154704Smjacob	nt.nt_tgt = inp->in_tgt;
619154704Smjacob	nt.nt_lun = inp->in_lun;
620154704Smjacob	IN_MAKE_TAGID(nt.nt_tagval, 0, inp);
621154704Smjacob	nt.nt_lreserved = inp;
622154704Smjacob
62355373Smjacob	if (status == IN_IDE_RECEIVED || status == IN_MSG_RECEIVED) {
624154704Smjacob		switch (inp->in_msg[0]) {
625154704Smjacob		case MSG_ABORT:
626154704Smjacob			nt.nt_ncode = NT_ABORT_TASK_SET;
627154704Smjacob			break;
628154704Smjacob		case MSG_BUS_DEV_RESET:
629154704Smjacob			nt.nt_ncode = NT_TARGET_RESET;
630154704Smjacob			break;
631154704Smjacob		case MSG_ABORT_TAG:
632154704Smjacob			nt.nt_ncode = NT_ABORT_TASK;
633154704Smjacob			break;
634154704Smjacob		case MSG_CLEAR_QUEUE:
635154704Smjacob			nt.nt_ncode = NT_CLEAR_TASK_SET;
636154704Smjacob			break;
637154704Smjacob		case MSG_REL_RECOVERY:
638154704Smjacob			nt.nt_ncode = NT_CLEAR_ACA;
639154704Smjacob			break;
640154704Smjacob		case MSG_TERM_IO_PROC:
641154704Smjacob			nt.nt_ncode = NT_ABORT_TASK;
642154704Smjacob			break;
643154704Smjacob		case MSG_LUN_RESET:
644154704Smjacob			nt.nt_ncode = NT_LUN_RESET;
645154704Smjacob			break;
646154704Smjacob		default:
647154704Smjacob			isp_prt(isp, ISP_LOGERR,
648154704Smjacob			    "unhandled message 0x%x", inp->in_msg[0]);
649154704Smjacob			isp_notify_ack(isp, inp);
650154704Smjacob			return;
651154704Smjacob		}
652154704Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt);
65355373Smjacob	} else {
65464090Smjacob		isp_prt(isp, ISP_LOGERR,
65564090Smjacob		    "unknown immediate notify status 0x%x", inp->in_status);
656154704Smjacob		isp_notify_ack(isp, inp);
65755373Smjacob	}
65855373Smjacob}
65955373Smjacob
66055373Smjacob/*
66155373Smjacob * Synthesize a message from the task management flags in a FCP_CMND_IU.
66255373Smjacob */
66355373Smjacobstatic void
664154704Smjacobisp_got_msg_fc(struct ispsoftc *isp, in_fcentry_t *inp)
66555373Smjacob{
666154704Smjacob	tmd_notify_t nt;
667154704Smjacob	static const char f1[] = "%s from iid 0x%08x%08x lun %d seq 0x%x";
66875196Smjacob	static const char f2[] =
669154704Smjacob	    "unknown %s 0x%x lun %d iid 0x%08x%08x task flags 0x%x seq 0x%x\n";
67055373Smjacob
671154704Smjacob	MEMZERO(&nt, sizeof (tmd_notify_t));
672154704Smjacob	nt.nt_hba = isp;
673154704Smjacob	/*
674154704Smjacob	 * XXX: LOOK UP TRANSLATION IN CURRENT LPORTDB
675154704Smjacob	 */
676154704Smjacob	if (IS_2KLOGIN(isp)) {
677154704Smjacob		nt.nt_iid = ((in_fcentry_e_t *)inp)->in_iid;
678154704Smjacob	} else {
679154704Smjacob		nt.nt_iid = inp->in_iid; /* possibly reset in outer layer */
680154704Smjacob	}
681154704Smjacob	/* nt_tgt set in outer layers */
68282843Smjacob	if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {
683154704Smjacob		nt.nt_lun = inp->in_scclun;
68482843Smjacob	} else {
685154704Smjacob		nt.nt_lun = inp->in_lun;
68682843Smjacob	}
687154704Smjacob	IN_FC_MAKE_TAGID(nt.nt_tagval, 0, inp);
688154704Smjacob	nt.nt_lreserved = inp;
68982843Smjacob
69055373Smjacob	if (inp->in_status != IN_MSG_RECEIVED) {
69164090Smjacob		isp_prt(isp, ISP_LOGINFO, f2, "immediate notify status",
692154704Smjacob		    inp->in_status, nt.nt_lun, (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid,
69355373Smjacob		    inp->in_task_flags,  inp->in_seqid);
694154704Smjacob		isp_notify_ack(isp, inp);
695154704Smjacob		return;
696154704Smjacob	}
697154704Smjacob
698154704Smjacob	if (inp->in_task_flags & TASK_FLAGS_ABORT_TASK_SET) {
699154704Smjacob		isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK SET",
700154704Smjacob		    (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid);
701154704Smjacob		nt.nt_ncode = NT_ABORT_TASK_SET;
702154704Smjacob	} else if (inp->in_task_flags & TASK_FLAGS_CLEAR_TASK_SET) {
703154704Smjacob		isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET",
704154704Smjacob		    (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid);
705154704Smjacob		nt.nt_ncode = NT_CLEAR_TASK_SET;
706154704Smjacob	} else if (inp->in_task_flags & TASK_FLAGS_LUN_RESET) {
707154704Smjacob		isp_prt(isp, ISP_LOGINFO, f1, "LUN RESET",
708154704Smjacob		    (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid);
709154704Smjacob		nt.nt_ncode = NT_LUN_RESET;
710154704Smjacob	} else if (inp->in_task_flags & TASK_FLAGS_TARGET_RESET) {
711154704Smjacob		isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET",
712154704Smjacob		    (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid);
713154704Smjacob		nt.nt_ncode = NT_TARGET_RESET;
714154704Smjacob	} else if (inp->in_task_flags & TASK_FLAGS_CLEAR_ACA) {
715154704Smjacob		isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA",
716154704Smjacob		    (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid);
717154704Smjacob		nt.nt_ncode = NT_CLEAR_ACA;
71855373Smjacob	} else {
719154704Smjacob		isp_prt(isp, ISP_LOGWARN, f2, "task flag",
720154704Smjacob		    inp->in_status, nt.nt_lun, (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid,
721154704Smjacob		    inp->in_task_flags,  inp->in_seqid);
722154704Smjacob		isp_notify_ack(isp, inp);
723154704Smjacob		return;
72455373Smjacob	}
725154704Smjacob	(void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt);
72655373Smjacob}
72755373Smjacob
728154704Smjacobvoid
72975196Smjacobisp_notify_ack(struct ispsoftc *isp, void *arg)
73055373Smjacob{
73155373Smjacob	char storage[QENTRY_LEN];
73287635Smjacob	u_int16_t nxti, optr;
73355373Smjacob	void *outp;
73455373Smjacob
73587635Smjacob	if (isp_getrqentry(isp, &nxti, &optr, &outp)) {
73664090Smjacob		isp_prt(isp, ISP_LOGWARN,
73764090Smjacob		    "Request Queue Overflow For isp_notify_ack");
73855373Smjacob		return;
73955373Smjacob	}
74055373Smjacob
74156006Smjacob	MEMZERO(storage, QENTRY_LEN);
74255373Smjacob
74355373Smjacob	if (IS_FC(isp)) {
74455373Smjacob		na_fcentry_t *na = (na_fcentry_t *) storage;
74555373Smjacob		if (arg) {
74655373Smjacob			in_fcentry_t *inp = arg;
74756006Smjacob			MEMCPY(storage, arg, sizeof (isphdr_t));
748154704Smjacob			if (IS_2KLOGIN(isp)) {
749154704Smjacob				((na_fcentry_e_t *)na)->na_iid = ((in_fcentry_e_t *)inp)->in_iid;
750154704Smjacob			} else {
751154704Smjacob				na->na_iid = inp->in_iid;
752154704Smjacob			}
75382843Smjacob			if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {
75461774Smjacob				na->na_lun = inp->in_scclun;
75561774Smjacob			} else {
75661774Smjacob				na->na_lun = inp->in_lun;
75761774Smjacob			}
75855373Smjacob			na->na_task_flags = inp->in_task_flags;
75955373Smjacob			na->na_seqid = inp->in_seqid;
76055373Smjacob			na->na_flags = NAFC_RCOUNT;
76190224Smjacob			na->na_status = inp->in_status;
76255373Smjacob			if (inp->in_status == IN_RESET) {
76355373Smjacob				na->na_flags |= NAFC_RST_CLRD;
76455373Smjacob			}
76555373Smjacob		} else {
76655373Smjacob			na->na_flags = NAFC_RST_CLRD;
76755373Smjacob		}
76859453Smjacob		na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK;
76959453Smjacob		na->na_header.rqs_entry_count = 1;
770154704Smjacob		if (IS_2KLOGIN(isp)) {
771154704Smjacob			isp_put_notify_ack_fc_e(isp, (na_fcentry_e_t *) na, (na_fcentry_e_t *)outp);
772154704Smjacob		} else {
773154704Smjacob			isp_put_notify_ack_fc(isp, na, (na_fcentry_t *)outp);
774154704Smjacob		}
77555373Smjacob	} else {
77655373Smjacob		na_entry_t *na = (na_entry_t *) storage;
77755373Smjacob		if (arg) {
77855373Smjacob			in_entry_t *inp = arg;
77956006Smjacob			MEMCPY(storage, arg, sizeof (isphdr_t));
78055373Smjacob			na->na_iid = inp->in_iid;
78155373Smjacob			na->na_lun = inp->in_lun;
78255373Smjacob			na->na_tgt = inp->in_tgt;
78355373Smjacob			na->na_seqid = inp->in_seqid;
78455373Smjacob			if (inp->in_status == IN_RESET) {
78559453Smjacob				na->na_event = NA_RST_CLRD;
78655373Smjacob			}
78755373Smjacob		} else {
78859453Smjacob			na->na_event = NA_RST_CLRD;
78955373Smjacob		}
79059453Smjacob		na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK;
79159453Smjacob		na->na_header.rqs_entry_count = 1;
79287635Smjacob		isp_put_notify_ack(isp, na, (na_entry_t *)outp);
79355373Smjacob	}
79455373Smjacob	ISP_TDQE(isp, "isp_notify_ack", (int) optr, storage);
79587635Smjacob	ISP_ADD_REQUEST(isp, nxti);
79655373Smjacob}
79755373Smjacob
79855373Smjacobstatic void
79975196Smjacobisp_handle_atio(struct ispsoftc *isp, at_entry_t *aep)
80055373Smjacob{
80155373Smjacob	int lun;
80255373Smjacob	lun = aep->at_lun;
80355373Smjacob	/*
80455373Smjacob	 * The firmware status (except for the QLTM_SVALID bit) indicates
80555373Smjacob	 * why this ATIO was sent to us.
80655373Smjacob	 *
80755373Smjacob	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
80855373Smjacob	 *
80955373Smjacob	 * If the DISCONNECTS DISABLED bit is set in the flags field,
81055373Smjacob	 * we're still connected on the SCSI bus - i.e. the initiator
81155373Smjacob	 * did not set DiscPriv in the identify message. We don't care
81255373Smjacob	 * about this so it's ignored.
81355373Smjacob	 */
81455373Smjacob
81555373Smjacob	switch(aep->at_status & ~QLTM_SVALID) {
81655373Smjacob	case AT_PATH_INVALID:
81755373Smjacob		/*
81855373Smjacob		 * ATIO rejected by the firmware due to disabled lun.
81955373Smjacob		 */
82064090Smjacob		isp_prt(isp, ISP_LOGERR,
82164090Smjacob		    "rejected ATIO for disabled lun %d", lun);
82255373Smjacob		break;
82355373Smjacob	case AT_NOCAP:
82455373Smjacob		/*
82555373Smjacob		 * Requested Capability not available
82655373Smjacob		 * We sent an ATIO that overflowed the firmware's
82755373Smjacob		 * command resource count.
82855373Smjacob		 */
82964090Smjacob		isp_prt(isp, ISP_LOGERR,
83064090Smjacob		    "rejected ATIO for lun %d because of command count"
83164090Smjacob		    " overflow", lun);
83255373Smjacob		break;
83355373Smjacob
83455373Smjacob	case AT_BDR_MSG:
83555373Smjacob		/*
83655373Smjacob		 * If we send an ATIO to the firmware to increment
83755373Smjacob		 * its command resource count, and the firmware is
83855373Smjacob		 * recovering from a Bus Device Reset, it returns
83955373Smjacob		 * the ATIO with this status. We set the command
84087635Smjacob		 * resource count in the Enable Lun entry and do
84155373Smjacob		 * not increment it. Therefore we should never get
84255373Smjacob		 * this status here.
84355373Smjacob		 */
84483027Smjacob		isp_prt(isp, ISP_LOGERR, atiocope, lun,
84583027Smjacob		    GET_BUS_VAL(aep->at_iid));
84655373Smjacob		break;
84755373Smjacob
84855373Smjacob	case AT_CDB:		/* Got a CDB */
84955373Smjacob	case AT_PHASE_ERROR:	/* Bus Phase Sequence Error */
85055373Smjacob		/*
85155373Smjacob		 * Punt to platform specific layer.
85255373Smjacob		 */
85355373Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep);
85455373Smjacob		break;
85555373Smjacob
85655373Smjacob	case AT_RESET:
85755373Smjacob		/*
858108470Sschweikh		 * A bus reset came along and blew away this command. Why
85955373Smjacob		 * they do this in addition the async event code stuff,
86055373Smjacob		 * I dunno.
86155373Smjacob		 *
86255373Smjacob		 * Ignore it because the async event will clear things
86355373Smjacob		 * up for us.
86455373Smjacob		 */
86583027Smjacob		isp_prt(isp, ISP_LOGWARN, atior, lun,
86683027Smjacob		    GET_IID_VAL(aep->at_iid), GET_BUS_VAL(aep->at_iid));
86755373Smjacob		break;
86855373Smjacob
86955373Smjacob
87055373Smjacob	default:
87164090Smjacob		isp_prt(isp, ISP_LOGERR,
87264090Smjacob		    "Unknown ATIO status 0x%x from initiator %d for lun %d",
87364090Smjacob		    aep->at_status, aep->at_iid, lun);
87475196Smjacob		(void) isp_target_put_atio(isp, aep);
87555373Smjacob		break;
87655373Smjacob	}
87755373Smjacob}
87855373Smjacob
87955373Smjacobstatic void
88075196Smjacobisp_handle_atio2(struct ispsoftc *isp, at2_entry_t *aep)
88155373Smjacob{
882154704Smjacob	int lun, iid;
88361774Smjacob
88482843Smjacob	if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {
88561774Smjacob		lun = aep->at_scclun;
88661774Smjacob	} else {
88761774Smjacob		lun = aep->at_lun;
88861774Smjacob	}
88961774Smjacob
890154704Smjacob	if (IS_2KLOGIN(isp)) {
891154704Smjacob		iid = ((at2e_entry_t *)aep)->at_iid;
892154704Smjacob	} else {
893154704Smjacob		iid = aep->at_iid;
894154704Smjacob	}
895154704Smjacob
89655373Smjacob	/*
89755373Smjacob	 * The firmware status (except for the QLTM_SVALID bit) indicates
89855373Smjacob	 * why this ATIO was sent to us.
89955373Smjacob	 *
90055373Smjacob	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
90155373Smjacob	 *
90255373Smjacob	 * If the DISCONNECTS DISABLED bit is set in the flags field,
90355373Smjacob	 * we're still connected on the SCSI bus - i.e. the initiator
90455373Smjacob	 * did not set DiscPriv in the identify message. We don't care
90555373Smjacob	 * about this so it's ignored.
90655373Smjacob	 */
90755373Smjacob
90855373Smjacob	switch(aep->at_status & ~QLTM_SVALID) {
90955373Smjacob	case AT_PATH_INVALID:
91055373Smjacob		/*
91155373Smjacob		 * ATIO rejected by the firmware due to disabled lun.
91255373Smjacob		 */
91364090Smjacob		isp_prt(isp, ISP_LOGERR,
91464090Smjacob		    "rejected ATIO2 for disabled lun %d", lun);
91555373Smjacob		break;
91655373Smjacob	case AT_NOCAP:
91755373Smjacob		/*
91855373Smjacob		 * Requested Capability not available
91955373Smjacob		 * We sent an ATIO that overflowed the firmware's
92055373Smjacob		 * command resource count.
92155373Smjacob		 */
92264090Smjacob		isp_prt(isp, ISP_LOGERR,
92364090Smjacob		    "rejected ATIO2 for lun %d- command count overflow", lun);
92455373Smjacob		break;
92555373Smjacob
92655373Smjacob	case AT_BDR_MSG:
92755373Smjacob		/*
92855373Smjacob		 * If we send an ATIO to the firmware to increment
92955373Smjacob		 * its command resource count, and the firmware is
93055373Smjacob		 * recovering from a Bus Device Reset, it returns
93155373Smjacob		 * the ATIO with this status. We set the command
93255373Smjacob		 * resource count in the Enable Lun entry and no
93355373Smjacob		 * not increment it. Therefore we should never get
93455373Smjacob		 * this status here.
93555373Smjacob		 */
93683027Smjacob		isp_prt(isp, ISP_LOGERR, atiocope, lun, 0);
93755373Smjacob		break;
93855373Smjacob
93955373Smjacob	case AT_CDB:		/* Got a CDB */
94055373Smjacob		/*
94155373Smjacob		 * Punt to platform specific layer.
94255373Smjacob		 */
94355373Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep);
94455373Smjacob		break;
94555373Smjacob
94655373Smjacob	case AT_RESET:
94755373Smjacob		/*
94855373Smjacob		 * A bus reset came along an blew away this command. Why
94955373Smjacob		 * they do this in addition the async event code stuff,
95055373Smjacob		 * I dunno.
95155373Smjacob		 *
95255373Smjacob		 * Ignore it because the async event will clear things
95355373Smjacob		 * up for us.
95455373Smjacob		 */
955154704Smjacob		isp_prt(isp, ISP_LOGERR, atior, lun, iid, 0);
95655373Smjacob		break;
95755373Smjacob
95855373Smjacob
95955373Smjacob	default:
96064090Smjacob		isp_prt(isp, ISP_LOGERR,
96164090Smjacob		    "Unknown ATIO2 status 0x%x from initiator %d for lun %d",
962154704Smjacob		    aep->at_status, iid, lun);
96375196Smjacob		(void) isp_target_put_atio(isp, aep);
96455373Smjacob		break;
96555373Smjacob	}
96655373Smjacob}
96755373Smjacob
96855373Smjacobstatic void
96975196Smjacobisp_handle_ctio(struct ispsoftc *isp, ct_entry_t *ct)
97055373Smjacob{
97174232Smjacob	void *xs;
97264090Smjacob	int pl = ISP_LOGTDEBUG2;
97355373Smjacob	char *fmsg = NULL;
97455373Smjacob
97574232Smjacob	if (ct->ct_syshandle) {
976129643Snjl		xs = isp_find_xs_tgt(isp, ct->ct_syshandle);
97755373Smjacob		if (xs == NULL)
97864090Smjacob			pl = ISP_LOGALL;
97955373Smjacob	} else {
98055373Smjacob		xs = NULL;
98155373Smjacob	}
98255373Smjacob
98355373Smjacob	switch(ct->ct_status & ~QLTM_SVALID) {
98455373Smjacob	case CT_OK:
98555373Smjacob		/*
98655373Smjacob		 * There are generally 3 possibilities as to why we'd get
98755373Smjacob		 * this condition:
98855373Smjacob		 * 	We disconnected after receiving a CDB.
98955373Smjacob		 * 	We sent or received data.
99055373Smjacob		 * 	We sent status & command complete.
99155373Smjacob		 */
99255373Smjacob
99359453Smjacob		if (ct->ct_flags & CT_SENDSTATUS) {
99459453Smjacob			break;
99559453Smjacob		} else if ((ct->ct_flags & CT_DATAMASK) == CT_NO_DATA) {
99655373Smjacob			/*
99755373Smjacob			 * Nothing to do in this case.
99855373Smjacob			 */
99964090Smjacob			isp_prt(isp, pl, "CTIO- iid %d disconnected OK",
100064090Smjacob			    ct->ct_iid);
100155373Smjacob			return;
100255373Smjacob		}
100355373Smjacob		break;
100455373Smjacob
100555373Smjacob	case CT_BDR_MSG:
100655373Smjacob		/*
100755373Smjacob		 * Bus Device Reset message received or the SCSI Bus has
100855373Smjacob		 * been Reset; the firmware has gone to Bus Free.
100955373Smjacob		 *
101055373Smjacob		 * The firmware generates an async mailbox interupt to
101155373Smjacob		 * notify us of this and returns outstanding CTIOs with this
101255373Smjacob		 * status. These CTIOs are handled in that same way as
101355373Smjacob		 * CT_ABORTED ones, so just fall through here.
101455373Smjacob		 */
101555373Smjacob		fmsg = "Bus Device Reset";
101655373Smjacob		/*FALLTHROUGH*/
101755373Smjacob	case CT_RESET:
101855373Smjacob		if (fmsg == NULL)
101955373Smjacob			fmsg = "Bus Reset";
102055373Smjacob		/*FALLTHROUGH*/
102155373Smjacob	case CT_ABORTED:
102255373Smjacob		/*
102355373Smjacob		 * When an Abort message is received the firmware goes to
102455373Smjacob		 * Bus Free and returns all outstanding CTIOs with the status
102555373Smjacob		 * set, then sends us an Immediate Notify entry.
102655373Smjacob		 */
102755373Smjacob		if (fmsg == NULL)
102883027Smjacob			fmsg = "ABORT TAG message sent by Initiator";
102955373Smjacob
103064090Smjacob		isp_prt(isp, ISP_LOGWARN, "CTIO destroyed by %s", fmsg);
103155373Smjacob		break;
103255373Smjacob
103355373Smjacob	case CT_INVAL:
103455373Smjacob		/*
103555373Smjacob		 * CTIO rejected by the firmware due to disabled lun.
103655373Smjacob		 * "Cannot Happen".
103755373Smjacob		 */
103864090Smjacob		isp_prt(isp, ISP_LOGERR,
103964090Smjacob		    "Firmware rejected CTIO for disabled lun %d",
104064090Smjacob		    ct->ct_lun);
104155373Smjacob		break;
104255373Smjacob
104355373Smjacob	case CT_NOPATH:
104455373Smjacob		/*
104555373Smjacob		 * CTIO rejected by the firmware due "no path for the
104655373Smjacob		 * nondisconnecting nexus specified". This means that
104755373Smjacob		 * we tried to access the bus while a non-disconnecting
104855373Smjacob		 * command is in process.
104955373Smjacob		 */
105064090Smjacob		isp_prt(isp, ISP_LOGERR,
105164090Smjacob		    "Firmware rejected CTIO for bad nexus %d/%d/%d",
105264090Smjacob		    ct->ct_iid, ct->ct_tgt, ct->ct_lun);
105355373Smjacob		break;
105455373Smjacob
105555373Smjacob	case CT_RSELTMO:
105655373Smjacob		fmsg = "Reselection";
105755373Smjacob		/*FALLTHROUGH*/
105855373Smjacob	case CT_TIMEOUT:
105955373Smjacob		if (fmsg == NULL)
106055373Smjacob			fmsg = "Command";
106164090Smjacob		isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg);
106255373Smjacob		break;
106355373Smjacob
106475196Smjacob	case	CT_PANIC:
106575196Smjacob		if (fmsg == NULL)
106675196Smjacob			fmsg = "Unrecoverable Error";
106775196Smjacob		/*FALLTHROUGH*/
106855373Smjacob	case CT_ERR:
106975196Smjacob		if (fmsg == NULL)
107075196Smjacob			fmsg = "Completed with Error";
107155373Smjacob		/*FALLTHROUGH*/
107255373Smjacob	case CT_PHASE_ERROR:
107355373Smjacob		if (fmsg == NULL)
107455373Smjacob			fmsg = "Phase Sequence Error";
107555373Smjacob		/*FALLTHROUGH*/
107655373Smjacob	case CT_TERMINATED:
107755373Smjacob		if (fmsg == NULL)
107855373Smjacob			fmsg = "terminated by TERMINATE TRANSFER";
107955373Smjacob		/*FALLTHROUGH*/
108055373Smjacob	case CT_NOACK:
108155373Smjacob		if (fmsg == NULL)
108255373Smjacob			fmsg = "unacknowledged Immediate Notify pending";
108364090Smjacob		isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg);
108455373Smjacob		break;
108555373Smjacob	default:
108664090Smjacob		isp_prt(isp, ISP_LOGERR, "Unknown CTIO status 0x%x",
108755373Smjacob		    ct->ct_status & ~QLTM_SVALID);
108855373Smjacob		break;
108955373Smjacob	}
109055373Smjacob
109155373Smjacob	if (xs == NULL) {
109255373Smjacob		/*
109355373Smjacob		 * There may be more than one CTIO for a data transfer,
109455373Smjacob		 * or this may be a status CTIO we're not monitoring.
109555373Smjacob		 *
109655373Smjacob		 * The assumption is that they'll all be returned in the
109755373Smjacob		 * order we got them.
109855373Smjacob		 */
109974232Smjacob		if (ct->ct_syshandle == 0) {
110055373Smjacob			if ((ct->ct_flags & CT_SENDSTATUS) == 0) {
110164090Smjacob				isp_prt(isp, pl,
110264090Smjacob				    "intermediate CTIO completed ok");
110355373Smjacob			} else {
110464090Smjacob				isp_prt(isp, pl,
110564090Smjacob				    "unmonitored CTIO completed ok");
110655373Smjacob			}
110755373Smjacob		} else {
110864090Smjacob			isp_prt(isp, pl,
110964090Smjacob			    "NO xs for CTIO (handle 0x%x) status 0x%x",
111074232Smjacob			    ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID);
111155373Smjacob		}
111255373Smjacob	} else {
111377365Smjacob		/*
111477365Smjacob		 * Final CTIO completed. Release DMA resources and
111577365Smjacob		 * notify platform dependent layers.
111677365Smjacob		 */
111777365Smjacob		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
111874232Smjacob			ISP_DMAFREE(isp, xs, ct->ct_syshandle);
111955373Smjacob		}
112075196Smjacob		isp_prt(isp, pl, "final CTIO complete");
112155373Smjacob		/*
112255373Smjacob		 * The platform layer will destroy the handle if appropriate.
112355373Smjacob		 */
112475196Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct);
112555373Smjacob	}
112655373Smjacob}
112755373Smjacob
112855373Smjacobstatic void
112975196Smjacobisp_handle_ctio2(struct ispsoftc *isp, ct2_entry_t *ct)
113055373Smjacob{
113164090Smjacob	XS_T *xs;
113264090Smjacob	int pl = ISP_LOGTDEBUG2;
113355373Smjacob	char *fmsg = NULL;
113455373Smjacob
113574232Smjacob	if (ct->ct_syshandle) {
1136129643Snjl		xs = isp_find_xs_tgt(isp, ct->ct_syshandle);
113755373Smjacob		if (xs == NULL)
113864090Smjacob			pl = ISP_LOGALL;
113955373Smjacob	} else {
114055373Smjacob		xs = NULL;
114155373Smjacob	}
114255373Smjacob
114355373Smjacob	switch(ct->ct_status & ~QLTM_SVALID) {
114477365Smjacob	case CT_BUS_ERROR:
114577365Smjacob		isp_prt(isp, ISP_LOGERR, "PCI DMA Bus Error");
114677365Smjacob		/* FALL Through */
114777365Smjacob	case CT_DATA_OVER:
114877365Smjacob	case CT_DATA_UNDER:
114955373Smjacob	case CT_OK:
115055373Smjacob		/*
115155373Smjacob		 * There are generally 2 possibilities as to why we'd get
115255373Smjacob		 * this condition:
115355373Smjacob		 * 	We sent or received data.
115455373Smjacob		 * 	We sent status & command complete.
115555373Smjacob		 */
115655373Smjacob
115755373Smjacob		break;
115855373Smjacob
115955373Smjacob	case CT_BDR_MSG:
116055373Smjacob		/*
116177365Smjacob		 * Target Reset function received.
116255373Smjacob		 *
116355373Smjacob		 * The firmware generates an async mailbox interupt to
116455373Smjacob		 * notify us of this and returns outstanding CTIOs with this
116555373Smjacob		 * status. These CTIOs are handled in that same way as
116655373Smjacob		 * CT_ABORTED ones, so just fall through here.
116755373Smjacob		 */
116877365Smjacob		fmsg = "TARGET RESET Task Management Function Received";
116955373Smjacob		/*FALLTHROUGH*/
117055373Smjacob	case CT_RESET:
117155373Smjacob		if (fmsg == NULL)
117277365Smjacob			fmsg = "LIP Reset";
117355373Smjacob		/*FALLTHROUGH*/
117455373Smjacob	case CT_ABORTED:
117555373Smjacob		/*
117655373Smjacob		 * When an Abort message is received the firmware goes to
117755373Smjacob		 * Bus Free and returns all outstanding CTIOs with the status
117855373Smjacob		 * set, then sends us an Immediate Notify entry.
117955373Smjacob		 */
118055373Smjacob		if (fmsg == NULL)
118177365Smjacob			fmsg = "ABORT Task Management Function Received";
118255373Smjacob
118364090Smjacob		isp_prt(isp, ISP_LOGERR, "CTIO2 destroyed by %s", fmsg);
118455373Smjacob		break;
118555373Smjacob
118655373Smjacob	case CT_INVAL:
118755373Smjacob		/*
118856006Smjacob		 * CTIO rejected by the firmware - invalid data direction.
118955373Smjacob		 */
1190120016Smjacob		isp_prt(isp, ISP_LOGERR, "CTIO2 had wrong data direction");
119155373Smjacob		break;
119255373Smjacob
119355373Smjacob	case CT_RSELTMO:
119477365Smjacob		fmsg = "failure to reconnect to initiator";
119555373Smjacob		/*FALLTHROUGH*/
119655373Smjacob	case CT_TIMEOUT:
119755373Smjacob		if (fmsg == NULL)
119877365Smjacob			fmsg = "command";
119964090Smjacob		isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg);
120055373Smjacob		break;
120155373Smjacob
120255373Smjacob	case CT_ERR:
120355373Smjacob		fmsg = "Completed with Error";
120455373Smjacob		/*FALLTHROUGH*/
120555373Smjacob	case CT_LOGOUT:
120655373Smjacob		if (fmsg == NULL)
120755373Smjacob			fmsg = "Port Logout";
120855373Smjacob		/*FALLTHROUGH*/
120955373Smjacob	case CT_PORTNOTAVAIL:
121055373Smjacob		if (fmsg == NULL)
121155373Smjacob			fmsg = "Port not available";
1212115521Sphk		/*FALLTHROUGH*/
121377365Smjacob	case CT_PORTCHANGED:
121477365Smjacob		if (fmsg == NULL)
121577365Smjacob			fmsg = "Port Changed";
1216115521Sphk		/*FALLTHROUGH*/
121755373Smjacob	case CT_NOACK:
121855373Smjacob		if (fmsg == NULL)
121955373Smjacob			fmsg = "unacknowledged Immediate Notify pending";
122064090Smjacob		isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg);
122155373Smjacob		break;
122255373Smjacob
122355373Smjacob	case CT_INVRXID:
122455373Smjacob		/*
122555373Smjacob		 * CTIO rejected by the firmware because an invalid RX_ID.
122655373Smjacob		 * Just print a message.
122755373Smjacob		 */
122864090Smjacob		isp_prt(isp, ISP_LOGERR,
122964090Smjacob		    "CTIO2 completed with Invalid RX_ID 0x%x", ct->ct_rxid);
123055373Smjacob		break;
123155373Smjacob
123255373Smjacob	default:
123375196Smjacob		isp_prt(isp, ISP_LOGERR, "Unknown CTIO2 status 0x%x",
123464090Smjacob		    ct->ct_status & ~QLTM_SVALID);
123555373Smjacob		break;
123655373Smjacob	}
123755373Smjacob
123855373Smjacob	if (xs == NULL) {
123955373Smjacob		/*
124055373Smjacob		 * There may be more than one CTIO for a data transfer,
124155373Smjacob		 * or this may be a status CTIO we're not monitoring.
124255373Smjacob		 *
124355373Smjacob		 * The assumption is that they'll all be returned in the
124455373Smjacob		 * order we got them.
124555373Smjacob		 */
124674232Smjacob		if (ct->ct_syshandle == 0) {
1247125187Smjacob			if ((ct->ct_flags & CT2_SENDSTATUS) == 0) {
124864090Smjacob				isp_prt(isp, pl,
124964090Smjacob				    "intermediate CTIO completed ok");
125055373Smjacob			} else {
125164090Smjacob				isp_prt(isp, pl,
125264090Smjacob				    "unmonitored CTIO completed ok");
125355373Smjacob			}
125455373Smjacob		} else {
125564090Smjacob			isp_prt(isp, pl,
125664090Smjacob			    "NO xs for CTIO (handle 0x%x) status 0x%x",
125774232Smjacob			    ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID);
125855373Smjacob		}
125955373Smjacob	} else {
126077365Smjacob		if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
126177365Smjacob			ISP_DMAFREE(isp, xs, ct->ct_syshandle);
126277365Smjacob		}
1263125187Smjacob		if (ct->ct_flags & CT2_SENDSTATUS) {
126455373Smjacob			/*
126555373Smjacob			 * Sent status and command complete.
126655373Smjacob			 *
126755373Smjacob			 * We're now really done with this command, so we
126855373Smjacob			 * punt to the platform dependent layers because
126955373Smjacob			 * only there can we do the appropriate command
127055373Smjacob			 * complete thread synchronization.
127155373Smjacob			 */
127264090Smjacob			isp_prt(isp, pl, "status CTIO complete");
127355373Smjacob		} else {
127455373Smjacob			/*
127555373Smjacob			 * Final CTIO completed. Release DMA resources and
127655373Smjacob			 * notify platform dependent layers.
127755373Smjacob			 */
127864090Smjacob			isp_prt(isp, pl, "data CTIO complete");
127955373Smjacob		}
128055373Smjacob		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct);
128155373Smjacob		/*
128255373Smjacob		 * The platform layer will destroy the handle if appropriate.
128355373Smjacob		 */
128455373Smjacob	}
128555373Smjacob}
128655373Smjacob#endif
1287