patch-2.4.10 linux/drivers/message/fusion/mptbase.c

Next file: linux/drivers/message/fusion/mptbase.h
Previous file: linux/drivers/message/fusion/lsi/mpi_targ.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.9/linux/drivers/message/fusion/mptbase.c linux/drivers/message/fusion/mptbase.c
@@ -42,7 +42,7 @@
  *  Originally By: Steven J. Ralston
  *  (mailto:Steve.Ralston@lsil.com)
  *
- *  $Id: mptbase.c,v 1.47 2001/03/22 10:32:23 sralston Exp $
+ *  $Id: mptbase.c,v 1.53.4.1 2001/08/24 20:07:05 sralston Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -130,6 +130,8 @@
 const char **mpt_ScsiOpcodesPtr = NULL;
 int mpt_ASCQ_TableSz = 0;
 
+#define WHOINIT_UNKNOWN		0xAA
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Private data...
@@ -143,6 +145,8 @@
 static int	 		 MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
 					/* Event handler lookup table */
 static MPT_EVHANDLER		 MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
+					/* Reset handler lookup table */
+static MPT_RESETHANDLER		 MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
 
 static int	FusionInitCalled = 0;
 static int	mpt_base_index = -1;
@@ -154,25 +158,27 @@
 static void	mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
 static int	mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
 
+static int 	mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason);
 static int 	mpt_adapter_install(struct pci_dev *pdev);
 static void	mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev);
-static void	mpt_adapter_disable(MPT_ADAPTER *ioc);
+static void	mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup);
 static void	mpt_adapter_dispose(MPT_ADAPTER *ioc);
 
 static void	MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
+static int	MakeIocReady(MPT_ADAPTER *ioc, int force);
 static u32	GetIocState(MPT_ADAPTER *ioc, int cooked);
 static int	GetIocFacts(MPT_ADAPTER *ioc);
-static int	GetPortFacts(MPT_ADAPTER *ioc);
+static int	GetPortFacts(MPT_ADAPTER *ioc, int portnum);
 static int	SendIocInit(MPT_ADAPTER *ioc);
 static int	SendPortEnable(MPT_ADAPTER *ioc, int portnum);
-static int	mpt_fc9x9_reset(MPT_ADAPTER *ioc);
-static int	KickStart(MPT_ADAPTER *ioc);
+static int	mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore);
+static int	KickStart(MPT_ADAPTER *ioc, int ignore);
 static int	SendIocReset(MPT_ADAPTER *ioc, u8 reset_type);
 static int	PrimeIocFifos(MPT_ADAPTER *ioc);
-static int	HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply);
-static int	WaitForDoorbellAck(MPT_ADAPTER *ioc);
-static int	WaitForDoorbellInt(MPT_ADAPTER *ioc);
-static int	WaitForDoorbellReply(MPT_ADAPTER *ioc);
+static int	HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait);
+static int	WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong);
+static int	WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong);
+static int	WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong);
 static int	GetLanConfigPages(MPT_ADAPTER *ioc);
 static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
 static int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
@@ -192,6 +198,7 @@
 static struct proc_dir_entry	*procmpt_root_dir = NULL;
 
 int		fusion_init(void);
+static void	fusion_exit(void);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* 20000207 -sralston
@@ -586,6 +593,45 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
+ *	mpt_reset_register - Register protocol-specific IOC reset handler.
+ *	@cb_idx: previously registered (via mpt_register) callback handle
+ *	@reset_func: reset function
+ *
+ *	This routine can be called by one or more protocol-specific drivers
+ *	if/when they choose to be notified of IOC resets.
+ *
+ *	Returns 0 for success.
+ */
+int
+mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
+{
+	if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+		return -1;
+
+	MptResetHandlers[cb_idx] = reset_func;
+	return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
+ *	@cb_idx: previously registered callback handle
+ *
+ *	Each protocol-specific driver should call this routine
+ *	when it does not (or can no longer) handle IOC reset handling,
+ *	or when it's module is unloaded.
+ */
+void
+mpt_reset_deregister(int cb_idx)
+{
+	if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+		return;
+
+	MptResetHandlers[cb_idx] = NULL;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
  *	mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
  *	allocated per MPT adapter.
  *	@handle: Handle of registered MPT protocol driver
@@ -723,13 +769,29 @@
 
 	iocp = mpt_adapters[iocid];
 	if (iocp != NULL) {
-		u8 *req_as_bytes;
-		int i;
+		u8		*req_as_bytes;
+		u32		 ioc_raw_state;
+		int		 i;
+
+		/* YIKES!  We already know something is amiss.
+		 * Do upfront check on IOC state.
+		 */
+		ioc_raw_state = GetIocState(iocp, 0);
+		if ((ioc_raw_state & MPI_DOORBELL_ACTIVE) ||
+		    ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL)) {
+			printk(KERN_WARNING MYNAM ": %s: Bad IOC state (%08x) WARNING!\n",
+					iocp->name, ioc_raw_state);
+			if ((r = mpt_do_ioc_recovery(iocp, MPT_HOSTEVENT_IOC_RECOVER)) != 0) {
+				printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
+						r, iocp->name);
+				return r;
+			}
+		}
 
 		/*
-		 *  Emulate what mpt_put_msg_frame() does /wrt to sanity
-		 *  setting cb_idx/req_idx.  But ONLY if this request
-		 *  is in proper (pre-alloc'd) request buffer range...
+		 * Emulate what mpt_put_msg_frame() does /wrt to sanity
+		 * setting cb_idx/req_idx.  But ONLY if this request
+		 * is in proper (pre-alloc'd) request buffer range...
 		 */
 		i = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req);
 		if (reqBytes >= 12 && i >= 0 && i < iocp->req_depth) {
@@ -738,17 +800,15 @@
 			mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
 		}
 
-		/*  Make sure there are no doorbells  */
+		/* Make sure there are no doorbells */
 		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
 
 		CHIPREG_WRITE32(&iocp->chip->Doorbell,
 				((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
 				 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
 
-		/*  Wait for IOC doorbell int  */
-		if ((i = WaitForDoorbellInt(iocp)) < 0) {
-			/* FIXME! Recovery action(s)? */
-			/*i = unresponsive_ioc(i);*/
+		/* Wait for IOC doorbell int */
+		if ((i = WaitForDoorbellInt(iocp, 2)) < 0) {
 			return i;
 		}
 
@@ -757,10 +817,11 @@
 
 		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
 
-		if ((r = WaitForDoorbellAck(iocp)) < 0)
+		if ((r = WaitForDoorbellAck(iocp, 1)) < 0) {
 			return -2;
+		}
 
-		/*  Send request via doorbell handshake  */
+		/* Send request via doorbell handshake */
 		req_as_bytes = (u8 *) req;
 		for (i = 0; i < reqBytes/4; i++) {
 			u32 word;
@@ -770,15 +831,19 @@
 				(req_as_bytes[(i*4) + 2] << 16) |
 				(req_as_bytes[(i*4) + 3] << 24));
 			CHIPREG_WRITE32(&iocp->chip->Doorbell, word);
-			if ((r = WaitForDoorbellAck(iocp)) < 0) {
+			if ((r = WaitForDoorbellAck(iocp, 1)) < 0) {
 				r = -3;
 				break;
 			}
 		}
 
-		/*  Make sure there are no doorbells  */
-		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
+		if ((r = WaitForDoorbellInt(iocp, 2)) >= 0)
+			r = 0;
+		else
+			r = -4;
 
+		/* Make sure there are no doorbells */
+		CHIPREG_WRITE32(&iocp->chip->IntStatus, 0);
 	}
 
 	return r;
@@ -849,9 +914,8 @@
 
 		if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) &&
 		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) &&
-#if 0
-		    /* FIXME! FC919 */
 		    (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) &&
+#if 0
 		    /* FIXME! C103x family */
 		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) &&
 		    (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) &&
