svn commit: r240016 - stable/9/sys/dev/isp

Matt Jacob mjacob at FreeBSD.org
Sun Sep 2 15:04:40 UTC 2012


Author: mjacob
Date: Sun Sep  2 15:04:39 2012
New Revision: 240016
URL: http://svn.freebsd.org/changeset/base/240016

Log:
  MFC of 239143
  
  More rototilling with target mode in an attemp to get multiple...

Modified:
  stable/9/sys/dev/isp/isp_freebsd.c
  stable/9/sys/dev/isp/isp_freebsd.h
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)
  stable/9/sys/dev/isp/   (props changed)

Modified: stable/9/sys/dev/isp/isp_freebsd.c
==============================================================================
--- stable/9/sys/dev/isp/isp_freebsd.c	Sun Sep  2 15:03:40 2012	(r240015)
+++ stable/9/sys/dev/isp/isp_freebsd.c	Sun Sep  2 15:04:39 2012	(r240016)
@@ -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 ***


More information about the svn-src-all mailing list