From 6bcdc2b5d294b68eff57d05482e825105759bee9 Mon Sep 17 00:00:00 2001
From: mjacob <mjacob@NetBSD.org>
Date: Sat, 30 Jan 1999 07:31:50 +0000
Subject: [PATCH] Implement and use Fast Posting for both parallel && fibre.
 Redo a bit of the startup code. Implement a call to outer framework function
 so that asynchronous events can be handled (e.g., speed negotiation, target
 mode).

Roll internal release tags.
---
 sys/dev/ic/isp.c        | 468 +++++++++++++++++++++++-----------------
 sys/dev/ic/isp_netbsd.c |  55 ++++-
 sys/dev/ic/isp_netbsd.h |   5 +-
 sys/dev/ic/ispmbox.h    |   8 +-
 sys/dev/ic/ispreg.h     |   5 +-
 sys/dev/ic/ispvar.h     |  36 +++-
 6 files changed, 363 insertions(+), 214 deletions(-)

diff --git a/sys/dev/ic/isp.c b/sys/dev/ic/isp.c
index c6f7b0ae0820..41ca063db62b 100644
--- a/sys/dev/ic/isp.c
+++ b/sys/dev/ic/isp.c
@@ -1,5 +1,5 @@
-/* $NetBSD: isp.c,v 1.30 1999/01/10 05:07:53 mjacob Exp $ */
-/* release_12_28_98_A+ */
+/* $NetBSD: isp.c,v 1.31 1999/01/30 07:31:50 mjacob Exp $ */
+/* release_01_29_99 */
 /*
  * Machine and OS Independent (well, as best as possible)
  * code for the Qlogic ISP SCSI adapters.
@@ -118,7 +118,7 @@ static void isp_rdnvram_word __P((struct ispsoftc *, int, u_int16_t *));
 /*
  * Reset Hardware.
  *
- * Hit the chip over the head, download new f/w.
+ * Hit the chip over the head, download new f/w and set it running.
  *
  * Locking done elsewhere.
  */
