[Midnightbsd-cvs] src [7987] trunk/sys/dev/isp: make some changes with target mode

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Thu Sep 15 04:27:12 EDT 2016


Revision: 7987
          http://svnweb.midnightbsd.org/src/?rev=7987
Author:   laffer1
Date:     2016-09-15 04:27:12 -0400 (Thu, 15 Sep 2016)
Log Message:
-----------
make some changes with target mode

Modified Paths:
--------------
    trunk/sys/dev/isp/isp_freebsd.c
    trunk/sys/dev/isp/isp_freebsd.h

Modified: trunk/sys/dev/isp/isp_freebsd.c
===================================================================
--- trunk/sys/dev/isp/isp_freebsd.c	2016-09-15 08:26:26 UTC (rev 7986)
+++ trunk/sys/dev/isp/isp_freebsd.c	2016-09-15 08:27:12 UTC (rev 7987)
@@ -74,6 +74,7 @@
 static void isp_target_thread_pi(void *);
 static void isp_target_thread_fc(void *);
 #endif
+static int isp_timer_count;
 static void isp_timer(void *);
 
 static struct cdevsw isp_cdevsw = {
@@ -225,7 +226,8 @@
 	}
 
 	callout_init_mtx(&isp->isp_osinfo.tmo, &isp->isp_osinfo.lock, 0);
-	callout_reset(&isp->isp_osinfo.tmo, hz, isp_timer, isp);
+	isp_timer_count = hz >> 2;
+	callout_reset(&isp->isp_osinfo.tmo, isp_timer_count, isp_timer, isp);
 	isp->isp_osinfo.timer_active = 1;
 
 	isp->isp_osinfo.cdev = make_dev(&isp_cdevsw, du, UID_ROOT, GID_OPERATOR, 0600, "%s", nu);
@@ -777,6 +779,7 @@
 isp_free_pcmd(ispsoftc_t *isp, union ccb *ccb)
 {
 	if (ISP_PCMD(ccb)) {
+		memset(ISP_PCMD(ccb), 0, sizeof (struct isp_pcmd));
 		((struct isp_pcmd *)ISP_PCMD(ccb))->next = isp->isp_osinfo.pcmd_free;
 		isp->isp_osinfo.pcmd_free = ISP_PCMD(ccb);
 		ISP_PCMD(ccb) = NULL;
@@ -813,7 +816,7 @@
 static timeout_t isp_refire_notify_ack;
 static void isp_complete_ctio(union ccb *);
 static void isp_target_putback_atio(union ccb *);
-enum Start_Ctio_How { FROM_CAM, FROM_SRR, FROM_CTIO_DONE };
+enum Start_Ctio_How { FROM_CAM, FROM_TIMER, FROM_SRR, FROM_CTIO_DONE };
 static void isp_target_start_ctio(ispsoftc_t *, union ccb *, enum Start_Ctio_How);
 static void isp_handle_platform_atio(ispsoftc_t *, at_entry_t *);
 static void isp_handle_platform_atio2(ispsoftc_t *, at2_entry_t *);
@@ -975,7 +978,9 @@
 isp_tmcmd_restart(ispsoftc_t *isp)
 {
 	inot_private_data_t *ntp;
+	inot_private_data_t *restart_queue;
 	tstate_t *tptr;
+	union ccb *ccb;
 	struct tslist *lhp;
 	int bus, i;
 
@@ -983,8 +988,8 @@
 		for (i = 0; i < LUN_HASH_SIZE; i++) {
 			ISP_GET_PC_ADDR(isp, bus, lun_hash[i], lhp);
 			SLIST_FOREACH(tptr, lhp, next) {
-				inot_private_data_t *restart_queue = tptr->restart_queue;
-				tptr->restart_queue = NULL;
+				if ((restart_queue = tptr->restart_queue) != NULL)
+					tptr->restart_queue = NULL;
 				while (restart_queue) {
 					ntp = restart_queue;
 					restart_queue = ntp->rd.nt.nt_hba;
@@ -1006,6 +1011,14 @@
 						break;
 					}
 				}
+				/*
+				 * We only need to do this once per tptr
+				 */
+				if (!TAILQ_EMPTY(&tptr->waitq)) {
+					ccb = (union ccb *)TAILQ_LAST(&tptr->waitq, isp_ccbq);
+					TAILQ_REMOVE(&tptr->waitq, &ccb->ccb_h, periph_links.tqe);
+					isp_target_start_ctio(isp, ccb, FROM_TIMER);
+				}
 			}
 		}
 	}
@@ -1052,8 +1065,8 @@
 		if (atp->tag == 0) {
 			continue;
 		}
-		xpt_print(tptr->owner, "ATP: [0x%x] origdlen %u bytes_xfrd %u last_xfr %u lun %u nphdl 0x%04x s_id 0x%06x d_id 0x%06x oxid 0x%04x state %s\n",
-                    atp->tag, atp->orig_datalen, atp->bytes_xfered, atp->last_xframt, atp->lun, atp->nphdl, atp->sid, atp->portid, atp->oxid, states[atp->state & 0x7]);
+		xpt_print(tptr->owner, "ATP: [0x%x] origdlen %u bytes_xfrd %u lun %u nphdl 0x%04x s_id 0x%06x d_id 0x%06x oxid 0x%04x state %s\n",
+                    atp->tag, atp->orig_datalen, atp->bytes_xfered, atp->lun, atp->nphdl, atp->sid, atp->portid, atp->oxid, states[atp->state & 0x7]);
 	}
 }
 
@@ -1118,6 +1131,7 @@
 	}
 	SLIST_INIT(&tptr->atios);
 	SLIST_INIT(&tptr->inots);
+	TAILQ_INIT(&tptr->waitq);
 	for (i = 0; i < ATPDPSIZE-1; i++) {
 		tptr->atpool[i].next = &tptr->atpool[i+1];
 		tptr->ntpool[i].next = &tptr->ntpool[i+1];
@@ -1534,533 +1548,544 @@
 static void
 isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how)
 {
-
-	void *qe;
-	int fctape, sendstatus, resid, repval = ISP_LOGTDEBUG0;
+	int fctape, sendstatus, resid;
 	tstate_t *tptr;
 	fcparam *fcp;
 	atio_private_data_t *atp;
-	struct ccb_scsiio *cso = &ccb->csio;
-	uint32_t dmaresult, handle, xfrlen, sense_length;
+	struct ccb_scsiio *cso;
+	uint32_t dmaresult, handle, xfrlen, sense_length, tmp;
 	uint8_t local[QENTRY_LEN];
 
-	/*
-	 * Do some sanity checks.
-	 */
-	xfrlen = cso->dxfer_len;
-	if (xfrlen == 0) {
-		if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) {
-			ISP_PATH_PRT(isp, ISP_LOGERR, ccb->ccb_h.path, "a data transfer length of zero but no status to send is wrong\n");
-			ccb->ccb_h.status = CAM_REQ_INVALID;
-			xpt_done(ccb);
-			return;
-		}
-	}
-
 	tptr = get_lun_statep(isp, XS_CHANNEL(ccb), XS_LUN(ccb));
 	if (tptr == NULL) {
 		tptr = get_lun_statep(isp, XS_CHANNEL(ccb), CAM_LUN_WILDCARD);
 		if (tptr == NULL) {
-			ISP_PATH_PRT(isp, ISP_LOGERR, ccb->ccb_h.path, "%s: [0x%x] cannot find tstate pointer in %s\n", __func__, cso->tag_id);
+			isp_prt(isp, ISP_LOGERR, "%s: [0x%x] cannot find tstate pointer", __func__, ccb->csio.tag_id);
 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
 			xpt_done(ccb);
 			return;
 		}
 	}
+	isp_prt(isp, ISP_LOGTDEBUG0, "%s: ENTRY[0x%x] how %u xfrlen %u sendstatus %d sense_len %u", __func__, ccb->csio.tag_id, how, ccb->csio.dxfer_len,
+	    (ccb->ccb_h.flags & CAM_SEND_STATUS) != 0, ((ccb->ccb_h.flags & CAM_SEND_SENSE)? ccb->csio.sense_len : 0));
 
-	atp = isp_get_atpd(isp, tptr, cso->tag_id);
-	if (atp == NULL) {
-		ISP_PATH_PRT(isp, ISP_LOGERR, ccb->ccb_h.path, "%s: [0x%x] cannot find private data adjunct\n", __func__, cso->tag_id);
-		isp_dump_atpd(isp, tptr);
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-		xpt_done(ccb);
-		return;
+	switch (how) {
+	case FROM_TIMER:
+	case FROM_CAM:
+		/*
+		 * Insert at the tail of the list, if any, waiting CTIO CCBs
+		 */
+		TAILQ_INSERT_TAIL(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 
+		break;
+	case FROM_SRR:
+	case FROM_CTIO_DONE:
+		TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 
+		break;
 	}
 
-	/*
-	 * Is this command a dead duck?
-	 */
-	if (atp->dead) {
-		ISP_PATH_PRT(isp, ISP_LOGERR, ccb->ccb_h.path, "%s: [0x%x] not sending a CTIO for a dead command\n", __func__, cso->tag_id);
-		ccb->ccb_h.status = CAM_REQ_ABORTED;
-		xpt_done(ccb);
-		return;
-	}
+	while (TAILQ_FIRST(&tptr->waitq) != NULL) {
+		ccb = (union ccb *) TAILQ_FIRST(&tptr->waitq);
+		TAILQ_REMOVE(&tptr->waitq, &ccb->ccb_h, periph_links.tqe);
 
-	/*
-	 * Check to make sure we're still in target mode.
-	 */
-	fcp = FCPARAM(isp, XS_CHANNEL(ccb));
-	if ((fcp->role & ISP_ROLE_TARGET) == 0) {
-		ISP_PATH_PRT(isp, ISP_LOGERR, ccb->ccb_h.path, "%s: [0x%x] stopping sending a CTIO because we're no longer in target mode\n", __func__, cso->tag_id);
-		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
-		xpt_done(ccb);
-		return;
-	}
+		cso = &ccb->csio;
+		xfrlen = cso->dxfer_len;
+		if (xfrlen == 0) {
+			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) {
+				ISP_PATH_PRT(isp, ISP_LOGERR, ccb->ccb_h.path, "a data transfer length of zero but no status to send is wrong\n");
+				ccb->ccb_h.status = CAM_REQ_INVALID;
+				xpt_done(ccb);
+				continue;
+			}
+		}
 
-	/*
-	 * We're only handling one outstanding CTIO at a time (which
-	 * could be split into two to split data and status)
-	 */
-	if (atp->ctcnt) {
-		ISP_PATH_PRT(isp, ISP_LOGINFO, ccb->ccb_h.path, "sending only one CTIO at a time\n");
-		goto restart_delay;
-	}
+		atp = isp_get_atpd(isp, tptr, cso->tag_id);
+		if (atp == NULL) {
+			isp_prt(isp, ISP_LOGERR, "%s: [0x%x] cannot find private data adjunct in %s", __func__, cso->tag_id, __func__);
+			isp_dump_atpd(isp, tptr);
+			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+			xpt_done(ccb);
+			continue;
+		}
 
+		/*
+		 * Is this command a dead duck?
+		 */
+		if (atp->dead) {
+			isp_prt(isp, ISP_LOGERR, "%s: [0x%x] not sending a CTIO for a dead command", __func__, cso->tag_id);
+			ccb->ccb_h.status = CAM_REQ_ABORTED;
+			xpt_done(ccb);
+			continue;
+		}
 
-	/*
-	 * Get some resources
-	 */
-	if (isp_get_pcmd(isp, ccb)) {
-		ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "out of PCMDs\n");
-		goto restart_delay;
-	}
-	qe = isp_getrqentry(isp);
-	if (qe == NULL) {
-		ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, rqo, __func__);
-		goto restart_delay;
-	}
-	memset(local, 0, QENTRY_LEN);
+		/*
+		 * Check to make sure we're still in target mode.
+		 */
+		fcp = FCPARAM(isp, XS_CHANNEL(ccb));
+		if ((fcp->role & ISP_ROLE_TARGET) == 0) {
+			isp_prt(isp, ISP_LOGERR, "%s: [0x%x] stopping sending a CTIO because we're no longer in target mode", __func__, cso->tag_id);
+			ccb->ccb_h.status = CAM_PROVIDE_FAIL;
+			xpt_done(ccb);
+			continue;
+		}
 
