xref: /freebsd/sys/dev/isp/isp_target.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
1 /* $FreeBSD$ */
2 /*
3  * Machine and OS Independent Target Mode Code for the Qlogic SCSI/FC adapters.
4  *
5  * Copyright (c) 1999 by Matthew Jacob
6  * All rights reserved.
7  * mjacob@feral.com
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice immediately at the beginning of the file, without modification,
14  *    this list of conditions, and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
25  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*
35  * Include header file appropriate for platform we're building on.
36  */
37 
38 #ifdef	__NetBSD__
39 #include <dev/ic/isp_netbsd.h>
40 #endif
41 #ifdef	__FreeBSD__
42 #include <dev/isp/isp_freebsd.h>
43 #endif
44 #ifdef	__OpenBSD__
45 #include <dev/ic/isp_openbsd.h>
46 #endif
47 #ifdef	__linux__
48 #include "isp_linux.h"
49 #endif
50 
51 #ifdef	ISP_TARGET_MODE
52 int isp_tdebug = 0;
53 
54 static void isp_got_msg __P((struct ispsoftc *, int, in_entry_t *));
55 static void isp_got_msg_fc __P((struct ispsoftc *, int, in_fcentry_t *));
56 static void isp_notify_ack __P((struct ispsoftc *, void *));
57 static void isp_handle_atio(struct ispsoftc *, at_entry_t *);
58 static void isp_handle_atio2(struct ispsoftc *, at2_entry_t *);
59 static void isp_handle_ctio(struct ispsoftc *, ct_entry_t *);
60 static void isp_handle_ctio2(struct ispsoftc *, ct2_entry_t *);
61 
62 /*
63  * The Qlogic driver gets an interrupt to look at response queue entries.
64  * Some of these are status completions for initiatior mode commands, but
65  * if target mode is enabled, we get a whole wad of response queue entries
66  * to be handled here.
67  *
68  * Basically the split into 3 main groups: Lun Enable/Modification responses,
69  * SCSI Command processing, and Immediate Notification events.
70  *
71  * You start by writing a request queue entry to enable target mode (and
72  * establish some resource limitations which you can modify later).
73  * The f/w responds with a LUN ENABLE or LUN MODIFY response with
74  * the status of this action. If the enable was successful, you can expect...
75  *
76  * Response queue entries with SCSI commands encapsulate show up in an ATIO
77  * (Accept Target IO) type- sometimes with enough info to stop the command at
78  * this level. Ultimately the driver has to feed back to the f/w's request
79  * queue a sequence of CTIOs (continue target I/O) that describe data to
80  * be moved and/or status to be sent) and finally finishing with sending
81  * to the f/w's response queue an ATIO which then completes the handshake
82  * with the f/w for that command. There's a lot of variations on this theme,
83  * including flags you can set in the CTIO for the Qlogic 2X00 fibre channel
84  * cards that 'auto-replenish' the f/w's ATIO count, but this is the basic
85  * gist of it.
86  *
87  * The third group that can show up in the response queue are Immediate
88  * Notification events. These include things like notifications of SCSI bus
89  * resets, or Bus Device Reset messages or other messages received. This
90  * a classic oddbins area. It can get  a little wierd because you then turn
91  * around and acknowledge the Immediate Notify by writing an entry onto the
92  * request queue and then the f/w turns around and gives you an acknowledgement
93  * to *your* acknowledgement on the response queue (the idea being to let
94  * the f/w tell you when the event is *really* over I guess).
95  *
96  */
97 
98 
99 /*
100  * A new response queue entry has arrived. The interrupt service code
101  * has already swizzled it into the platform dependent from canonical form.
102  *
103  * Because of the way this driver is designed, unfortunately most of the
104  * actual synchronization work has to be done in the platform specific
105  * code- we have no synchroniation primitives in the common code.
106  */
107 
108 int
109 isp_target_notify(isp, vptr, optrp)
110 	struct ispsoftc *isp;
111 	void *vptr;
112 	u_int16_t *optrp;
113 {
114 	u_int16_t status, seqid;
115 	union {
116 		at_entry_t	*atiop;
117 		at2_entry_t	*at2iop;
118 		ct_entry_t	*ctiop;
119 		ct2_entry_t	*ct2iop;
120 		lun_entry_t	*lunenp;
121 		in_entry_t	*inotp;
122 		in_fcentry_t	*inot_fcp;
123 		na_entry_t	*nackp;
124 		na_fcentry_t	*nack_fcp;
125 		isphdr_t	*hp;
126 		void *		*vp;
127 #define	atiop		unp.atiop
128 #define	at2iop		unp.at2iop
129 #define	ctiop		unp.ctiop
130 #define	ct2iop		unp.ct2iop
131 #define	lunenp		unp.lunenp
132 #define	inotp		unp.inotp
133 #define	inot_fcp	unp.inot_fcp
134 #define	nackp		unp.nackp
135 #define	nack_fcp	unp.nack_fcp
136 #define	hdrp		unp.hp
137 	} unp;
138 	int bus, rval = 0;
139 
140 	unp.vp = vptr;
141 
142 	ISP_TDQE(isp, "isp_target_notify", (int) *optrp, vptr);
143 
144 	switch(hdrp->rqs_entry_type) {
145 	case RQSTYPE_ATIO:
146 		isp_handle_atio(isp, atiop);
147 		break;
148 	case RQSTYPE_CTIO:
149 		isp_handle_ctio(isp, ctiop);
150 		break;
151 	case RQSTYPE_ATIO2:
152 		isp_handle_atio2(isp, at2iop);
153 		break;
154 	case RQSTYPE_CTIO2:
155 		isp_handle_ctio2(isp, ct2iop);
156 		break;
157 	case RQSTYPE_ENABLE_LUN:
158 	case RQSTYPE_MODIFY_LUN:
159 		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, vptr);
160 		break;
161 
162 	case RQSTYPE_NOTIFY:
163 		/*
164 		 * Either the ISP received a SCSI message it can't
165 		 * handle, or it's returning an Immed. Notify entry
166 		 * we sent. We can send Immed. Notify entries to
167 		 * increment the firmware's resource count for them
168 		 * (we set this initially in the Enable Lun entry).
169 		 */
170 		bus = 0;
171 		if (IS_FC(isp)) {
172 			status = inot_fcp->in_status;
173 			seqid = inot_fcp->in_seqid;
174 		} else {
175 			status = inotp->in_status & 0xff;
176 			seqid = inotp->in_seqid;
177 			if (IS_DUALBUS(isp)) {
178 				bus = (inotp->in_iid & 0x80) >> 7;
179 				inotp->in_iid &= ~0x80;
180 			}
181 		}
182 		ITDEBUG(2, ("isp_target_notify: Immediate Notify, "
183 		    "status=0x%x seqid=0x%x\n", status, seqid));
184 		switch (status) {
185 		case IN_RESET:
186 			(void) isp_async(isp, ISPASYNC_BUS_RESET, &bus);
187 			break;
188 		case IN_MSG_RECEIVED:
189 		case IN_IDE_RECEIVED:
190 			if (IS_FC(isp)) {
191 				isp_got_msg_fc(isp, bus, vptr);
192 			} else {
193 				isp_got_msg(isp, bus, vptr);
194 			}
195 			break;
196 		case IN_RSRC_UNAVAIL:
197 			PRINTF("%s: Firmware out of ATIOs\n", isp->isp_name);
198 			break;
199 		case IN_ABORT_TASK:
200 			PRINTF("%s: Abort Task for Initiator %d RX_ID 0x%x\n",
201 			    isp->isp_name, inot_fcp->in_iid, seqid);
202 			break;
203 		case IN_PORT_LOGOUT:
204 			PRINTF("%s: Port Logout for Initiator %d RX_ID 0x%x\n",
205 			    isp->isp_name, inot_fcp->in_iid, seqid);
206 			break;
207 		case IN_PORT_CHANGED:
208 			PRINTF("%s: Port Changed for Initiator %d RX_ID 0x%x\n",
209 			    isp->isp_name, inot_fcp->in_iid, seqid);
210 			break;
211 		case IN_GLOBAL_LOGO:
212 			PRINTF("%s: All ports logged out\n", isp->isp_name);
213 			break;
214 		default:
215 			PRINTF("%s: bad status (0x%x) in isp_target_notify\n",
216 			    isp->isp_name, status);
217 			break;
218 		}
219 		isp_notify_ack(isp, vptr);
220 		break;
221 
222 	case RQSTYPE_NOTIFY_ACK:
223 		/*
224 		 * The ISP is acknowledging our acknowledgement of an
225 		 * Immediate Notify entry for some asynchronous event.
226 		 */
227 		if (IS_FC(isp)) {
228 			ITDEBUG(2, ("%s: Notify Ack status=0x%x seqid 0x%x\n",
229 			    isp->isp_name, nack_fcp->na_status,
230 			    nack_fcp->na_seqid));
231 		} else {
232 			ITDEBUG(2, ("%s: Notify Ack event 0x%x status=0x%x "
233 			    "seqid 0x%x\n", isp->isp_name, nackp->na_event,
234 			    nackp->na_status, nackp->na_seqid));
235 		}
236 		break;
237 	default:
238 		PRINTF("%s: Unknown entry type 0x%x in isp_target_notify",
239 		    isp->isp_name, hdrp->rqs_entry_type);
240 		rval = -1;
241 		break;
242 	}
243 	if (isp_tdebug) {
244 		MEMZERO(vptr, QENTRY_LEN);
245 	}
246 #undef	atiop
247 #undef	at2iop
248 #undef	ctiop
249 #undef	ct2iop
250 #undef	lunenp
251 #undef	inotp
252 #undef	inot_fcp
253 #undef	nackp
254 #undef	nack_fcp
255 #undef	hdrp
256 	return (rval);
257 }
258 
259 
260 /*
261  * Toggle (on/off) target mode for bus/target/lun
262  *
263  * The caller has checked for overlap and legality.
264  *
265  * Note that not all of bus, target or lun can be paid attention to.
266  * Note also that this action will not be complete until the f/w writes
267  * response entry. The caller is responsible for synchronizing this.
268  */
269 int
270 isp_lun_cmd(isp, cmd, bus, tgt, lun, opaque)
271 	struct ispsoftc *isp;
272 	int cmd;
273 	int bus;
274 	int tgt;
275 	int lun;
276 	u_int32_t opaque;
277 {
278 	lun_entry_t el;
279 	u_int16_t iptr, optr;
280 	void *outp;
281 
282 
283 	MEMZERO(&el, sizeof (el));
284 	if (IS_DUALBUS(isp)) {
285 		el.le_rsvd = (bus & 0x1) << 7;
286 	}
287 	el.le_cmd_count = DFLT_CMD_CNT;
288 	el.le_in_count = DFLT_INOTIFY;
289 	if (cmd == RQSTYPE_ENABLE_LUN) {
290 		if (IS_SCSI(isp)) {
291 			el.le_flags = LUN_TQAE|LUN_DISAD;
292 			el.le_cdb6len = 12;
293 			el.le_cdb7len = 12;
294 		}
295 	} else if (cmd == -RQSTYPE_ENABLE_LUN) {
296 		cmd = RQSTYPE_ENABLE_LUN;
297 		el.le_cmd_count = 0;
298 		el.le_in_count = 0;
299 	} else if (cmd == -RQSTYPE_MODIFY_LUN) {
300 		cmd = RQSTYPE_MODIFY_LUN;
301 		el.le_ops = LUN_CCDECR | LUN_INDECR;
302 	} else {
303 		el.le_ops = LUN_CCINCR | LUN_ININCR;
304 	}
305 	el.le_header.rqs_entry_type = cmd;
306 	el.le_header.rqs_entry_count = 1;
307 	el.le_reserved = opaque;
308 	if (IS_SCSI(isp)) {
309 		el.le_tgt = tgt;
310 		el.le_lun = lun;
311 	} else if (isp->isp_maxluns <= 16) {
312 		el.le_lun = lun;
313 	}
314 
315 	if (isp_getrqentry(isp, &iptr, &optr, &outp)) {
316 		PRINTF("%s: Request Queue Overflow in isp_lun_cmd\n",
317 		    isp->isp_name);
318 		return (-1);
319 	}
320 	ISP_SWIZ_ENABLE_LUN(isp, outp, &el);
321 	ISP_TDQE(isp, "isp_lun_cmd", (int) optr, &el);
322 	ISP_ADD_REQUEST(isp, iptr);
323 	return (0);
324 }
325 
326 
327 int
328 isp_target_put_entry(isp, ap)
329 	struct ispsoftc *isp;
330 	void *ap;
331 {
332 	void *outp;
333 	u_int16_t iptr, optr;
334 	u_int8_t etype = ((isphdr_t *) ap)->rqs_entry_type;
335 
336 	if (isp_getrqentry(isp, &iptr, &optr, &outp)) {
337 		PRINTF("%s: Request Queue Overflow in isp_target_put_entry "
338 		    "for type 0x%x\n", isp->isp_name, etype);
339 		return (-1);
340 	}
341 	switch (etype) {
342 	case RQSTYPE_ATIO:
343 		ISP_SWIZ_ATIO(isp, outp, ap);
344 		break;
345 	case RQSTYPE_ATIO2:
346 		ISP_SWIZ_ATIO2(isp, outp, ap);
347 		break;
348 	case RQSTYPE_CTIO:
349 		ISP_SWIZ_CTIO(isp, outp, ap);
350 		break;
351 	case RQSTYPE_CTIO2:
352 		ISP_SWIZ_CTIO2(isp, outp, ap);
353 		break;
354 	default:
355 		PRINTF("%s: Unknown type 0x%x in isp_put_entry\n",
356 		    isp->isp_name, etype);
357 		return (-1);
358 	}
359 
360 	ISP_TDQE(isp, "isp_target_put_entry", (int) optr, ap);;
361 
362 	ISP_ADD_REQUEST(isp, iptr);
363 	return (0);
364 }
365 
366 int
367 isp_target_put_atio(isp, iid, tgt, lun, ttype, tval)
368 	struct ispsoftc *isp;
369 	int iid;
370 	int tgt;
371 	int lun;
372 	int ttype;
373 	int tval;
374 {
375 	union {
376 		at_entry_t _atio;
377 		at2_entry_t _atio2;
378 	} atun;
379 
380 	MEMZERO(&atun, sizeof atun);
381 	if (IS_FC(isp)) {
382 		atun._atio2.at_header.rqs_entry_type = RQSTYPE_ATIO2;
383 		atun._atio2.at_header.rqs_entry_count = 1;
384 		if (isp->isp_maxluns > 16) {
385 			atun._atio2.at_scclun = (u_int16_t) lun;
386 		} else {
387 			atun._atio2.at_lun = (u_int8_t) lun;
388 		}
389 		atun._atio2.at_status = CT_OK;
390 	} else {
391 		atun._atio.at_header.rqs_entry_type = RQSTYPE_ATIO;
392 		atun._atio.at_header.rqs_entry_count = 1;
393 		atun._atio.at_iid = iid;
394 		atun._atio.at_tgt = tgt;
395 		atun._atio.at_lun = lun;
396 		atun._atio.at_tag_type = ttype;
397 		atun._atio.at_tag_val = tval;
398 		atun._atio.at_status = CT_OK;
399 	}
400 	return (isp_target_put_entry(isp, &atun));
401 }
402 
403 /*
404  * Command completion- both for handling cases of no resources or
405  * no blackhole driver, or other cases where we have to, inline,
406  * finish the command sanely, or for normal command completion.
407  *
408  * The 'completion' code value has the scsi status byte in the low 8 bits.
409  * If status is a CHECK CONDITION and bit 8 is nonzero, then bits 12..15 have
410  * the sense key and  bits 16..23 have the ASCQ and bits 24..31 have the ASC
411  * values.
412  *
413  * NB: the key, asc, ascq, cannot be used for parallel SCSI as it doesn't
414  * NB: inline SCSI sense reporting.
415  *
416  * For both parallel && fibre channel, we use the feature that does
417  * an automatic resource autoreplenish so we don't have then later do
418  * put of an atio to replenish the f/w's resource count.
419  */
420 
421 int
422 isp_endcmd(struct ispsoftc *isp, void *arg, u_int32_t code, u_int32_t hdl)
423 {
424 	int sts;
425 	union {
426 		ct_entry_t _ctio;
427 		ct2_entry_t _ctio2;
428 	} un;
429 
430 	MEMZERO(&un, sizeof un);
431 	sts = code & 0xff;
432 
433 	if (IS_FC(isp)) {
434 		at2_entry_t *aep = arg;
435 		ct2_entry_t *cto = &un._ctio2;
436 
437 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
438 		cto->ct_header.rqs_entry_count = 1;
439 		cto->ct_iid = aep->at_iid;
440 		if (isp->isp_maxluns <= 16) {
441 			cto->ct_lun = aep->at_lun;
442 		}
443 		cto->ct_rxid = aep->at_rxid;
444 		cto->rsp.m1.ct_scsi_status = sts & 0xff;
445 		cto->ct_flags = CT2_SENDSTATUS | CT2_NO_DATA | CT2_FLAG_MODE1;
446 		if (hdl == 0) {
447 			cto->ct_flags |= CT2_CCINCR;
448 		}
449 		if (aep->at_datalen) {
450 			cto->ct_resid = aep->at_datalen;
451 			cto->ct_flags |= CT2_DATA_UNDER;
452 		}
453 		if ((sts & 0xff) == SCSI_CHECK && (sts & ECMD_SVALID)) {
454 			cto->rsp.m1.ct_resp[0] = 0xf0;
455 			cto->rsp.m1.ct_resp[2] = (code >> 12) & 0xf;
456 			cto->rsp.m1.ct_resp[7] = 8;
457 			cto->rsp.m1.ct_resp[12] = (code >> 24) & 0xff;
458 			cto->rsp.m1.ct_resp[13] = (code >> 16) & 0xff;
459 			cto->rsp.m1.ct_senselen = 16;
460 			cto->ct_flags |= CT2_SNSLEN_VALID;
461 		}
462 		cto->ct_reserved = hdl;
463 	} else {
464 		at_entry_t *aep = arg;
465 		ct_entry_t *cto = &un._ctio;
466 
467 		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
468 		cto->ct_header.rqs_entry_count = 1;
469 		cto->ct_iid = aep->at_iid;
470 		cto->ct_tgt = aep->at_tgt;
471 		cto->ct_lun = aep->at_lun;
472 		cto->ct_tag_type = aep->at_tag_type;
473 		cto->ct_tag_val = aep->at_tag_val;
474 		cto->ct_flags = CT_SENDSTATUS | CT_NO_DATA;
475 		if (hdl == 0) {
476 			cto->ct_flags |= CT_CCINCR;
477 		}
478 		cto->ct_scsi_status = sts;
479 		cto->ct_reserved = hdl;
480 	}
481 	return (isp_target_put_entry(isp, &un));
482 }
483 
484 void
485 isp_target_async(isp, bus, event)
486 	struct ispsoftc *isp;
487 	int bus;
488 	int event;
489 {
490 	tmd_event_t evt;
491 	tmd_msg_t msg;
492 
493 	switch (event) {
494 	/*
495 	 * These three we handle here to propagate an effective bus reset
496 	 * upstream, but these do not require any immediate notify actions
497 	 * so we return when done.
498 	 */
499 	case ASYNC_LIP_OCCURRED:
500 	case ASYNC_LOOP_UP:
501 	case ASYNC_LOOP_DOWN:
502 		evt.ev_bus = bus;
503 		evt.ev_event = event;
504 		(void) isp_async(isp, ISPASYNC_TARGET_EVENT, &evt);
505 		return;
506 
507 	case ASYNC_LOOP_RESET:
508 	case ASYNC_BUS_RESET:
509 	case ASYNC_TIMEOUT_RESET:
510 		if (IS_FC(isp)) {
511 			return;	/* we'll be getting an inotify instead */
512 		}
513 		evt.ev_bus = bus;
514 		evt.ev_event = event;
515 		(void) isp_async(isp, ISPASYNC_TARGET_EVENT, &evt);
516 		break;
517 	case ASYNC_DEVICE_RESET:
518 		/*
519 		 * Bus Device Reset resets a specific target, so
520 		 * we pass this as a synthesized message.
521 		 */
522 		MEMZERO(&msg, sizeof msg);
523 		if (IS_FC(isp)) {
524 			msg.nt_iid =
525 			    ((fcparam *)isp->isp_param)->isp_loopid;
526 		} else {
527 			msg.nt_iid =
528 			    ((sdparam *)isp->isp_param)->isp_initiator_id;
529 		}
530 		msg.nt_bus = bus;
531 		msg.nt_msg[0] = MSG_BUS_DEV_RESET;
532 		(void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg);
533 		break;
534 	default:
535 		PRINTF("%s: isp_target_async: unknown event 0x%x\n",
536 		    isp->isp_name, event);
537 		break;
538 	}
539 	if (isp->isp_state == ISP_RUNSTATE)
540 		isp_notify_ack(isp, NULL);
541 }
542 
543 
544 /*
545  * Process a received message.
546  * The ISP firmware can handle most messages, there are only
547  * a few that we need to deal with:
548  * - abort: clean up the current command
549  * - abort tag and clear queue
550  */
551 
552 static void
553 isp_got_msg(isp, bus, inp)
554 	struct ispsoftc *isp;
555 	int bus;
556 	in_entry_t *inp;
557 {
558 	u_int8_t status = inp->in_status & ~QLTM_SVALID;
559 
560 	if (status == IN_IDE_RECEIVED || status == IN_MSG_RECEIVED) {
561 		tmd_msg_t msg;
562 
563 		MEMZERO(&msg, sizeof (msg));
564 		msg.nt_bus = bus;
565 		msg.nt_iid = inp->in_iid;
566 		msg.nt_tgt = inp->in_tgt;
567 		msg.nt_lun = inp->in_lun;
568 		msg.nt_tagtype = inp->in_tag_type;
569 		msg.nt_tagval = inp->in_tag_val;
570 		MEMCPY(msg.nt_msg, inp->in_msg, IN_MSGLEN);
571 		(void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg);
572 	} else {
573 		PRINTF("%s: unknown immediate notify status 0x%x\n",
574 		    isp->isp_name, inp->in_status);
575 	}
576 }
577 
578 /*
579  * Synthesize a message from the task management flags in a FCP_CMND_IU.
580  */
581 static void
582 isp_got_msg_fc(isp, bus, inp)
583 	struct ispsoftc *isp;
584 	int bus;
585 	in_fcentry_t *inp;
586 {
587 	static char *f1 = "%s: %s from iid %d lun %d seq 0x%x\n";
588 	static char *f2 =
589 	    "%s: unknown %s 0x%x lun %d iid %d task flags 0x%x seq 0x%x\n";
590 
591 	if (inp->in_status != IN_MSG_RECEIVED) {
592 		PRINTF(f2, isp->isp_name, "immediate notify status",
593 		    inp->in_status, inp->in_lun, inp->in_iid,
594 		    inp->in_task_flags,  inp->in_seqid);
595 	} else {
596 		tmd_msg_t msg;
597 
598 		MEMZERO(&msg, sizeof (msg));
599 		msg.nt_bus = bus;
600 		msg.nt_iid = inp->in_iid;
601 		if (isp->isp_maxluns > 16) {
602 			msg.nt_lun = inp->in_scclun;
603 		} else {
604 			msg.nt_lun = inp->in_lun;
605 		}
606 		msg.nt_tagval = inp->in_seqid;
607 
608 		if (inp->in_task_flags & TASK_FLAGS_ABORT_TASK) {
609 			PRINTF(f1, isp->isp_name, "ABORT TASK",
610 			    inp->in_iid, inp->in_lun, inp->in_seqid);
611 			msg.nt_msg[0] = MSG_ABORT_TAG;
612 		} else if (inp->in_task_flags & TASK_FLAGS_CLEAR_TASK_SET) {
613 			PRINTF(f1, isp->isp_name, "CLEAR TASK SET",
614 			    inp->in_iid, inp->in_lun, inp->in_seqid);
615 			msg.nt_msg[0] = MSG_CLEAR_QUEUE;
616 		} else if (inp->in_task_flags & TASK_FLAGS_TARGET_RESET) {
617 			PRINTF(f1, isp->isp_name, "TARGET RESET",
618 			    inp->in_iid, inp->in_lun, inp->in_seqid);
619 			msg.nt_msg[0] = MSG_BUS_DEV_RESET;
620 		} else if (inp->in_task_flags & TASK_FLAGS_CLEAR_ACA) {
621 			PRINTF(f1, isp->isp_name, "CLEAR ACA",
622 			    inp->in_iid, inp->in_lun, inp->in_seqid);
623 			/* ???? */
624 			msg.nt_msg[0] = MSG_REL_RECOVERY;
625 		} else if (inp->in_task_flags & TASK_FLAGS_TERMINATE_TASK) {
626 			PRINTF(f1, isp->isp_name, "TERMINATE TASK",
627 			    inp->in_iid, inp->in_lun, inp->in_seqid);
628 			msg.nt_msg[0] = MSG_TERM_IO_PROC;
629 		} else {
630 			PRINTF(f2, isp->isp_name, "task flag",
631 			    inp->in_status, inp->in_lun, inp->in_iid,
632 			    inp->in_task_flags,  inp->in_seqid);
633 		}
634 		if (msg.nt_msg[0]) {
635 			(void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg);
636 		}
637 	}
638 }
639 
640 static void
641 isp_notify_ack(isp, arg)
642 	struct ispsoftc *isp;
643 	void *arg;
644 {
645 	char storage[QENTRY_LEN];
646 	u_int16_t iptr, optr;
647 	void *outp;
648 
649 	if (isp_getrqentry(isp, &iptr, &optr, &outp)) {
650 		PRINTF("%s: Request Queue Overflow For isp_notify_ack\n",
651 		    isp->isp_name);
652 		return;
653 	}
654 
655 	MEMZERO(storage, QENTRY_LEN);
656 
657 	if (IS_FC(isp)) {
658 		na_fcentry_t *na = (na_fcentry_t *) storage;
659 		if (arg) {
660 			in_fcentry_t *inp = arg;
661 			MEMCPY(storage, arg, sizeof (isphdr_t));
662 			na->na_iid = inp->in_iid;
663 			if (isp->isp_maxluns > 16) {
664 				na->na_lun = inp->in_scclun;
665 			} else {
666 				na->na_lun = inp->in_lun;
667 			}
668 			na->na_task_flags = inp->in_task_flags;
669 			na->na_seqid = inp->in_seqid;
670 			na->na_flags = NAFC_RCOUNT;
671 			if (inp->in_status == IN_RESET) {
672 				na->na_flags |= NAFC_RST_CLRD;
673 			}
674 		} else {
675 			na->na_flags = NAFC_RST_CLRD;
676 		}
677 		na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK;
678 		na->na_header.rqs_entry_count = 1;
679 		ISP_SWIZ_NOT_ACK_FC(isp, outp, na);
680 	} else {
681 		na_entry_t *na = (na_entry_t *) storage;
682 		if (arg) {
683 			in_entry_t *inp = arg;
684 			MEMCPY(storage, arg, sizeof (isphdr_t));
685 			na->na_iid = inp->in_iid;
686 			na->na_lun = inp->in_lun;
687 			na->na_tgt = inp->in_tgt;
688 			na->na_seqid = inp->in_seqid;
689 			if (inp->in_status == IN_RESET) {
690 				na->na_event = NA_RST_CLRD;
691 			}
692 		} else {
693 			na->na_event = NA_RST_CLRD;
694 		}
695 		na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK;
696 		na->na_header.rqs_entry_count = 1;
697 		ISP_SWIZ_NOT_ACK(isp, outp, na);
698 	}
699 	ISP_TDQE(isp, "isp_notify_ack", (int) optr, storage);
700 	ISP_ADD_REQUEST(isp, iptr);
701 }
702 
703 static void
704 isp_handle_atio(isp, aep)
705 	struct ispsoftc *isp;
706 	at_entry_t *aep;
707 {
708 	int lun;
709 	lun = aep->at_lun;
710 	/*
711 	 * The firmware status (except for the QLTM_SVALID bit) indicates
712 	 * why this ATIO was sent to us.
713 	 *
714 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
715 	 *
716 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
717 	 * we're still connected on the SCSI bus - i.e. the initiator
718 	 * did not set DiscPriv in the identify message. We don't care
719 	 * about this so it's ignored.
720 	 */
721 
722 	switch(aep->at_status & ~QLTM_SVALID) {
723 	case AT_PATH_INVALID:
724 		/*
725 		 * ATIO rejected by the firmware due to disabled lun.
726 		 */
727 		PRINTF("%s: rejected ATIO for disabled lun %d\n",
728 		    isp->isp_name, lun);
729 		break;
730 	case AT_NOCAP:
731 		/*
732 		 * Requested Capability not available
733 		 * We sent an ATIO that overflowed the firmware's
734 		 * command resource count.
735 		 */
736 		PRINTF("%s: rejected ATIO for lun %d because of command count"
737 		    " overflow\n", isp->isp_name, lun);
738 		break;
739 
740 	case AT_BDR_MSG:
741 		/*
742 		 * If we send an ATIO to the firmware to increment
743 		 * its command resource count, and the firmware is
744 		 * recovering from a Bus Device Reset, it returns
745 		 * the ATIO with this status. We set the command
746 		 * resource count in the Enable Lun entry and no
747 		 * not increment it. Therefore we should never get
748 		 * this status here.
749 		 */
750 		PRINTF("%s: ATIO returned for lun %d because it was in the "
751 		    " middle of coping with a Bus Device Reset\n",
752 		    isp->isp_name, lun);
753 		break;
754 
755 	case AT_CDB:		/* Got a CDB */
756 	case AT_PHASE_ERROR:	/* Bus Phase Sequence Error */
757 		/*
758 		 * Punt to platform specific layer.
759 		 */
760 		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep);
761 		break;
762 
763 	case AT_RESET:
764 		/*
765 		 * A bus reset came along an blew away this command. Why
766 		 * they do this in addition the async event code stuff,
767 		 * I dunno.
768 		 *
769 		 * Ignore it because the async event will clear things
770 		 * up for us.
771 		 */
772 		PRINTF("%s: ATIO returned for lun %d from initiator %d because"
773 		    " a Bus Reset occurred\n", isp->isp_name, lun,
774 		    aep->at_iid);
775 		break;
776 
777 
778 	default:
779 		PRINTF("%s: Unknown ATIO status 0x%x from initiator %d for lun"
780 		    " %d\n", isp->isp_name, aep->at_status, aep->at_iid, lun);
781 		(void) isp_target_put_atio(isp, aep->at_iid, aep->at_tgt,
782 		    lun, aep->at_tag_type, aep->at_tag_val);
783 		break;
784 	}
785 }
786 
787 static void
788 isp_handle_atio2(isp, aep)
789 	struct ispsoftc *isp;
790 	at2_entry_t *aep;
791 {
792 	int lun;
793 
794 	if (isp->isp_maxluns > 16) {
795 		lun = aep->at_scclun;
796 	} else {
797 		lun = aep->at_lun;
798 	}
799 
800 	/*
801 	 * The firmware status (except for the QLTM_SVALID bit) indicates
802 	 * why this ATIO was sent to us.
803 	 *
804 	 * If QLTM_SVALID is set, the firware has recommended Sense Data.
805 	 *
806 	 * If the DISCONNECTS DISABLED bit is set in the flags field,
807 	 * we're still connected on the SCSI bus - i.e. the initiator
808 	 * did not set DiscPriv in the identify message. We don't care
809 	 * about this so it's ignored.
810 	 */
811 
812 	switch(aep->at_status & ~QLTM_SVALID) {
813 	case AT_PATH_INVALID:
814 		/*
815 		 * ATIO rejected by the firmware due to disabled lun.
816 		 */
817 		PRINTF("%s: rejected ATIO2 for disabled lun %d\n",
818 		    isp->isp_name, lun);
819 		break;
820 	case AT_NOCAP:
821 		/*
822 		 * Requested Capability not available
823 		 * We sent an ATIO that overflowed the firmware's
824 		 * command resource count.
825 		 */
826 		PRINTF("%s: rejected ATIO2 for lun %d because of command count"
827 		    " overflow\n", isp->isp_name, lun);
828 		break;
829 
830 	case AT_BDR_MSG:
831 		/*
832 		 * If we send an ATIO to the firmware to increment
833 		 * its command resource count, and the firmware is
834 		 * recovering from a Bus Device Reset, it returns
835 		 * the ATIO with this status. We set the command
836 		 * resource count in the Enable Lun entry and no
837 		 * not increment it. Therefore we should never get
838 		 * this status here.
839 		 */
840 		PRINTF("%s: ATIO2 returned for lun %d because it was in the "
841 		    " middle of coping with a Bus Device Reset\n",
842 		    isp->isp_name, lun);
843 		break;
844 
845 	case AT_CDB:		/* Got a CDB */
846 		/*
847 		 * Punt to platform specific layer.
848 		 */
849 		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep);
850 		break;
851 
852 	case AT_RESET:
853 		/*
854 		 * A bus reset came along an blew away this command. Why
855 		 * they do this in addition the async event code stuff,
856 		 * I dunno.
857 		 *
858 		 * Ignore it because the async event will clear things
859 		 * up for us.
860 		 */
861 		PRINTF("%s: ATIO2 returned for lun %d from initiator %d because"
862 		    " a Bus Reset occurred\n", isp->isp_name, lun,
863 		    aep->at_iid);
864 		break;
865 
866 
867 	default:
868 		PRINTF("%s: Unknown ATIO2 status 0x%x from initiator %d for lun"
869 		    " %d\n", isp->isp_name, aep->at_status, aep->at_iid, lun);
870 		(void) isp_target_put_atio(isp, aep->at_iid, 0, lun, 0, 0);
871 		break;
872 	}
873 }
874 
875 static void
876 isp_handle_ctio(isp, ct)
877 	struct ispsoftc *isp;
878 	ct_entry_t *ct;
879 {
880 	ISP_SCSI_XFER_T *xs;
881 	int pl = 0;
882 	char *fmsg = NULL;
883 
884 	if (ct->ct_reserved) {
885 		xs = isp_find_xs(isp, ct->ct_reserved);
886 		if (xs == NULL)
887 			pl = 0;
888 	} else {
889 		pl = 2;
890 		xs = NULL;
891 	}
892 
893 	switch(ct->ct_status & ~QLTM_SVALID) {
894 	case CT_OK:
895 		/*
896 		 * There are generally 3 possibilities as to why we'd get
897 		 * this condition:
898 		 * 	We disconnected after receiving a CDB.
899 		 * 	We sent or received data.
900 		 * 	We sent status & command complete.
901 		 */
902 
903 		if (ct->ct_flags & CT_SENDSTATUS) {
904 			break;
905 		} else if ((ct->ct_flags & CT_DATAMASK) == CT_NO_DATA) {
906 			/*
907 			 * Nothing to do in this case.
908 			 */
909 			IDPRINTF(pl, ("%s:CTIO- iid %d disconnected OK\n",
910 			    isp->isp_name, ct->ct_iid));
911 			return;
912 		}
913 		break;
914 
915 	case CT_BDR_MSG:
916 		/*
917 		 * Bus Device Reset message received or the SCSI Bus has
918 		 * been Reset; the firmware has gone to Bus Free.
919 		 *
920 		 * The firmware generates an async mailbox interupt to
921 		 * notify us of this and returns outstanding CTIOs with this
922 		 * status. These CTIOs are handled in that same way as
923 		 * CT_ABORTED ones, so just fall through here.
924 		 */
925 		fmsg = "Bus Device Reset";
926 		/*FALLTHROUGH*/
927 	case CT_RESET:
928 		if (fmsg == NULL)
929 			fmsg = "Bus Reset";
930 		/*FALLTHROUGH*/
931 	case CT_ABORTED:
932 		/*
933 		 * When an Abort message is received the firmware goes to
934 		 * Bus Free and returns all outstanding CTIOs with the status
935 		 * set, then sends us an Immediate Notify entry.
936 		 */
937 		if (fmsg == NULL)
938 			fmsg = "ABORT TASK sent by Initiator";
939 
940 		PRINTF("%s: CTIO destroyed by %s\n", isp->isp_name, fmsg);
941 		break;
942 
943 	case CT_INVAL:
944 		/*
945 		 * CTIO rejected by the firmware due to disabled lun.
946 		 * "Cannot Happen".
947 		 */
948 		PRINTF("%s: Firmware rejected CTIO for disabled lun %d\n",
949 		    isp->isp_name, ct->ct_lun);
950 		break;
951 
952 	case CT_NOPATH:
953 		/*
954 		 * CTIO rejected by the firmware due "no path for the
955 		 * nondisconnecting nexus specified". This means that
956 		 * we tried to access the bus while a non-disconnecting
957 		 * command is in process.
958 		 */
959 		PRINTF("%s: Firmware rejected CTIO for bad nexus %d/%d/%d\n",
960 		    isp->isp_name, ct->ct_iid, ct->ct_tgt, ct->ct_lun);
961 		break;
962 
963 	case CT_RSELTMO:
964 		fmsg = "Reselection";
965 		/*FALLTHROUGH*/
966 	case CT_TIMEOUT:
967 		if (fmsg == NULL)
968 			fmsg = "Command";
969 		PRINTF("%s: Firmware timed out on %s\n", isp->isp_name, fmsg);
970 		break;
971 
972 	case CT_ERR:
973 		fmsg = "Completed with Error";
974 		/*FALLTHROUGH*/
975 	case CT_PHASE_ERROR:
976 		if (fmsg == NULL)
977 			fmsg = "Phase Sequence Error";
978 		/*FALLTHROUGH*/
979 	case CT_TERMINATED:
980 		if (fmsg == NULL)
981 			fmsg = "terminated by TERMINATE TRANSFER";
982 		/*FALLTHROUGH*/
983 	case CT_NOACK:
984 		if (fmsg == NULL)
985 			fmsg = "unacknowledged Immediate Notify pending";
986 
987 		PRINTF("%s: CTIO returned by f/w- %s\n", isp->isp_name, fmsg);
988 #if	0
989 			if (status & SENSEVALID) {
990 				bcopy((caddr_t) (cep + CTIO_SENSE_OFFSET),
991 				    (caddr_t) &cdp->cd_sensedata,
992 				    sizeof(scsi_sense_t));
993 				cdp->cd_flags |= CDF_SENSEVALID;
994 			}
995 #endif
996 		break;
997 	default:
998 		PRINTF("%s: Unknown CTIO status 0x%x\n", isp->isp_name,
999 		    ct->ct_status & ~QLTM_SVALID);
1000 		break;
1001 	}
1002 
1003 	if (xs == NULL) {
1004 		/*
1005 		 * There may be more than one CTIO for a data transfer,
1006 		 * or this may be a status CTIO we're not monitoring.
1007 		 *
1008 		 * The assumption is that they'll all be returned in the
1009 		 * order we got them.
1010 		 */
1011 		if (ct->ct_reserved == 0) {
1012 			if ((ct->ct_flags & CT_SENDSTATUS) == 0) {
1013 				IDPRINTF(pl,
1014 				    ("%s: intermediate CTIO completed ok\n",
1015 				    isp->isp_name));
1016 			} else {
1017 				IDPRINTF(pl,
1018 				    ("%s: unmonitored CTIO completed ok\n",
1019 				    isp->isp_name));
1020 			}
1021 		} else {
1022 			IDPRINTF(pl,
1023 			    ("%s: NO xs for CTIO (handle 0x%x) status 0x%x\n",
1024 			    isp->isp_name, ct->ct_reserved,
1025 			    ct->ct_status & ~QLTM_SVALID));
1026 		}
1027 	} else {
1028 		if (ct->ct_flags & CT_SENDSTATUS) {
1029 			/*
1030 			 * Sent status and command complete.
1031 			 *
1032 			 * We're now really done with this command, so we
1033 			 * punt to the platform dependent layers because
1034 			 * only there can we do the appropriate command
1035 			 * complete thread synchronization.
1036 			 */
1037 			IDPRINTF(pl,
1038 			    ("%s:status CTIO complete\n", isp->isp_name));
1039 		} else {
1040 			/*
1041 			 * Final CTIO completed. Release DMA resources and
1042 			 * notify platform dependent layers.
1043 			 */
1044 			IDPRINTF(pl,
1045 			    ("%s: data CTIO complete\n", isp->isp_name));
1046 			ISP_DMAFREE(isp, xs, ct->ct_reserved);
1047 		}
1048 		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct);
1049 		/*
1050 		 * The platform layer will destroy the handle if appropriate.
1051 		 */
1052 	}
1053 }
1054 
1055 static void
1056 isp_handle_ctio2(isp, ct)
1057 	struct ispsoftc *isp;
1058 	ct2_entry_t *ct;
1059 {
1060 	ISP_SCSI_XFER_T *xs;
1061 	int pl = 3;
1062 	char *fmsg = NULL;
1063 
1064 	if (ct->ct_reserved) {
1065 		xs = isp_find_xs(isp, ct->ct_reserved);
1066 		if (xs == NULL)
1067 			pl = 0;
1068 	} else {
1069 		pl = 2;
1070 		xs = NULL;
1071 	}
1072 
1073 	switch(ct->ct_status & ~QLTM_SVALID) {
1074 	case CT_OK:
1075 		/*
1076 		 * There are generally 2 possibilities as to why we'd get
1077 		 * this condition:
1078 		 * 	We sent or received data.
1079 		 * 	We sent status & command complete.
1080 		 */
1081 
1082 		break;
1083 
1084 	case CT_BDR_MSG:
1085 		/*
1086 		 * Bus Device Reset message received or the SCSI Bus has
1087 		 * been Reset; the firmware has gone to Bus Free.
1088 		 *
1089 		 * The firmware generates an async mailbox interupt to
1090 		 * notify us of this and returns outstanding CTIOs with this
1091 		 * status. These CTIOs are handled in that same way as
1092 		 * CT_ABORTED ones, so just fall through here.
1093 		 */
1094 		fmsg = "Bus Device Reset";
1095 		/*FALLTHROUGH*/
1096 	case CT_RESET:
1097 		if (fmsg == NULL)
1098 			fmsg = "Bus Reset";
1099 		/*FALLTHROUGH*/
1100 	case CT_ABORTED:
1101 		/*
1102 		 * When an Abort message is received the firmware goes to
1103 		 * Bus Free and returns all outstanding CTIOs with the status
1104 		 * set, then sends us an Immediate Notify entry.
1105 		 */
1106 		if (fmsg == NULL)
1107 			fmsg = "ABORT TASK sent by Initiator";
1108 
1109 		PRINTF("%s: CTIO2 destroyed by %s\n", isp->isp_name, fmsg);
1110 		break;
1111 
1112 	case CT_INVAL:
1113 		/*
1114 		 * CTIO rejected by the firmware - invalid data direction.
1115 		 */
1116 		PRINTF("%s: CTIO2 had wrong data directiond\n", isp->isp_name);
1117 		break;
1118 
1119 	case CT_NOPATH:
1120 		/*
1121 		 * CTIO rejected by the firmware due "no path for the
1122 		 * nondisconnecting nexus specified". This means that
1123 		 * we tried to access the bus while a non-disconnecting
1124 		 * command is in process.
1125 		 */
1126 		PRINTF("%s: Firmware rejected CTIO2 for bad nexus %d->%d\n",
1127 		    isp->isp_name, ct->ct_iid, ct->ct_lun);
1128 		break;
1129 
1130 	case CT_RSELTMO:
1131 		fmsg = "Reselection";
1132 		/*FALLTHROUGH*/
1133 	case CT_TIMEOUT:
1134 		if (fmsg == NULL)
1135 			fmsg = "Command";
1136 		PRINTF("%s: Firmware timed out on %s\n", isp->isp_name, fmsg);
1137 		break;
1138 
1139 	case CT_ERR:
1140 		fmsg = "Completed with Error";
1141 		/*FALLTHROUGH*/
1142 	case CT_PHASE_ERROR:	/* Bus phase sequence error */
1143 		if (fmsg == NULL)
1144 			fmsg = "Phase Sequence Error";
1145 		/*FALLTHROUGH*/
1146 	case CT_TERMINATED:
1147 		if (fmsg == NULL)
1148 			fmsg = "terminated by TERMINATE TRANSFER";
1149 		/*FALLTHROUGH*/
1150 	case CT_LOGOUT:
1151 		if (fmsg == NULL)
1152 			fmsg = "Port Logout";
1153 		/*FALLTHROUGH*/
1154 	case CT_PORTNOTAVAIL:
1155 		if (fmsg == NULL)
1156 			fmsg = "Port not available";
1157 	case CT_NOACK:
1158 		if (fmsg == NULL)
1159 			fmsg = "unacknowledged Immediate Notify pending";
1160 
1161 		PRINTF("%s: CTIO returned by f/w- %s\n", isp->isp_name, fmsg);
1162 #if	0
1163 			if (status & SENSEVALID) {
1164 				bcopy((caddr_t) (cep + CTIO_SENSE_OFFSET),
1165 				    (caddr_t) &cdp->cd_sensedata,
1166 				    sizeof(scsi_sense_t));
1167 				cdp->cd_flags |= CDF_SENSEVALID;
1168 			}
1169 #endif
1170 		break;
1171 
1172 	case CT_INVRXID:
1173 		/*
1174 		 * CTIO rejected by the firmware because an invalid RX_ID.
1175 		 * Just print a message.
1176 		 */
1177 		PRINTF("%s: CTIO2 completed with Invalid RX_ID 0x%x\n",
1178 		    isp->isp_name, ct->ct_rxid);
1179 		break;
1180 
1181 	default:
1182 		IDPRINTF(pl, ("%s: Unknown CTIO status 0x%x\n", isp->isp_name,
1183 		    ct->ct_status & ~QLTM_SVALID));
1184 		break;
1185 	}
1186 
1187 	if (xs == NULL) {
1188 		/*
1189 		 * There may be more than one CTIO for a data transfer,
1190 		 * or this may be a status CTIO we're not monitoring.
1191 		 *
1192 		 * The assumption is that they'll all be returned in the
1193 		 * order we got them.
1194 		 */
1195 		if (ct->ct_reserved == 0) {
1196 			if ((ct->ct_flags & CT_SENDSTATUS) == 0) {
1197 				IDPRINTF(pl,
1198 				    ("%s: intermediate CTIO completed ok\n",
1199 				    isp->isp_name));
1200 			} else {
1201 				IDPRINTF(pl,
1202 				    ("%s: unmonitored CTIO completed ok\n",
1203 				    isp->isp_name));
1204 			}
1205 		} else {
1206 			IDPRINTF(pl,
1207 			    ("%s: NO xs for CTIO (handle 0x%x) status 0x%x\n",
1208 			    isp->isp_name, ct->ct_reserved,
1209 			    ct->ct_status & ~QLTM_SVALID));
1210 		}
1211 	} else {
1212 		if (ct->ct_flags & CT_SENDSTATUS) {
1213 			/*
1214 			 * Sent status and command complete.
1215 			 *
1216 			 * We're now really done with this command, so we
1217 			 * punt to the platform dependent layers because
1218 			 * only there can we do the appropriate command
1219 			 * complete thread synchronization.
1220 			 */
1221 			IDPRINTF(pl,
1222 			    ("%s: status CTIO complete\n", isp->isp_name));
1223 		} else {
1224 			/*
1225 			 * Final CTIO completed. Release DMA resources and
1226 			 * notify platform dependent layers.
1227 			 */
1228 			IDPRINTF(pl,
1229 			    ("%s: data CTIO complete\n", isp->isp_name));
1230 			ISP_DMAFREE(isp, xs, ct->ct_reserved);
1231 		}
1232 		(void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct);
1233 		/*
1234 		 * The platform layer will destroy the handle if appropriate.
1235 		 */
1236 	}
1237 }
1238 #endif
1239