@@ -128,7 +128,7 @@ isp_reset(isp)
 {
 	static char once = 1;
 	mbreg_t mbs;
-	int loops, i, dodnld = 1, deadchip;
+	int loops, i, dodnld = 1;
 	char *revname;
 
 	isp->isp_state = ISP_NILSTATE;
@@ -139,17 +139,40 @@ isp_reset(isp)
 	 * here.
 	 */
 	isp->isp_dblev = DFLT_DBLEVEL;
-	deadchip = ISP_READ(isp, HCCR) & HCCR_RESET;
-	if (deadchip) {
+
+	/*
+	 * Get the current running firmware revision out of the
+	 * chip before we hit it over the head (if this is our
+	 * first time through). Note that we store this as the
+	 * 'ROM' firmware revision- which it may not be. In any
+	 * case, we don't really use this yet, but we may in
+	 * the future.
+	 */
+	if (once == 1) {
+		/*
+		 * Just in case it was paused...
+		 */
 		ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
-		if (ISP_READ(isp, HCCR) & HCCR_RESET) {
-			isp_dumpregs(isp, "still reset after release");
-			SYS_DELAY(1000);
+		once = 0;
+		mbs.param[0] = MBOX_ABOUT_FIRMWARE;
+		isp_mboxcmd(isp, &mbs);
+		if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+			/*
+			 * If this fails, it probably means we're running
+			 * an old prom, if anything at all...
+			 */
+			isp->isp_romfw_rev = 0;
 		} else {
-			deadchip = 1;
+			isp->isp_romfw_rev =
+			    (((u_int16_t) mbs.param[1]) << 10) + mbs.param[2];
 		}
 	}
 
+	/*
+	 * Put it into PAUSE mode.
+	 */
+	ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
+
 	if (isp->isp_type & ISP_HA_FC) {
 		revname = "2100";
 	} else {
@@ -192,62 +215,36 @@ isp_reset(isp)
 			break;
 		}
 		/*
-		 * Try and figure out if we're connected to a differential bus.
-		 * You have to pause the RISC processor to read SXP registers.
+		 * Now, while we're at it, gather info about ultra
+		 * and/or differential mode.
 		 */
-		if (deadchip == 0) {
-			ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
-			i = 100;
-			while ((ISP_READ(isp, HCCR) & HCCR_PAUSE) == 0) {
-				SYS_DELAY(20);
-				if (--i == 0) {
-					isp_dumpregs(isp,
-					    "cannot stop RISC processor");
-					i = -1;
-					break;
-				}
-			}
+		if (isp->isp_bustype != ISP_BT_SBUS) {
+			ISP_SETBITS(isp, BIU_CONF1, BIU_PCI_CONF1_SXP);
+		}
+		if (ISP_READ(isp, SXP_PINS_DIFF) & SXP_PINS_DIFF_MODE) {
+			PRINTF("%s: Differential Mode\n", isp->isp_name);
+			sdp->isp_diffmode = 1;
 		} else {
-			i = 0;
+			sdp->isp_diffmode = 0;
 		}
-		if (i > 0) {
-			if (isp->isp_bustype != ISP_BT_SBUS) {
-				ISP_SETBITS(isp, BIU_CONF1, BIU_PCI_CONF1_SXP);
-			}
-			if (ISP_READ(isp, SXP_PINS_DIFF) & SXP_PINS_DIFF_MODE) {
-				IDPRINTF(2, ("%s: Differential Mode Set\n",
-				    isp->isp_name));
-				sdp->isp_diffmode = 1;
-			} else {
-				sdp->isp_diffmode = 0;
-			}
-
-			if (isp->isp_bustype != ISP_BT_SBUS) {
-				ISP_CLRBITS(isp, BIU_CONF1, BIU_PCI_CONF1_SXP);
-			}
-
-			/*
-			 * Figure out whether we're ultra capable.
-			 */
-			i = ISP_READ(isp, RISC_PSR);
-			if (isp->isp_bustype != ISP_BT_SBUS) {
-				i &= RISC_PSR_PCI_ULTRA;
-			} else {
-				i &= RISC_PSR_SBUS_ULTRA;
-			}
-			if (i) {
-				IDPRINTF(2, ("%s: Ultra Mode Capable\n",
-				    isp->isp_name));
-				sdp->isp_clock = 60;
-			} else {
-				sdp->isp_clock = 40;
-			}
-			/*
-			 * Restart processor, if necessary.
-			 */
-			if (deadchip == 0)
-				ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
+		i = ISP_READ(isp, RISC_PSR);
+		if (isp->isp_bustype == ISP_BT_SBUS) {
+			i &= RISC_PSR_SBUS_ULTRA;
+		} else {
+			i &= RISC_PSR_PCI_ULTRA;
 		}
+		if (isp->isp_bustype != ISP_BT_SBUS) {
+			ISP_CLRBITS(isp, BIU_CONF1, BIU_PCI_CONF1_SXP);
+		}
+		if (i != 0) {
+			PRINTF("%s: Ultra Mode Capable\n", isp->isp_name);
+			sdp->isp_ultramode = 1;
+			sdp->isp_clock = 60;
+                } else {
+			sdp->isp_ultramode = 0;
+			sdp->isp_clock = 40;
+		}
+
 		/*
 		 * Machine dependent clock (if set) overrides
 		 * our generic determinations.
@@ -257,6 +254,7 @@ isp_reset(isp)
 				sdp->isp_clock = isp->isp_mdvec->dv_clock;
 			}
 		}
+
 	}
 
 	/*
@@ -264,27 +262,7 @@ isp_reset(isp)
 	 */
 	ISP_RESET0(isp);
 
-	if (once == 1 && deadchip == 0) {
-		once = 0;
-		/*
-		 * Get the current running firmware revision out of the
-		 * chip before we hit it over the head (if this is our
-		 * first time through). Note that we store this as the
-		 * 'ROM' firmware revision- which it may not be. In any
-		 * case, we don't really use this yet, but we may in
-		 * the future.
-		 */
-		mbs.param[0] = MBOX_ABOUT_FIRMWARE;
-		isp_mboxcmd(isp, &mbs);
-		if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
-			IDPRINTF(3, ("%s: initial ABOUT FIRMWARE command "
-			    "failed\n", isp->isp_name));
-		} else {
-			isp->isp_romfw_rev =
-			    (((u_int16_t) mbs.param[1]) << 10) + mbs.param[2];
-		}
-	}
-
+again:
 
 	/*
 	 * Hit the chip over the head with hammer,
@@ -311,6 +289,10 @@ isp_reset(isp)
 		 * A slight delay...
 		 */
 		SYS_DELAY(100);
+
+		/*
+		 * Clear data && control DMA engines.
+		 */
 		ISP_WRITE(isp, CDMA2100_CONTROL,
 			DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT);
 		ISP_WRITE(isp, TDMA2100_CONTROL,
@@ -337,41 +319,62 @@ isp_reset(isp)
 			return;
 		}
 	}
+
 	/*
-	 * More initialization
+	 * After we've fired this chip up, zero out the conf1 register
+	 * for SCSI adapters and other settings for the 2100.
 	 */
-	if (isp->isp_type & ISP_HA_SCSI) {      
+
+	if (isp->isp_type & ISP_HA_SCSI) {
 		ISP_WRITE(isp, BIU_CONF1, 0);
 	} else {
 		ISP_WRITE(isp, BIU2100_CSR, 0);
-		/*
-		 * All 2100's are 60Mhz with fast rams onboard.
-		 */
-		ISP_WRITE(isp, RISC_MTR2100, 0x1212);
 	}
 
+	/*
+	 * Reset RISC Processor
+	 */
 	ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
 	SYS_DELAY(100);
 
 	/*
-	 * Establish some initial burst rate thingies
+	 * Establish some initial burst rate stuff.
 	 * (only for the 1XX0 boards). This really should
 	 * be done later after fetching from NVRAM.
 	 */
 	if (isp->isp_type & ISP_HA_SCSI) {
-		u_int16_t conf1 = isp->isp_mdvec->dv_conf1;
+		u_int16_t tmp = isp->isp_mdvec->dv_conf1;
 		/*
 		 * Busted FIFO. Turn off all but burst enables.
 		 */
 		if (isp->isp_type == ISP_HA_SCSI_1040A) {
-			conf1 &= BIU_BURST_ENABLE;
+			tmp &= BIU_BURST_ENABLE;
 		}
-		ISP_SETBITS(isp, BIU_CONF1, conf1);
-		if (conf1 & BIU_BURST_ENABLE) {
+		ISP_SETBITS(isp, BIU_CONF1, tmp);
+		if (tmp & BIU_BURST_ENABLE) {
 			ISP_SETBITS(isp, CDMA_CONF, DMA_ENABLE_BURST);
 			ISP_SETBITS(isp, DDMA_CONF, DMA_ENABLE_BURST);
 		}
+#ifdef	PTI_CARDS
+		if (((sdparam *) isp->isp_param)->isp_ultramode) {
+                	while(ISP_READ(isp, RISC_MTR) != 0x1313) {
+				ISP_WRITE(isp, RISC_MTR, 0x1313);
+				ISP_WRITE(isp, HCCR, HCCR_CMD_STEP);
+			}
+                } else {
+			ISP_WRITE(isp, RISC_MTR, 0x1212);
+		}
+		/*
+		 * PTI specific register
+		 */
+		ISP_WRITE(isp, RISC_EMB, DUAL_BANK)
+#else
+		ISP_WRITE(isp, RISC_MTR, 0x1212);
+#endif
+	} else {
+		ISP_WRITE(isp, RISC_MTR2100, 0x1212);
 	}
+
 	ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); /* release paused processor */
 
 	/*
@@ -384,6 +387,25 @@ isp_reset(isp)
 	 */
 	ENABLE_INTS(isp);
 
+	/*
+	 * Wait for everything to finish firing up...
+	 */
+	loops = MBOX_DELAY_COUNT;
+	while (ISP_READ(isp, OUTMAILBOX0) == MBOX_BUSY) {
+		SYS_DELAY(100);
+		if (--loops < 0) {
+			PRINTF("%s: MBOX_BUSY never cleared on reset\n",
+			    isp->isp_name);
+			return;
+		}
+	}
+
+	/*
+	 * Up until this point we've done everything by just reading or
+	 * setting registers. From this point on we rely on at least *some*
+	 * kind of firmware running in the card.
+	 */
+
 	/*
 	 * Do some sanity checking.
 	 */
@@ -430,29 +452,29 @@ isp_reset(isp)
 		dodnld = 0;
 	}
 
-	if (dodnld) {
+	if (dodnld && isp->isp_mdvec->dv_fwlen) {
 		for (i = 0; i < isp->isp_mdvec->dv_fwlen; i++) {
 			mbs.param[0] = MBOX_WRITE_RAM_WORD;
 			mbs.param[1] = isp->isp_mdvec->dv_codeorg + i;
 			mbs.param[2] = isp->isp_mdvec->dv_ispfw[i];
 			isp_mboxcmd(isp, &mbs);
 			if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
-				isp_dumpregs(isp, "f/w download failed");
-				return;
+				PRINTF("%s: F/W download failed at word %d\n",
+				    isp->isp_name, i);
+				dodnld = 0;
+				goto again;
 			}
 		}
 
-		if (isp->isp_mdvec->dv_fwlen) {
-			/*
-			 * Verify that it downloaded correctly.
-			 */
-			mbs.param[0] = MBOX_VERIFY_CHECKSUM;
-			mbs.param[1] = isp->isp_mdvec->dv_codeorg;
-			isp_mboxcmd(isp, &mbs);
-			if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
-				isp_dumpregs(isp, "ram checksum failure");
-				return;
-			}
+		/*
+		 * Verify that it downloaded correctly.
+		 */
+		mbs.param[0] = MBOX_VERIFY_CHECKSUM;
+		mbs.param[1] = isp->isp_mdvec->dv_codeorg;
+		isp_mboxcmd(isp, &mbs);
+		if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+			isp_dumpregs(isp, "ram checksum failure");
+			return;
 		}
 	} else {
 		IDPRINTF(3, ("%s: skipping f/w download\n", isp->isp_name));
@@ -466,7 +488,10 @@ isp_reset(isp)
 	 */
 
 	mbs.param[0] = MBOX_EXEC_FIRMWARE;
-	mbs.param[1] = isp->isp_mdvec->dv_codeorg;
+	if (isp->isp_mdvec->dv_codeorg)
+		mbs.param[1] = isp->isp_mdvec->dv_codeorg;
+	else
+		mbs.param[1] = 0x1000;
 	isp_mboxcmd(isp, &mbs);
 
 	if (isp->isp_type & ISP_HA_SCSI) {
@@ -506,7 +531,7 @@ isp_reset(isp)
 }
 
 /*
- * Initialize Hardware to known state
+ * Initialize Parameters of Hardware to a known state.
  *
  * Locks are held before coming here.
  */
@@ -674,6 +699,10 @@ isp_init(isp)
 				break;
 			}
 		}