-	/*
-	 * Does the initiator expect FC-Tape style responses?
-	 * Can we provide them?
-	 */
-	if ((atp->word3 & PRLI_WD3_RETRY) && fcp->fctape_enabled) {
-		fctape = 1;
-	} else {
-		fctape = 0;
-	}
+		/*
+		 * We're only handling ATPD_CCB_OUTSTANDING outstanding CCB at a time (one of which
+		 * could be split into two CTIOs to split data and status).
+		 */
+		if (atp->ctcnt >= ATPD_CCB_OUTSTANDING) {
+			isp_prt(isp, ISP_LOGTINFO, "[0x%x] handling only %d CCBs at a time (flags for this ccb: 0x%x)", cso->tag_id, ATPD_CCB_OUTSTANDING, ccb->ccb_h.flags);
+			TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 
+			break;
+		}
 
-	/*
-	 * If we already did the data xfer portion of a CTIO that sends data
-	 * and status, don't do it again and do the status portion now.
-	 */
-	if (atp->sendst) {
-		xfrlen = 0;	/* we already did the data transfer */
-		atp->sendst = 0;
-	}
-	if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
-		sendstatus = 1;
-	} else {
-		sendstatus = 0;
-	}
-
-	if (ccb->ccb_h.flags & CAM_SEND_SENSE) {
 		/*
-		 * Sense length is not the entire sense data structure size. Periph
-		 * drivers don't seem to be setting sense_len to reflect the actual
-		 * size. We'll peek inside to get the right amount.
+		 * Does the initiator expect FC-Tape style responses?
 		 */
-		sense_length = cso->sense_len;
+		if ((atp->word3 & PRLI_WD3_RETRY) && fcp->fctape_enabled) {
+			fctape = 1;
+		} else {
+			fctape = 0;
+		}
 
 		/*
-		 * This 'cannot' happen
+		 * If we already did the data xfer portion of a CTIO that sends data
+		 * and status, don't do it again and do the status portion now.
 		 */
-		if (sense_length > (XCMD_SIZE - MIN_FCP_RESPONSE_SIZE)) {
-			sense_length = XCMD_SIZE - MIN_FCP_RESPONSE_SIZE;
+		if (atp->sendst) {
+			isp_prt(isp, ISP_LOGTINFO, "[0x%x] now sending synthesized status orig_dl=%u xfered=%u bit=%u",
+			    cso->tag_id, atp->orig_datalen, atp->bytes_xfered, atp->bytes_in_transit);
+			xfrlen = 0;	/* we already did the data transfer */
+			atp->sendst = 0;
 		}
-	} else {
-		sense_length = 0;
-	}
+		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
+			sendstatus = 1;
+		} else {
+			sendstatus = 0;
+		}
 
-	if (how == FROM_SRR || atp->nsrr)
-		repval = ISP_LOGINFO;
+		if (ccb->ccb_h.flags & CAM_SEND_SENSE) {
+			KASSERT((sendstatus != 0), ("how can you have CAM_SEND_SENSE w/o CAM_SEND_STATUS?"));
+			/*
+			 * Sense length is not the entire sense data structure size. Periph
+			 * drivers don't seem to be setting sense_len to reflect the actual
+			 * size. We'll peek inside to get the right amount.
+			 */
+			sense_length = cso->sense_len;
 
-	if (IS_24XX(isp)) {
-		ct7_entry_t *cto = (ct7_entry_t *) local;
+			/*
+			 * This 'cannot' happen
+			 */
+			if (sense_length > (XCMD_SIZE - MIN_FCP_RESPONSE_SIZE)) {
+				sense_length = XCMD_SIZE - MIN_FCP_RESPONSE_SIZE;
+			}
+		} else {
+			sense_length = 0;
+		}
 
-		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
-		cto->ct_header.rqs_entry_count = 1;
-		cto->ct_header.rqs_seqno = 1;
-		cto->ct_nphdl = atp->nphdl;
-		cto->ct_rxid = atp->tag;
-		cto->ct_iid_lo = atp->portid;
-		cto->ct_iid_hi = atp->portid >> 16;
-		cto->ct_oxid = atp->oxid;
-		cto->ct_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(ccb));
-		cto->ct_timeout = 120;
-		cto->ct_flags = atp->tattr << CT7_TASK_ATTR_SHIFT;
+		memset(local, 0, QENTRY_LEN);
 
 		/*
-		 * Mode 1, status, no data. Only possible when we are sending status, have
-		 * no data to transfer, and any sense length can fit in the ct7_entry.
-		 *
-		 * Mode 2, status, no data. We have to use this in the case sense data
-		 * won't fit into a ct7_entry_t.
-		 *
+		 * Check for overflow
 		 */
-		if (sendstatus && xfrlen == 0) {
-			cto->ct_flags |= CT7_SENDSTATUS | CT7_NO_DATA;
-			resid = atp->orig_datalen - atp->bytes_xfered;
-			if (sense_length <= MAXRESPLEN_24XX) {
-				if (resid < 0) {
-					cto->ct_resid = -resid;
-				} else if (resid > 0) {
-					cto->ct_resid = resid;
-				}
-				cto->ct_flags |= CT7_FLAG_MODE1;
-				cto->ct_scsi_status = cso->scsi_status;
-				if (resid < 0) {
-					cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8);
-				} else if (resid > 0) {
-					cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8);
-				}
-				if (fctape) {
-					cto->ct_flags |= CT7_CONFIRM|CT7_EXPLCT_CONF;
-				}
-				if (sense_length) {
-					cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8);
-					cto->rsp.m1.ct_resplen = cto->ct_senselen = sense_length;
-					memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, sense_length);
-				}
-			} else {
-				bus_addr_t addr;
-				char buf[XCMD_SIZE];
-				fcp_rsp_iu_t *rp;
+		tmp = atp->bytes_xfered + atp->bytes_in_transit + xfrlen;
+		if (tmp > atp->orig_datalen) {
+			isp_prt(isp, ISP_LOGERR, "%s: [0x%x] data overflow by %u bytes", __func__, cso->tag_id, tmp - atp->orig_datalen);
+			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
+			xpt_done(ccb);
+			continue;
+		}
 
-				if (atp->ests == NULL) {
-					atp->ests = isp_get_ecmd(isp);
+		if (IS_24XX(isp)) {
+			ct7_entry_t *cto = (ct7_entry_t *) local;
+
+			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
+			cto->ct_header.rqs_entry_count = 1;
+			cto->ct_header.rqs_seqno |= ATPD_SEQ_NOTIFY_CAM;
+			ATPD_SET_SEQNO(cto, atp);
+			cto->ct_nphdl = atp->nphdl;
+			cto->ct_rxid = atp->tag;
+			cto->ct_iid_lo = atp->portid;
+			cto->ct_iid_hi = atp->portid >> 16;
+			cto->ct_oxid = atp->oxid;
+			cto->ct_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(ccb));
+			cto->ct_timeout = 120;
+			cto->ct_flags = atp->tattr << CT7_TASK_ATTR_SHIFT;
+
+			/*
+			 * Mode 1, status, no data. Only possible when we are sending status, have
+			 * no data to transfer, and any sense length can fit in the ct7_entry.
+			 *
+			 * Mode 2, status, no data. We have to use this in the case sense data
+			 * won't fit into a ct7_entry_t.
+			 *
+			 */
+			if (sendstatus && xfrlen == 0) {
+				cto->ct_flags |= CT7_SENDSTATUS | CT7_NO_DATA;
+				resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit;
+				if (sense_length <= MAXRESPLEN_24XX) {
+					if (resid < 0) {
+						cto->ct_resid = -resid;
+					} else if (resid > 0) {
+						cto->ct_resid = resid;
+					}
+					cto->ct_flags |= CT7_FLAG_MODE1;
+					cto->ct_scsi_status = cso->scsi_status;
+					if (resid < 0) {
+						cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8);
+					} else if (resid > 0) {
+						cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8);
+					}
+					if (fctape) {
+						cto->ct_flags |= CT7_CONFIRM|CT7_EXPLCT_CONF;
+					}
+					if (sense_length) {
+						cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8);
+						cto->rsp.m1.ct_resplen = cto->ct_senselen = sense_length;
+						memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, sense_length);
+					}
+				} else {
+					bus_addr_t addr;
+					char buf[XCMD_SIZE];
+					fcp_rsp_iu_t *rp;
+
 					if (atp->ests == NULL) {
-						goto restart_delay;
+						atp->ests = isp_get_ecmd(isp);
+						if (atp->ests == NULL) {
+							TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 
+							break;
+						}
 					}
+					memset(buf, 0, sizeof (buf));
+					rp = (fcp_rsp_iu_t *)buf;
+					if (fctape) {
+						cto->ct_flags |= CT7_CONFIRM|CT7_EXPLCT_CONF;
+						rp->fcp_rsp_bits |= FCP_CONF_REQ;
+					}
+					cto->ct_flags |= CT7_FLAG_MODE2;
+	        			rp->fcp_rsp_scsi_status = cso->scsi_status;
+					if (resid < 0) {
+						rp->fcp_rsp_resid = -resid;
+						rp->fcp_rsp_bits |= FCP_RESID_OVERFLOW;
+					} else if (resid > 0) {
+						rp->fcp_rsp_resid = resid;
+						rp->fcp_rsp_bits |= FCP_RESID_UNDERFLOW;
+					}
+					if (sense_length) {
+	        				rp->fcp_rsp_snslen = sense_length;
+						cto->ct_senselen = sense_length;
+						rp->fcp_rsp_bits |= FCP_SNSLEN_VALID;
+						isp_put_fcp_rsp_iu(isp, rp, atp->ests);
+						memcpy(((fcp_rsp_iu_t *)atp->ests)->fcp_rsp_extra, &cso->sense_data, sense_length);
+					} else {
+						isp_put_fcp_rsp_iu(isp, rp, atp->ests);
+					}
+					if (isp->isp_dblev & ISP_LOGTDEBUG1) {
+						isp_print_bytes(isp, "FCP Response Frame After Swizzling", MIN_FCP_RESPONSE_SIZE + sense_length, atp->ests);
+					}
+					addr = isp->isp_osinfo.ecmd_dma;
+					addr += ((((isp_ecmd_t *)atp->ests) - isp->isp_osinfo.ecmd_base) * XCMD_SIZE);
+					isp_prt(isp, ISP_LOGTDEBUG0, "%s: ests base %p vaddr %p ecmd_dma %jx addr %jx len %u", __func__, isp->isp_osinfo.ecmd_base, atp->ests,
+					    (uintmax_t) isp->isp_osinfo.ecmd_dma, (uintmax_t)addr, MIN_FCP_RESPONSE_SIZE + sense_length);
+					cto->rsp.m2.ct_datalen = MIN_FCP_RESPONSE_SIZE + sense_length;
+					cto->rsp.m2.ct_fcp_rsp_iudata.ds_base = DMA_LO32(addr);
+					cto->rsp.m2.ct_fcp_rsp_iudata.ds_basehi = DMA_HI32(addr);
+					cto->rsp.m2.ct_fcp_rsp_iudata.ds_count = MIN_FCP_RESPONSE_SIZE + sense_length;
 				}