@@ -897,8 +961,10 @@
 	printk(KERN_INFO MYNAM ": %d MPT adapter%s found, %d installed.\n",
 		 found, (found==1) ? "" : "s", count);
 
-	if (count == 0)
+	if (!found || !count) {
+		fusion_exit();
 		return -ENODEV;
+	}
 
 #ifdef CONFIG_PROC_FS
 	if (procmpt_create() != 0)
@@ -962,12 +1028,9 @@
 	unsigned long	 port;
 	u32		 msize;
 	u32		 psize;
-	u32		 ioc_state;
 	int		 i;
 	int		 r = -ENODEV;
-	int 		 cntdn;
 	int		 len;
-	int		 statefault = 0;
 
 	ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_KERNEL);
 	if (ioc == NULL) {
@@ -980,7 +1043,7 @@
 
 	ioc->pcidev = pdev;
 
-	/*  Find lookup slot.  GRRRR...  */
+	/* Find lookup slot. */
 	for (i=0; i < MPT_MAX_ADAPTERS; i++) {
 		if (mpt_adapters[i] == NULL) {
 			ioc->id = i;		/* Assign adapter unique id (lookup) */
@@ -997,11 +1060,11 @@
 	port = psize = 0;
 	for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
 		if (pdev->PCI_BASEADDR_FLAGS(i) & PCI_BASE_ADDRESS_SPACE_IO) {
-			/*  Get I/O space!  */
+			/* Get I/O space! */
 			port = pdev->PCI_BASEADDR_START(i);
 			psize = PCI_BASEADDR_SIZE(pdev,i);
 		} else {
-			/*  Get memmap  */
+			/* Get memmap */
 			mem_phys = pdev->PCI_BASEADDR_START(i);
 			msize = PCI_BASEADDR_SIZE(pdev,i);
 			break;
@@ -1021,7 +1084,7 @@
 
 	mem = NULL;
 	if (! PortIo) {
-		/*  Get logical ptr for PciMem0 space  */
+		/* Get logical ptr for PciMem0 space */
 		/*mem = ioremap(mem_phys, msize);*/
 		mem = ioremap(mem_phys, 0x100);
 		if (mem == NULL) {
@@ -1051,11 +1114,11 @@
 		ioc->chip_type = FC929;
 		ioc->prod_name = "LSIFC929";
 	}
-#if 0
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
-		ioc->chip_type = C1030;
+		ioc->chip_type = FC919;
 		ioc->prod_name = "LSIFC919";
 	}
+#if 0
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) {
 		ioc->chip_type = C1030;
 		ioc->prod_name = "LSI53C1030";
@@ -1070,10 +1133,10 @@
 	Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR);
 	spin_lock_init(&ioc->FreeQlock);
 
-	/*  Disable all!  */
+	/* Disable all! */
 	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
-	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 	ioc->active = 0;
+	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
 	ioc->pci_irq = -1;
 	if (pdev->irq) {
@@ -1094,7 +1157,7 @@
 		dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq));
 	}
 
-	/*  tack onto tail of our MPT adapter list  */
+	/* tack onto tail of our MPT adapter list */
 	Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER);
 
 	/* Set lookup ptr. */
@@ -1106,115 +1169,168 @@
 	if (ioc->chip_type == FC929)
 		mpt_detect_929_bound_ports(ioc, pdev);
 
-	/*  Get current [raw] IOC state  */
-	ioc_state = GetIocState(ioc, 0);
-	dhsprintk((KERN_INFO MYNAM ": %s initial [raw] state=%08x\n", ioc->name, ioc_state));
+	if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) {
+		printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n",
+				ioc->name, r);
+	}
 
-	/*
-	 *  Check to see if IOC got left/stuck in doorbell handshake
-	 *  grip of death.  If so, hard reset the IOC.
-	 */
-	if (ioc_state & MPI_DOORBELL_ACTIVE) {
-		statefault = 1;
-		printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n",
+	return r;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mpt_do_ioc_recovery - Initialize or recover MPT adapter.
+ *	@ioc: Pointer to MPT adapter structure
+ *	@reason: Event word / reason
+ *
+ *	This routine performs all the steps necessary to bring the IOC
+ *	to a OPERATIONAL state.
+ *
+ *	This routine also pre-fetches the LAN MAC address of a Fibre Channel
+ *	MPT adapter.
+ *
+ *	Returns 0 for success.
+ */
+static int
+mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason)
+{
+	int	 hard_reset_done = 0;
+	int	 alt_ioc_ready = 0;
+	int	 hard;
+	int	 r;
+	int	 i;
+	int	 handlers;
+
+	printk(KERN_INFO MYNAM ": Initiating %s %s\n",
+			ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
+
+	/* Disable reply interrupts */
+	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+	ioc->active = 0;
+	/* NOTE: Access to IOC's request FreeQ is now blocked! */
+
+// FIXME? Cleanup all IOC requests here! (or below?)
+// But watch out for event associated request?
+
+	hard = HardReset;
+	if (ioc->alt_ioc && (reason == MPT_HOSTEVENT_IOC_BRINGUP))
+		hard = 0;
+
+	if ((hard_reset_done = MakeIocReady(ioc, hard)) < 0) {
+		printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
 				ioc->name);
+		return -1;
 	}
 
-	/*
-	 *  Check to see if IOC is in FAULT state.
-	 *  If so, hard reset the IOC.
-	 */
-	if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
-		statefault = 2;
-		printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n",
-				ioc->name);
-		printk(KERN_WARNING "           FAULT code = %04xh\n",
-				ioc_state & MPI_DOORBELL_DATA_MASK);
+// NEW!
+#if 0						// Kiss-of-death!?!
+	if (ioc->alt_ioc) {
+// Grrr... Hold off any alt-IOC interrupts (and events) while
+// handshaking to <this> IOC, needed because?
+		/* Disable alt-IOC's reply interrupts for a bit ... */
+		alt_ioc_intmask = CHIPREG_READ32(&ioc->alt_ioc->chip->IntMask);
+		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
+		ioc->alt_ioc->active = 0;
+		/* NOTE: Access to alt-IOC's request FreeQ is now blocked! */
 	}
+#endif
 