+		/*
+		 * And mark this as an unannounced device
+		 */
+		sdp->isp_devparam[tgt].dev_announced = 0;
 	}
 
 	/*
@@ -710,6 +739,19 @@ isp_init(isp)
 	}
 	isp->isp_reqidx = isp->isp_reqodx = 0;
 
+	/*
+	 *  Turn on Fast Posting
+	 */
+	if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
+		mbs.param[0] = MBOX_SET_FW_FEATURES;
+		mbs.param[1] = FW_FEATURE_FAST_POST;
+		isp_mboxcmd(isp, &mbs);
+		if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+			PRINTF("%s: unable to enable FAST Posting\n",
+			    isp->isp_name);
+		}
+	}
+
 	/*	
 	 * XXX: See whether or not for 7.55 F/W or later we
 	 * XXX: can do without this, and see whether we should
@@ -763,6 +805,15 @@ isp_fibre_init(isp)
 	loopid = fcp->isp_loopid;
 #endif
 
+#if	defined(ISP2100_FABRIC) && defined(ISP2100_SCCLUN)
+	PRINTF("%s: Fabric Support, Expanded Lun Support\n", isp->isp_name);
+#endif
+#if	defined(ISP2100_FABRIC) && !defined(ISP2100_SCCLUN)
+	PRINTF("%s: Fabric Support\n", isp->isp_name);
+#endif
+#if	!defined(ISP2100_FABRIC) && defined(ISP2100_SCCLUN)
+	PRINTF("%s: Expanded Lun Support\n", isp->isp_name);
+#endif
 
 	icbp = (isp_icb_t *) fcp->isp_scratch;
 	MEMZERO(icbp, sizeof (*icbp));
@@ -773,7 +824,7 @@ isp_fibre_init(isp)
 #else
 	fcp->isp_fwoptions = 0;
 #endif
-	fcp->isp_fwoptions |= ICBOPT_INI_ADISC|ICBOPT_FAIRNESS;
+	fcp->isp_fwoptions |= ICBOPT_INI_ADISC|ICBOPT_FAIRNESS|ICBOPT_FAST_POST;
 	fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE;
 	fcp->isp_fwoptions |= ICBOPT_HARD_ADDRESS;
 #ifdef	CHECKME
@@ -785,6 +836,7 @@ isp_fibre_init(isp)
 	 */
 	fcp->isp_fwoptions |= ICBOPT_FULL_LOGIN;
 #endif