-				memset(buf, 0, sizeof (buf));
-				rp = (fcp_rsp_iu_t *)buf;
-				if (fctape) {
-					cto->ct_flags |= CT7_CONFIRM|CT7_EXPLCT_CONF;
-					rp->fcp_rsp_bits |= FCP_CONF_REQ;
-				}
-				cto->ct_flags |= CT7_FLAG_MODE2;
-        			rp->fcp_rsp_scsi_status = cso->scsi_status;
-				if (resid < 0) {
-					rp->fcp_rsp_resid = -resid;
-					rp->fcp_rsp_bits |= FCP_RESID_OVERFLOW;
-				} else if (resid > 0) {
-					rp->fcp_rsp_resid = resid;
-					rp->fcp_rsp_bits |= FCP_RESID_UNDERFLOW;
-				}
 				if (sense_length) {
-        				rp->fcp_rsp_snslen = sense_length;
-					cto->ct_senselen = sense_length;
-					rp->fcp_rsp_bits |= FCP_SNSLEN_VALID;
-					isp_put_fcp_rsp_iu(isp, rp, atp->ests);
-					memcpy(((fcp_rsp_iu_t *)atp->ests)->fcp_rsp_extra, &cso->sense_data, sense_length);
+					isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO7[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x resid=%d slen %u sense: %x %x/%x/%x", __func__,
+					    cto->ct_rxid, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cto->ct_scsi_status, cto->ct_flags, cto->ct_resid, sense_length,
+					    cso->sense_data.error_code, cso->sense_data.sense_buf[1], cso->sense_data.sense_buf[11], cso->sense_data.sense_buf[12]);
 				} else {
-					isp_put_fcp_rsp_iu(isp, rp, atp->ests);
+					isp_prt(isp, ISP_LOGDEBUG0, "%s: CTIO7[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x resid=%d", __func__,
+					    cto->ct_rxid, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cto->ct_scsi_status, cto->ct_flags, cto->ct_resid);
 				}
-				if (isp->isp_dblev & ISP_LOGTDEBUG1) {
-					isp_print_bytes(isp, "FCP Response Frame After Swizzling", MIN_FCP_RESPONSE_SIZE + sense_length, atp->ests);
-				}
-				addr = isp->isp_osinfo.ecmd_dma;
-				addr += ((((isp_ecmd_t *)atp->ests) - isp->isp_osinfo.ecmd_base) * XCMD_SIZE);
-				isp_prt(isp, repval, "%s: ests base %p vaddr %p ecmd_dma %jx addr %jx len %u", __func__, isp->isp_osinfo.ecmd_base, atp->ests,
-				    (uintmax_t) isp->isp_osinfo.ecmd_dma, (uintmax_t)addr, MIN_FCP_RESPONSE_SIZE + sense_length);
-				cto->rsp.m2.ct_datalen = MIN_FCP_RESPONSE_SIZE + sense_length;
-				cto->rsp.m2.ct_fcp_rsp_iudata.ds_base = DMA_LO32(addr);
-				cto->rsp.m2.ct_fcp_rsp_iudata.ds_basehi = DMA_HI32(addr);
-				cto->rsp.m2.ct_fcp_rsp_iudata.ds_count = MIN_FCP_RESPONSE_SIZE + sense_length;
+				atp->state = ATPD_STATE_LAST_CTIO;
 			}
-			if (sense_length) {
-				isp_prt(isp, repval, "%s: CTIO7[0x%x] CDB0=%x sstatus=0x%x flags=0x%x resid=%d slen %u sense: %x %x/%x/%x", __func__,
-				    cto->ct_rxid, atp->cdb0, cto->ct_scsi_status, cto->ct_flags, cto->ct_resid, sense_length, cso->sense_data.error_code,
-				    cso->sense_data.sense_buf[1], cso->sense_data.sense_buf[11], cso->sense_data.sense_buf[12]);
-			} else {
-				isp_prt(isp, repval, "%s: CTIO7[0x%x] CDB0=%x sstatus=0x%x flags=0x%x resid=%d", __func__,
-				    cto->ct_rxid, atp->cdb0, cto->ct_scsi_status, cto->ct_flags, cto->ct_resid);
-			}
-			atp->state = ATPD_STATE_LAST_CTIO;
-		}
 
-		/*
-		 * Mode 0 data transfers, *possibly* with status.
-		 */
-		if (xfrlen != 0) {
-			cto->ct_flags |= CT7_FLAG_MODE0;
-			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
-				cto->ct_flags |= CT7_DATA_IN;
-			} else {
-				cto->ct_flags |= CT7_DATA_OUT;
-			}
-
 			/*
-			 * Don't overrun the limits placed on us, but record it as
-			 * if we had so that we can set an overflow bit later.
+			 * Mode 0 data transfers, *possibly* with status.
 			 */
-			atp->last_xframt = xfrlen;
-			if (atp->bytes_xfered >= atp->orig_datalen) {
-				resid = atp->orig_datalen - (atp->bytes_xfered + xfrlen);
-			} else if (atp->bytes_xfered + xfrlen > atp->orig_datalen) {
-				resid = atp->orig_datalen - (atp->bytes_xfered + xfrlen);
-				xfrlen = atp->orig_datalen - atp->bytes_xfered;
-			} else {
-				resid = atp->orig_datalen - xfrlen;
-			}
-			cto->rsp.m0.reloff = atp->bytes_xfered;
-			cto->rsp.m0.ct_xfrlen = xfrlen;
+			if (xfrlen != 0) {
+				cto->ct_flags |= CT7_FLAG_MODE0;
+				if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
+					cto->ct_flags |= CT7_DATA_IN;
+				} else {
+					cto->ct_flags |= CT7_DATA_OUT;
+				}
 
+				cto->rsp.m0.reloff = atp->bytes_xfered + atp->bytes_in_transit;
+				cto->rsp.m0.ct_xfrlen = xfrlen;
+
 #ifdef	DEBUG
-			if (ISP_FC_PC(isp, XS_CHANNEL(ccb))->inject_lost_data_frame && xfrlen > ISP_FC_PC(isp, XS_CHANNEL(ccb))->inject_lost_data_frame) {
-				isp_prt(isp, ISP_LOGWARN, "%s: truncating data frame with xfrlen %d to %d", __func__, xfrlen, xfrlen - (xfrlen >> 2));
-				ISP_FC_PC(isp, XS_CHANNEL(ccb))->inject_lost_data_frame = 0;
-				cto->rsp.m0.ct_xfrlen -= xfrlen >> 2;
-			}
+				if (ISP_FC_PC(isp, XS_CHANNEL(ccb))->inject_lost_data_frame && xfrlen > ISP_FC_PC(isp, XS_CHANNEL(ccb))->inject_lost_data_frame) {
+					isp_prt(isp, ISP_LOGWARN, "%s: truncating data frame with xfrlen %d to %d", __func__, xfrlen, xfrlen - (xfrlen >> 2));
+					ISP_FC_PC(isp, XS_CHANNEL(ccb))->inject_lost_data_frame = 0;
+					cto->rsp.m0.ct_xfrlen -= xfrlen >> 2;
+				}
 #endif