-	if (HardReset || statefault) {
-		if ((r = KickStart(ioc)) != 0) {
-			r = -ENODEV;
-			goto ioc_up_fail;
-		}
+	if (hard_reset_done && ioc->alt_ioc) {
+		if ((r = MakeIocReady(ioc->alt_ioc, 0)) == 0)
+			alt_ioc_ready = 1;
+		else
+			printk(KERN_WARNING MYNAM ": alt-%s: (%d) Not ready WARNING!\n",
+					ioc->alt_ioc->name, r);
+	}
+
+	if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
+		/* Get IOC facts! */
+		if ((r = GetIocFacts(ioc)) != 0)
+			return -2;
+		MptDisplayIocCapabilities(ioc);
 	}
 
 	/*
-	 *  Loop here waiting for IOC to come READY.
-	 */
-	i = 0;
-	cntdn = HZ * 10;
-	while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
-		if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
-			/*
-			 *  BIOS or previous driver load left IOC in OP state.
-			 *  Reset messaging FIFOs.
-			 */
-			dprintk((KERN_WARNING MYNAM ": %s: Sending IOC msg unit reset!\n", ioc->name));
-			if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) {
-				printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name);
-				r = -ENODEV;
-				goto ioc_up_fail;
-			}
-		} else if (ioc_state == MPI_IOC_STATE_RESET) {
-			/*
-			 *  Something is wrong.  Try to get IOC back
-			 *  to a known state.
-			 */
-			dprintk((KERN_WARNING MYNAM ": %s: Sending IO unit reset!\n", ioc->name));
-			if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) {
-				printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name);
-				r = -ENODEV;
-				goto ioc_up_fail;
+	 * Call each currently registered protocol IOC reset handler
+	 * with pre-reset indication.
+	 * NOTE: If we're doing _IOC_BRINGUP, there can be no
+	 * MptResetHandlers[] registered yet.
+	 */
+	if (hard_reset_done) {
+		r = handlers = 0;
+		for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
+			if (MptResetHandlers[i]) {
+				dprintk((KERN_INFO MYNAM ": %s: Calling IOC pre_reset handler #%d\n",
+						ioc->name, i));
+				r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_PRE_RESET);
+				handlers++;
+
+				if (alt_ioc_ready) {
+					dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC pre_reset handler #%d\n",
+							ioc->alt_ioc->name, i));
+					r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_PRE_RESET);
+					handlers++;
+				}
 			}
 		}
+		/* FIXME?  Examine results here? */
+	}
 
-		i++; cntdn--;
-		if (!cntdn) {
-			printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
-					ioc->name, (i+5)/HZ);
-			r = -ETIME;
-			goto ioc_up_fail;
-		}
+	// May need to check/upload firmware & data here!
 
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+	if ((r = SendIocInit(ioc)) != 0)
+		return -3;
+// NEW!
+	if (alt_ioc_ready) {
+		if ((r = SendIocInit(ioc->alt_ioc)) != 0) {
+			alt_ioc_ready = 0;
+			printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n",
+					ioc->alt_ioc->name, r);
+		}
 	}
 
-	if (statefault) {
-		printk(KERN_WARNING MYNAM ": %s: Whew!  Recovered from %s\n",
-				ioc->name, statefault==1 ? "stuck handshake" : "IOC FAULT");
+	/*
+	 * Call each currently registered protocol IOC reset handler
+	 * with post-reset indication.
+	 * NOTE: If we're doing _IOC_BRINGUP, there can be no
+	 * MptResetHandlers[] registered yet.
+	 */
+	if (hard_reset_done) {
+		r = handlers = 0;
+		for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
+			if (MptResetHandlers[i]) {
+				dprintk((KERN_INFO MYNAM ": %s: Calling IOC post_reset handler #%d\n",
+						ioc->name, i));
+				r += (*(MptResetHandlers[i]))(ioc, MPT_IOC_POST_RESET);
+				handlers++;
+
+				if (alt_ioc_ready) {
+					dprintk((KERN_INFO MYNAM ": %s: Calling alt-IOC post_reset handler #%d\n",
+							ioc->alt_ioc->name, i));
+					r += (*(MptResetHandlers[i]))(ioc->alt_ioc, MPT_IOC_POST_RESET);
+					handlers++;
+				}
+			}
+		}
+		/* FIXME?  Examine results here? */
 	}
 
-	/*  Enable! (reply interrupt)  */
-	CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
-	ioc->active = 1;
-
-	/*  Get IOC facts! (first time, ioc->facts0 and ioc->pfacts0)  */
-	if ((r = GetIocFacts(ioc)) != 0)
-		goto ioc_up_fail;
-
-	/* Does IocFacts.EventState need any looking at / attention here? */
-
-	if ((r = SendIocInit(ioc)) != 0)
-		goto ioc_up_fail;
-
 	/*
-	 *  Prime reply & request queues!
-	 *  (mucho alloc's)
+	 * Prime reply & request queues!
+	 * (mucho alloc's)
 	 */
 	if ((r = PrimeIocFifos(ioc)) != 0)
-		goto ioc_up_fail;
-
-	/*  Get IOC facts again! (2nd time, ioc->factsN and ioc->pfactsN)  */
-	if ((r = GetIocFacts(ioc)) != 0)
-		goto ioc_up_fail;
-
-	/* Does IocFacts.EventState need any looking at / attention here? */
+		return -4;
+// NEW!
+	if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
+		printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
+				ioc->alt_ioc->name, r);
+	}
 
-	MptDisplayIocCapabilities(ioc);
+// FIXME! Cleanup all IOC (and alt-IOC?) requests here!
 
-	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+	if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
+	    (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
 		/*
 		 *  Pre-fetch the ports LAN MAC address!
 		 *  (LANPage1_t stuff)
@@ -1229,19 +1345,34 @@
 #endif
 	}
 
+	/* Enable! (reply interrupt) */
+	CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+	ioc->active = 1;
+
+// NEW!
+#if 0						// Kiss-of-death!?!
+	if (alt_ioc_ready && (r==0)) {
+		/* (re)Enable alt-IOC! (reply interrupt) */
+		dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
+				ioc->alt_ioc->name));
+		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+		ioc->alt_ioc->active = 1;
+	}
+#endif
+
 	/* NEW!  20010120 -sralston
 	 *  Enable MPT base driver management of EventNotification
 	 *  and EventAck handling.
 	 */
-	(void) SendEventNotification(ioc, 1);	/* 1=Enable EventNotification */
+	if (!ioc->facts.EventState)
+		(void) SendEventNotification(ioc, 1);	/* 1=Enable EventNotification */
+// NEW!
+// FIXME!?!
+//	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) {
+//		(void) SendEventNotification(ioc->alt_ioc, 1);	/* 1=Enable EventNotification */
+//	}
 
 	return 0;
-
-ioc_up_fail:
-	//Q_DEL_ITEM(ioc);
-	//mpt_adapter_dispose(ioc);
-	mpt_adapter_disable(ioc);
-	return r;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1297,20 +1428,25 @@
 /*
  *	mpt_adapter_disable - Disable misbehaving MPT adapter.
  *	@this: Pointer to MPT adapter structure
+ *	@free: Free up alloc'd reply, request, etc.
  */
 static void
