Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 8 Aug 2012 18:24:34 +0000 (UTC)
From:      Matt Jacob <mjacob@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r239143 - head/sys/dev/isp
Message-ID:  <201208081824.q78IOYC9013334@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mjacob
Date: Wed Aug  8 18:24:33 2012
New Revision: 239143
URL: http://svn.freebsd.org/changeset/base/239143

Log:
  More rototilling with target mode in an attemp to get multiple
  CCB at a time outstanding reliable. It's not there yet, but this
  is the direction to go in so might as well commit. So far,
  multiple at a time CCBs work (see ISP_INTERNAL_TARGET test mode),
  but it fails if there are more downstream than the SIM wants
  to handle and SRR is sort of confused when this happens, plus
  it is not entirely quite clear what one does if a CCB/CTIO fails
  and you have more in flight (that don't fail, say) and more queued
  up at the SIM level that haven't been started yet.
  
  Some of this is driven because there apparently is no flow control
  to requeue XPT_CONTINUE_IO requests like there are for XPT_SCSI_IO
  requests. It is also more driven in that the few target mode
  periph drivers there are are not really set up for handling pushback-
  heck most of them don't even check for errors (and what would they
  really do with them anyway? It's the initiator's problem, really....).
  
  The data transfer arithmetic has been worked over again to handle
  multiple outstanding commands, so you have a notion of what's been
  moved already as well as what's currently in flight. It turns that
  this led to uncovering a REPORT_LUNS bug in the ISP_INTERNAL_TARGET
  code which was sending back 24 bytes of rpl data instead of the
  specified 16. What happened furthermore here is that sending back
  16 bytes and reporting an overrun of 8 bytes made the initiator
  (running FC-Tape aware f/w) mad enough to request, and keep
  requesting, another FCP response (I guess it didn't like the answer
  so kept asking for it again).
  
  Sponsored by: Spectralogic
  MFC after:	1 month

Modified:
  head/sys/dev/isp/isp_freebsd.c
  head/sys/dev/isp/isp_freebsd.h

Modified: head/sys/dev/isp/isp_freebsd.c
==============================================================================
--- head/sys/dev/isp/isp_freebsd.c	Wed Aug  8 17:16:06 2012	(r239142)
+++ head/sys/dev/isp/isp_freebsd.c	Wed Aug  8 18:24:33 2012	(r239143)
@@ -74,6 +74,7 @@ static void isp_action(struct cam_sim *,
 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 @@ isp_attach(ispsoftc_t *isp)
 	}
 
 	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 @@ static ISP_INLINE void
 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_putback_atio
 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 @@ static void
 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 @@ isp_tmcmd_restart(ispsoftc_t *isp)
 		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 @@ isp_tmcmd_restart(ispsoftc_t *isp)
 						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 @@ isp_dump_atpd(ispsoftc_t *isp, tstate_t 
 		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 @@ create_lun_state(ispsoftc_t *isp, int bu
 	}
 	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 @@ isp_ledone(ispsoftc_t *isp, lun_entry_t 
 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;
-	}
-
-	/*
-	 * 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;
+	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;
 	}
 
-	/*
-	 * 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;
-	}
+	while (TAILQ_FIRST(&tptr->waitq) != NULL) {
+		ccb = (union ccb *) TAILQ_FIRST(&tptr->waitq);
+		TAILQ_REMOVE(&tptr->waitq, &ccb->ccb_h, periph_links.tqe);
 
-	/*
-	 * 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;
-	}
+		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;
+			}
+		}
 
+		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;
+		}
 
-	/*
-	 * 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);
+		/*
+		 * 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;
+		}
 
-	/*
-	 * 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;
-	}
+		/*
+		 * 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;
+		}
 
-	/*
-	 * 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;
-	}
+		/*
+		 * 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 (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;
+		}
+		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
+			sendstatus = 1;
+		} else {
+			sendstatus = 0;
 		}
-	} else {
-		sense_length = 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 (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) {
-					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 |= 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;
+					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;
 				}
 				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);
-				}
-				if (isp->isp_dblev & ISP_LOGTDEBUG1) {
-					isp_print_bytes(isp, "FCP Response Frame After Swizzling", MIN_FCP_RESPONSE_SIZE + sense_length, 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);
 				}
-				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;
-			}
-			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;
+				atp->state = ATPD_STATE_LAST_CTIO;
 			}
 
 			/*
-			 * 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);
-				}
-				if (isp->isp_dblev & ISP_LOGTDEBUG1) {
-					isp_print_bytes(isp, "FCP Response Frame After Swizzling", MIN_FCP_RESPONSE_SIZE + sense_length, 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);
 				}
-				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;
+				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->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;
+					cto->ct_flags |= CT2_DATA_OUT;
 				}
-			}
-			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;
-		}
 
-		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_reloff = atp->bytes_xfered + atp->bytes_in_transit;
+				cto->rsp.m0.ct_xfrlen = xfrlen;
 
-			/*
-			 * 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;
-			}
-			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;
+				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 {
-					atp->sendst = 1;	/* send status later */
-					cto->ct_header.rqs_seqno = 0;
 					atp->state = ATPD_STATE_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;
+
+			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;
+			}
+			if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
+				cto->ct_flags |= CT_NODISC;
+			}
+			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 (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
-			cto->ct_flags |= CT_NODISC;
-		}
-		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 (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_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);
+		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;
 		}
-		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

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201208081824.q78IOYC9013334>