-			if (sendstatus) {
-				if (cso->scsi_status == SCSI_STATUS_OK && resid == 0 && fctape == 0) {
-					cto->ct_flags |= CT7_SENDSTATUS;
-					atp->state = ATPD_STATE_LAST_CTIO;
+				if (sendstatus) {
+					resid = atp->orig_datalen - atp->bytes_xfered - xfrlen;
+					if (cso->scsi_status == SCSI_STATUS_OK && resid == 0 /* && fctape == 0 */) {
+						cto->ct_flags |= CT7_SENDSTATUS;
+						atp->state = ATPD_STATE_LAST_CTIO;
+						if (fctape) {
+							cto->ct_flags |= CT7_CONFIRM|CT7_EXPLCT_CONF;
+						}
+					} else {
+						atp->sendst = 1;	/* send status later */
+						cto->ct_header.rqs_seqno &= ~ATPD_SEQ_NOTIFY_CAM;
+						atp->state = ATPD_STATE_CTIO;
+					}
 				} else {
-					atp->sendst = 1;	/* send status later */
-					cto->ct_header.rqs_seqno = 0;
 					atp->state = ATPD_STATE_CTIO;
 				}
-			} else {
-				atp->state = ATPD_STATE_CTIO;
+				isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO7[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x xfrlen=%u off=%u", __func__,
+				    cto->ct_rxid, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cto->ct_scsi_status, cto->ct_flags, xfrlen, atp->bytes_xfered);
 			}
-			isp_prt(isp, repval, "%s: CTIO7[0x%x] CDB0=%x sstatus=0x%x flags=0x%x xfrlen=%u off=%u", __func__,
-			    cto->ct_rxid, atp->cdb0, cto->ct_scsi_status, cto->ct_flags, xfrlen, atp->bytes_xfered);
-		}
-	} else if (IS_FC(isp)) {
-		ct2_entry_t *cto = (ct2_entry_t *) local;
+		} else if (IS_FC(isp)) {
+			ct2_entry_t *cto = (ct2_entry_t *) local;
 
-		if (isp->isp_osinfo.sixtyfourbit)
-			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO3;
-		else
-			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
-		cto->ct_header.rqs_entry_count = 1;
-		cto->ct_header.rqs_seqno = 1;
-		if (ISP_CAP_2KLOGIN(isp) == 0) {
-			((ct2e_entry_t *)cto)->ct_iid = cso->init_id;
-		} else {
-			cto->ct_iid = cso->init_id;
-			if (ISP_CAP_SCCFW(isp) == 0) {
-				cto->ct_lun = ccb->ccb_h.target_lun;
+			if (isp->isp_osinfo.sixtyfourbit)
+				cto->ct_header.rqs_entry_type = RQSTYPE_CTIO3;
+			else
+				cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
+			cto->ct_header.rqs_entry_count = 1;
+			cto->ct_header.rqs_seqno |= ATPD_SEQ_NOTIFY_CAM;
+			ATPD_SET_SEQNO(cto, atp);
+			if (ISP_CAP_2KLOGIN(isp) == 0) {
+				((ct2e_entry_t *)cto)->ct_iid = cso->init_id;
+			} else {
+				cto->ct_iid = cso->init_id;
+				if (ISP_CAP_SCCFW(isp) == 0) {
+					cto->ct_lun = ccb->ccb_h.target_lun;
+				}
 			}
-		}
-		cto->ct_timeout = 10;
-		cto->ct_rxid = cso->tag_id;
+			cto->ct_timeout = 10;
+			cto->ct_rxid = cso->tag_id;
 
-		/*
-		 * Mode 1, status, no data. Only possible when we are sending status, have
-		 * no data to transfer, and the sense length can fit in the ct7_entry.
-		 *
-		 * Mode 2, status, no data. We have to use this in the case the the response
-		 * length won't fit into a ct2_entry_t.
-		 *
-		 * We'll fill out this structure with information as if this were a
-		 * Mode 1. The hardware layer will create the Mode 2 FCP RSP IU as
-		 * needed based upon this.
-		 */
-		if (sendstatus && xfrlen == 0) {
-			cto->ct_flags |= CT2_SENDSTATUS | CT2_NO_DATA;
-			resid = atp->orig_datalen - atp->bytes_xfered;
-			if (sense_length <= MAXRESPLEN) {
-				if (resid < 0) {
-					cto->ct_resid = -resid;
-				} else if (resid > 0) {
-					cto->ct_resid = resid;
-				}
-				cto->ct_flags |= CT2_FLAG_MODE1;
-				cto->rsp.m1.ct_scsi_status = cso->scsi_status;
-				if (resid < 0) {
-					cto->rsp.m1.ct_scsi_status |= CT2_DATA_OVER;
-				} else if (resid > 0) {
-					cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER;
-				}
-				if (fctape) {
-					cto->ct_flags |= CT2_CONFIRM;
-				}
-				if (sense_length) {
-					cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
-					cto->rsp.m1.ct_resplen = cto->rsp.m1.ct_senselen = sense_length;
-					memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, sense_length);
-				}
-			} else {
-				bus_addr_t addr;
-				char buf[XCMD_SIZE];
-				fcp_rsp_iu_t *rp;
+			/*
+			 * Mode 1, status, no data. Only possible when we are sending status, have
+			 * no data to transfer, and the sense length can fit in the ct7_entry.
+			 *
+			 * Mode 2, status, no data. We have to use this in the case the the response
+			 * length won't fit into a ct2_entry_t.
+			 *
+			 * We'll fill out this structure with information as if this were a
+			 * Mode 1. The hardware layer will create the Mode 2 FCP RSP IU as
+			 * needed based upon this.
+			 */
+			if (sendstatus && xfrlen == 0) {
+				cto->ct_flags |= CT2_SENDSTATUS | CT2_NO_DATA;
+				resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit;
+				if (sense_length <= MAXRESPLEN) {
+					if (resid < 0) {
+						cto->ct_resid = -resid;
+					} else if (resid > 0) {
+						cto->ct_resid = resid;
+					}
+					cto->ct_flags |= CT2_FLAG_MODE1;
+					cto->rsp.m1.ct_scsi_status = cso->scsi_status;
+					if (resid < 0) {
+						cto->rsp.m1.ct_scsi_status |= CT2_DATA_OVER;
+					} else if (resid > 0) {
+						cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER;
+					}
+					if (fctape) {
+						cto->ct_flags |= CT2_CONFIRM;
+					}
+					if (sense_length) {
+						cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
+						cto->rsp.m1.ct_resplen = cto->rsp.m1.ct_senselen = sense_length;
+						memcpy(cto->rsp.m1.ct_resp, &cso->sense_data, sense_length);
+					}
+				} else {
+					bus_addr_t addr;
+					char buf[XCMD_SIZE];
+					fcp_rsp_iu_t *rp;
 
-				if (atp->ests == NULL) {
-					atp->ests = isp_get_ecmd(isp);
 					if (atp->ests == NULL) {
-						goto restart_delay;
+						atp->ests = isp_get_ecmd(isp);
+						if (atp->ests == NULL) {
+							TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 
+							break;
+						}
 					}
+					memset(buf, 0, sizeof (buf));
+					rp = (fcp_rsp_iu_t *)buf;
+					if (fctape) {
+						cto->ct_flags |= CT2_CONFIRM;
+						rp->fcp_rsp_bits |= FCP_CONF_REQ;
+					}
+					cto->ct_flags |= CT2_FLAG_MODE2;
+	        			rp->fcp_rsp_scsi_status = cso->scsi_status;
+					if (resid < 0) {
+						rp->fcp_rsp_resid = -resid;
+						rp->fcp_rsp_bits |= FCP_RESID_OVERFLOW;
+					} else if (resid > 0) {
+						rp->fcp_rsp_resid = resid;
+						rp->fcp_rsp_bits |= FCP_RESID_UNDERFLOW;
+					}
+					if (sense_length) {
+	        				rp->fcp_rsp_snslen = sense_length;
+						rp->fcp_rsp_bits |= FCP_SNSLEN_VALID;
+						isp_put_fcp_rsp_iu(isp, rp, atp->ests);
+						memcpy(((fcp_rsp_iu_t *)atp->ests)->fcp_rsp_extra, &cso->sense_data, sense_length);
+					} else {
+						isp_put_fcp_rsp_iu(isp, rp, atp->ests);
+					}
+					if (isp->isp_dblev & ISP_LOGTDEBUG1) {
+						isp_print_bytes(isp, "FCP Response Frame After Swizzling", MIN_FCP_RESPONSE_SIZE + sense_length, atp->ests);
+					}
+					addr = isp->isp_osinfo.ecmd_dma;
+					addr += ((((isp_ecmd_t *)atp->ests) - isp->isp_osinfo.ecmd_base) * XCMD_SIZE);
+					isp_prt(isp, ISP_LOGTDEBUG0, "%s: ests base %p vaddr %p ecmd_dma %jx addr %jx len %u", __func__, isp->isp_osinfo.ecmd_base, atp->ests,
+					    (uintmax_t) isp->isp_osinfo.ecmd_dma, (uintmax_t)addr, MIN_FCP_RESPONSE_SIZE + sense_length);
+					cto->rsp.m2.ct_datalen = MIN_FCP_RESPONSE_SIZE + sense_length;
+					if (isp->isp_osinfo.sixtyfourbit) {
+						cto->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base = DMA_LO32(addr);
+						cto->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi = DMA_HI32(addr);
+						cto->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count = MIN_FCP_RESPONSE_SIZE + sense_length;
+					} else {
+						cto->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base = DMA_LO32(addr);
+						cto->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count = MIN_FCP_RESPONSE_SIZE + sense_length;
+					}
 				}
-				memset(buf, 0, sizeof (buf));
-				rp = (fcp_rsp_iu_t *)buf;
-				if (fctape) {
-					cto->ct_flags |= CT2_CONFIRM;
-					rp->fcp_rsp_bits |= FCP_CONF_REQ;
-				}
-				cto->ct_flags |= CT2_FLAG_MODE2;
-        			rp->fcp_rsp_scsi_status = cso->scsi_status;
-				if (resid < 0) {
-					rp->fcp_rsp_resid = -resid;
-					rp->fcp_rsp_bits |= FCP_RESID_OVERFLOW;
-				} else if (resid > 0) {
-					rp->fcp_rsp_resid = resid;
-					rp->fcp_rsp_bits |= FCP_RESID_UNDERFLOW;
-				}
 				if (sense_length) {
-        				rp->fcp_rsp_snslen = sense_length;
-					rp->fcp_rsp_bits |= FCP_SNSLEN_VALID;
-					isp_put_fcp_rsp_iu(isp, rp, atp->ests);
-					memcpy(((fcp_rsp_iu_t *)atp->ests)->fcp_rsp_extra, &cso->sense_data, sense_length);
+					isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO2[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x resid=%d sense: %x %x/%x/%x", __func__,
+					    cto->ct_rxid, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cso->scsi_status, cto->ct_flags, cto->ct_resid,
+					    cso->sense_data.error_code, cso->sense_data.sense_buf[1], cso->sense_data.sense_buf[11], cso->sense_data.sense_buf[12]);
 				} else {
-					isp_put_fcp_rsp_iu(isp, rp, atp->ests);
+					isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO2[0x%x] seq %u nc %d CDB0=%x sstatus=0x%x flags=0x%x resid=%d", __func__, cto->ct_rxid,
+					    ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cso->scsi_status, cto->ct_flags, cto->ct_resid);
 				}
-				if (isp->isp_dblev & ISP_LOGTDEBUG1) {
-					isp_print_bytes(isp, "FCP Response Frame After Swizzling", MIN_FCP_RESPONSE_SIZE + sense_length, atp->ests);
+				atp->state = ATPD_STATE_LAST_CTIO;
+			}
+
+			if (xfrlen != 0) {
+				cto->ct_flags |= CT2_FLAG_MODE0;
+				if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
+					cto->ct_flags |= CT2_DATA_IN;
+				} else {
+					cto->ct_flags |= CT2_DATA_OUT;
 				}
-				addr = isp->isp_osinfo.ecmd_dma;
-				addr += ((((isp_ecmd_t *)atp->ests) - isp->isp_osinfo.ecmd_base) * XCMD_SIZE);
-				isp_prt(isp, repval, "%s: ests base %p vaddr %p ecmd_dma %jx addr %jx len %u", __func__, isp->isp_osinfo.ecmd_base, atp->ests,
-				    (uintmax_t) isp->isp_osinfo.ecmd_dma, (uintmax_t)addr, MIN_FCP_RESPONSE_SIZE + sense_length);
-				cto->rsp.m2.ct_datalen = MIN_FCP_RESPONSE_SIZE + sense_length;
-				if (isp->isp_osinfo.sixtyfourbit) {
-					cto->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base = DMA_LO32(addr);
-					cto->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi = DMA_HI32(addr);
-					cto->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count = MIN_FCP_RESPONSE_SIZE + sense_length;
+
+				cto->ct_reloff = atp->bytes_xfered + atp->bytes_in_transit;
+				cto->rsp.m0.ct_xfrlen = xfrlen;
+
+				if (sendstatus) {
+					resid = atp->orig_datalen - atp->bytes_xfered - xfrlen;
+					if (cso->scsi_status == SCSI_STATUS_OK && resid == 0 /*&& fctape == 0*/) {
+						cto->ct_flags |= CT2_SENDSTATUS;
+						atp->state = ATPD_STATE_LAST_CTIO;
+						if (fctape) {
+							cto->ct_flags |= CT2_CONFIRM;
+						}
+					} else {
+						atp->sendst = 1;	/* send status later */
+						cto->ct_header.rqs_seqno &= ~ATPD_SEQ_NOTIFY_CAM;
+						atp->state = ATPD_STATE_CTIO;
+					}
 				} else {
-					cto->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base = DMA_LO32(addr);
-					cto->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count = MIN_FCP_RESPONSE_SIZE + sense_length;
+					atp->state = ATPD_STATE_CTIO;
 				}
 			}
-			if (sense_length) {
-				isp_prt(isp, repval, "%s: CTIO2[0x%x] CDB0=%x sstatus=0x%x flags=0x%x resid=%d sense: %x %x/%x/%x", __func__,
-				    cto->ct_rxid, atp->cdb0, cso->scsi_status, cto->ct_flags, cto->ct_resid, cso->sense_data.error_code,
-				    cso->sense_data.sense_buf[1], cso->sense_data.sense_buf[11], cso->sense_data.sense_buf[12]);
-			} else {
-				isp_prt(isp, repval, "%s: CTIO2[0x%x] CDB0=%x sstatus=0x%x flags=0x%x resid=%d", __func__,
-				    cto->ct_rxid, atp->cdb0, cso->scsi_status, cto->ct_flags, cto->ct_resid);
-			}
-			atp->state = ATPD_STATE_LAST_CTIO;
-		}
+			isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO2[%x] seq %u nc %d CDB0=%x scsi status %x flags %x resid %d xfrlen %u offset %u", __func__, cto->ct_rxid,
+			    ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), atp->cdb0, cso->scsi_status, cto->ct_flags, cto->ct_resid, cso->dxfer_len, atp->bytes_xfered);
+		} else {
+			ct_entry_t *cto = (ct_entry_t *) local;
 
-		if (xfrlen != 0) {
-			int resid = 0;
-			cto->ct_flags |= CT2_FLAG_MODE0;
-			if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
-				cto->ct_flags |= CT2_DATA_IN;
-			} else {
-				cto->ct_flags |= CT2_DATA_OUT;
+			cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
+			cto->ct_header.rqs_entry_count = 1;
+			cto->ct_header.rqs_seqno |= ATPD_SEQ_NOTIFY_CAM;
+			ATPD_SET_SEQNO(cto, atp);
+			cto->ct_iid = cso->init_id;
+			cto->ct_iid |= XS_CHANNEL(ccb) << 7;
+			cto->ct_tgt = ccb->ccb_h.target_id;
+			cto->ct_lun = ccb->ccb_h.target_lun;
+			cto->ct_fwhandle = cso->tag_id;
+			if (atp->rxid) {
+				cto->ct_tag_val = atp->rxid;
+				cto->ct_flags |= CT_TQAE;
 			}
-
-			/*
-			 * Don't overrun the limits placed on us, but record it as
-			 * if we had so that we can set an overflow bit later.
-			 */
-			atp->last_xframt = xfrlen;
-			if (atp->bytes_xfered + xfrlen > atp->orig_datalen) {
-				resid = 1;
-				xfrlen = atp->orig_datalen - atp->bytes_xfered;
+			if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
+				cto->ct_flags |= CT_NODISC;
 			}
-			cto->ct_reloff = atp->bytes_xfered;
-			cto->rsp.m0.ct_xfrlen = xfrlen;
-
-			if (sendstatus) {
-				if (cso->scsi_status == SCSI_STATUS_OK && resid == 0 && fctape == 0) {
-					cto->ct_flags |= CT2_SENDSTATUS;
-					atp->state = ATPD_STATE_LAST_CTIO;
-				} else {
-					atp->sendst = 1;	/* send status later */
-					cto->ct_header.rqs_seqno = 0;
-					atp->state = ATPD_STATE_CTIO;
-				}
+			if (cso->dxfer_len == 0) {
+				cto->ct_flags |= CT_NO_DATA;
+			} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
+				cto->ct_flags |= CT_DATA_IN;
 			} else {
-				atp->state = ATPD_STATE_CTIO;
+				cto->ct_flags |= CT_DATA_OUT;
 			}
+			if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
+				cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
+				cto->ct_scsi_status = cso->scsi_status;
+				cto->ct_resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit - xfrlen;
+				isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO[%x] seq %u nc %d scsi status %x resid %d tag_id %x", __func__,
+				    cto->ct_fwhandle, ATPD_GET_SEQNO(cto), ATPD_GET_NCAM(cto), cso->scsi_status, cso->resid, cso->tag_id);
+			}
+			ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
+			cto->ct_timeout = 10;
 		}