-mpt_adapter_disable(MPT_ADAPTER *this)
+mpt_adapter_disable(MPT_ADAPTER *this, int freeup)
 {
 	if (this != NULL) {
 		int sz;
 
+		/* Disable the FW */
+		if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET) != 0)
+			(void) KickStart(this, 1);
+
 		/* Disable adapter interrupts! */
 		CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+		this->active = 0;
 		/* Clear any lingering interrupt */
 		CHIPREG_WRITE32(&this->chip->IntStatus, 0);
-		this->active = 0;
 
-		if (this->reply_alloc != NULL) {
+		if (freeup && this->reply_alloc != NULL) {
 			sz = (this->reply_sz * this->reply_depth) + 128;
 			pci_free_consistent(this->pcidev, sz,
 					this->reply_alloc, this->reply_alloc_dma);
@@ -1319,7 +1455,7 @@
 			this->alloc_total -= sz;
 		}
 
-		if (this->req_alloc != NULL) {
+		if (freeup && this->req_alloc != NULL) {
 			sz = (this->req_sz * this->req_depth) + 128;
 			/*
 			 *  Rounding UP to nearest 4-kB boundary here...
@@ -1332,7 +1468,7 @@
 			this->alloc_total -= sz;
 		}
 
-		if (this->sense_buf_pool != NULL) {
+		if (freeup && this->sense_buf_pool != NULL) {
 			sz = (this->req_depth * 256);
 			pci_free_consistent(this->pcidev, sz,
 					this->sense_buf_pool, this->sense_buf_pool_dma);
@@ -1359,7 +1495,7 @@
 
 		sz_first = this->alloc_total;
 
-		mpt_adapter_disable(this);
+		mpt_adapter_disable(this, 1);
 
 		if (this->pci_irq != -1) {
 			free_irq(this->pci_irq, this);
@@ -1401,17 +1537,17 @@
 		printk("%s: ", ioc->prod_name+3);
 	printk("Capabilities={");
 
-	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
+	if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
 		printk("Initiator");
 		i++;
 	}
 
-	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+	if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
 		printk("%sTarget", i ? "," : "");
 		i++;
 	}
 
-	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+	if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
 		printk("%sLAN", i ? "," : "");
 		i++;
 	}
@@ -1420,7 +1556,7 @@
 	/*
 	 *  This would probably evoke more questions than it's worth
 	 */
-	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
+	if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
 		printk("%sLogBusAddr", i ? "," : "");
 		i++;
 	}
@@ -1431,6 +1567,113 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
+ *	MakeIocReady - Get IOC to a READY state, using KickStart if needed.
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@kick: Force hard KickStart of IOC
+ *
+ *	Returns 0 for already-READY, 1 for hard reset success,
+ *	else negative for failure.
+ */
+static int
+MakeIocReady(MPT_ADAPTER *ioc, int force)
+{
+	u32	 ioc_state;
+	int	 statefault = 0;
+	int 	 cntdn;
+	int	 hard_reset_done = 0;
+	int	 r;
+	int	 i;
+
+	/* Get current [raw] IOC state  */
+	ioc_state = GetIocState(ioc, 0);
+	dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
+
+	/*
+	 *	Check to see if IOC got left/stuck in doorbell handshake
+	 *	grip of death.  If so, hard reset the IOC.
+	 */
+	if (ioc_state & MPI_DOORBELL_ACTIVE) {
+		statefault = 1;
+		printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n",
+				ioc->name);
+	}
+
+	/* Is it already READY? */
+	if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
+		return 0;
+
+	/*
+	 *	Check to see if IOC is in FAULT state.
+	 */
+	if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+		statefault = 2;
+		printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n",
+				ioc->name);
+		printk(KERN_WARNING "           FAULT code = %04xh\n",
+				ioc_state & MPI_DOORBELL_DATA_MASK);
+	}
+
+	/*
+	 *	Hmmm...  Did it get left operational?
+	 */
+	if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
+		statefault = 3;
+		dprintk((KERN_WARNING MYNAM ": %s: Hmmm... IOC operational unexpected\n",
+				ioc->name));
+	}
+
+	hard_reset_done = KickStart(ioc, statefault||force);
+	if (hard_reset_done < 0)
+		return -1;
+
+	/*
+	 *  Loop here waiting for IOC to come READY.
+	 */
+	i = 0;
+	cntdn = HZ * 15;
+	while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
+		if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
+			/*
+			 *  BIOS or previous driver load left IOC in OP state.
+			 *  Reset messaging FIFOs.
+			 */
+			if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) {
+				printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name);
+				return -2;
+			}
+		} else if (ioc_state == MPI_IOC_STATE_RESET) {
+			/*
+			 *  Something is wrong.  Try to get IOC back
+			 *  to a known state.
+			 */
+			if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) {
+				printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name);
+				return -3;
+			}
+		}
+
+		i++; cntdn--;
+		if (!cntdn) {
+			printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
+					ioc->name, (i+5)/HZ);
+			return -ETIME;
+		}
+
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+
+	if (statefault < 3) {
+		printk(KERN_WARNING MYNAM ": %s: Whew!  Recovered from %s\n",
+				ioc->name,
+				statefault==1 ? "stuck handshake" : "IOC FAULT");
+	}
+
+	return hard_reset_done;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
  *	GetIocState - Get the current state of a MPT adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@cooked: Request raw or cooked IOC state
@@ -1471,7 +1714,7 @@
 	int			 reply_sz;
 	u32			 status;
 
-	/*  IOC *must* NOT be in RESET state!  */
+	/* IOC *must* NOT be in RESET state! */
 	if (ioc->last_state == MPI_IOC_STATE_RESET) {
 		printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
 				ioc->name,
@@ -1479,44 +1722,45 @@
 		return -44;
 	}
 
-	facts = &ioc->facts0;
-	/*  Nth (2,3,...) time thru? (been here, done that?)  */
-	if (ioc->facts0.Function == MPI_FUNCTION_IOC_FACTS) {
-		facts = &ioc->factsN;
-	}
+	facts = &ioc->facts;
 
-	/*  Destination (reply area)...  */
+	/* Destination (reply area)... */
 	reply_sz = sizeof(*facts);
 	memset(facts, 0, reply_sz);
 
-	/*  Request area (get_facts on the stack right now!)  */
+	/* Request area (get_facts on the stack right now!) */
 	req_sz = sizeof(get_facts);
 	memset(&get_facts, 0, req_sz);
 
 	get_facts.Function = MPI_FUNCTION_IOC_FACTS;