+
 	icbp->icb_fwoptions = fcp->isp_fwoptions;
 	icbp->icb_maxfrmlen = fcp->isp_maxfrmlen;
 	if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN ||
@@ -1058,7 +1110,7 @@ ispscsicmd(xs)
 #endif
 
 	}
-	memcpy(reqp->req_cdb, XS_CDBP(xs), XS_CDBLEN(xs));
+	MEMCPY(reqp->req_cdb, XS_CDBP(xs), XS_CDBLEN(xs));
 
 	IDPRINTF(5, ("%s(%d.%d): START%d cmd 0x%x datalen %d\n", isp->isp_name,
 	    XS_TGT(xs), XS_LUN(xs), reqp->req_header.rqs_seqno,
@@ -1227,9 +1279,28 @@ isp_intr(arg)
 
 	if (ISP_READ(isp, BIU_SEMA) & 1) {
 		u_int16_t mbox = ISP_READ(isp, OUTMAILBOX0);
-		if (isp_parse_async(isp, (int) mbox))
-			return (1);
+		u_int32_t fast_post_handle = isp_parse_async(isp, (int) mbox);
 		ISP_WRITE(isp, BIU_SEMA, 0);
+		if (fast_post_handle < 0) {
+			return (1);
+		} else if (fast_post_handle > 0) {
+			xs = (ISP_SCSI_XFER_T *)
+			    isp->isp_xflist[fast_post_handle - 1];
+			isp->isp_xflist[fast_post_handle - 1] = NULL;
+			/*
+			 * Since we don't have a result queue entry item,
+			 * we must believe that SCSI status is zero and
+			 * that all data transferred.
+			 */
+			XS_RESID(xs) = 0;
+			XS_STS(xs) = 0;
+			if (XS_XFRLEN(xs)) {
+				ISP_DMAFREE(isp, xs, fast_post_handle - 1);
+			}
+			if (isp->isp_nactive > 0)
+			    isp->isp_nactive--;
+			complist[ndone++] = xs;	
+		}
 	}
 
 	ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
@@ -1319,14 +1390,24 @@ isp_intr(arg)
 		XS_STS(xs) = sp->req_scsi_status & 0xff;
 		if (isp->isp_type & ISP_HA_SCSI) {
 			if (sp->req_state_flags & RQSF_GOT_SENSE) {
-				memcpy(XS_SNSP(xs), sp->req_sense_data,
+				MEMCPY(XS_SNSP(xs), sp->req_sense_data,
 					XS_SNSLEN(xs));
 				XS_SNS_IS_VALID(xs);
 			}
+			/*
+			 * A new synchronous rate was negotiated for this
+			 * target. Mark state such that we'll go look up
+			 * that which has changed later.
+			 */
+			if (sp->req_status_flags & RQSTF_NEGOTIATION) {
+				sdparam *sdp = isp->isp_param;
+				isp->isp_update = 1;
+				sdp->isp_devparam[XS_TGT(xs)].dev_refresh = 1;
+			}
 		} else {
 			if (XS_STS(xs) == SCSI_CHECK) {
 				XS_SNS_IS_VALID(xs);
-				memcpy(XS_SNSP(xs), sp->req_sense_data,
+				MEMCPY(XS_SNSP(xs), sp->req_sense_data,
 					XS_SNSLEN(xs));
 				sp->req_state_flags |= RQSF_GOT_SENSE;
 			}
@@ -1419,6 +1500,8 @@ isp_parse_async(isp, mbox)
 	struct ispsoftc *isp;
 	int mbox;
 {
+	u_int32_t fast_post_handle = 0;
+
 	switch (mbox) {
 	case ASYNC_BUS_RESET:
 		PRINTF("%s: SCSI bus reset detected\n", isp->isp_name);
@@ -1434,7 +1517,7 @@ isp_parse_async(isp, mbox)
 		    isp->isp_name, mbox);
 		isp_restart(isp);
 		/* no point continuing after this */
-		return (1);
+		return (-1);
 
 	case ASYNC_RQS_XFER_ERR:
 		PRINTF("%s: Request Queue Transfer Error\n", isp->isp_name);
@@ -1489,11 +1572,10 @@ isp_parse_async(isp, mbox)
 		break;
 
 	case ASYNC_CMD_CMPLT:
-		PRINTF("%s: fast post completion\n", isp->isp_name);
-#if	0
-		fast_post_handle = (ISP_READ(isp, OUTMAILBOX1) << 16) |
-		    ISP_READ(isp, OUTMAILBOX2);
-#endif
+		fast_post_handle = (ISP_READ(isp, OUTMAILBOX2) << 16) |
+		    ISP_READ(isp, OUTMAILBOX1);
+		IDPRINTF(3, ("%s: fast post completion of %u\n", isp->isp_name,
+		    fast_post_handle));
 		break;
 
 	case ASYNC_CTIO_DONE:
@@ -1532,7 +1614,7 @@ isp_parse_async(isp, mbox)
 		PRINTF("%s: async %x\n", isp->isp_name, mbox);
 		break;
 	}
-	return (0);
+	return (fast_post_handle);
 }
 
 static int
@@ -1718,7 +1800,7 @@ isp_handle_other_response(isp, sp, optrp)
 			ct2->req_seg_count = 1;
 			if (at2->req_cdb[0] == 0x12) {
 				s = sizeof(tgtiqd);
-				memcpy(fcp->isp_scratch, tgtiqd, s);
+				MEMCPY(fcp->isp_scratch, tgtiqd, s);
 			} else {
 				s = at2->req_datalen;
 				MEMZERO(fcp->isp_scratch, s);
@@ -1773,7 +1855,7 @@ isp_handle_other_response(isp, sp, optrp)
 				ct2->req_m.mode1.req_sense_len = 18;
 				ct2->req_m.mode1.req_scsi_status |=
 				    at2->req_scsi_status;
-				memcpy(ct2->req_m.mode1.req_response,
+				MEMCPY(ct2->req_m.mode1.req_response,
 				    at2->req_sense, sizeof (at2->req_sense));
 			}
 			break;
@@ -1826,7 +1908,7 @@ isp_handle_other_response(isp, sp, optrp)
 			PRINTF("%s: Request Queue Overflow other response\n",
 			    isp->isp_name);
 		} else {
-			memcpy(reqp, ireqp, reqsize);
+			MEMCPY(reqp, ireqp, reqsize);
 			ISP_WRITE(isp, INMAILBOX4, iptr);
 			isp->isp_reqidx = iptr;
 		}
@@ -1954,7 +2036,7 @@ isp_notify_ack(isp, ptrp)
 		PRINTF("%s: Request Queue Overflow For isp_notify_ack\n",
 		    isp->isp_name);
 	} else {
-		memcpy(reqp, ireqp, sizeof (un));
+		MEMCPY(reqp, ireqp, sizeof (un));
 		ISP_WRITE(isp, INMAILBOX4, iptr);
 		isp->isp_reqidx = iptr;
 	}
@@ -2009,7 +2091,7 @@ isp_handle_atio (isp, aep)
 
 
 		if (status & TGTSVALID) {
-			memcpy(&cdp->cd_sensedata, aep->at_sense,
+			MEMCPY(&cdp->cd_sensedata, aep->at_sense,
 			    sizeof (cdp->cd_sensedata));
 			PRINTF("%s: Bus Phase Sequence error key 0x%x\n",
 			    isp->isp_name, cdp->cd_sensedata[2] & 0xf);
@@ -2050,7 +2132,7 @@ isp_handle_atio (isp, aep)
 		cdp->cd_lun = aep->at_lun;
 		cdp->cd_tagtype = aep->at_tag_type;
 		cdp->cd_tagval = aep->at_tag_val;
-		memcpy(cdp->cd_cdb, aep->at_cdb, 16);
+		MEMCPY(cdp->cd_cdb, aep->at_cdb, 16);
 		PRINTF("%s: CDB 0x%x itl %d/%d/%d\n", isp->isp_name,
 		    cdp->cd_cdb[0], cdp->cd_iid, cdp->cd_tgt, cdp->cd_lun);
 		(*isp->isp_tmd_newcmd)(isp, cdp);
@@ -2126,7 +2208,7 @@ isp_handle_atio2(isp, aep)
 		cdp->cd_iid = aep->at_iid;
 		cdp->cd_tgt = 0;
 		cdp->cd_lun = aep->at_lun;
-		memcpy(cdp->cd_cdb, aep->at_cdb, 16);
+		MEMCPY(cdp->cd_cdb, aep->at_cdb, 16);
 		cdp->cd_rxid = aep->at_rxid;
 		cdp->cp_origdlen = aep->at_datalen;
 		cdp->cp_totbytes = 0;
@@ -2354,8 +2436,8 @@ isp_parse_status(isp, sp, xs)
 		if (isp->isp_type & ISP_HA_SCSI) {
 			sdparam *sdp = isp->isp_param;
 			isp->isp_update = 1;
-			sdp->isp_devparam[XS_TGT(xs)].dev_update = 1;
 			sdp->isp_devparam[XS_TGT(xs)].dev_flags &= ~DPARM_WIDE;
+			sdp->isp_devparam[XS_TGT(xs)].dev_update = 1;
 		}
 		XS_SETERR(xs, HBA_NOERROR);
 		return;
@@ -2366,8 +2448,8 @@ isp_parse_status(isp, sp, xs)
 		if (isp->isp_type & ISP_HA_SCSI) {
 			sdparam *sdp = isp->isp_param;
 			isp->isp_update = 1;
-			sdp->isp_devparam[XS_TGT(xs)].dev_update = 1;
 			sdp->isp_devparam[XS_TGT(xs)].dev_flags &= ~DPARM_SYNC;
+			sdp->isp_devparam[XS_TGT(xs)].dev_update = 1;
 		}
 		break;
 
@@ -2491,8 +2573,8 @@ static u_int8_t mbpcnt[] = {
 	MAKNIB(0, 0),	/* 0x47: */
 	MAKNIB(0, 0),	/* 0x48: */
 	MAKNIB(0, 0),	/* 0x49: */
-	MAKNIB(0, 0),	/* 0x4a: */
-	MAKNIB(0, 0),	/* 0x4b: */
+	MAKNIB(2, 1),	/* 0x4a: MBOX_SET_FIRMWARE_FEATURES */
+	MAKNIB(1, 2),	/* 0x4b: MBOX_GET_FIRMWARE_FEATURES */
 	MAKNIB(0, 0),	/* 0x4c: */
 	MAKNIB(0, 0),	/* 0x4d: */
 	MAKNIB(0, 0),	/* 0x4e: */
@@ -2879,77 +2961,68 @@ isp_update(isp)
 
 	sdp = isp->isp_param;
 	for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
+		u_int16_t flags, period, offset, changed;
+		int get;
+
 		if (sdp->isp_devparam[tgt].dev_enable == 0) {
 			continue;
 		}
-		if (sdp->isp_devparam[tgt].dev_update == 0) {
+
+		if (sdp->isp_devparam[tgt].dev_update) {
+			mbs.param[0] = MBOX_SET_TARGET_PARAMS;
+			mbs.param[2] = sdp->isp_devparam[tgt].dev_flags;
+			mbs.param[3] =
+				(sdp->isp_devparam[tgt].sync_offset << 8) |
+				(sdp->isp_devparam[tgt].sync_period);
+			sdp->isp_devparam[tgt].dev_update = 0;
+			sdp->isp_devparam[tgt].dev_refresh = 1;
+			isp->isp_update = 1;
+			get = 0;
+		} else if (sdp->isp_devparam[tgt].dev_refresh) {
+			mbs.param[0] = MBOX_GET_TARGET_PARAMS;
+			sdp->isp_devparam[tgt].dev_refresh = 0;
+			get = 1;
+		} else {
+			continue;
+		}
+		mbs.param[1] = tgt << 8;
+		isp_mboxcmd(isp, &mbs);
+		if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+			PRINTF("%s: failed to %cet SCSI parameters for "
+			    "target %d\n", isp->isp_name, (get)? 'g' : 's',
+			    tgt);
 			continue;
 		}
 
-		mbs.param[0] = MBOX_SET_TARGET_PARAMS;
-		mbs.param[1] = tgt << 8;
-		mbs.param[2] = sdp->isp_devparam[tgt].dev_flags;
-		mbs.param[3] =
-			(sdp->isp_devparam[tgt].sync_offset << 8) |
-			(sdp->isp_devparam[tgt].sync_period);
-
-		IDPRINTF(3, ("\n%s: tgt %d cflags %x offset %x period %x\n",
-		    isp->isp_name, tgt, mbs.param[2], mbs.param[3] >> 8,
-		    mbs.param[3] & 0xff));
-
-		isp_mboxcmd(isp, &mbs);
-		if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
-			PRINTF("%s: failed to change SCSI parameters for "
-			    "target %d\n", isp->isp_name, tgt);
-		} else {
-			char *wt;
-			int x, flags;
-
-			flags = sdp->isp_devparam[tgt].cur_dflags =
+		if (get == 0) {
+			sdp->isp_devparam[tgt].cur_dflags =
 			    sdp->isp_devparam[tgt].dev_flags;
-
-			x = sdp->isp_devparam[tgt].sync_period & 0xff;
-			if (flags & DPARM_SYNC) {
-				if (x == (ISP_20M_SYNCPARMS & 0xff)) {
-					x = 20;
-				} else if (x == (ISP_10M_SYNCPARMS & 0xff)) {
-					x = 10;
-				} else if (x == (ISP_08M_SYNCPARMS & 0xff)) {
-					x = 8;
-				} else if (x == (ISP_05M_SYNCPARMS & 0xff)) {
-					x = 5;
-				} else if (x == (ISP_04M_SYNCPARMS & 0xff)) {
-					x = 4;
-				} else {
-					x = 0;
-				}
-			} else {
-				x = 0;
-			}
-			switch (flags & (DPARM_WIDE|DPARM_TQING)) {
-			case DPARM_WIDE:
-				wt = ", 16 bit wide\n";
-				break;
-			case DPARM_TQING:
-				wt = ", Tagged Queueing Enabled\n";
-				break;
-			case DPARM_WIDE|DPARM_TQING:
-				wt = ", 16 bit wide, Tagged Queueing Enabled\n";
-				break;
-
-			default:
-				wt = "\n";
-				break;
-			}
-			if (x) {
-				IDPRINTF(3, ("%s: Target %d maximum Sync Mode "
-				    "at %dMHz%s", isp->isp_name, tgt, x, wt));
-			} else {
-				IDPRINTF(3, ("%s: Target %d Async Mode%s",
-				    isp->isp_name, tgt, wt));
-			}
+			continue;
+		}
+		flags = mbs.param[2];
+		period = mbs.param[3] & 0xff;
+		offset = mbs.param[3] >> 8;
+		if (sdp->isp_devparam[tgt].cur_dflags != flags ||
+		    sdp->isp_devparam[tgt].sync_period != period ||
+		    sdp->isp_devparam[tgt].sync_offset != offset) {
+			IDPRINTF(3, ("%s: tgt %d flags 0x%x period %d "
+			    "off %d\n", isp->isp_name, tgt, flags,
+			    period, offset));
+			changed = 1;
+		} else {
+			changed = 0;
+		}
+
+		sdp->isp_devparam[tgt].cur_dflags = flags;
+		sdp->isp_devparam[tgt].dev_flags = flags;
+		sdp->isp_devparam[tgt].sync_period = period;
+		sdp->isp_devparam[tgt].sync_offset = offset;
+		if (sdp->isp_devparam[tgt].dev_announced == 0 || changed) {
+			if (isp_async(isp, ISPASYNC_NEW_TGT_PARAMS, &tgt))
+				sdp->isp_devparam[tgt].dev_announced = 0;
+			else
+				sdp->isp_devparam[tgt].dev_announced = 1;
 		}
-		sdp->isp_devparam[tgt].dev_update = 0;
 	}
 }
 
@@ -3283,7 +3356,6 @@ isp_read_nvram(isp)
 			ISP_NVRAM_MAX_QUEUE_DEPTH(nvram_data);
 
 		sdp->isp_fast_mttr = ISP_NVRAM_FAST_MTTR_ENABLE(nvram_data);
-
 #if	0
 		PRINTF("%s: fifo_threshold = 0x%x cbena%d dbena%d\n",
 		    isp->isp_name, sdp->isp_fifo_threshold,
diff --git a/sys/dev/ic/isp_netbsd.c b/sys/dev/ic/isp_netbsd.c
index 209e624b6993..3b762a7da071 100644
--- a/sys/dev/ic/isp_netbsd.c
+++ b/sys/dev/ic/isp_netbsd.c
@@ -1,5 +1,5 @@
-/* $NetBSD: isp_netbsd.c,v 1.8 1998/12/28 19:10:43 mjacob Exp $ */
-/* release_12_28_98_A */
+/* $NetBSD: isp_netbsd.c,v 1.9 1999/01/30 07:31:50 mjacob Exp $ */
+/* release_01_29_99 */
 /*
  * Platform (NetBSD) dependent common attachment code for Qlogic adapters.
  *
@@ -300,3 +300,54 @@ isp_uninit(isp)
 
 	ISP_IUNLOCK(isp);
 }
+
+int
+isp_async(isp, cmd, arg)
+	struct ispsoftc *isp;
+	ispasync_t cmd;
+	void *arg;
+{
+	switch (cmd) {
+	case ISPASYNC_NEW_TGT_PARAMS:
+		if (isp->isp_type & ISP_HA_SCSI) {
+			sdparam *sdp = isp->isp_param;
+			char *wt;
+			int ns, flags, tgt;
+
+			tgt = *((int *) arg);
+	
+			flags = sdp->isp_devparam[tgt].dev_flags;
+			if (flags & DPARM_SYNC) {
+				ns = sdp->isp_devparam[tgt].sync_period * 4;
+			} else {
+				ns = 0;
+			}
+			switch (flags & (DPARM_WIDE|DPARM_TQING)) {
+			case DPARM_WIDE:
+				wt = ", 16 bit wide\n";
+				break;
+			case DPARM_TQING:
+				wt = ", Tagged Queueing Enabled\n";
+				break;
+			case DPARM_WIDE|DPARM_TQING:
+				wt = ", 16 bit wide, Tagged Queueing Enabled\n";
+				break;
+			default:
+				wt = "\n";
+				break;
+			}
+			if (ns) {
+				printf("%s: Target %d at %dMHz Max Offset %d%s",
+				    isp->isp_name, tgt, 1000 / ns,
+				    sdp->isp_devparam[tgt].sync_offset, wt);
+			} else {
+				printf("%s: Target %d Async Mode%s",
+				    isp->isp_name, tgt, wt);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+	return (0);
+}
diff --git a/sys/dev/ic/isp_netbsd.h b/sys/dev/ic/isp_netbsd.h
index 73fc2107b716..0681198a768a 100644
--- a/sys/dev/ic/isp_netbsd.h
+++ b/sys/dev/ic/isp_netbsd.h
@@ -1,5 +1,5 @@
-/* $NetBSD: isp_netbsd.h,v 1.8 1999/01/10 05:04:18 mjacob Exp $ */
-/* release_12_28_98_A+ */
+/* $NetBSD: isp_netbsd.h,v 1.9 1999/01/30 07:31:50 mjacob Exp $ */
+/* release_01_29_99 */
 /*
  * NetBSD Specific definitions for the Qlogic ISP Host Adapter
  *
@@ -81,6 +81,7 @@ struct isposinfo {
 #define	IDPRINTF(lev, x)	if (isp->isp_dblev >= lev) printf x
 
 #define	MEMZERO			bzero
+#define	MEMCPY(dst, src, count)	bcopy((src), (dst), (count))
 
 #if	defined(SCSIDEBUG)
 #define	DFLT_DBLEVEL		3
diff --git a/sys/dev/ic/ispmbox.h b/sys/dev/ic/ispmbox.h
index 0dbe8f302f13..1d54fb6ef9df 100644
--- a/sys/dev/ic/ispmbox.h
+++ b/sys/dev/ic/ispmbox.h
@@ -1,5 +1,5 @@
-/* $NetBSD: ispmbox.h,v 1.11 1998/12/28 19:10:43 mjacob Exp $ */
-/* release_12_28_98_A */
+/* $NetBSD: ispmbox.h,v 1.12 1999/01/30 07:31:51 mjacob Exp $ */
+/* release_01_29_99 */
 /*
  * Mailbox and Queue Entry Definitions for for Qlogic ISP SCSI adapters.
  *
@@ -109,6 +109,10 @@
 #define	MBOX_RETURN_BIOS_BLOCK_ADDR	0x0040
 #define	MBOX_WRITE_FOUR_RAM_WORDS	0x0041
 #define	MBOX_EXEC_BIOS_IOCB		0x0042
+#define	MBOX_SET_FW_FEATURES		0x004a
+#define	MBOX_GET_FW_FEATURES		0x004b
+#define		FW_FEATURE_LVD_NOTIFY	0x2
+#define		FW_FEATURE_FAST_POST	0x1
 
 /* These are for the ISP2100 FC cards */
 #define	MBOX_GET_LOOP_ID		0x20
diff --git a/sys/dev/ic/ispreg.h b/sys/dev/ic/ispreg.h
index 5497d779b1c8..ce30f9ebb14a 100644
--- a/sys/dev/ic/ispreg.h
+++ b/sys/dev/ic/ispreg.h
@@ -1,5 +1,5 @@
-/* $NetBSD: ispreg.h,v 1.10 1998/12/28 19:10:43 mjacob Exp $ */
-/* release_12_28_98_A */
+/* $NetBSD: ispreg.h,v 1.11 1999/01/30 07:31:51 mjacob Exp $ */
+/* release_01_29_99 */
 /*
  * Machine Independent (well, as best as possible) register
  * definitions for Qlogic ISP SCSI adapters.
@@ -514,6 +514,7 @@
 #define		RISC_MTR2100	RISC_BLOCK+0x30
 
 #define	RISC_EMB	RISC_BLOCK+0x30	/* RW*: Ext Mem Boundary */
+#define		DUAL_BANK	8
 #define	RISC_SP		RISC_BLOCK+0x32	/* RW*: Stack Pointer */
 #define	RISC_HRL	RISC_BLOCK+0x3e	/* R *: Hardware Rev Level */
 #define	HCCR		RISC_BLOCK+0x40	/* RW : Host Command & Ctrl */
diff --git a/sys/dev/ic/ispvar.h b/sys/dev/ic/ispvar.h
index 74d08416fecb..8be5919a7afb 100644
--- a/sys/dev/ic/ispvar.h
+++ b/sys/dev/ic/ispvar.h
@@ -1,5 +1,5 @@
-/* $NetBSD: ispvar.h,v 1.16 1999/01/10 05:04:46 mjacob Exp $ */
-/* release_12_28_98_A+ */
+/* $NetBSD: ispvar.h,v 1.17 1999/01/30 07:31:51 mjacob Exp $ */
+/* release_01_29_99 */
 /*
  * Soft Definitions for for Qlogic ISP SCSI adapters.
  *
@@ -51,7 +51,7 @@
 #define	ISP_CORE_VERSION_MINOR	5
 
 /*
- * Vector for MD code to provide specific services.
+ * Vector for bus specific code to provide specific services.
  */
 struct ispsoftc;
 struct ispmdvec {
@@ -91,7 +91,7 @@ struct ispmdvec {
 	((in == out)? (qlen - 1) : ((in > out)? \
 		((qlen - 1) - (in - out)) : (out - in - 1)))
 /*
- * SCSI (as opposed to FC-PH) Specific Host Adapter Parameters
+ * SCSI Specific Host Adapter Parameters
  */
 
 typedef struct {
@@ -100,6 +100,7 @@ typedef struct {
 			isp_cmd_dma_burst_enable: 1,
 			isp_data_dma_burst_enabl: 1,
 			isp_fifo_threshold	: 3,
+			isp_ultramode		: 1,
 			isp_diffmode		: 1,
 			isp_fast_mttr		: 1,
 			isp_initiator_id	: 4,
@@ -112,8 +113,11 @@ typedef struct {
         u_int8_t	isp_retry_count;
         u_int8_t	isp_retry_delay;
 	struct {
-		u_int	dev_update	:	1,
+		u_int
 			dev_enable	:	1,
+			dev_announced	:	1,
+			dev_update	:	1,
+			dev_refresh	:	1,
 			exc_throttle	:	7,
 			sync_offset	:	4,
 			sync_period	:	8;
@@ -272,7 +276,7 @@ struct ispsoftc {
 	 * jeez, so I blow a couple of KB per host adapter...
 	 * and it *is* faster.
 	 */
-	volatile ISP_SCSI_XFER_T *isp_xflist[RQUEST_QUEUE_LEN];
+	ISP_SCSI_XFER_T *isp_xflist[RQUEST_QUEUE_LEN];
 
 	/*
 	 * request/result queues and dma handles for them.
@@ -340,7 +344,7 @@ struct ispsoftc {
 #define	ISP_HA_FC_2100		0x10
 
 /*
- * Macros to read, write ISP registers through MD code
+ * Macros to read, write ISP registers through bus specific code.
  */
 
 #define	ISP_READ(isp, reg)	\
@@ -403,13 +407,14 @@ int isp_intr __P((void *));
 int32_t ispscsicmd __P((ISP_SCSI_XFER_T *));
 
 /*
- * Platform Dependent to Internal Control Point
+ * Platform Dependent to External to Internal Control Function
  *
  * For: 	Aborting a running command	- arg is an ISP_SCSI_XFER_T *
  *		Resetting a Device		- arg is target to reset
  *		Resetting a BUS			- arg is ignored
  *		Updating parameters		- arg is ignored
  *
+ * First argument is this instance's softc pointer.
  * Second argument is an index into xflist array.
  * Assumes all locks must be held already.
  */
@@ -421,6 +426,21 @@ typedef enum {
 } ispctl_t;
 int isp_control __P((struct ispsoftc *, ispctl_t, void *));
 
+
+/*
+ * Platform Dependent to Internal to External Control Function
+ * (each platform must provide such a function)
+ *
+ * For: 	Announcing Target Paramter Changes (arg is target)
+ *
+ * Assumes all locks are held.
+ */
+
+typedef enum {
+	ISPASYNC_NEW_TGT_PARAMS	
+} ispasync_t;
+int isp_async __P((struct ispsoftc *, ispasync_t, void *));
+
 /*
  * lost command routine (XXXX IN TRANSITION XXXX)
  */