-		isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO2[%x] CDB0=%x scsi status %x flags %x resid %d xfrlen %u offset %u", __func__, cto->ct_rxid,
-		    atp->cdb0, cso->scsi_status, cto->ct_flags, cto->ct_resid, cso->dxfer_len, atp->bytes_xfered);
-	} else {
-		ct_entry_t *cto = (ct_entry_t *) local;
 
-		cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
-		cto->ct_header.rqs_entry_count = 1;
-		cto->ct_header.rqs_seqno = 1;
-		cto->ct_iid = cso->init_id;
-		cto->ct_iid |= XS_CHANNEL(ccb) << 7;
-		cto->ct_tgt = ccb->ccb_h.target_id;
-		cto->ct_lun = ccb->ccb_h.target_lun;
-		cto->ct_fwhandle = cso->tag_id;
-		if (atp->rxid) {
-			cto->ct_tag_val = atp->rxid;
-			cto->ct_flags |= CT_TQAE;
+		if (isp_get_pcmd(isp, ccb)) {
+			ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "out of PCMDs\n");
+			TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 
+			break;
 		}
-		if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
-			cto->ct_flags |= CT_NODISC;
+		if (isp_allocate_xs_tgt(isp, ccb, &handle)) {
+			ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "No XFLIST pointers for %s\n", __func__);
+			TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 
+			isp_free_pcmd(isp, ccb);
+			break;
 		}
-		if (cso->dxfer_len == 0) {
-			cto->ct_flags |= CT_NO_DATA;
-		} else if ((cso->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
-			cto->ct_flags |= CT_DATA_IN;
-		} else {
-			cto->ct_flags |= CT_DATA_OUT;
-		}
-		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
-			cto->ct_flags |= CT_SENDSTATUS|CT_CCINCR;
-			cto->ct_scsi_status = cso->scsi_status;
-			cto->ct_resid = cso->resid;
-			isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO[%x] scsi status %x resid %d tag_id %x", __func__,
-			    cto->ct_fwhandle, cso->scsi_status, cso->resid, cso->tag_id);
-		}
-		ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
-		cto->ct_timeout = 10;
-	}
+		atp->bytes_in_transit += xfrlen;
+		PISP_PCMD(ccb)->datalen = xfrlen;
 
-	if (isp_allocate_xs_tgt(isp, ccb, &handle)) {
-		ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "No XFLIST pointers for %s\n", __func__);
-		goto restart_delay;
-	}
 
-	/*
-	 * Call the dma setup routines for this entry (and any subsequent
-	 * CTIOs) if there's data to move, and then tell the f/w it's got
-	 * new things to play with. As with isp_start's usage of DMA setup,
-	 * any swizzling is done in the machine dependent layer. Because
-	 * of this, we put the request onto the queue area first in native
-	 * format.
-	 */
+		/*
+		 * Call the dma setup routines for this entry (and any subsequent
+		 * CTIOs) if there's data to move, and then tell the f/w it's got
+		 * new things to play with. As with isp_start's usage of DMA setup,
+		 * any swizzling is done in the machine dependent layer. Because
+		 * of this, we put the request onto the queue area first in native
+		 * format.
+		 */
 
-	if (IS_24XX(isp)) {
-		ct7_entry_t *cto = (ct7_entry_t *) local;
-		cto->ct_syshandle = handle;
-	} else if (IS_FC(isp)) {
-		ct2_entry_t *cto = (ct2_entry_t *) local;
-		cto->ct_syshandle = handle;
-	} else {
-		ct_entry_t *cto = (ct_entry_t *) local;
-		cto->ct_syshandle = handle;
-	}
+		if (IS_24XX(isp)) {
+			ct7_entry_t *cto = (ct7_entry_t *) local;
+			cto->ct_syshandle = handle;
+		} else if (IS_FC(isp)) {
+			ct2_entry_t *cto = (ct2_entry_t *) local;
+			cto->ct_syshandle = handle;
+		} else {
+			ct_entry_t *cto = (ct_entry_t *) local;
+			cto->ct_syshandle = handle;
+		}
 
-	dmaresult = ISP_DMASETUP(isp, cso, (ispreq_t *) local);
-	if (dmaresult == CMD_QUEUED) {
+		dmaresult = ISP_DMASETUP(isp, cso, (ispreq_t *) local);
+		if (dmaresult != CMD_QUEUED) {
+			isp_destroy_tgt_handle(isp, handle);
+			isp_free_pcmd(isp, ccb);
+			if (dmaresult == CMD_EAGAIN) {
+				TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe); 
+				break;
+			}
+			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+			xpt_done(ccb);
+			continue;
+		}
 		isp->isp_nactive++;
+		ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED;
 		if (xfrlen) {
 			ccb->ccb_h.spriv_field0 = atp->bytes_xfered;
 		} else {
 			ccb->ccb_h.spriv_field0 = ~0;
 		}
-		ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED;
 		atp->ctcnt++;
-		rls_lun_statep(isp, tptr);
-		return;
+		atp->seqno++;
 	}
-	isp_destroy_tgt_handle(isp, handle);
-	if (dmaresult != CMD_EAGAIN) {
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-		goto out;
-	}
-restart_delay:
-	cam_freeze_devq(ccb->ccb_h.path);
-	cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 250, 0);
-	ccb->ccb_h.status = CAM_REQUEUE_REQ;
-out:
 	rls_lun_statep(isp, tptr);
-	isp_free_pcmd(isp, ccb);
-	xpt_done(ccb);
 }
 
 static void
@@ -2262,7 +2287,6 @@
 	}
 	atp->orig_datalen = 0;
 	atp->bytes_xfered = 0;
-	atp->last_xframt = 0;
 	atp->lun = aep->at_lun;
 	atp->nphdl = aep->at_iid;
 	atp->portid = PORT_NONE;
@@ -2426,7 +2450,6 @@
 
 	atp->orig_datalen = aep->at_datalen;
 	atp->bytes_xfered = 0;
-	atp->last_xframt = 0;
 	atp->lun = lun;
 	atp->nphdl = atiop->init_id;
 	atp->sid = PORT_ANY;
@@ -2648,7 +2671,6 @@
 	}
 	atp->orig_datalen = aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl;
 	atp->bytes_xfered = 0;
-	atp->last_xframt = 0;
 	atp->lun = lun;
 	atp->nphdl = nphdl;
 	atp->portid = sid;
@@ -2697,7 +2719,7 @@
 	atp->srr_ccb = NULL;
 	atp->nsrr++;
 	if (ccb == NULL) {
-		isp_prt(isp, ISP_LOGWARN, "SRR[0x%08x] null ccb", atp->tag);
+		isp_prt(isp, ISP_LOGWARN, "SRR[0x%x] null ccb", atp->tag);
 		goto fail;
 	}
 