-	/*  Assert: All other get_facts fields are zero!  */
+	/* Assert: All other get_facts fields are zero! */
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending IocFacts%s request\n",
-			ioc->name, facts == &ioc->facts0 ? "0" : "N" ));
+	dprintk((KERN_INFO MYNAM ": %s: Sending get IocFacts request\n", ioc->name));
 
 	/* No non-zero fields in the get_facts request are greater than
 	 * 1 byte in size, so we can just fire it off as is.
 	 */
 	r = HandShakeReqAndReply(ioc,
 			req_sz, (u32*)&get_facts,
-			reply_sz, (u16*)facts);
+			reply_sz, (u16*)facts, 3);
 	if (r != 0)
 		return r;
 
 	/*
-	 *  Now byte swap the necessary fields before any further
-	 *  inspection of reply contents.
+	 * Now byte swap (GRRR) the necessary fields before any further
+	 * inspection of reply contents.
 	 *
-	 *  But need to do some sanity checks on MsgLength (byte) field
-	 *  to make sure we don't zero IOC's req_sz!
+	 * But need to do some sanity checks on MsgLength (byte) field
+	 * to make sure we don't zero IOC's req_sz!
 	 */
 	/* Did we get a valid reply? */
 	if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
+		/*
+		 * If not been here, done that, save off first WhoInit value
+		 */
+		if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
+			ioc->FirstWhoInit = facts->WhoInit;
+
 		facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
 		facts->MsgContext = le32_to_cpu(facts->MsgContext);
 		facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
@@ -1537,9 +1781,9 @@
 				le16_to_cpu(facts->CurReplyFrameSize);
 
 		/*
-		 *  Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
-		 *  Older MPI-1.00.xx struct had 13 dwords, and enlarged
-		 *  to 14 in MPI-1.01.0x.
+		 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
+		 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
+		 * to 14 in MPI-1.01.0x.
 		 */
 		if (facts->MsgLength >= sizeof(IOCFactsReply_t)/sizeof(u32) && facts->MsgVersion > 0x0100) {
 			facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
@@ -1548,7 +1792,7 @@
 
 		if (facts->RequestFrameSize) {
 			/*
-			 *  Set values for this IOC's REQUEST queue size & depth...
+			 * Set values for this IOC's REQUEST queue size & depth...
 			 */
 			ioc->req_sz = MIN(MPT_REQ_SIZE, facts->RequestFrameSize * 4);
 
@@ -1582,8 +1826,8 @@
 		dprintk((KERN_INFO MYNAM ": %s: req_sz  =%3d, req_depth  =%4d\n",
 				ioc->name, ioc->req_sz, ioc->req_depth));
 
-		/*  Get port facts!  */
-		if ( (r = GetPortFacts(ioc)) != 0 )
+		/* Get port facts! */
+		if ( (r = GetPortFacts(ioc, 0)) != 0 )
 			return r;
 	} else {
 		printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n",
@@ -1598,11 +1842,12 @@
 /*
  *	GetPortFacts - Send PortFacts request to MPT adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@portnum: Port number
  *
  *	Returns 0 for success, non-zero for failure.
  */
 static int
-GetPortFacts(MPT_ADAPTER *ioc)
+GetPortFacts(MPT_ADAPTER *ioc, int portnum)
 {
 	PortFacts_t		 get_pfacts;
 	PortFactsReply_t	*pfacts;
@@ -1610,7 +1855,7 @@
 	int			 req_sz;
 	int			 reply_sz;
 
-	/*  IOC *must* NOT be in RESET state!  */
+	/* IOC *must* NOT be in RESET state! */
 	if (ioc->last_state == MPI_IOC_STATE_RESET) {
 		printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
 				ioc->name,
@@ -1618,31 +1863,28 @@
 		return -4;
 	}
 
-	pfacts = &ioc->pfacts0;
-	/*  Nth (2,3,...) time thru? (been here, done that?)  */
-	if (ioc->pfacts0.Function == MPI_FUNCTION_PORT_FACTS) {
-		pfacts = &ioc->pfactsN;
-	}
+	pfacts = &ioc->pfacts[portnum];
 
-	/*  Destination (reply area)...  */
+	/* Destination (reply area)...  */
 	reply_sz = sizeof(*pfacts);
 	memset(pfacts, 0, reply_sz);
 
-	/*  Request area (get_pfacts on the stack right now!)  */
+	/* Request area (get_pfacts on the stack right now!) */
 	req_sz = sizeof(get_pfacts);
 	memset(&get_pfacts, 0, req_sz);
 
 	get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
-	/*  Assert: All other get_pfacts fields are zero!  */
+	get_pfacts.PortNumber = portnum;
+	/* Assert: All other get_pfacts fields are zero! */
 
-	dprintk((KERN_INFO MYNAM ": %s: Sending PortFacts%s request\n",
-			ioc->name, pfacts == &ioc->pfacts0 ? "0" : "N" ));
+	dprintk((KERN_INFO MYNAM ": %s: Sending get PortFacts(%d) request\n",
+			ioc->name, portnum));
 
 	/* No non-zero fields in the get_pfacts request are greater than
 	 * 1 byte in size, so we can just fire it off as is.
 	 */
 	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&get_pfacts,
-				reply_sz, (u16*)pfacts);
+				reply_sz, (u16*)pfacts, 3);
 	if (i != 0)
 		return i;
 
@@ -1702,7 +1944,7 @@
 	dprintk((KERN_INFO MYNAM ": %s: Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init));
 
 	r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
-			sizeof(MPIDefaultReply_t), (u16*)&init_reply);
+			sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10);
 	if (r != 0)
 		return r;
 
@@ -1775,7 +2017,7 @@
 			ioc->name, portnum, &port_enable));
 
 	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&port_enable,
-			reply_sz, (u16*)&reply_buf);
+			reply_sz, (u16*)&reply_buf, 65);
 	if (i != 0)
 		return i;
 
@@ -1790,24 +2032,28 @@
 /*
  *	KickStart - Perform hard reset of MPT adapter.
  *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@force: Force hard reset
  *
  *	This routine places MPT adapter in diagnostic mode via the
  *	WriteSequence register, and then performs a hard reset of adapter
  *	via the Diagnostic register.
  *
- *	Returns 0 for success, non-zero for failure.
+ *	Returns 0 for soft reset success, 1 for hard reset success,
+ *	else a negative value for failure.
  */
 static int
-KickStart(MPT_ADAPTER *ioc)
+KickStart(MPT_ADAPTER *ioc, int force)
 {
-	int r;
+	int hard_reset_done = 0;
 	u32 ioc_state;
 	int cnt = 0;
 
 	dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
 
-	if (ioc->chip_type == FC909) {
-		r = mpt_fc9x9_reset(ioc);
+	hard_reset_done = mpt_fc9x9_reset(ioc, force);
+#if 0
+	if (ioc->chip_type == FC909 || ioc->chip-type == FC919) {
+		hard_reset_done = mpt_fc9x9_reset(ioc, force);
 	} else if (ioc->chip_type == FC929) {
 		unsigned long delta;
 
@@ -1815,15 +2061,12 @@
 		dprintk((KERN_INFO MYNAM ": %s: 929 KickStart, last=%ld, delta = %ld\n",
 				ioc->name, ioc->last_kickstart, delta));
 		if ((ioc->sod_reset == 0) || (delta >= 10*HZ))
-			r = mpt_fc9x9_reset(ioc);
+			hard_reset_done = mpt_fc9x9_reset(ioc, ignore);
 		else {
 			dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n",
 					ioc->name, delta));
 			return 0;
 		}
-	/* TODO! Add FC919!
-	} else if (ioc->chip_type == FC919) {
-	 */
 	/* TODO! Add C1030!
 	} else if (ioc->chip_type == C1030) {
 	 */
@@ -1832,9 +2075,10 @@
 				ioc->name, ioc->chip_type);
 		return -5;
 	}
+#endif
 
-	if (r != 0)
-		return -r;
+	if (hard_reset_done < 0)
+		return hard_reset_done;
 
 	dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n",
 			ioc->name));
@@ -1843,7 +2087,7 @@
 		if ((ioc_state = GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) {
 			dprintk((KERN_INFO MYNAM ": %s: KickStart successful! (cnt=%d)\n",
 					ioc->name, cnt));
-			return 0;
+			return hard_reset_done;
 		}
 		/* udelay(10000) ? */
 		current->state = TASK_INTERRUPTIBLE;
@@ -1867,52 +2111,112 @@
  *	Returns 0 for success, non-zero for failure.
  */
 static int
-mpt_fc9x9_reset(MPT_ADAPTER *ioc)
+mpt_fc9x9_reset(MPT_ADAPTER *ioc, int ignore)
 {
-	u32 diagval;
+	u32 diag0val;
+	int hard_reset_done = 0;
 
 	/* Use "Diagnostic reset" method! (only thing available!) */
 
-	/*
-	 * Extra read to handle 909 B.0 chip problem with reset
-	 * logic not finishing the RAM access before hard reset hits.
-	 * (? comment taken from NT SYMMPI source)
-	 */
-	(void) CHIPREG_READ32(&ioc->chip->Fubar);
+	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+{
+	u32 diag1val = 0;
+	if (ioc->alt_ioc)
+		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+	dprintk((KERN_INFO MYNAM ": %s: DBG1: diag0=%08x, diag1=%08x\n",
+			ioc->name, diag0val, diag1val));
+}
+#endif
+	if (diag0val & MPI_DIAG_DRWE) {
+		dprintk((KERN_INFO MYNAM ": %s: DiagWriteEn bit already set\n",
+				ioc->name));
+	} else {
+		/* Write magic sequence to WriteSequence register */
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+		dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence [spot#1]\n",
+				ioc->name));
+	}
 
-	/*
-	 * Write magic sequence to WriteSequence register.
-	 * But, send 0x0F first to insure a reset to the beginning of the sequence.
-	 */
-	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_KEY_VALUE_MASK);
+	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+{
+	u32 diag1val = 0;
+	if (ioc->alt_ioc)
+		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+	dprintk((KERN_INFO MYNAM ": %s: DbG2: diag0=%08x, diag1=%08x\n",
+			ioc->name, diag0val, diag1val));
+}
+#endif
+	if (!ignore && (diag0val & MPI_DIAG_RESET_HISTORY)) {
+		dprintk((KERN_INFO MYNAM ": %s: Skipping due to ResetHistory bit set!\n",
+				ioc->name));
+	} else {
+		/*
+		 * Now hit the reset bit in the Diagnostic register
+		 * (THE BIG HAMMER!)
+		 */
+		CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER);
+		hard_reset_done = 1;
+		dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset performed\n",
+				ioc->name));
 
-	/* Now write magic sequence */
-	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
-	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
-	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
-	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
-	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
-	dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence\n",
-			ioc->name));
+		/* want udelay(100) */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
 
-	/* Now hit the reset bit in the Diagnostic register */
-	CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER);
+		/* Write magic sequence to WriteSequence register */
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
+		dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence [spot#2]\n",
+				ioc->name));
+	}
 
-	udelay(100);
+	/* Clear RESET_HISTORY bit! */
+	CHIPREG_WRITE32(&ioc->chip->Diagnostic, 0x0);
 
-	if ((diagval = CHIPREG_READ32(&ioc->chip->Diagnostic)) &
-				(MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_DISABLE_ARM)) {
-		printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED!\n",
+	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+{
+	u32 diag1val = 0;
+	if (ioc->alt_ioc)
+		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+	dprintk((KERN_INFO MYNAM ": %s: DbG3: diag0=%08x, diag1=%08x\n",
+			ioc->name, diag0val, diag1val));
+}
+#endif
+	if (diag0val & MPI_DIAG_RESET_HISTORY) {
+		printk(KERN_WARNING MYNAM ": %s: WARNING - ResetHistory bit failed to clear!\n",
 				ioc->name);
-		return -9;
 	}
 
-	/* TODO!
-	 * Cleanup all event stuff for this IOC;
-	 * re-issue EventNotification request if needed.
+	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+#ifdef MPT_DEBUG
+{
+	u32 diag1val = 0;
+	if (ioc->alt_ioc)
+		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+	dprintk((KERN_INFO MYNAM ": %s: DbG4: diag0=%08x, diag1=%08x\n",
+			ioc->name, diag0val, diag1val));
+}
+#endif
+	if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
+		printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED! (%02xh)\n",
+				ioc->name, diag0val);
+		return -3;
+	}
+
+	/*
+	 * Reset flag that says we've enabled event notification
 	 */
-	if (ioc->factsN.Function)
-		ioc->factsN.EventState = 0;
+	ioc->facts.EventState = 0;
 
 	/* NEW!  20010220 -sralston
 	 * Try to avoid redundant resets of the 929.
@@ -1924,7 +2228,7 @@
 		ioc->alt_ioc->last_kickstart = ioc->last_kickstart;
 	}
 
-	return 0;
+	return hard_reset_done;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1943,18 +2247,18 @@
 {
 	int r;
 
-	printk(KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
-			ioc->name, reset_type);
+	dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
+			ioc->name, reset_type));
 	CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
-	if ((r = WaitForDoorbellAck(ioc)) < 0)
+	if ((r = WaitForDoorbellAck(ioc, 2)) < 0)
 		return r;
 
 	/* TODO!
 	 *  Cleanup all event stuff for this IOC; re-issue EventNotification
 	 *  request if needed.
 	 */
-	if (ioc->factsN.Function)
-		ioc->factsN.EventState = 0;
+	if (ioc->facts.Function)
+		ioc->facts.EventState = 0;
 
 	return 0;
 }
@@ -2125,6 +2429,7 @@
  *	@req: Pointer to MPT request frame
  *	@replyBytes: Expected size of the reply in bytes
  *	@u16reply: Pointer to area where reply should be written
+ *	@maxwait: Max wait time for a reply (in seconds)
  *
  *	NOTES: It is the callers responsibility to byte-swap fields in the
  *	request which are greater than 1 byte in size.  It is also the
@@ -2134,7 +2439,7 @@
  *	Returns 0 for success, non-zero for failure.
  */
 static int
-HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply)
+HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait)
 {
 	MPIDefaultReply_t *mptReply;
 	int failcnt = 0;
@@ -2160,7 +2465,7 @@
 	/*
 	 * Wait for IOC's doorbell handshake int
 	 */
-	if ((t = WaitForDoorbellInt(ioc)) < 0)
+	if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
 		failcnt++;
 
 	dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n",
@@ -2172,7 +2477,7 @@
 	 * our handshake request.
 	 */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-	if (!failcnt && (t = WaitForDoorbellAck(ioc)) < 0)
+	if (!failcnt && (t = WaitForDoorbellAck(ioc, 2)) < 0)
 		failcnt++;
 
 	if (!failcnt) {
@@ -2190,7 +2495,7 @@
 				    (req_as_bytes[(i*4) + 3] << 24));
 
 			CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
-			if ((t = WaitForDoorbellAck(ioc)) < 0)
+			if ((t = WaitForDoorbellAck(ioc, 2)) < 0)
 				failcnt++;
 		}
 
@@ -2203,7 +2508,7 @@
 		/*
 		 * Wait for completion of doorbell handshake reply from the IOC
 		 */
-		if (!failcnt && (t = WaitForDoorbellReply(ioc)) < 0)
+		if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait)) < 0)
 			failcnt++;
 
 		/*
@@ -2223,16 +2528,17 @@
  *	WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit
  *	in it's IntStatus register.
  *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@howlong: How long to wait (in seconds)
  *
- *	This routine waits (up to ~30 seconds max) for IOC doorbell
+ *	This routine waits (up to ~2 seconds max) for IOC doorbell
  *	handshake ACKnowledge.
  *
  *	Returns a negative value on failure, else wait loop count.
  */
 static int
-WaitForDoorbellAck(MPT_ADAPTER *ioc)
+WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong)
 {
-	int cntdn = HZ * 30;			/* ~30 seconds */
+	int cntdn = HZ * howlong;
 	int count = 0;
 	u32 intstat;
 
@@ -2261,15 +2567,16 @@
  *	WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit
  *	in it's IntStatus register.
  *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@howlong: How long to wait (in seconds)
  *
- *	This routine waits (up to ~30 seconds max) for IOC doorbell interrupt.
+ *	This routine waits (up to ~2 seconds max) for IOC doorbell interrupt.
  *
  *	Returns a negative value on failure, else wait loop count.
  */
 static int
-WaitForDoorbellInt(MPT_ADAPTER *ioc)
+WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong)
 {
-	int cntdn = HZ * 30;			/* ~30 seconds */
+	int cntdn = HZ * howlong;
 	int count = 0;
 	u32 intstat;
 
@@ -2297,6 +2604,7 @@
 /*
  *	WaitForDoorbellReply - Wait for and capture a IOC handshake reply.
  *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@howlong: How long to wait (in seconds)
  *
  *	This routine polls the IOC for a handshake reply, 16 bits at a time.
  *	Reply is cached to IOC private area large enough to hold a maximum
@@ -2305,7 +2613,7 @@
  *	Returns a negative value on failure, else size of reply in WORDS.
  */
 static int
-WaitForDoorbellReply(MPT_ADAPTER *ioc)
+WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong)
 {
 	int u16cnt = 0;
 	int failcnt = 0;
@@ -2319,11 +2627,18 @@
 	/*
 	 * Get first two u16's so we can look at IOC's intended reply MsgLength
 	 */
-	for (u16cnt=0; !failcnt && u16cnt < 2; u16cnt++) {
-		if ((t = WaitForDoorbellInt(ioc)) < 0)
-			failcnt++;
-		hs_reply[u16cnt] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+	u16cnt=0;
+	if ((t = WaitForDoorbellInt(ioc, howlong)) < 0) {
+		failcnt++;
+	} else {
+		hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
 		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+		if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
+			failcnt++;
+		else {
+			hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
+			CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+		}
 	}
 
 	dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n",
@@ -2335,7 +2650,7 @@
 	 * reply 16 bits at a time.
 	 */
 	for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
-		if ((t = WaitForDoorbellInt(ioc)) < 0)
+		if ((t = WaitForDoorbellInt(ioc, 2)) < 0)
 			failcnt++;
 		hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
 		/* don't overflow our IOC hs_reply[] buffer! */
@@ -2344,7 +2659,7 @@
 		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 	}
 
-	if (!failcnt && (t = WaitForDoorbellInt(ioc)) < 0)
+	if (!failcnt && (t = WaitForDoorbellInt(ioc, 2)) < 0)
 		failcnt++;
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
@@ -2428,7 +2743,7 @@
 			ioc->name));
 
 	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
-				reply_sz, (u16*)&config_reply);
+				reply_sz, (u16*)&config_reply, 3);
 	pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE);
 	if (i != 0)
 		return i;
@@ -2472,7 +2787,7 @@
 			ioc->name));
 
 	i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req,
-				reply_sz, (u16*)&config_reply);
+				reply_sz, (u16*)&config_reply, 3);
 	pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE);
 	if (i != 0)
 		return i;
@@ -2564,7 +2879,6 @@
 	return len;			\
 }
 
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
@@ -2653,6 +2967,9 @@
 {
 	MPT_ADAPTER *ioc;
 
+	if (!procmpt_root_dir)
+		return 0;
+
 	/*
 	 * 	BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt"
 	 * 	(single level) to multi level (e.g. "driver/message/fusion")
@@ -2685,6 +3002,7 @@
 
 	if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) {
 		remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0);
+		procmpt_root_dir = NULL;
 		return 0;
 	}
 
@@ -2724,7 +3042,7 @@
 
 // Too verbose!
 //		mpt_print_ioc_facts(ioc, out, &more, 0);
-		mpt_print_ioc_summary(ioc, out, &more, 0);
+		mpt_print_ioc_summary(ioc, out, &more, 0, 1);
 
 		out += more;
 		if ((out-page) >= count) {
@@ -2784,15 +3102,15 @@
 static void
 mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
 {
-	if ((ioc->facts0.FWVersion & 0xF000) == 0xE000)
+	if ((ioc->facts.FWVersion & 0xF000) == 0xE000)
 		sprintf(buf, " (Exp %02d%02d)",
-			(ioc->facts0.FWVersion & 0x0F00) >> 8,	/* Month */
-			ioc->facts0.FWVersion & 0x001F);	/* Day */
+			(ioc->facts.FWVersion & 0x0F00) >> 8,	/* Month */
+			ioc->facts.FWVersion & 0x001F);		/* Day */
 	else
 		buf[0] ='\0';
 
 	/* insider hack! */
-	if (ioc->facts0.FWVersion & 0x0080) {
+	if (ioc->facts.FWVersion & 0x0080) {
 		strcat(buf, " [MDBG]");
 	}
 }
@@ -2804,17 +3122,17 @@
  *	@buffer: Pointer to buffer where IOC summary info should be written
  *	@size: Pointer to number of bytes we wrote (set by this routine)
  *	@len: Offset at which to start writing in buffer
+ *	@showlan: Display LAN stuff?
  *
  * 	This routine writes (english readable) ASCII text, which represents
  * 	a summary of IOC information, to a buffer.
  */
 void
-mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len)
+mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
 {
 	char expVer[32];
 	int y;
 
-
 	mpt_get_fw_exp_ver(expVer, ioc);
 
 	/*
@@ -2824,17 +3142,20 @@
 			ioc->name,
 			ioc->prod_name,
 			MPT_FW_REV_MAGIC_ID_STRING,	/* "FwRev=" or somesuch */
-			ioc->facts0.FWVersion,
+			ioc->facts.FWVersion,
 			expVer,
-			ioc->facts0.NumberOfPorts,
+			ioc->facts.NumberOfPorts,
 			ioc->req_depth);
 