@@ -2711,20 +2733,19 @@
 		 * We have to restart a FCP_DATA data out transaction
 		 */
 		atp->sendst = 0;
-		atp->last_xframt = 0;
 		atp->bytes_xfered = srr_off;
 		if (ccb_len == 0) {
-			isp_prt(isp, ISP_LOGWARN, "SRR[0x%08x] SRR offset 0x%x but current CCB doesn't transfer data", atp->tag, srr_off);
+			isp_prt(isp, ISP_LOGWARN, "SRR[0x%x] SRR offset 0x%x but current CCB doesn't transfer data", atp->tag, srr_off);
 			goto mdp;
 		}
  		if (srr_off < ccb_off || ccb_off > srr_off + ccb_len) {
-			isp_prt(isp, ISP_LOGWARN, "SRR[0x%08x] SRR offset 0x%x not covered by current CCB data range [0x%x..0x%x]", atp->tag, srr_off, ccb_off, ccb_end);
+			isp_prt(isp, ISP_LOGWARN, "SRR[0x%x] SRR offset 0x%x not covered by current CCB data range [0x%x..0x%x]", atp->tag, srr_off, ccb_off, ccb_end);
 			goto mdp;
 		}
-		isp_prt(isp, ISP_LOGWARN, "SRR[0x%08x] SRR offset 0x%x covered by current CCB data range [0x%x..0x%x]", atp->tag, srr_off, ccb_off, ccb_end);
+		isp_prt(isp, ISP_LOGWARN, "SRR[0x%x] SRR offset 0x%x covered by current CCB data range [0x%x..0x%x]", atp->tag, srr_off, ccb_off, ccb_end);
 		break;
 	case R_CTL_INFO_COMMAND_STATUS:
-		isp_prt(isp, ISP_LOGTINFO, "SRR[0x%08x] Got an FCP RSP SRR- resending status", atp->tag);
+		isp_prt(isp, ISP_LOGTINFO, "SRR[0x%x] Got an FCP RSP SRR- resending status", atp->tag);
 		atp->sendst = 1;
 		/*
 		 * We have to restart a FCP_RSP IU transaction
@@ -2812,7 +2833,7 @@
 	}
 	atp->srr_notify_rcvd = 1;
 	memcpy(atp->srr, inot, sizeof (atp->srr));
-	isp_prt(isp, ISP_LOGTINFO /* ISP_LOGTDEBUG0 */, "SRR[0x%08x] inot->in_rxid flags 0x%x srr_iu=%x reloff 0x%x", inot->in_rxid, inot->in_flags, inot->in_srr_iu,
+	isp_prt(isp, ISP_LOGTINFO /* ISP_LOGTDEBUG0 */, "SRR[0x%x] inot->in_rxid flags 0x%x srr_iu=%x reloff 0x%x", inot->in_rxid, inot->in_flags, inot->in_srr_iu,
 	    inot->in_srr_reloff_lo | (inot->in_srr_reloff_hi << 16));
 	if (atp->srr_ccb)
 		isp_handle_srr_start(isp, tptr, atp);
@@ -2823,11 +2844,11 @@
 isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
 {
 	union ccb *ccb;
-	int sentstatus = 0, ok = 0, notify_cam = 0, resid = 0, moved_data = 0, failure = 0;
+	int sentstatus = 0, ok = 0, notify_cam = 0, resid = 0, failure = 0;
 	tstate_t *tptr = NULL;
 	atio_private_data_t *atp = NULL;
 	int bus;
-	uint32_t handle;
+	uint32_t handle, moved_data = 0, data_requested;
 
 	/*
 	 * CTIO handles are 16 bits.
@@ -2845,6 +2866,7 @@
 		return;
 	}
 	isp_destroy_tgt_handle(isp, handle);
+	data_requested = PISP_PCMD(ccb)->datalen;
 	isp_free_pcmd(isp, ccb);
 	if (isp->isp_nactive) {
 		isp->isp_nactive--;
@@ -2873,6 +2895,7 @@
 		return;
 	}
 	KASSERT((atp->ctcnt > 0), ("ctio count not greater than zero"));
+	atp->bytes_in_transit -= data_requested;
 	atp->ctcnt -= 1;
 	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
 
@@ -2891,14 +2914,14 @@
 		} else {
 			sentstatus = ct->ct_flags & CT7_SENDSTATUS;
 			ok = (ct->ct_nphdl == CT7_OK);
-			notify_cam = ct->ct_header.rqs_seqno & 0x1;
+			notify_cam = (ct->ct_header.rqs_seqno & ATPD_SEQ_NOTIFY_CAM) != 0;
 			if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) {
 				resid = ct->ct_resid;
-				moved_data = 1;
+				moved_data = data_requested - resid;
 			}
 		}
-		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO7[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__,
-		    ct->ct_rxid, ct->ct_nphdl, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
+		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO7[%x] seq %u nc %d sts 0x%x flg 0x%x sns %d resid %d %s", __func__, ct->ct_rxid, ATPD_GET_SEQNO(ct),
+		   notify_cam, ct->ct_nphdl, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
 	} else if (IS_FC(isp)) {
 		ct2_entry_t *ct = arg;
 		if (ct->ct_status == CT_SRR) {
@@ -2914,14 +2937,14 @@
 		} else {
 			sentstatus = ct->ct_flags & CT2_SENDSTATUS;
 			ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
-			notify_cam = ct->ct_header.rqs_seqno & 0x1;
+			notify_cam = (ct->ct_header.rqs_seqno & ATPD_SEQ_NOTIFY_CAM) != 0;
 			if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
 				resid = ct->ct_resid;
-				moved_data = 1;
+				moved_data = data_requested - resid;
 			}
 		}
-		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s", __func__,
-		    ct->ct_rxid, ct->ct_status, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
+		isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO2[%x] seq %u nc %d sts 0x%x flg 0x%x sns %d resid %d %s", __func__, ct->ct_rxid, ATPD_GET_SEQNO(ct),
+		    notify_cam, ct->ct_status, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
 	} else {
 		ct_entry_t *ct = arg;
 
@@ -2930,20 +2953,19 @@
 		} else {
 			sentstatus = ct->ct_flags & CT_SENDSTATUS;
 			ok = (ct->ct_status  & ~QLTM_SVALID) == CT_OK;
-			notify_cam = ct->ct_header.rqs_seqno & 0x1;
+			notify_cam = (ct->ct_header.rqs_seqno & ATPD_SEQ_NOTIFY_CAM) != 0;
 		}
 		if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
 			resid = ct->ct_resid;
-			moved_data = 1;
+			moved_data = data_requested - resid;
 		}
-		isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO[%x] tag %x S_ID 0x%x lun %d sts %x flg %x resid %d %s", __func__,
-		    ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, ct->ct_status, ct->ct_flags, resid, sentstatus? "FIN" : "MID");
+		isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO[%x] seq %u nc %d tag %x S_ID 0x%x lun %d sts %x flg %x resid %d %s", __func__, ct->ct_fwhandle, ATPD_GET_SEQNO(ct),
+		    notify_cam, ct->ct_tag_val, ct->ct_iid, ct->ct_lun, ct->ct_status, ct->ct_flags, resid, sentstatus? "FIN" : "MID");
 	}
 	if (ok) {
 		if (moved_data) {
-			ccb->csio.resid += resid;
-			atp->bytes_xfered += (atp->last_xframt - resid);
-			atp->last_xframt = 0;
+			atp->bytes_xfered += moved_data;
+			ccb->csio.resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit;
 		}
 		if (sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
 			ccb->ccb_h.status |= CAM_SENT_SENSE;
@@ -2963,7 +2985,8 @@
 	 * We never *not* notify CAM when there has been any error (ok == 0),
 	 * so we never need to do an ATIO putback if we're not notifying CAM.
 	 */
-	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done (notify_cam=%d nowsendstatus=%d)", (sentstatus)? "  FINAL " : "MIDTERM ", atp->tag, notify_cam, atp->sendst);
+	isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO[0x%x] done (ok=%d nc=%d nowsendstatus=%d ccb ss=%d)",
+	    (sentstatus)? "  FINAL " : "MIDTERM ", atp->tag, ok, notify_cam, atp->sendst, (ccb->ccb_h.flags & CAM_SEND_STATUS) != 0);
 	if (notify_cam == 0) {
 		if (atp->sendst) {
 			isp_target_start_ctio(isp, ccb, FROM_CTIO_DONE);
@@ -3522,25 +3545,47 @@
 
 
 #ifdef	ISP_INTERNAL_TARGET
-// #define	ISP_FORCE_TIMEOUT		1
-// #define	ISP_TEST_WWNS			1
-// #define	ISP_TEST_SEPARATE_STATUS	1
+//#define	ISP_SEPARATE_STATUS	1
+#define	ISP_MULTI_CCBS		1
+#if defined(ISP_MULTI_CCBS) && !defined(ISP_SEPARATE_STATUS)
+#define	ISP_SEPARATE_STATUS 1
+#endif
 
-#define	ccb_data_offset		ppriv_field0
+typedef struct periph_private_data_t {
+	union ccb *ccb;			/* original ATIO or Immediate Notify */
+	unsigned long	offset;		/* current offset */
+	int		sequence;	/* current CTIO sequence */
+	int		ctio_cnt;	/* current # of ctio's outstanding */
+	int
+		status_sent	: 1,
+		on_queue	: 1;	/* on restart queue */
+} ppd_t;
+/*
+ * Each ATIO we allocate will have periph private data associated with it
+ * that maintains per-command state. This private to each ATIO.
+ */
+#define	ATIO_PPD(ccb)		((ppd_t *)(((struct ccb_hdr *)ccb)->ppriv_ptr0))
+/*
+ * Each CTIO we send downstream will get a pointer to the ATIO itself
+ * so that on completion we can retrieve that pointer.
+ */
 #define	ccb_atio		ppriv_ptr1
 #define	ccb_inot		ppriv_ptr1
 
+/*
+ * Each CTIO we send downstream will contain a sequence number
+ */
+#define	CTIO_SEQ(ccb)		ccb->ccb_h.ppriv_field0
+
 #define	MAX_ISP_TARG_TRANSFER	(2 << 20)
-#define	NISP_TARG_CMDS		1024
-#define	NISP_TARG_NOTIFIES	1024
+#define	NISP_TARG_CMDS		64
+#define	NISP_TARG_NOTIFIES	64
 #define	DISK_SHIFT		9
 #define	JUNK_SIZE		256
+#define	MULTI_CCB_DATA_LIM	8192
+//#define	MULTI_CCB_DATA_CNT	64
+#define	MULTI_CCB_DATA_CNT	8
 
-#ifndef	VERIFY_10
-#define	VERIFY_10	0x2f
-#endif
-
-TAILQ_HEAD(ccb_queue, ccb_hdr);
 extern u_int vm_kmem_size;
 static int ca;
 static uint32_t disk_size;
@@ -3549,10 +3594,10 @@
 static MALLOC_DEFINE(M_ISPTARG, "ISPTARG", "ISP TARGET data");
 struct isptarg_softc {
 	/* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */
-	struct ccb_queue	work_queue;
-	struct ccb_queue	rework_queue;
-	struct ccb_queue	running_queue;
-	struct ccb_queue	inot_queue;
+	struct isp_ccbq		work_queue;
+	struct isp_ccbq		rework_queue;
+	struct isp_ccbq		running_queue;
+	struct isp_ccbq		inot_queue;
 	struct cam_periph       *periph;
 	struct cam_path	 	*path;
 	ispsoftc_t		*isp;
@@ -3569,7 +3614,7 @@
 
 static struct periph_driver isptargdriver =
 {
-	isptarginit, "isptarg", TAILQ_HEAD_INITIALIZER(isptargdriver.units), /* generation */ 0
+	isptarginit, "isptarg", TAILQ_HEAD_INITIALIZER(isptargdriver.units), 0
 };
 
 static void
@@ -3613,7 +3658,8 @@
 		'O', 'R', 'Y', ' ', 'D', 'I', 'S', 'K',
 		'0', '0', '0', '1'
 	};
-	int r, i, more = 0, last;
+	int r, i, more = 0, last, is_data_cmd = 0, is_write;
+	char *queue;
 	struct isptarg_softc *softc = periph->softc;
 	struct ccb_scsiio *csio;
 	lun_id_t return_lun;
@@ -3647,10 +3693,10 @@
 		atio = (struct ccb_accept_tio *)ccbh;
 		TAILQ_REMOVE(&softc->rework_queue, ccbh, periph_links.tqe);
 		more = TAILQ_FIRST(&softc->work_queue) || TAILQ_FIRST(&softc->rework_queue);
+		queue = "rework";
 	} else {
 		ccbh = TAILQ_FIRST(&softc->work_queue);
 		if (ccbh == NULL) {
-			ISP_PATH_PRT(softc->isp, ISP_LOGWARN, iccb->ccb_h.path, "%s: woken up but no work?\n", __func__);
 			xpt_release_ccb(iccb);
 			return;
 		}
@@ -3657,22 +3703,23 @@
 		atio = (struct ccb_accept_tio *)ccbh;
 		TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
 		more = TAILQ_FIRST(&softc->work_queue) != NULL;
-		atio->ccb_h.ccb_data_offset = 0;
+		queue = "work";
 	}
+	ATIO_PPD(atio)->on_queue = 0;
 
 	if (atio->tag_id == 0xffffffff || atio->ccb_h.func_code != XPT_ACCEPT_TARGET_IO) {
 		panic("BAD ATIO");
 	}
 
+	data_len = is_write = 0;
 	data_ptr = NULL;
-	data_len = 0;
 	csio = &iccb->csio;
 	status = SCSI_STATUS_OK;
 	flags = CAM_SEND_STATUS;
 	memset(&atio->sense_data, 0, sizeof (atio->sense_data));
 	cdb = atio->cdb_io.cdb_bytes;
-	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG1, ccbh->path, "%s: [0x%x] processing ATIO from 0x%x CDB=0x%x data_offset=%u\n", __func__, atio->tag_id, atio->init_id,
-	    cdb[0], atio->ccb_h.ccb_data_offset);
+	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, ccbh->path, "%s: [0x%x] processing ATIO from %s queue initiator 0x%x CDB=0x%x data_offset=%u\n", __func__, atio->tag_id,
+	    queue, atio->init_id, cdb[0], ATIO_PPD(atio)->offset);
 
 	return_lun = XS_LUN(atio);
 	if (return_lun != 0) {
@@ -3700,11 +3747,18 @@
 			data_ptr = junk_data;
 		}
 		break;
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:
+	case WRITE_16:
+		is_write = 1;
+		/* FALLTHROUGH */
 	case READ_6:
 	case READ_10:
 	case READ_12:
 	case READ_16:
-		r = isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last);
+		is_data_cmd = 1;
+		r = isptarg_rwparm(cdb, disk_data, disk_size, ATIO_PPD(atio)->offset, &data_ptr, &data_len, &last);
 		if (r != 0) {
 			status = SCSI_STATUS_CHECK_COND;
 			SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR;
@@ -3716,19 +3770,7 @@
 			}
 			atio->sense_len = SSD_MIN_SIZE;
 		} else {
-#ifdef	ISP_FORCE_TIMEOUT
-			{
-				static int foo;
-				if (foo++ == 500) {
-					if (more) {
-						xpt_schedule(periph, 1);
-					}
-					foo = 0;
-					return;
-				}
-			}
-#endif
-#ifdef	ISP_TEST_SEPARATE_STATUS
+#ifdef	ISP_SEPARATE_STATUS
 			if (last && data_len) {
 				last = 0;
 			}
@@ -3737,57 +3779,16 @@
 				flags &= ~CAM_SEND_STATUS;
 			}
 			if (data_len) {
-				atio->ccb_h.ccb_data_offset += data_len;
-				flags |= CAM_DIR_IN;
+				ATIO_PPD(atio)->offset += data_len;
+				if (is_write)
+					flags |= CAM_DIR_OUT;
+				else
+					flags |= CAM_DIR_IN;
 			} else {
 				flags |= CAM_DIR_NONE;
 			}
 		}
 		break;
-	case WRITE_6:
-	case WRITE_10:
-	case WRITE_12:
-	case WRITE_16:
-		r = isptarg_rwparm(cdb, disk_data, disk_size, atio->ccb_h.ccb_data_offset, &data_ptr, &data_len, &last);
-		if (r != 0) {
-			status = SCSI_STATUS_CHECK_COND;
-			SDFIXED(atio->sense_data)->error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR;
-			SDFIXED(atio->sense_data)->flags = SSD_KEY_ILLEGAL_REQUEST;
-			if (r == -1) {
-				SDFIXED(atio->sense_data)->add_sense_code = 0x21;	/* LOGICAL BLOCK ADDRESS OUT OF RANGE */
-			} else {
-				SDFIXED(atio->sense_data)->add_sense_code = 0x20;	/* INVALID COMMAND OPERATION CODE */
-			}
-			atio->sense_len = SSD_MIN_SIZE;
-		} else {
-#ifdef	ISP_FORCE_TIMEOUT
-			{
-				static int foo;
-				if (foo++ == 500) {
-					if (more) {
-						xpt_schedule(periph, 1);
-					}
-					foo = 0;
-					return;
-				}
-			}
-#endif
-#ifdef	ISP_TEST_SEPARATE_STATUS
-			if (last && data_len) {
-				last = 0;
-			}
-#endif
-			if (last == 0) {
-				flags &= ~CAM_SEND_STATUS;
-			}
-			if (data_len) {
-				atio->ccb_h.ccb_data_offset += data_len;
-				flags |= CAM_DIR_OUT;
-			} else {
-				flags |= CAM_DIR_NONE;
-			}
-		}
-		break;
 	case INQUIRY:
 		flags |= CAM_DIR_IN;
 		if (cdb[1] || cdb[2] || cdb[3]) {
@@ -3875,7 +3876,7 @@
 		junk_data[3] = (1 << 3);
 		ptr = NULL;
 		for (i = 0; i < 1; i++) {
-			ptr = &junk_data[8 + (1 << 3)];
+			ptr = &junk_data[8 + (i << 3)];
 			if (i >= 256) {
 				ptr[0] = 0x40 | ((i >> 8) & 0x3f);
 			}
@@ -3909,10 +3910,17 @@
 		data_len = 0;
 		data_ptr = NULL;
 	}
-	cam_fill_ctio(csio, 0, isptarg_done, flags, MSG_SIMPLE_Q_TAG, atio->tag_id, atio->init_id, status, data_ptr, data_len, 0);
+	cam_fill_ctio(csio, 0, isptarg_done, flags, MSG_SIMPLE_Q_TAG, atio->tag_id, atio->init_id, status, data_ptr, data_len, 30 * hz);
 	iccb->ccb_h.target_id = atio->ccb_h.target_id;
 	iccb->ccb_h.target_lun = return_lun;
 	iccb->ccb_h.ccb_atio = atio;
+	CTIO_SEQ(iccb) = ATIO_PPD(atio)->sequence++;
+	ATIO_PPD(atio)->ctio_cnt++;
+	if (flags & CAM_SEND_STATUS) {
+		KASSERT((ATIO_PPD(atio)->status_sent == 0), ("we have already sent status for 0x%x in %s", atio->tag_id, __func__));
+		ATIO_PPD(atio)->status_sent = 1;
+	}
+	ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, atio->ccb_h.path, "%s: sending downstream for  0x%x sequence %u len %u flags %x\n", __func__, atio->tag_id, CTIO_SEQ(iccb), data_len, flags);
 	xpt_action(iccb);
 
 	if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
@@ -3919,6 +3927,14 @@
 		cam_release_devq(periph->path, 0, 0, 0, 0); 
 		atio->ccb_h.status &= ~CAM_DEV_QFRZN;
 	}
+#ifdef	ISP_MULTI_CCBS
+	if (is_data_cmd && ATIO_PPD(atio)->status_sent == 0 && ATIO_PPD(atio)->ctio_cnt < MULTI_CCB_DATA_CNT && ATIO_PPD(atio)->on_queue == 0) {
+		ISP_PATH_PRT(softc->isp, ISP_LOGTDEBUG0, atio->ccb_h.path, "%s: more still to do for 0x%x\n", __func__, atio->tag_id);
+		TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe); 
+		ATIO_PPD(atio)->on_queue = 1;
+		more = 1;
+	}
+#endif
 	if (more) {
 		xpt_schedule(periph, 1);
 	}
@@ -3953,6 +3969,7 @@
 {
 	struct isptarg_softc *softc;
 	ispsoftc_t *isp;
+	uint32_t newoff;
 	struct ccb_accept_tio *atio;
 	struct ccb_immediate_notify *inot;
 	cam_status status;
@@ -3964,41 +3981,56 @@
 	switch (ccb->ccb_h.func_code) {
 	case XPT_ACCEPT_TARGET_IO:
 		atio = (struct ccb_accept_tio *) ccb;
-		ISP_PATH_PRT(isp, ISP_LOGTDEBUG1, ccb->ccb_h.path, "[0x%x] ATIO seen in %s\n", atio->tag_id, __func__);
+		ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] ATIO seen in %s\n", atio->tag_id, __func__);
+		memset(ATIO_PPD(atio), 0, sizeof (ppd_t));
 		TAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h, periph_links.tqe); 
+		ATIO_PPD(atio)->on_queue = 1;
 		xpt_schedule(periph, 1);
 		break;
 	case XPT_IMMEDIATE_NOTIFY:
 		inot = (struct ccb_immediate_notify *) ccb;
-		ISP_PATH_PRT(isp, ISP_LOGTDEBUG1, ccb->ccb_h.path, "[0x%x] INOT for 0x%x seen in %s\n", inot->tag_id, inot->seq_id, __func__);
+		ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] INOT for 0x%x seen in %s\n", inot->tag_id, inot->seq_id, __func__);
 		TAILQ_INSERT_TAIL(&softc->inot_queue, &ccb->ccb_h, periph_links.tqe); 
 		xpt_schedule(periph, 1);
 		break;
 	case XPT_CONT_TARGET_IO:
-		if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
-			cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 
-			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
-		}
 		atio = ccb->ccb_h.ccb_atio;
+		KASSERT((ATIO_PPD(atio)->ctio_cnt != 0), ("ctio zero when finishing a CTIO"));
+		ATIO_PPD(atio)->ctio_cnt--;
 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-			if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_MESSAGE_RECV) {
-				uint32_t newoff = (ccb->csio.msg_ptr[3] << 24) | (ccb->csio.msg_ptr[4] << 16) | (ccb->csio.msg_ptr[5] << 8) | (ccb->csio.msg_ptr[6]);
-				ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "[0x%08x] got message to return to reset offset to 0x%x\n", atio->tag_id, newoff);
-				atio->ccb_h.ccb_data_offset = newoff;
-				TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe); 
+			switch (ccb->ccb_h.status & CAM_STATUS_MASK) {
+			case CAM_MESSAGE_RECV:
+				newoff = (ccb->csio.msg_ptr[3] << 24) | (ccb->csio.msg_ptr[4] << 16) | (ccb->csio.msg_ptr[5] << 8) | (ccb->csio.msg_ptr[6]);
+				ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "[0x%x] got message to return to reset offset to 0x%x at sequence %u\n", atio->tag_id, newoff, CTIO_SEQ(ccb));
+				ATIO_PPD(atio)->offset = newoff;
+				ATIO_PPD(atio)->status_sent = 0;
+				if (ATIO_PPD(atio)->on_queue == 0) {
+					TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe); 
+					ATIO_PPD(atio)->on_queue = 1;
+				}
 				xpt_schedule(periph, 1);
-			} else {
+				break;
+			default:
 				cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL);
 				xpt_action((union ccb *)atio);
+				break;
 			}
 		} else if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) {
-			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] MID CTIO seen in %s\n", atio->tag_id, __func__);
-			TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe); 
+			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] MID CTIO sequence %u seen in %s\n", atio->tag_id, CTIO_SEQ(ccb), __func__);
+			if (ATIO_PPD(atio)->status_sent == 0 && ATIO_PPD(atio)->on_queue == 0) {
+				TAILQ_INSERT_TAIL(&softc->rework_queue, &atio->ccb_h, periph_links.tqe); 
+				ATIO_PPD(atio)->on_queue = 1;
+			}
 			xpt_schedule(periph, 1);
 		} else {
-			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] FINAL CTIO seen in %s\n", atio->tag_id, __func__);
+			KASSERT((ATIO_PPD(atio)->ctio_cnt == 0), ("ctio count still %d when we think we've sent the STATUS ctio", ATIO_PPD(atio)->ctio_cnt));
+			ISP_PATH_PRT(isp, ISP_LOGTDEBUG0, ccb->ccb_h.path, "[0x%x] FINAL CTIO sequence %u seen in %s\n", atio->tag_id, CTIO_SEQ(ccb), __func__);
 			xpt_action((union ccb *)atio);
 		}
+		if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+			cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0); 
+			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
+		}
 		xpt_release_ccb(ccb);
 		break;
 	case XPT_NOTIFY_ACKNOWLEDGE:
@@ -4133,13 +4165,7 @@
 	xpt_setup_ccb(&ccb->ccb_h, periph->path, 10);
 	ccb->ccb_h.func_code = XPT_SET_SIM_KNOB;
 	ccb->knob.xport_specific.fc.role = KNOB_ROLE_NONE;
-#ifdef	ISP_TEST_WWNS
-	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE | KNOB_VALID_ADDRESS;
-	ccb->knob.xport_specific.fc.wwnn = 0x508004d000000000ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16);
-	ccb->knob.xport_specific.fc.wwpn = 0x508004d000000001ULL | (device_get_unit(isp->isp_osinfo.dev) << 8) | (chan << 16);
-#else
 	ccb->knob.xport_specific.fc.valid = KNOB_VALID_ROLE;
-#endif
 
 	ISP_LOCK(isp);
 	xpt_action(ccb);
@@ -4182,6 +4208,7 @@
 		xpt_setup_ccb(&ccb->ccb_h, wperiph->path, 1);
 		ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
 		ccb->ccb_h.cbfcnp = isptarg_done;
+		ccb->ccb_h.ppriv_ptr0 = malloc(sizeof (ppd_t), M_ISPTARG, M_WAITOK | M_ZERO);
 		ISP_LOCK(isp);
 		xpt_action(ccb);
 		ISP_UNLOCK(isp);
@@ -4191,6 +4218,7 @@
 		xpt_setup_ccb(&ccb->ccb_h, periph->path, 1);
 		ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
 		ccb->ccb_h.cbfcnp = isptarg_done;
+		ccb->ccb_h.ppriv_ptr0 = malloc(sizeof (ppd_t), M_ISPTARG, M_WAITOK | M_ZERO);
 		ISP_LOCK(isp);
 		xpt_action(ccb);
 		ISP_UNLOCK(isp);
@@ -4342,7 +4370,6 @@
 		return (-2);
 	}
 
-
 	curcnt = MAX_ISP_TARG_TRANSFER;
 	if (offset + curcnt >= cnt) {
 		curcnt = cnt - offset;
@@ -4350,6 +4377,10 @@
 	} else {
 		*lp = 0;
 	}
+#ifdef	ISP_MULTI_CCBS
+	if (curcnt > MULTI_CCB_DATA_LIM)
+		curcnt = MULTI_CCB_DATA_LIM;
+#endif
 	*tl = curcnt;
 	*kp = &dp[lba + offset];
 	return (0);
@@ -4646,7 +4677,7 @@
 			if (dbidx != (FCPARAM(isp, chan)->isp_dev_map[XS_TGT(xs)] - 1)) {
 				continue;
 			}
-			isp_prt(isp, ISP_LOGWARN, "command handle 0x%08x for %d.%d.%d orphaned by loop down timeout",
+			isp_prt(isp, ISP_LOGWARN, "command handle 0x%x for %d.%d.%d orphaned by loop down timeout",
 			    isp->isp_xflist[i].handle, chan, XS_TGT(xs), XS_LUN(xs));
 		}
 
@@ -4962,6 +4993,7 @@
 			SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h, sim_links.sle);
 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, ccb->ccb_h.path, "Put FREE ATIO (tag id 0x%x), count now %d\n",
 			    ccb->atio.tag_id, tptr->atio_count);
+			ccb->atio.tag_id = 0;
 		} else if (ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY) {
 			if (ccb->cin1.tag_id) {
 				inot_private_data_t *ntp = isp_find_ntpd(isp, tptr, ccb->cin1.tag_id, ccb->cin1.seq_id);
@@ -4973,11 +5005,13 @@
 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle);
 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n",
 			    ccb->cin1.seq_id, tptr->inot_count);
+			ccb->cin1.seq_id = 0;
 		} else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
 			tptr->inot_count++;
 			SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h, sim_links.sle);
 			ISP_PATH_PRT(isp, ISP_LOGTDEBUG2, ccb->ccb_h.path, "Put FREE INOT, (seq id 0x%x) count now %d\n",
 			    ccb->cin1.seq_id, tptr->inot_count);
+			ccb->cin1.seq_id = 0;
 		}
 		rls_lun_statep(isp, tptr);
 		ccb->ccb_h.status = CAM_REQ_INPROG;
@@ -6330,6 +6364,9 @@
 	return (-1);
 }
 
+/*
+ * We enter with the lock held
+ */
 void
 isp_timer(void *arg)
 {
@@ -6337,7 +6374,7 @@
 #ifdef	ISP_TARGET_MODE
 	isp_tmcmd_restart(isp);
 #endif
-	callout_reset(&isp->isp_osinfo.tmo, hz, isp_timer, isp);
+	callout_reset(&isp->isp_osinfo.tmo, isp_timer_count, isp_timer, isp);
 }
 
 isp_ecmd_t *

Modified: trunk/sys/dev/isp/isp_freebsd.h
===================================================================
--- trunk/sys/dev/isp/isp_freebsd.h	2016-09-15 08:26:26 UTC (rev 7986)
+++ trunk/sys/dev/isp/isp_freebsd.h	2016-09-15 08:27:12 UTC (rev 7987)
@@ -102,7 +102,7 @@
 	void *		next;
 	uint32_t	orig_datalen;
 	uint32_t	bytes_xfered;
-	uint32_t	last_xframt;
+	uint32_t	bytes_in_transit;
 	uint32_t	tag;		/* typically f/w RX_ID */
 	uint32_t	lun;
 	uint32_t	nphdl;
@@ -112,6 +112,7 @@
 	uint16_t	oxid;	/* wire oxid */
 	uint16_t	word3;	/* PRLI word3 params */
 	uint16_t	ctcnt;	/* number of CTIOs currently active */
+	uint8_t		seqno;	/* CTIO sequence number */
 	uint32_t
 			srr_notify_rcvd	: 1,
 			cdb0		: 8,
@@ -134,6 +135,14 @@
 #define	ATPD_STATE_LAST_CTIO		4
 #define	ATPD_STATE_PDON			5
 
+#define	ATPD_CCB_OUTSTANDING		16
+
+#define	ATPD_SEQ_MASK			0x7f
+#define	ATPD_SEQ_NOTIFY_CAM		0x80
+#define	ATPD_SET_SEQNO(hdrp, atp)	((isphdr_t *)hdrp)->rqs_seqno &= ~ATPD_SEQ_MASK, ((isphdr_t *)hdrp)->rqs_seqno |= (atp)->seqno
+#define	ATPD_GET_SEQNO(hdrp)		(((isphdr_t *)hdrp)->rqs_seqno & ATPD_SEQ_MASK)
+#define	ATPD_GET_NCAM(hdrp)		((((isphdr_t *)hdrp)->rqs_seqno & ATPD_SEQ_NOTIFY_CAM) != 0)
+
 typedef union inot_private_data inot_private_data_t;
 union inot_private_data {
 	inot_private_data_t *next;
@@ -149,9 +158,11 @@
 	uint8_t data[64];	 /* sb QENTRY_LEN, but order of definitions is wrong */
 } isp_tna_t;
 
+TAILQ_HEAD(isp_ccbq, ccb_hdr);
 typedef struct tstate {
 	SLIST_ENTRY(tstate) next;
 	struct cam_path *owner;
+	struct isp_ccbq waitq;		/* waiting CCBs */
 	struct ccb_hdr_slist atios;
 	struct ccb_hdr_slist inots;
 	uint32_t hold;
@@ -179,6 +190,7 @@
 	bus_dmamap_t 		dmap;		/* dma map for this command */
 	struct ispsoftc *	isp;		/* containing isp */
 	struct callout		wdog;		/* watchdog timer */
+	uint32_t		datalen;	/* data length for this command (target mode only) */
 	uint8_t			totslen;	/* sense length on status response */
 	uint8_t			cumslen;	/* sense length on status response */
 	uint8_t 		crn;		/* command reference number */



More information about the Midnightbsd-cvs mailing list