-	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+	if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
 		u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
 		y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
 			a[5], a[4], a[3], a[2], a[1], a[0]);
 	}
 
+	if (ioc->pci_irq < 100)
+		y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
+
 	if (!ioc->active)
 		y += sprintf(buffer+len+y, " (disabled)");
 
@@ -2861,32 +3182,34 @@
 	char iocName[16];
 	int sz;
 	int y;
-
+	int p;
 
 	mpt_get_fw_exp_ver(expVer, ioc);
 
 	strcpy(iocName, ioc->name);
 	y = sprintf(buffer+len, "%s:\n", iocName);
 
-	y += sprintf(buffer+len+y, "  ProductID = 0x%04x\n", ioc->facts0.ProductID);
-	y += sprintf(buffer+len+y, "  PortNumber = %d (of %d)\n",
-		ioc->pfacts0.PortNumber+1,
-		ioc->facts0.NumberOfPorts);
-	if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
-		u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
-		y += sprintf(buffer+len+y, "  LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
-			a[5], a[4], a[3], a[2], a[1], a[0]);
+	y += sprintf(buffer+len+y, "  ProductID = 0x%04x\n", ioc->facts.ProductID);
+	for (p=0; p < ioc->facts.NumberOfPorts; p++) {
+		y += sprintf(buffer+len+y, "  PortNumber = %d (of %d)\n",
+			p+1,
+			ioc->facts.NumberOfPorts);
+		if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
+			u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+			y += sprintf(buffer+len+y, "  LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+				a[5], a[4], a[3], a[2], a[1], a[0]);
+		}
 	}
-	y += sprintf(buffer+len+y, "  FWVersion = 0x%04x%s\n", ioc->facts0.FWVersion, expVer);
-	y += sprintf(buffer+len+y, "  MsgVersion = 0x%04x\n", ioc->facts0.MsgVersion);
-	y += sprintf(buffer+len+y, "  WhoInit = 0x%02x\n", ioc->facts0.WhoInit);
-	y += sprintf(buffer+len+y, "  EventState = 0x%02x\n", ioc->facts0.EventState);
+	y += sprintf(buffer+len+y, "  FWVersion = 0x%04x%s\n", ioc->facts.FWVersion, expVer);
+	y += sprintf(buffer+len+y, "  MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
+	y += sprintf(buffer+len+y, "  FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
+	y += sprintf(buffer+len+y, "  EventState = 0x%02x\n", ioc->facts.EventState);
 	y += sprintf(buffer+len+y, "  CurrentHostMfaHighAddr = 0x%08x\n",
-		 	ioc->facts0.CurrentHostMfaHighAddr);
+		 	ioc->facts.CurrentHostMfaHighAddr);
 	y += sprintf(buffer+len+y, "  CurrentSenseBufferHighAddr = 0x%08x\n",
-			ioc->facts0.CurrentSenseBufferHighAddr);
-	y += sprintf(buffer+len+y, "  MaxChainDepth = 0x%02x frames\n", ioc->facts0.MaxChainDepth);
-	y += sprintf(buffer+len+y, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts0.BlockSize);
+			ioc->facts.CurrentSenseBufferHighAddr);
+	y += sprintf(buffer+len+y, "  MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
+	y += sprintf(buffer+len+y, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
 
 	y += sprintf(buffer+len+y, "  RequestFrames @ 0x%p (Dma @ 0x%08x)\n",
 					ioc->req_alloc, ioc->req_alloc_dma);
@@ -2898,8 +3221,8 @@
 	y += sprintf(buffer+len+y, "    {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
 					ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
 	y += sprintf(buffer+len+y, "    {MaxReqSz=%d}   {MaxReqDepth=%d}\n",
-					4*ioc->facts0.RequestFrameSize,
-					ioc->facts0.GlobalCredits);
+					4*ioc->facts.RequestFrameSize,
+					ioc->facts.GlobalCredits);
 
 	y += sprintf(buffer+len+y, "  ReplyFrames   @ 0x%p (Dma @ 0x%08x)\n",
 					ioc->reply_alloc, ioc->reply_alloc_dma);
@@ -2907,8 +3230,8 @@
 	y += sprintf(buffer+len+y, "    {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
 					ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
 	y += sprintf(buffer+len+y, "    {MaxRepSz=%d}   {MaxRepDepth=%d}\n",
-					ioc->factsN.CurReplyFrameSize,
-					ioc->facts0.ReplyQueueDepth);
+					ioc->facts.CurReplyFrameSize,
+					ioc->facts.ReplyQueueDepth);
 
 	*size = y;
 }
@@ -3045,8 +3368,8 @@
 			/* CHECKME! What if evState unexpectedly says OFF (0)? */
 
 			/* Update EventState field in cached IocFacts */
-			if (ioc->factsN.Function) {
-				ioc->factsN.EventState = evState;
+			if (ioc->facts.Function) {
+				ioc->facts.EventState = evState;
 			}
 		}
 		break;
@@ -3182,6 +3505,9 @@
 	case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED:
 		desc = "Not synchronized to signal or still negotiating (possible cable problem)";
 		break;
+	case MPI_IOCLOGINFO_FC_LINK_CRC_ERROR:
+		desc = "CRC check detected error on received frame";
+		break;
 	}
 
 	printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}",
@@ -3259,6 +3585,8 @@
 EXPORT_SYMBOL(mpt_deregister);
 EXPORT_SYMBOL(mpt_event_register);
 EXPORT_SYMBOL(mpt_event_deregister);
+EXPORT_SYMBOL(mpt_reset_register);
+EXPORT_SYMBOL(mpt_reset_deregister);
 EXPORT_SYMBOL(mpt_get_msg_frame);
 EXPORT_SYMBOL(mpt_put_msg_frame);
 EXPORT_SYMBOL(mpt_free_msg_frame);
@@ -3299,6 +3627,7 @@
 		MptCallbacks[i] = NULL;
 		MptDriverClass[i] = MPTUNKNOWN_DRIVER;
 		MptEvHandlers[i] = NULL;
+		MptResetHandlers[i] = NULL;
 	}
 
 	/* NEW!  20010120 -sralston
@@ -3323,22 +3652,8 @@
 static void fusion_exit(void)
 {
 	MPT_ADAPTER *this;
-	int i;
 
 	dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
-
-	/*
-	 *  Paranoia; disable interrupts on all MPT adapters.
-	 */
-	for (i=0; i<MPT_MAX_ADAPTERS; i++) {
-		if ((this = mpt_adapters[i]) != NULL) {
-			/* Disable adapter interrupts! */
-			CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
-			/* Clear any lingering interrupt */
-			CHIPREG_WRITE32(&this->chip->IntStatus, 0);
-			this->active = 0;
-		}
-	}
 
 	/* Whups?  20010120 -sralston
 	 *  Moved this *above* removal of all MptAdapters!

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)