[Midnightbsd-cvs] src [10094] trunk/sys/dev/mps: sync mps

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun May 27 19:35:40 EDT 2018


Revision: 10094
          http://svnweb.midnightbsd.org/src/?rev=10094
Author:   laffer1
Date:     2018-05-27 19:35:39 -0400 (Sun, 27 May 2018)
Log Message:
-----------
sync mps

Modified Paths:
--------------
    trunk/sys/dev/mps/mpi/mpi2.h
    trunk/sys/dev/mps/mpi/mpi2_cnfg.h
    trunk/sys/dev/mps/mpi/mpi2_hbd.h
    trunk/sys/dev/mps/mpi/mpi2_history.txt
    trunk/sys/dev/mps/mpi/mpi2_init.h
    trunk/sys/dev/mps/mpi/mpi2_ioc.h
    trunk/sys/dev/mps/mpi/mpi2_ra.h
    trunk/sys/dev/mps/mpi/mpi2_raid.h
    trunk/sys/dev/mps/mpi/mpi2_sas.h
    trunk/sys/dev/mps/mpi/mpi2_targ.h
    trunk/sys/dev/mps/mpi/mpi2_tool.h
    trunk/sys/dev/mps/mpi/mpi2_type.h
    trunk/sys/dev/mps/mps.c
    trunk/sys/dev/mps/mps_config.c
    trunk/sys/dev/mps/mps_ioctl.h
    trunk/sys/dev/mps/mps_mapping.c
    trunk/sys/dev/mps/mps_mapping.h
    trunk/sys/dev/mps/mps_pci.c
    trunk/sys/dev/mps/mps_sas.c
    trunk/sys/dev/mps/mps_sas.h
    trunk/sys/dev/mps/mps_sas_lsi.c
    trunk/sys/dev/mps/mps_table.c
    trunk/sys/dev/mps/mps_table.h
    trunk/sys/dev/mps/mps_user.c
    trunk/sys/dev/mps/mpsvar.h

Property Changed:
----------------
    trunk/sys/dev/mps/mpi/mpi2_history.txt

Modified: trunk/sys/dev/mps/mpi/mpi2.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2006-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2006-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2.h

Modified: trunk/sys/dev/mps/mpi/mpi2_cnfg.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_cnfg.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_cnfg.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2006-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_cnfg.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2006-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_cnfg.h

Modified: trunk/sys/dev/mps/mpi/mpi2_hbd.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_hbd.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_hbd.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2009-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_hbd.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2009-2012 LSI Corporation.
+ *  Copyright (c) 2009-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_hbd.h

Modified: trunk/sys/dev/mps/mpi/mpi2_history.txt
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_history.txt	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_history.txt	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,6 @@
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2000-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,9 +24,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_history.txt 281564 2015-04-15 21:47:15Z slm $
  */
 
  ==============================
@@ -32,7 +33,8 @@
  Fusion-MPT MPI 2.0 Header File Change History
  ==============================
 
- Copyright (c) 2000-2012 LSI Corporation.
+ Copyright (c) 2000-2015 LSI Corporation.
+ Copyright (c) 2013-2015 Avago Technologies
 
  ---------------------------------------
  Header Set Release Version:    02.00.18


Property changes on: trunk/sys/dev/mps/mpi/mpi2_history.txt
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/dev/mps/mpi/mpi2_init.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_init.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_init.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2006-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_init.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2006-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_init.h

Modified: trunk/sys/dev/mps/mpi/mpi2_ioc.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_ioc.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_ioc.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2006-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_ioc.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2006-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_ioc.h

Modified: trunk/sys/dev/mps/mpi/mpi2_ra.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_ra.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_ra.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2009-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_ra.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2012 LSI Corporation.
+ *  Copyright (c) 2009-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_ra.h

Modified: trunk/sys/dev/mps/mpi/mpi2_raid.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_raid.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_raid.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2007-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_raid.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2007-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_raid.h

Modified: trunk/sys/dev/mps/mpi/mpi2_sas.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_sas.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_sas.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2007-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_sas.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2007-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_sas.h

Modified: trunk/sys/dev/mps/mpi/mpi2_targ.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_targ.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_targ.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2006-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_targ.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2006-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_targ.h

Modified: trunk/sys/dev/mps/mpi/mpi2_tool.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_tool.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_tool.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2007-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_tool.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2007-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_tool.h

Modified: trunk/sys/dev/mps/mpi/mpi2_type.h
===================================================================
--- trunk/sys/dev/mps/mpi/mpi2_type.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpi/mpi2_type.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2006-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,14 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpi/mpi2_type.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2006-2015 LSI Corporation.
+ *  Copyright (c) 2013-2015 Avago Technologies
  *
  *
  *           Name:  mpi2_type.h

Modified: trunk/sys/dev/mps/mps.c
===================================================================
--- trunk/sys/dev/mps/mps.c	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps.c	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,6 +1,8 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009 Yahoo! Inc.
- * Copyright (c) 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -24,15 +26,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mps.c 322661 2017-08-18 15:38:08Z ken $
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/mps/mps.c 322661 2017-08-18 15:38:08Z ken $");
 
-/* Communications core for LSI MPT2 */
+/* Communications core for Avago Technologies (LSI) MPT2 */
 
 /* TODO Move headers to mpsvar */
 #include <sys/types.h>
@@ -51,6 +53,7 @@
 #include <sys/sysctl.h>
 #include <sys/queue.h>
 #include <sys/kthread.h>
+#include <sys/taskqueue.h>
 #include <sys/endian.h>
 #include <sys/eventhandler.h>
 
@@ -61,6 +64,7 @@
 
 #include <dev/pci/pcivar.h>
 
+#include <cam/cam.h>
 #include <cam/scsi/scsi_all.h>
 
 #include <dev/mps/mpi/mpi2_type.h>
@@ -78,10 +82,16 @@
 static int mps_init_queues(struct mps_softc *sc);
 static int mps_message_unit_reset(struct mps_softc *sc, int sleep_flag);
 static int mps_transition_operational(struct mps_softc *sc);
+static int mps_iocfacts_allocate(struct mps_softc *sc, uint8_t attaching);
+static void mps_iocfacts_free(struct mps_softc *sc);
 static void mps_startup(void *arg);
 static int mps_send_iocinit(struct mps_softc *sc);
+static int mps_alloc_queues(struct mps_softc *sc);
+static int mps_alloc_replies(struct mps_softc *sc);
+static int mps_alloc_requests(struct mps_softc *sc);
 static int mps_attach_log(struct mps_softc *sc);
-static __inline void mps_complete_command(struct mps_command *cm);
+static __inline void mps_complete_command(struct mps_softc *sc,
+    struct mps_command *cm);
 static void mps_dispatch_event(struct mps_softc *sc, uintptr_t data,
     MPI2_EVENT_NOTIFICATION_REPLY *reply);
 static void mps_config_complete(struct mps_softc *sc, struct mps_command *cm);
@@ -88,6 +98,7 @@
 static void mps_periodic(void *);
 static int mps_reregister_events(struct mps_softc *sc);
 static void mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm);
+static int mps_get_iocfacts(struct mps_softc *sc, MPI2_IOC_FACTS_REPLY *facts);
 static int mps_wait_db_ack(struct mps_softc *sc, int timeout, int sleep_flag);
 SYSCTL_NODE(_hw, OID_AUTO, mps, CTLFLAG_RD, 0, "MPS Driver Parameters");
 
@@ -113,6 +124,9 @@
         } u;
 }reply_descriptor,address_descriptor;
 
+/* Rate limit chain-fail messages to 1 per minute */
+static struct timeval mps_chainfail_interval = { 60, 0 };
+
 /* 
  * sleep_flag can be either CAN_SLEEP or NO_SLEEP.
  * If this function is called from process context, it can sleep
@@ -128,6 +142,7 @@
 {
 	uint32_t reg;
 	int i, error, tries = 0;
+	uint8_t first_wait_done = FALSE;
 
 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
 
@@ -136,8 +151,8 @@
 
 	/*Force NO_SLEEP for threads prohibited to sleep
  	* e.a Thread from interrupt handler are prohibited to sleep.
- 	*/	
-	if(curthread->td_pflags & TDP_NOSLEEPING)
+ 	*/
+	if (curthread->td_no_sleeping != 0)
 		sleep_flag = NO_SLEEP;
  
 	/* Push the magic sequence */
@@ -148,7 +163,8 @@
 			    mpt2_reset_magic[i]);
 		/* wait 100 msec */
 		if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP)
-			msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0, "mpsdiag", hz/10);
+			msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0,
+			    "mpsdiag", hz/10);
 		else if (sleep_flag == CAN_SLEEP)
 			pause("mpsdiag", hz/10);
 		else
@@ -169,14 +185,32 @@
 
 	/* Wait up to 300 seconds in 50ms intervals */
 	error = ETIMEDOUT;
-	for (i = 0; i < 60000; i++) {
-		/* wait 50 msec */
-		if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP)
-			msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0, "mpsdiag", hz/20);
-		else if (sleep_flag == CAN_SLEEP)
-			pause("mpsdiag", hz/20);
-		else
-			DELAY(50 * 1000);
+	for (i = 0; i < 6000; i++) {
+		/*
+		 * Wait 50 msec. If this is the first time through, wait 256
+		 * msec to satisfy Diag Reset timing requirements.
+		 */
+		if (first_wait_done) {
+			if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP)
+				msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0,
+				    "mpsdiag", hz/20);
+			else if (sleep_flag == CAN_SLEEP)
+				pause("mpsdiag", hz/20);
+			else
+				DELAY(50 * 1000);
+		} else {
+			DELAY(256 * 1000);
+			first_wait_done = TRUE;
+		}
+		/*
+		 * Check for the RESET_ADAPTER bit to be cleared first, then
+		 * wait for the RESET state to be cleared, which takes a little
+		 * longer.
+		 */
+		reg = mps_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET);
+		if (reg & MPI2_DIAG_RESET_ADAPTER) {
+			continue;
+		}
 		reg = mps_regread(sc, MPI2_DOORBELL_OFFSET);
 		if ((reg & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_RESET) {
 			error = 0;
@@ -195,7 +229,7 @@
 mps_message_unit_reset(struct mps_softc *sc, int sleep_flag)
 {
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	mps_regwrite(sc, MPI2_DOORBELL_OFFSET,
 	    MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET <<
@@ -217,14 +251,14 @@
 	int error, tries = 0;
 	int sleep_flags;
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 	/* If we are in attach call, do not sleep */
 	sleep_flags = (sc->mps_flags & MPS_FLAGS_ATTACH_DONE)
 					? CAN_SLEEP:NO_SLEEP;
 	error = 0;
-	while (tries++ < 5) {
+	while (tries++ < 1200) {
 		reg = mps_regread(sc, MPI2_DOORBELL_OFFSET);
-		mps_dprint(sc, MPS_INFO, "Doorbell= 0x%x\n", reg);
+		mps_dprint(sc, MPS_INIT, "Doorbell= 0x%x\n", reg);
 
 		/*
 		 * Ensure the IOC is ready to talk.  If it's not, try
@@ -250,7 +284,7 @@
 			error = 0;
 			break;
 		} else if (state == MPI2_IOC_STATE_FAULT) {
-			mps_dprint(sc, MPS_INFO, "IOC in fault state 0x%x\n",
+			mps_dprint(sc, MPS_FAULT, "IOC in fault state 0x%x, resetting\n",
 			    state & MPI2_DOORBELL_FAULT_CODE_MASK);
 			mps_diag_reset(sc, sleep_flags);
 		} else if (state == MPI2_IOC_STATE_OPERATIONAL) {
@@ -283,11 +317,11 @@
 	uint32_t reg, state;
 	int error;
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	error = 0;
 	reg = mps_regread(sc, MPI2_DOORBELL_OFFSET);
-	mps_dprint(sc, MPS_INFO, "Doorbell= 0x%x\n", reg);
+	mps_dprint(sc, MPS_INIT, "Doorbell= 0x%x\n", reg);
 
 	state = reg & MPI2_IOC_STATE_MASK;
 	if (state != MPI2_IOC_STATE_READY) {
@@ -302,9 +336,341 @@
 	return (error);
 }
 
+/*
+ * This is called during attach and when re-initializing due to a Diag Reset.
+ * IOC Facts is used to allocate many of the structures needed by the driver.
+ * If called from attach, de-allocation is not required because the driver has
+ * not allocated any structures yet, but if called from a Diag Reset, previously
+ * allocated structures based on IOC Facts will need to be freed and re-
+ * allocated bases on the latest IOC Facts.
+ */
+static int
+mps_iocfacts_allocate(struct mps_softc *sc, uint8_t attaching)
+{
+	int error;
+	Mpi2IOCFactsReply_t saved_facts;
+	uint8_t saved_mode, reallocating;
+
+	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+	/* Save old IOC Facts and then only reallocate if Facts have changed */
+	if (!attaching) {
+		bcopy(sc->facts, &saved_facts, sizeof(MPI2_IOC_FACTS_REPLY));
+	}
+
+	/*
+	 * Get IOC Facts.  In all cases throughout this function, panic if doing
+	 * a re-initialization and only return the error if attaching so the OS
+	 * can handle it.
+	 */
+	if ((error = mps_get_iocfacts(sc, sc->facts)) != 0) {
+		if (attaching) {
+			mps_dprint(sc, MPS_FAULT, "%s failed to get IOC Facts "
+			    "with error %d\n", __func__, error);
+			return (error);
+		} else {
+			panic("%s failed to get IOC Facts with error %d\n",
+			    __func__, error);
+		}
+	}
+
+	MPS_DPRINT_PAGE(sc, MPS_XINFO, iocfacts, sc->facts);
+
+	snprintf(sc->fw_version, sizeof(sc->fw_version), 
+	    "%02d.%02d.%02d.%02d", 
+	    sc->facts->FWVersion.Struct.Major,
+	    sc->facts->FWVersion.Struct.Minor,
+	    sc->facts->FWVersion.Struct.Unit,
+	    sc->facts->FWVersion.Struct.Dev);
+
+	mps_printf(sc, "Firmware: %s, Driver: %s\n", sc->fw_version,
+	    MPS_DRIVER_VERSION);
+	mps_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities,
+	    "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf"
+	    "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR"
+	    "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc");
+
+	/*
+	 * If the chip doesn't support event replay then a hard reset will be
+	 * required to trigger a full discovery.  Do the reset here then
+	 * retransition to Ready.  A hard reset might have already been done,
+	 * but it doesn't hurt to do it again.  Only do this if attaching, not
+	 * for a Diag Reset.
+	 */
+	if (attaching) {
+		if ((sc->facts->IOCCapabilities &
+		    MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) {
+			mps_diag_reset(sc, NO_SLEEP);
+			if ((error = mps_transition_ready(sc)) != 0) {
+				mps_dprint(sc, MPS_FAULT, "%s failed to "
+				    "transition to ready with error %d\n",
+				    __func__, error);
+				return (error);
+			}
+		}
+	}
+
+	/*
+	 * Set flag if IR Firmware is loaded.  If the RAID Capability has
+	 * changed from the previous IOC Facts, log a warning, but only if
+	 * checking this after a Diag Reset and not during attach.
+	 */
+	saved_mode = sc->ir_firmware;
+	if (sc->facts->IOCCapabilities &
+	    MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
+		sc->ir_firmware = 1;
+	if (!attaching) {
+		if (sc->ir_firmware != saved_mode) {
+			mps_dprint(sc, MPS_FAULT, "%s new IR/IT mode in IOC "
+			    "Facts does not match previous mode\n", __func__);
+		}
+	}
+
+	/* Only deallocate and reallocate if relevant IOC Facts have changed */
+	reallocating = FALSE;
+	sc->mps_flags &= ~MPS_FLAGS_REALLOCATED;
+
+	if ((!attaching) &&
+	    ((saved_facts.MsgVersion != sc->facts->MsgVersion) ||
+	    (saved_facts.HeaderVersion != sc->facts->HeaderVersion) ||
+	    (saved_facts.MaxChainDepth != sc->facts->MaxChainDepth) ||
+	    (saved_facts.RequestCredit != sc->facts->RequestCredit) ||
+	    (saved_facts.ProductID != sc->facts->ProductID) ||
+	    (saved_facts.IOCCapabilities != sc->facts->IOCCapabilities) ||
+	    (saved_facts.IOCRequestFrameSize !=
+	    sc->facts->IOCRequestFrameSize) ||
+	    (saved_facts.MaxTargets != sc->facts->MaxTargets) ||
+	    (saved_facts.MaxSasExpanders != sc->facts->MaxSasExpanders) ||
+	    (saved_facts.MaxEnclosures != sc->facts->MaxEnclosures) ||
+	    (saved_facts.HighPriorityCredit != sc->facts->HighPriorityCredit) ||
+	    (saved_facts.MaxReplyDescriptorPostQueueDepth !=
+	    sc->facts->MaxReplyDescriptorPostQueueDepth) ||
+	    (saved_facts.ReplyFrameSize != sc->facts->ReplyFrameSize) ||
+	    (saved_facts.MaxVolumes != sc->facts->MaxVolumes) ||
+	    (saved_facts.MaxPersistentEntries !=
+	    sc->facts->MaxPersistentEntries))) {
+		reallocating = TRUE;
+
+		/* Record that we reallocated everything */
+		sc->mps_flags |= MPS_FLAGS_REALLOCATED;
+	}
+
+	/*
+	 * Some things should be done if attaching or re-allocating after a Diag
+	 * Reset, but are not needed after a Diag Reset if the FW has not
+	 * changed.
+	 */
+	if (attaching || reallocating) {
+		/*
+		 * Check if controller supports FW diag buffers and set flag to
+		 * enable each type.
+		 */
+		if (sc->facts->IOCCapabilities &
+		    MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER)
+			sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].
+			    enabled = TRUE;
+		if (sc->facts->IOCCapabilities &
+		    MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
+			sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].
+			    enabled = TRUE;
+		if (sc->facts->IOCCapabilities &
+		    MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
+			sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].
+			    enabled = TRUE;
+
+		/*
+		 * Set flag if EEDP is supported and if TLR is supported.
+		 */
+		if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP)
+			sc->eedp_enabled = TRUE;
+		if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)
+			sc->control_TLR = TRUE;
+
+		/*
+		 * Size the queues. Since the reply queues always need one free
+		 * entry, we'll just deduct one reply message here.
+		 */
+		sc->num_reqs = MIN(MPS_REQ_FRAMES, sc->facts->RequestCredit);
+		sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES,
+		    sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
+
+		/*
+		 * Initialize all Tail Queues
+		 */
+		TAILQ_INIT(&sc->req_list);
+		TAILQ_INIT(&sc->high_priority_req_list);
+		TAILQ_INIT(&sc->chain_list);
+		TAILQ_INIT(&sc->tm_list);
+	}
+
+	/*
+	 * If doing a Diag Reset and the FW is significantly different
+	 * (reallocating will be set above in IOC Facts comparison), then all
+	 * buffers based on the IOC Facts will need to be freed before they are
+	 * reallocated.
+	 */
+	if (reallocating) {
+		mps_iocfacts_free(sc);
+		mpssas_realloc_targets(sc, saved_facts.MaxTargets +
+		    saved_facts.MaxVolumes);
+	}
+
+	/*
+	 * Any deallocation has been completed.  Now start reallocating
+	 * if needed.  Will only need to reallocate if attaching or if the new
+	 * IOC Facts are different from the previous IOC Facts after a Diag
+	 * Reset. Targets have already been allocated above if needed.
+	 */
+	if (attaching || reallocating) {
+		if (((error = mps_alloc_queues(sc)) != 0) ||
+		    ((error = mps_alloc_replies(sc)) != 0) ||
+		    ((error = mps_alloc_requests(sc)) != 0)) {
+			if (attaching ) {
+				mps_dprint(sc, MPS_FAULT, "%s failed to alloc "
+				    "queues with error %d\n", __func__, error);
+				mps_free(sc);
+				return (error);
+			} else {
+				panic("%s failed to alloc queues with error "
+				    "%d\n", __func__, error);
+			}
+		}
+	}
+
+	/* Always initialize the queues */
+	bzero(sc->free_queue, sc->fqdepth * 4);
+	mps_init_queues(sc);
+
+	/*
+	 * Always get the chip out of the reset state, but only panic if not
+	 * attaching.  If attaching and there is an error, that is handled by
+	 * the OS.
+	 */
+	error = mps_transition_operational(sc);
+	if (error != 0) {
+		if (attaching) {
+			mps_printf(sc, "%s failed to transition to operational "
+			    "with error %d\n", __func__, error);
+			mps_free(sc);
+			return (error);
+		} else {
+			panic("%s failed to transition to operational with "
+			    "error %d\n", __func__, error);
+		}
+	}
+
+	/*
+	 * Finish the queue initialization.
+	 * These are set here instead of in mps_init_queues() because the
+	 * IOC resets these values during the state transition in
+	 * mps_transition_operational().  The free index is set to 1
+	 * because the corresponding index in the IOC is set to 0, and the
+	 * IOC treats the queues as full if both are set to the same value.
+	 * Hence the reason that the queue can't hold all of the possible
+	 * replies.
+	 */
+	sc->replypostindex = 0;
+	mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
+	mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 0);
+
+	/*
+	 * Attach the subsystems so they can prepare their event masks.
+	 */
+	/* XXX Should be dynamic so that IM/IR and user modules can attach */
+	if (attaching) {
+		if (((error = mps_attach_log(sc)) != 0) ||
+		    ((error = mps_attach_sas(sc)) != 0) ||
+		    ((error = mps_attach_user(sc)) != 0)) {
+			mps_printf(sc, "%s failed to attach all subsystems: "
+			    "error %d\n", __func__, error);
+			mps_free(sc);
+			return (error);
+		}
+
+		if ((error = mps_pci_setup_interrupts(sc)) != 0) {
+			mps_printf(sc, "%s failed to setup interrupts\n",
+			    __func__);
+			mps_free(sc);
+			return (error);
+		}
+	}
+
+	/*
+	 * Set flag if this is a WD controller.  This shouldn't ever change, but
+	 * reset it after a Diag Reset, just in case.
+	 */
+	sc->WD_available = FALSE;
+	if (pci_get_device(sc->mps_dev) == MPI2_MFGPAGE_DEVID_SSS6200)
+		sc->WD_available = TRUE;
+
+	return (error);
+}
+
+/*
+ * This is called if memory is being free (during detach for example) and when
+ * buffers need to be reallocated due to a Diag Reset.
+ */
+static void
+mps_iocfacts_free(struct mps_softc *sc)
+{
+	struct mps_command *cm;
+	int i;
+
+	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+	if (sc->free_busaddr != 0)
+		bus_dmamap_unload(sc->queues_dmat, sc->queues_map);
+	if (sc->free_queue != NULL)
+		bus_dmamem_free(sc->queues_dmat, sc->free_queue,
+		    sc->queues_map);
+	if (sc->queues_dmat != NULL)
+		bus_dma_tag_destroy(sc->queues_dmat);
+
+	if (sc->chain_busaddr != 0)
+		bus_dmamap_unload(sc->chain_dmat, sc->chain_map);
+	if (sc->chain_frames != NULL)
+		bus_dmamem_free(sc->chain_dmat, sc->chain_frames,
+		    sc->chain_map);
+	if (sc->chain_dmat != NULL)
+		bus_dma_tag_destroy(sc->chain_dmat);
+
+	if (sc->sense_busaddr != 0)
+		bus_dmamap_unload(sc->sense_dmat, sc->sense_map);
+	if (sc->sense_frames != NULL)
+		bus_dmamem_free(sc->sense_dmat, sc->sense_frames,
+		    sc->sense_map);
+	if (sc->sense_dmat != NULL)
+		bus_dma_tag_destroy(sc->sense_dmat);
+
+	if (sc->reply_busaddr != 0)
+		bus_dmamap_unload(sc->reply_dmat, sc->reply_map);
+	if (sc->reply_frames != NULL)
+		bus_dmamem_free(sc->reply_dmat, sc->reply_frames,
+		    sc->reply_map);
+	if (sc->reply_dmat != NULL)
+		bus_dma_tag_destroy(sc->reply_dmat);
+
+	if (sc->req_busaddr != 0)
+		bus_dmamap_unload(sc->req_dmat, sc->req_map);
+	if (sc->req_frames != NULL)
+		bus_dmamem_free(sc->req_dmat, sc->req_frames, sc->req_map);
+	if (sc->req_dmat != NULL)
+		bus_dma_tag_destroy(sc->req_dmat);
+
+	if (sc->chains != NULL)
+		free(sc->chains, M_MPT2);
+	if (sc->commands != NULL) {
+		for (i = 1; i < sc->num_reqs; i++) {
+			cm = &sc->commands[i];
+			bus_dmamap_destroy(sc->buffer_dmat, cm->cm_dmamap);
+		}
+		free(sc->commands, M_MPT2);
+	}
+	if (sc->buffer_dmat != NULL)
+		bus_dma_tag_destroy(sc->buffer_dmat);
+}
+
 /* 
- * XXX Some of this should probably move to mps.c
- *
  * The terms diag reset and hard reset are used interchangeably in the MPI
  * docs to mean resetting the controller chip.  In this code diag reset
  * cleans everything up, and the hard reset function just sends the reset
@@ -316,27 +682,35 @@
 mps_reinit(struct mps_softc *sc)
 {
 	int error;
-	uint32_t db;
+	struct mpssas_softc *sassc;
 
-	mps_printf(sc, "%s sc %p\n", __func__, sc);
+	sassc = sc->sassc;
 
+	MPS_FUNCTRACE(sc);
+
 	mtx_assert(&sc->mps_mtx, MA_OWNED);
 
 	if (sc->mps_flags & MPS_FLAGS_DIAGRESET) {
-		mps_printf(sc, "%s reset already in progress\n", __func__);
+		mps_dprint(sc, MPS_INIT, "%s reset already in progress\n",
+			   __func__);
 		return 0;
 	}
 
+	mps_dprint(sc, MPS_INFO, "Reinitializing controller,\n");
 	/* make sure the completion callbacks can recognize they're getting
 	 * a NULL cm_reply due to a reset.
 	 */
 	sc->mps_flags |= MPS_FLAGS_DIAGRESET;
 
-	mps_printf(sc, "%s mask interrupts\n", __func__);
+	/*
+	 * Mask interrupts here.
+	 */
+	mps_dprint(sc, MPS_INIT, "%s mask interrupts\n", __func__);
 	mps_mask_intr(sc);
 
 	error = mps_diag_reset(sc, CAN_SLEEP);
 	if (error != 0) {
+		/* XXXSL No need to panic here */
 		panic("%s hard reset failed with error %d\n",
 		    __func__, error);
 	}
@@ -347,48 +721,51 @@
 	/* Give the I/O subsystem special priority to get itself prepared */
 	mpssas_handle_reinit(sc);
 
-	/* reinitialize queues after the reset */
-	bzero(sc->free_queue, sc->fqdepth * 4);
-	mps_init_queues(sc);
-
-	/* get the chip out of the reset state */
-	error = mps_transition_operational(sc);
-	if (error != 0)
-		panic("%s transition operational failed with error %d\n",
+	/*
+	 * Get IOC Facts and allocate all structures based on this information.
+	 * The attach function will also call mps_iocfacts_allocate at startup.
+	 * If relevant values have changed in IOC Facts, this function will free
+	 * all of the memory based on IOC Facts and reallocate that memory.
+	 */
+	if ((error = mps_iocfacts_allocate(sc, FALSE)) != 0) {
+		panic("%s IOC Facts based allocation failed with error %d\n",
 		    __func__, error);
+	}
 
-	/* Reinitialize the reply queue. This is delicate because this
-	 * function is typically invoked by task mgmt completion callbacks,
-	 * which are called by the interrupt thread.  We need to make sure
-	 * the interrupt handler loop will exit when we return to it, and
-	 * that it will recognize the indexes we've changed.
+	/*
+	 * Mapping structures will be re-allocated after getting IOC Page8, so
+	 * free these structures here.
 	 */
-	sc->replypostindex = 0;
-	mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
-	mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, sc->replypostindex);
+	mps_mapping_exit(sc);
 
-	db = mps_regread(sc, MPI2_DOORBELL_OFFSET);
-	mps_printf(sc, "%s doorbell 0x%08x\n", __func__, db);
-
-	mps_printf(sc, "%s unmask interrupts post %u free %u\n", __func__,
-	    sc->replypostindex, sc->replyfreeindex);
-
+	/*
+	 * The static page function currently read is IOC Page8.  Others can be
+	 * added in future.  It's possible that the values in IOC Page8 have
+	 * changed after a Diag Reset due to user modification, so always read
+	 * these.  Interrupts are masked, so unmask them before getting config
+	 * pages.
+	 */
 	mps_unmask_intr(sc);
+	sc->mps_flags &= ~MPS_FLAGS_DIAGRESET;
+	mps_base_static_config_pages(sc);
 
-	mps_printf(sc, "%s restarting post %u free %u\n", __func__,
-	    sc->replypostindex, sc->replyfreeindex);
+	/*
+	 * Some mapping info is based in IOC Page8 data, so re-initialize the
+	 * mapping tables.
+	 */
+	mps_mapping_initialize(sc);
 
-	/* restart will reload the event masks clobbered by the reset, and
+	/*
+	 * Restart will reload the event masks clobbered by the reset, and
 	 * then enable the port.
 	 */
 	mps_reregister_events(sc);
 
 	/* the end of discovery will release the simq, so we're done. */
-	mps_printf(sc, "%s finished sc %p post %u free %u\n", 
-	    __func__, sc, 
-	    sc->replypostindex, sc->replyfreeindex);
+	mps_dprint(sc, MPS_INFO, "%s finished sc %p post %u free %u\n", 
+	    __func__, sc, sc->replypostindex, sc->replyfreeindex);
 
-	sc->mps_flags &= ~MPS_FLAGS_DIAGRESET;
+	mpssas_release_simq_reinit(sassc);
 
 	return 0;
 }
@@ -411,7 +788,7 @@
 	do {
 		int_status = mps_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET);
 		if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
-			mps_dprint(sc, MPS_INFO, 
+			mps_dprint(sc, MPS_INIT, 
 			"%s: successfull count(%d), timeout(%d)\n",
 			__func__, count, timeout);
 		return 0;
@@ -469,8 +846,8 @@
 	uint16_t *data16;
 	int i, count, ioc_sz, residual;
 	int sleep_flags = CAN_SLEEP;
-	
-	if(curthread->td_pflags & TDP_NOSLEEPING)
+
+	if (curthread->td_no_sleeping != 0)
 		sleep_flags = NO_SLEEP;
 
 	/* Step 1 */
@@ -546,7 +923,7 @@
 	count = MIN((reply_sz / 4), ioc_sz) * 2;
 	if (count < ioc_sz * 2) {
 		residual = ioc_sz * 2 - count;
-		mps_dprint(sc, MPS_FAULT, "Driver error, throwing away %d "
+		mps_dprint(sc, MPS_ERROR, "Driver error, throwing away %d "
 		    "residual message words\n", residual);
 	}
 
@@ -592,7 +969,8 @@
 mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm)
 {
 	reply_descriptor rd;
-	mps_dprint(sc, MPS_TRACE, "%s SMID %u cm %p ccb %p\n", __func__,
+	MPS_FUNCTRACE(sc);
+	mps_dprint(sc, MPS_TRACE, "SMID %u cm %p ccb %p\n",
 	    cm->cm_desc.Default.SMID, cm, cm->cm_ccb);
 
 	if (sc->mps_flags & MPS_FLAGS_ATTACH_DONE && !(sc->mps_flags & MPS_FLAGS_SHUTDOWN))
@@ -620,7 +998,7 @@
 	MPI2_IOC_FACTS_REQUEST request;
 	int error, req_sz, reply_sz;
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	req_sz = sizeof(MPI2_IOC_FACTS_REQUEST);
 	reply_sz = sizeof(MPI2_IOC_FACTS_REPLY);
@@ -634,50 +1012,15 @@
 }
 
 static int
-mps_get_portfacts(struct mps_softc *sc, MPI2_PORT_FACTS_REPLY *facts, int port)
-{
-	MPI2_PORT_FACTS_REQUEST *request;
-	MPI2_PORT_FACTS_REPLY *reply;
-	struct mps_command *cm;
-	int error;
-
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-	if ((cm = mps_alloc_command(sc)) == NULL)
-		return (EBUSY);
-	request = (MPI2_PORT_FACTS_REQUEST *)cm->cm_req;
-	request->Function = MPI2_FUNCTION_PORT_FACTS;
-	request->PortNumber = port;
-	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_PORT_FACTS_REPLY *)cm->cm_reply;
-	if (reply == NULL) {
-		mps_printf(sc, "%s NULL reply\n", __func__);
-		goto done;
-	}
-	if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) {
-		mps_printf(sc, 
-		    "%s error %d iocstatus 0x%x iocloginfo 0x%x type 0x%x\n",
-		    __func__, error, reply->IOCStatus, reply->IOCLogInfo, 
-		    reply->PortType);
-		error = ENXIO;
-	}
-	bcopy(reply, facts, sizeof(MPI2_PORT_FACTS_REPLY));
-done:
-	mps_free_command(sc, cm);
-
-	return (error);
-}
-
-static int
 mps_send_iocinit(struct mps_softc *sc)
 {
 	MPI2_IOC_INIT_REQUEST	init;
 	MPI2_DEFAULT_REPLY	reply;
 	int req_sz, reply_sz, error;
+	struct timeval now;
+	uint64_t time_in_msec;
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	req_sz = sizeof(MPI2_IOC_INIT_REQUEST);
 	reply_sz = sizeof(MPI2_IOC_INIT_REPLY);
@@ -704,14 +1047,16 @@
 	init.ReplyDescriptorPostQueueAddress.Low = htole32((uint32_t)sc->post_busaddr);
 	init.ReplyFreeQueueAddress.High = 0;
 	init.ReplyFreeQueueAddress.Low = htole32((uint32_t)sc->free_busaddr);
-	init.TimeStamp.High = 0;
-	init.TimeStamp.Low = htole32((uint32_t)time_uptime);
+	getmicrotime(&now);
+	time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000);
+	init.TimeStamp.High = htole32((time_in_msec >> 32) & 0xFFFFFFFF);
+	init.TimeStamp.Low = htole32(time_in_msec & 0xFFFFFFFF);
 
 	error = mps_request_sync(sc, &init, &reply, req_sz, reply_sz, 5);
 	if ((reply.IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
 		error = ENXIO;
 
-	mps_dprint(sc, MPS_INFO, "IOCInit status= 0x%x\n", reply.IOCStatus);
+	mps_dprint(sc, MPS_INIT, "IOCInit status= 0x%x\n", reply.IOCStatus);
 	return (error);
 }
 
@@ -924,7 +1269,7 @@
 				NULL, NULL,		/* filter, filterarg */
                                 BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
                                 nsegs,			/* nsegments */
-                                BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
+                                BUS_SPACE_MAXSIZE_24BIT,/* maxsegsize */
                                 BUS_DMA_ALLOCNOW,	/* flags */
                                 busdma_lock_mutex,	/* lockfunc */
 				&sc->mps_mtx,		/* lockarg */
@@ -1002,16 +1347,20 @@
  * Next are the global settings, if they exist.  Highest are the per-unit
  * settings, if they exist.
  */
-static void
+void
 mps_get_tunables(struct mps_softc *sc)
 {
 	char tmpstr[80];
 
 	/* XXX default to some debugging for now */
-	sc->mps_debug = MPS_FAULT;
+	sc->mps_debug = MPS_INFO|MPS_FAULT;
 	sc->disable_msix = 0;
 	sc->disable_msi = 0;
 	sc->max_chains = MPS_CHAIN_FRAMES;
+	sc->max_io_pages = MPS_MAXIO_PAGES;
+	sc->enable_ssu = MPS_SSU_ENABLE_SSD_DISABLE_HDD;
+	sc->spinup_wait_time = DEFAULT_SPINUP_WAIT;
+	sc->use_phynum = 1;
 
 	/*
 	 * Grab the global variables.
@@ -1020,6 +1369,10 @@
 	TUNABLE_INT_FETCH("hw.mps.disable_msix", &sc->disable_msix);
 	TUNABLE_INT_FETCH("hw.mps.disable_msi", &sc->disable_msi);
 	TUNABLE_INT_FETCH("hw.mps.max_chains", &sc->max_chains);
+	TUNABLE_INT_FETCH("hw.mps.max_io_pages", &sc->max_io_pages);
+	TUNABLE_INT_FETCH("hw.mps.enable_ssu", &sc->enable_ssu);
+	TUNABLE_INT_FETCH("hw.mps.spinup_wait_time", &sc->spinup_wait_time);
+	TUNABLE_INT_FETCH("hw.mps.use_phy_num", &sc->use_phynum);
 
 	/* Grab the unit-instance variables */
 	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.debug_level",
@@ -1037,6 +1390,27 @@
 	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_chains",
 	    device_get_unit(sc->mps_dev));
 	TUNABLE_INT_FETCH(tmpstr, &sc->max_chains);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_io_pages",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_io_pages);
+
+	bzero(sc->exclude_ids, sizeof(sc->exclude_ids));
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.exclude_ids",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_STR_FETCH(tmpstr, sc->exclude_ids, sizeof(sc->exclude_ids));
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.enable_ssu",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->enable_ssu);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.spinup_wait_time",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->spinup_wait_time);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.use_phy_num",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->use_phynum);
 }
 
 static void
@@ -1082,7 +1456,7 @@
 	    "Disable the use of MSI interrupts");
 
 	SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
-	    OID_AUTO, "firmware_version", CTLFLAG_RW, &sc->fw_version,
+	    OID_AUTO, "firmware_version", CTLFLAG_RW, sc->fw_version,
 	    strlen(sc->fw_version), "firmware version");
 
 	SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
@@ -1109,25 +1483,49 @@
 	    OID_AUTO, "max_chains", CTLFLAG_RD,
 	    &sc->max_chains, 0,"maximum chain frames that will be allocated");
 
-#if __FreeBSD_version >= 900030
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_io_pages", CTLFLAG_RD,
+	    &sc->max_io_pages, 0,"maximum pages to allow per I/O (if <1 use "
+	    "IOCFacts)");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "enable_ssu", CTLFLAG_RW, &sc->enable_ssu, 0,
+	    "enable SSU to SATA SSD/HDD at shutdown");
+
 	SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
 	    OID_AUTO, "chain_alloc_fail", CTLFLAG_RD,
 	    &sc->chain_alloc_fail, "chain allocation failures");
-#endif //FreeBSD_version >= 900030
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "spinup_wait_time", CTLFLAG_RD,
+	    &sc->spinup_wait_time, DEFAULT_SPINUP_WAIT, "seconds to wait for "
+	    "spinup after SATA ID error");
+
+	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "mapping_table_dump", CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
+	    mps_mapping_dump, "A", "Mapping Table Dump");
+
+	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "encl_table_dump", CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
+	    mps_mapping_encl_dump, "A", "Enclosure Table Dump");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "use_phy_num", CTLFLAG_RD, &sc->use_phynum, 0,
+	    "Use the phy number for enumeration");
 }
 
 int
 mps_attach(struct mps_softc *sc)
 {
-	int i, error;
+	int error;
 
-	mps_get_tunables(sc);
+	MPS_FUNCTRACE(sc);
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
 	mtx_init(&sc->mps_mtx, "MPT2SAS lock", NULL, MTX_DEF);
 	callout_init_mtx(&sc->periodic, &sc->mps_mtx, 0);
+	callout_init_mtx(&sc->device_check_callout, &sc->mps_mtx, 0);
 	TAILQ_INIT(&sc->event_list);
+	timevalclear(&sc->lastfail);
 
 	if ((error = mps_transition_ready(sc)) != 0) {
 		mps_printf(sc, "%s failed to transition ready\n", __func__);
@@ -1141,151 +1539,20 @@
 		 __func__, __LINE__);
 		return (ENOMEM);
 	}
-	if ((error = mps_get_iocfacts(sc, sc->facts)) != 0)
-		return (error);
 
-	mps_print_iocfacts(sc, sc->facts);
-
-	snprintf(sc->fw_version, sizeof(sc->fw_version), 
-	    "%02d.%02d.%02d.%02d", 
-	    sc->facts->FWVersion.Struct.Major,
-	    sc->facts->FWVersion.Struct.Minor,
-	    sc->facts->FWVersion.Struct.Unit,
-	    sc->facts->FWVersion.Struct.Dev);
-
-	mps_printf(sc, "Firmware: %s, Driver: %s\n", sc->fw_version,
-	    MPS_DRIVER_VERSION);
-	mps_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities,
-	    "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf"
-	    "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR"
-	    "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc");
-
 	/*
-	 * If the chip doesn't support event replay then a hard reset will be
-	 * required to trigger a full discovery.  Do the reset here then
-	 * retransition to Ready.  A hard reset might have already been done,
-	 * but it doesn't hurt to do it again.
+	 * Get IOC Facts and allocate all structures based on this information.
+	 * A Diag Reset will also call mps_iocfacts_allocate and re-read the IOC
+	 * Facts. If relevant values have changed in IOC Facts, this function
+	 * will free all of the memory based on IOC Facts and reallocate that
+	 * memory.  If this fails, any allocated memory should already be freed.
 	 */
-	if ((sc->facts->IOCCapabilities &
-	    MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) {
-		mps_diag_reset(sc, NO_SLEEP);
-		if ((error = mps_transition_ready(sc)) != 0)
-			return (error);
-	}
-
-	/*
-	 * Set flag if IR Firmware is loaded.
-	 */
-	if (sc->facts->IOCCapabilities &
-	    MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
-		sc->ir_firmware = 1;
-
-	/*
-	 * Check if controller supports FW diag buffers and set flag to enable
-	 * each type.
-	 */
-	if (sc->facts->IOCCapabilities &
-	    MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER)
-		sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].enabled =
-		    TRUE;
-	if (sc->facts->IOCCapabilities &
-	    MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
-		sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].enabled =
-		    TRUE;
-	if (sc->facts->IOCCapabilities &
-	    MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
-		sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].enabled =
-		    TRUE;
-
-	/*
-	 * Set flag if EEDP is supported and if TLR is supported.
-	 */
-	if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP)
-		sc->eedp_enabled = TRUE;
-	if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)
-		sc->control_TLR = TRUE;
-
-	/*
-	 * Size the queues. Since the reply queues always need one free entry,
-	 * we'll just deduct one reply message here.
-	 */
-	sc->num_reqs = MIN(MPS_REQ_FRAMES, sc->facts->RequestCredit);
-	sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES,
-	    sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
-	TAILQ_INIT(&sc->req_list);
-	TAILQ_INIT(&sc->high_priority_req_list);
-	TAILQ_INIT(&sc->chain_list);
-	TAILQ_INIT(&sc->tm_list);
-
-	if (((error = mps_alloc_queues(sc)) != 0) ||
-	    ((error = mps_alloc_replies(sc)) != 0) ||
-	    ((error = mps_alloc_requests(sc)) != 0)) {
-		mps_printf(sc, "%s failed to alloc\n", __func__);
-		mps_free(sc);
+	if ((error = mps_iocfacts_allocate(sc, TRUE)) != 0) {
+		mps_dprint(sc, MPS_FAULT, "%s IOC Facts based allocation "
+		    "failed with error %d\n", __func__, error);
 		return (error);
 	}
 
-	if (((error = mps_init_queues(sc)) != 0) ||
-	    ((error = mps_transition_operational(sc)) != 0)) {
-		mps_printf(sc, "%s failed to transition operational\n", __func__);
-		mps_free(sc);
-		return (error);
-	}
-
-	/*
-	 * Finish the queue initialization.
-	 * These are set here instead of in mps_init_queues() because the
-	 * IOC resets these values during the state transition in
-	 * mps_transition_operational().  The free index is set to 1
-	 * because the corresponding index in the IOC is set to 0, and the
-	 * IOC treats the queues as full if both are set to the same value.
-	 * Hence the reason that the queue can't hold all of the possible
-	 * replies.
-	 */
-	sc->replypostindex = 0;
-	mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
-	mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 0);
-
-	sc->pfacts = malloc(sizeof(MPI2_PORT_FACTS_REPLY) *
-	    sc->facts->NumberOfPorts, M_MPT2, M_ZERO|M_WAITOK);
-	if(!sc->pfacts) {
-		device_printf(sc->mps_dev, "Cannot allocate memory %s %d\n",
-		 __func__, __LINE__);
-		return (ENOMEM);
-	}
-	for (i = 0; i < sc->facts->NumberOfPorts; i++) {
-		if ((error = mps_get_portfacts(sc, &sc->pfacts[i], i)) != 0) {
-			mps_printf(sc, "%s failed to get portfacts for port %d\n",
-			    __func__, i);
-			mps_free(sc);
-			return (error);
-		}
-		mps_print_portfacts(sc, &sc->pfacts[i]);
-	}
-
-	/* Attach the subsystems so they can prepare their event masks. */
-	/* XXX Should be dynamic so that IM/IR and user modules can attach */
-	if (((error = mps_attach_log(sc)) != 0) ||
-	    ((error = mps_attach_sas(sc)) != 0) ||
-	    ((error = mps_attach_user(sc)) != 0)) {
-		mps_printf(sc, "%s failed to attach all subsystems: error %d\n",
-		    __func__, error);
-		mps_free(sc);
-		return (error);
-	}
-
-	if ((error = mps_pci_setup_interrupts(sc)) != 0) {
-		mps_printf(sc, "%s failed to setup interrupts\n", __func__);
-		mps_free(sc);
-		return (error);
-	}
-
-	/*
-	 * The static page function currently read is ioc page8.  Others can be
-	 * added in future.
-	 */
-	mps_base_static_config_pages(sc);
-
 	/* Start the periodic watchdog check on the IOC Doorbell */
 	mps_periodic(sc);
 
@@ -1297,7 +1564,7 @@
 	sc->mps_ich.ich_func = mps_startup;
 	sc->mps_ich.ich_arg = sc;
 	if (config_intrhook_establish(&sc->mps_ich) != 0) {
-		mps_dprint(sc, MPS_FAULT, "Cannot establish MPS config hook\n");
+		mps_dprint(sc, MPS_ERROR, "Cannot establish MPS config hook\n");
 		error = EINVAL;
 	}
 
@@ -1308,7 +1575,7 @@
 	    mpssas_ir_shutdown, sc, SHUTDOWN_PRI_DEFAULT);
 
 	if (sc->shutdown_eh == NULL)
-		mps_dprint(sc, MPS_FAULT, "shutdown event registration "
+		mps_dprint(sc, MPS_ERROR, "shutdown event registration "
 		    "failed\n");
 
 	mps_setup_sysctl(sc);
@@ -1328,7 +1595,9 @@
 
 	mps_lock(sc);
 	mps_unmask_intr(sc);
+
 	/* initialize device mapping tables */
+	mps_base_static_config_pages(sc);
 	mps_mapping_initialize(sc);
 	mpssas_startup(sc);
 	mps_unlock(sc);
@@ -1347,8 +1616,7 @@
 
 	db = mps_regread(sc, MPI2_DOORBELL_OFFSET);
 	if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
-		device_printf(sc->mps_dev, "IOC Fault 0x%08x, Resetting\n", db);
-
+		mps_dprint(sc, MPS_FAULT, "IOC Fault 0x%08x, Resetting\n", db);
 		mps_reinit(sc);
 	}
 
@@ -1361,16 +1629,17 @@
 {
 	MPI2_EVENT_DATA_LOG_ENTRY_ADDED *entry;
 
-	mps_print_event(sc, event);
+	MPS_DPRINT_EVENT(sc, generic, event);
 
 	switch (event->Event) {
 	case MPI2_EVENT_LOG_DATA:
-		device_printf(sc->mps_dev, "MPI2_EVENT_LOG_DATA:\n");
-		hexdump(event->EventData, event->EventDataLength, NULL, 0);
+		mps_dprint(sc, MPS_EVENT, "MPI2_EVENT_LOG_DATA:\n");
+		if (sc->mps_debug & MPS_EVENT)
+			hexdump(event->EventData, event->EventDataLength, NULL, 0);
 		break;
 	case MPI2_EVENT_LOG_ENTRY_ADDED:
 		entry = (MPI2_EVENT_DATA_LOG_ENTRY_ADDED *)event->EventData;
-		mps_dprint(sc, MPS_INFO, "MPI2_EVENT_LOG_ENTRY_ADDED event "
+		mps_dprint(sc, MPS_EVENT, "MPI2_EVENT_LOG_ENTRY_ADDED event "
 		    "0x%x Sequence %d:\n", entry->LogEntryQualifier,
 		     entry->LogSequence);
 		break;
@@ -1411,8 +1680,7 @@
 int
 mps_free(struct mps_softc *sc)
 {
-	struct mps_command *cm;
-	int i, error;
+	int error;
 
 	/* Turn off the watchdog */
 	mps_lock(sc);
@@ -1420,6 +1688,7 @@
 	mps_unlock(sc);
 	/* Lock must not be held for this */
 	callout_drain(&sc->periodic);
+	callout_drain(&sc->device_check_callout);
 
 	if (((error = mps_detach_log(sc)) != 0) ||
 	    ((error = mps_detach_sas(sc)) != 0))
@@ -1438,62 +1707,15 @@
 	if (sc->facts != NULL)
 		free(sc->facts, M_MPT2);
 
-	if (sc->pfacts != NULL)
-		free(sc->pfacts, M_MPT2);
+	/*
+	 * Free all buffers that are based on IOC Facts.  A Diag Reset may need
+	 * to free these buffers too.
+	 */
+	mps_iocfacts_free(sc);
 
-	if (sc->post_busaddr != 0)
-		bus_dmamap_unload(sc->queues_dmat, sc->queues_map);
-	if (sc->post_queue != NULL)
-		bus_dmamem_free(sc->queues_dmat, sc->post_queue,
-		    sc->queues_map);
-	if (sc->queues_dmat != NULL)
-		bus_dma_tag_destroy(sc->queues_dmat);
-
-	if (sc->chain_busaddr != 0)
-		bus_dmamap_unload(sc->chain_dmat, sc->chain_map);
-	if (sc->chain_frames != NULL)
-		bus_dmamem_free(sc->chain_dmat, sc->chain_frames,sc->chain_map);
-	if (sc->chain_dmat != NULL)
-		bus_dma_tag_destroy(sc->chain_dmat);
-
-	if (sc->sense_busaddr != 0)
-		bus_dmamap_unload(sc->sense_dmat, sc->sense_map);
-	if (sc->sense_frames != NULL)
-		bus_dmamem_free(sc->sense_dmat, sc->sense_frames,sc->sense_map);
-	if (sc->sense_dmat != NULL)
-		bus_dma_tag_destroy(sc->sense_dmat);
-
-	if (sc->reply_busaddr != 0)
-		bus_dmamap_unload(sc->reply_dmat, sc->reply_map);
-	if (sc->reply_frames != NULL)
-		bus_dmamem_free(sc->reply_dmat, sc->reply_frames,sc->reply_map);
-	if (sc->reply_dmat != NULL)
-		bus_dma_tag_destroy(sc->reply_dmat);
-
-	if (sc->req_busaddr != 0)
-		bus_dmamap_unload(sc->req_dmat, sc->req_map);
-	if (sc->req_frames != NULL)
-		bus_dmamem_free(sc->req_dmat, sc->req_frames, sc->req_map);
-	if (sc->req_dmat != NULL)
-		bus_dma_tag_destroy(sc->req_dmat);
-
-	if (sc->chains != NULL)
-		free(sc->chains, M_MPT2);
-	if (sc->commands != NULL) {
-		for (i = 1; i < sc->num_reqs; i++) {
-			cm = &sc->commands[i];
-			bus_dmamap_destroy(sc->buffer_dmat, cm->cm_dmamap);
-		}
-		free(sc->commands, M_MPT2);
-	}
-	if (sc->buffer_dmat != NULL)
-		bus_dma_tag_destroy(sc->buffer_dmat);
-
 	if (sc->sysctl_tree != NULL)
 		sysctl_ctx_free(&sc->sysctl_ctx);
 
-	mps_mapping_free_memory(sc);
-
 	/* Deregister the shutdown function */
 	if (sc->shutdown_eh != NULL)
 		EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_eh);
@@ -1504,22 +1726,28 @@
 }
 
 static __inline void
-mps_complete_command(struct mps_command *cm)
+mps_complete_command(struct mps_softc *sc, struct mps_command *cm)
 {
+	MPS_FUNCTRACE(sc);
+
+	if (cm == NULL) {
+		mps_dprint(sc, MPS_ERROR, "Completing NULL command\n");
+		return;
+	}
+
 	if (cm->cm_flags & MPS_CM_FLAGS_POLLED)
 		cm->cm_flags |= MPS_CM_FLAGS_COMPLETE;
 
 	if (cm->cm_complete != NULL) {
-		mps_dprint(cm->cm_sc, MPS_TRACE,
+		mps_dprint(sc, MPS_TRACE,
 			   "%s cm %p calling cm_complete %p data %p reply %p\n",
 			   __func__, cm, cm->cm_complete, cm->cm_complete_data,
 			   cm->cm_reply);
-		cm->cm_complete(cm->cm_sc, cm);
+		cm->cm_complete(sc, cm);
 	}
 
 	if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) {
-		mps_dprint(cm->cm_sc, MPS_TRACE, "%s: waking up %p\n",
-			   __func__, cm);
+		mps_dprint(sc, MPS_TRACE, "waking up %p\n", cm);
 		wakeup(cm);
 	}
 
@@ -1526,7 +1754,7 @@
 	if (cm->cm_sc->io_cmds_active != 0) {
 		cm->cm_sc->io_cmds_active--;
 	} else {
-		mps_dprint(cm->cm_sc, MPS_INFO, "Warning: io_cmds_active is "
+		mps_dprint(sc, MPS_ERROR, "Warning: io_cmds_active is "
 		    "out of sync - resynching to 0\n");
 	}
 }
@@ -1572,7 +1800,7 @@
 		break;
 }
 
-	mps_dprint(sc, MPS_INFO, "log_info(0x%08x): originator(%s), "
+	mps_dprint(sc, MPS_LOG, "log_info(0x%08x): originator(%s), "
 	"code(0x%02x), sub_code(0x%04x)\n", log_info,
 	originator_str, sas_loginfo.dw.code,
 	sas_loginfo.dw.subcode);
@@ -1722,9 +1950,10 @@
 					 */
 					rel_rep =
 					    (MPI2_DIAG_RELEASE_REPLY *)reply;
-					if (le16toh(rel_rep->IOCStatus) ==
+					if ((le16toh(rel_rep->IOCStatus) &
+					    MPI2_IOCSTATUS_MASK) ==
 					    MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED)
-					    {
+					{
 						pBuffer =
 						    &sc->fw_diag_buffer_list[
 						    rel_rep->BufferType];
@@ -1750,7 +1979,7 @@
 		case MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS:
 		default:
 			/* Unhandled */
-			device_printf(sc->mps_dev, "Unhandled reply 0x%x\n",
+			mps_dprint(sc, MPS_ERROR, "Unhandled reply 0x%x\n",
 			    desc->Default.ReplyFlags);
 			cm = NULL;
 			break;
@@ -1761,7 +1990,7 @@
 			// Print Error reply frame
 			if (cm->cm_reply)
 				mps_display_reply_info(sc,cm->cm_reply);
-			mps_complete_command(cm);
+			mps_complete_command(sc, cm);
 		}
 
 		desc->Words.Low = 0xffffffff;
@@ -1794,7 +2023,7 @@
 	}
 
 	if (handled == 0)
-		device_printf(sc->mps_dev, "Unhandled event 0x%x\n", le16toh(event));
+		mps_dprint(sc, MPS_EVENT, "Unhandled event 0x%x\n", le16toh(event));
 
 	/*
 	 * This is the only place that the event/reply should be freed.
@@ -1810,7 +2039,7 @@
 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
 
 	if (cm->cm_reply)
-		mps_print_event(sc,
+		MPS_DPRINT_EVENT(sc, generic,
 			(MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply);
 
 	mps_free_command(sc, cm);
@@ -1852,7 +2081,7 @@
     u32 *mask)
 {
 	MPI2_EVENT_NOTIFICATION_REQUEST *evtreq;
-	MPI2_EVENT_NOTIFICATION_REPLY *reply;
+	MPI2_EVENT_NOTIFICATION_REPLY *reply = NULL;
 	struct mps_command *cm;
 	int error, i;
 
@@ -1890,15 +2119,20 @@
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
 
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, 0);
+	if (cm != NULL)
+		reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply;
 	if ((reply == NULL) ||
 	    (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
 		error = ENXIO;
-	mps_print_event(sc, reply);
+
+	if (reply)
+		MPS_DPRINT_EVENT(sc, generic, reply);
+
 	mps_dprint(sc, MPS_TRACE, "%s finished error %d\n", __func__, error);
 
-	mps_free_command(sc, cm);
+	if (cm != NULL)
+		mps_free_command(sc, cm);
 	return (error);
 }
 
@@ -1914,7 +2148,7 @@
 
 	/* first, reregister events */
 
-    for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
+	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
 		sc->event_mask[i] = -1;
 
 	TAILQ_FOREACH(eh, &sc->event_list, eh_list) {
@@ -1946,7 +2180,8 @@
 
 	error = mps_map_command(sc, cm);
 
-	mps_dprint(sc, MPS_TRACE, "%s finished with error %d\n", __func__, error);
+	mps_dprint(sc, MPS_TRACE, "%s finished with error %d\n", __func__,
+	    error);
 	return (error);
 }
 
@@ -2014,7 +2249,6 @@
 	MPI2_SGE_SIMPLE64 *sge = sgep;
 	int error, type;
 	uint32_t saved_buf_len, saved_address_low, saved_address_high;
-	u32 sge_flags;
 
 	type = (tc->Flags & MPI2_SGE_FLAGS_ELEMENT_MASK);
 
@@ -2034,14 +2268,12 @@
 		break;
 	case MPI2_SGE_FLAGS_SIMPLE_ELEMENT:
 		/* Driver only uses 64-bit SGE simple elements */
-		sge = sgep;
 		if (len != MPS_SGE64_SIZE)
 			panic("SGE simple %p length %u or %zu?", sge,
 			    MPS_SGE64_SIZE, len);
-		if (((sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT) &
+		if (((le32toh(sge->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT) &
 		    MPI2_SGE_FLAGS_ADDRESS_SIZE) == 0)
-			panic("SGE simple %p flags %02x not marked 64-bit?",
-			    sge, sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT);
+			panic("SGE simple %p not marked 64-bit?", sge);
 
 		break;
 	default:
@@ -2073,8 +2305,8 @@
 		 * Mark as last element in this chain if necessary.
 		 */
 		if (type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) {
-			sge->FlagsLength |=
-				(MPI2_SGE_FLAGS_LAST_ELEMENT << MPI2_SGE_FLAGS_SHIFT);
+			sge->FlagsLength |= htole32(
+			    MPI2_SGE_FLAGS_LAST_ELEMENT << MPI2_SGE_FLAGS_SHIFT);
 		}
 
 		/*
@@ -2083,11 +2315,6 @@
 		 * understanding the code.
 		 */
 		cm->cm_sglsize -= len;
-		/* Endian Safe code */
-		sge_flags = sge->FlagsLength;
-		sge->FlagsLength = htole32(sge_flags);
-		sge->Address.High = htole32(sge->Address.High);	
-		sge->Address.Low = 	htole32(sge->Address.Low);
 		bcopy(sgep, cm->cm_sge, len);
 		cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
 		return (mps_add_chain(cm));
@@ -2127,27 +2354,22 @@
 		 * 2 SGL's for a bi-directional request, they both use the same
 		 * DMA buffer (same cm command).
 		 */
-		saved_buf_len = sge->FlagsLength & 0x00FFFFFF;
+		saved_buf_len = le32toh(sge->FlagsLength) & 0x00FFFFFF;
 		saved_address_low = sge->Address.Low;
 		saved_address_high = sge->Address.High;
 		if (cm->cm_out_len) {
-			sge->FlagsLength = cm->cm_out_len |
+			sge->FlagsLength = htole32(cm->cm_out_len |
 			    ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
 			    MPI2_SGE_FLAGS_END_OF_BUFFER |
 			    MPI2_SGE_FLAGS_HOST_TO_IOC |
 			    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
-			    MPI2_SGE_FLAGS_SHIFT);
+			    MPI2_SGE_FLAGS_SHIFT));
 			cm->cm_sglsize -= len;
-			/* Endian Safe code */
-			sge_flags = sge->FlagsLength;
-			sge->FlagsLength = htole32(sge_flags);
-			sge->Address.High = htole32(sge->Address.High);	
-			sge->Address.Low = 	htole32(sge->Address.Low);
 			bcopy(sgep, cm->cm_sge, len);
 			cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge
 			    + len);
 		}
-		sge->FlagsLength = saved_buf_len |
+		saved_buf_len |=
 		    ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
 		    MPI2_SGE_FLAGS_END_OF_BUFFER |
 		    MPI2_SGE_FLAGS_LAST_ELEMENT |
@@ -2155,24 +2377,20 @@
 		    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
 		    MPI2_SGE_FLAGS_SHIFT);
 		if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) {
-			sge->FlagsLength |=
+			saved_buf_len |=
 			    ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) <<
 			    MPI2_SGE_FLAGS_SHIFT);
 		} else {
-			sge->FlagsLength |=
+			saved_buf_len |=
 			    ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) <<
 			    MPI2_SGE_FLAGS_SHIFT);
 		}
+		sge->FlagsLength = htole32(saved_buf_len);
 		sge->Address.Low = saved_address_low;
 		sge->Address.High = saved_address_high;
 	}
 
 	cm->cm_sglsize -= len;
-	/* Endian Safe code */
-	sge_flags = sge->FlagsLength;
-	sge->FlagsLength = htole32(sge_flags);
-	sge->Address.High = htole32(sge->Address.High);	
-	sge->Address.Low = 	htole32(sge->Address.Low);
 	bcopy(sgep, cm->cm_sge, len);
 	cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
 	return (0);
@@ -2190,10 +2408,10 @@
 	/*
 	 * This driver always uses 64-bit address elements for simplicity.
 	 */
+	bzero(&sge, sizeof(sge));
 	flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
 	    MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
-	/* Set Endian safe macro in mps_push_sge */
-	sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT);
+	sge.FlagsLength = htole32(len | (flags << MPI2_SGE_FLAGS_SHIFT));
 	mps_from_u64(pa, &sge.Address);
 
 	return (mps_push_sge(cm, &sge, sizeof sge, segsleft));
@@ -2214,7 +2432,8 @@
 	 * user they did the wrong thing.
 	 */
 	if ((cm->cm_max_segs != 0) && (nsegs > cm->cm_max_segs)) {
-		mps_printf(sc, "%s: warning: busdma returned %d segments, "
+		mps_dprint(sc, MPS_ERROR,
+			   "%s: warning: busdma returned %d segments, "
 			   "more than the %d allowed\n", __func__, nsegs,
 			   cm->cm_max_segs);
 	}
@@ -2260,9 +2479,11 @@
 		    sflags, nsegs - i);
 		if (error != 0) {
 			/* Resource shortage, roll back! */
-			mps_dprint(sc, MPS_INFO, "out of chain frames\n");
+			if (ratecheck(&sc->lastfail, &mps_chainfail_interval))
+				mps_dprint(sc, MPS_INFO, "Out of chain frames, "
+				    "consider increasing hw.mps.max_chains.\n");
 			cm->cm_flags |= MPS_CM_FLAGS_CHAIN_FAILED;
-			mps_complete_command(cm);
+			mps_complete_command(sc, cm);
 			return;
 		}
 	}
@@ -2290,26 +2511,21 @@
 int
 mps_map_command(struct mps_softc *sc, struct mps_command *cm)
 {
-	MPI2_SGE_SIMPLE32 *sge;
 	int error = 0;
 
 	if (cm->cm_flags & MPS_CM_FLAGS_USE_UIO) {
 		error = bus_dmamap_load_uio(sc->buffer_dmat, cm->cm_dmamap,
 		    &cm->cm_uio, mps_data_cb2, cm, 0);
+	} else if (cm->cm_flags & MPS_CM_FLAGS_USE_CCB) {
+		error = bus_dmamap_load_ccb(sc->buffer_dmat, cm->cm_dmamap,
+		    cm->cm_data, mps_data_cb, cm, 0);
 	} else if ((cm->cm_data != NULL) && (cm->cm_length != 0)) {
 		error = bus_dmamap_load(sc->buffer_dmat, cm->cm_dmamap,
 		    cm->cm_data, cm->cm_length, mps_data_cb, cm, 0);
 	} else {
 		/* Add a zero-length element as needed */
-		if (cm->cm_sge != NULL) {
-			sge = (MPI2_SGE_SIMPLE32 *)cm->cm_sge;
-			sge->FlagsLength = htole32((MPI2_SGE_FLAGS_LAST_ELEMENT |
-			    MPI2_SGE_FLAGS_END_OF_BUFFER |
-			    MPI2_SGE_FLAGS_END_OF_LIST |
-			    MPI2_SGE_FLAGS_SIMPLE_ELEMENT) <<
-			    MPI2_SGE_FLAGS_SHIFT);
-			sge->Address = 0;
-		}
+		if (cm->cm_sge != NULL)
+			mps_add_dmaseg(cm, 0, 0, 0, 1);
 		mps_enqueue_request(sc, cm);	
 	}
 
@@ -2322,64 +2538,74 @@
  * be executed and enqueued automatically.  Other errors come from msleep().
  */
 int
-mps_wait_command(struct mps_softc *sc, struct mps_command *cm, int timeout)
+mps_wait_command(struct mps_softc *sc, struct mps_command **cmp, int timeout,
+    int sleep_flag)
 {
 	int error, rc;
+	struct timeval cur_time, start_time;
+	struct mps_command *cm = *cmp;
 
-	mtx_assert(&sc->mps_mtx, MA_OWNED);
-	
-	if(sc->mps_flags & MPS_FLAGS_DIAGRESET) 
+	if (sc->mps_flags & MPS_FLAGS_DIAGRESET) 
 		return  EBUSY;
 
 	cm->cm_complete = NULL;
-	cm->cm_flags |= MPS_CM_FLAGS_WAKEUP;
+	cm->cm_flags |= MPS_CM_FLAGS_POLLED;
 	error = mps_map_command(sc, cm);
 	if ((error != 0) && (error != EINPROGRESS))
 		return (error);
-	error = msleep(cm, &sc->mps_mtx, 0, "mpswait", timeout*hz);
-	if (error == EWOULDBLOCK) {
-		mps_dprint(sc, MPS_FAULT, "Calling Reinit from %s\n", __func__);
-		rc = mps_reinit(sc);
-		mps_dprint(sc, MPS_FAULT, "Reinit %s\n", 
-				(rc == 0) ? "success" : "failed");
-		error = ETIMEDOUT;
-	}
-	return (error);
-}
 
-/*
- * This is the routine to enqueue a command synchonously and poll for
- * completion.  Its use should be rare.
- */
-int
-mps_request_polled(struct mps_softc *sc, struct mps_command *cm)
-{
-	int error, timeout = 0, rc;
-
-	error = 0;
-
-	cm->cm_flags |= MPS_CM_FLAGS_POLLED;
-	cm->cm_complete = NULL;
-	mps_map_command(sc, cm);
-
-	while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) {
-		mps_intr_locked(sc);
-
-		DELAY(50 * 1000);
-		if (timeout++ > 1000) {
-			mps_dprint(sc, MPS_FAULT, "polling failed\n");
-			error = ETIMEDOUT;
-			break;
+	/*
+	 * Check for context and wait for 50 mSec at a time until time has
+	 * expired or the command has finished.  If msleep can't be used, need
+	 * to poll.
+	 */
+	if (curthread->td_no_sleeping != 0)
+		sleep_flag = NO_SLEEP;
+	getmicrouptime(&start_time);
+	if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP) {
+		cm->cm_flags |= MPS_CM_FLAGS_WAKEUP;
+		error = msleep(cm, &sc->mps_mtx, 0, "mpswait", timeout*hz);
+		if (error == EWOULDBLOCK) {
+			/*
+			 * Record the actual elapsed time in the case of a
+			 * timeout for the message below.
+			 */
+			getmicrouptime(&cur_time);
+			timevalsub(&cur_time, &start_time);
 		}
+	} else {
+		while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) {
+			mps_intr_locked(sc);
+			if (sleep_flag == CAN_SLEEP)
+				pause("mpswait", hz/20);
+			else
+				DELAY(50000);
+		
+			getmicrouptime(&cur_time);
+			timevalsub(&cur_time, &start_time);
+			if (cur_time.tv_sec > timeout) {
+				error = EWOULDBLOCK;
+				break;
+			}
+		}
 	}
-	
-	if (error) {
-		mps_dprint(sc, MPS_FAULT, "Calling Reinit from %s\n", __func__);
+
+	if (error == EWOULDBLOCK) {
+		mps_dprint(sc, MPS_FAULT, "Calling Reinit from %s, timeout=%d,"
+		    " elapsed=%jd\n", __func__, timeout,
+		    (intmax_t)cur_time.tv_sec);
 		rc = mps_reinit(sc);
-		mps_dprint(sc, MPS_FAULT, "Reinit %s\n", 
-				(rc == 0) ? "success" : "failed");
+		mps_dprint(sc, MPS_FAULT, "Reinit %s\n", (rc == 0) ? "success" :
+		    "failed");
+		if (sc->mps_flags & MPS_FLAGS_REALLOCATED) {
+			/*
+			 * Tell the caller that we freed the command in a
+			 * reinit.
+			 */
+			*cmp = NULL;
+		}
+		error = ETIMEDOUT;
 	}
-
 	return (error);
 }
 
@@ -2431,9 +2657,12 @@
 
 	cm->cm_data = params->buffer;
 	cm->cm_length = params->length;
-	cm->cm_sge = &req->PageBufferSGE;
-	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
-	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+	if (cm->cm_data != NULL) {
+		cm->cm_sge = &req->PageBufferSGE;
+		cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+		cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+	} else
+		cm->cm_sge = NULL;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 
 	cm->cm_complete_data = params;
@@ -2441,11 +2670,12 @@
 		cm->cm_complete = mps_config_complete;
 		return (mps_map_command(sc, cm));
 	} else {
-		error = mps_wait_command(sc, cm, 0);
+		error = mps_wait_command(sc, &cm, 0, CAN_SLEEP);
 		if (error) {
 			mps_dprint(sc, MPS_FAULT,
 			    "Error %d reading config page\n", error);
-			mps_free_command(sc, cm);
+			if (cm != NULL)
+				mps_free_command(sc, cm);
 			return (error);
 		}
 		mps_config_complete(sc, cm);
@@ -2466,6 +2696,7 @@
 	MPI2_CONFIG_REPLY *reply;
 	struct mps_config_params *params;
 
+	MPS_FUNCTRACE(sc);
 	params = cm->cm_complete_data;
 
 	if (cm->cm_data != NULL) {
@@ -2489,9 +2720,12 @@
 		goto done;
 	}
 	params->status = reply->IOCStatus;
-	if (params->hdr.Ext.ExtPageType != 0) {
+	if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) {
 		params->hdr.Ext.ExtPageType = reply->ExtPageType;
 		params->hdr.Ext.ExtPageLength = reply->ExtPageLength;
+		params->hdr.Ext.PageType = reply->Header.PageType;
+		params->hdr.Ext.PageNumber = reply->Header.PageNumber;
+		params->hdr.Ext.PageVersion = reply->Header.PageVersion;
 	} else {
 		params->hdr.Struct.PageType = reply->Header.PageType;
 		params->hdr.Struct.PageNumber = reply->Header.PageNumber;

Modified: trunk/sys/dev/mps/mps_config.c
===================================================================
--- trunk/sys/dev/mps/mps_config.c	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_config.c	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,11 +25,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/mps/mps_config.c 322661 2017-08-18 15:38:08Z ken $");
 
 /* TODO Move headers to mpsvar */
 #include <sys/types.h>
@@ -70,7 +72,7 @@
     Mpi2IOCPage8_t *config_page)
 {
 	MPI2_CONFIG_REQUEST *request;
-	MPI2_CONFIG_REPLY *reply;
+	MPI2_CONFIG_REPLY *reply = NULL;
 	struct mps_command *cm;
 	MPI2_CONFIG_PAGE_IOC_8 *page = NULL;
 	int error = 0;
@@ -93,12 +95,16 @@
 	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for header completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for header completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -107,7 +113,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: header read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -144,12 +153,17 @@
 		goto out;
 	}
 	cm->cm_data = page;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for page completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for page completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -158,7 +172,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: page read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -186,7 +203,7 @@
 mps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply)
 {
 	MPI2_CONFIG_REQUEST *request;
-	MPI2_CONFIG_REPLY *reply;
+	MPI2_CONFIG_REPLY *reply = NULL;
 	struct mps_command *cm;
 	pMpi2ManufacturingPagePS_t page = NULL;
 	uint32_t *pPS_info;
@@ -211,8 +228,14 @@
 	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+
+	/*
+	 * This page must be polled because the IOC isn't ready yet when this
+	 * page is needed.
+	 */  
+	error = mps_wait_command(sc, &cm, 60, 0);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
 		/* If the poll returns error then we need to do diag reset */ 
@@ -262,8 +285,14 @@
 		goto out;
 	}
 	cm->cm_data = page;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+
+	/*
+	 * This page must be polled because the IOC isn't ready yet when this
+	 * page is needed.
+	 */  
+	error = mps_wait_command(sc, &cm, 60, 0);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
 		/* If the poll returns error then we need to do diag reset */ 
@@ -475,7 +504,8 @@
 		 */
 		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply,
 		    raid_vol_pg0, (u32)raid_vol_pg0->DevHandle)) {
-			if (mpi_reply.IOCStatus !=
+			if ((le16toh(mpi_reply.IOCStatus) &
+			    MPI2_IOCSTATUS_MASK) !=
 			    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
 				mps_dprint(sc, MPS_FAULT,
 				    "Multiple RAID Volume Page0! Direct Drive "
@@ -534,7 +564,7 @@
     Mpi2DriverMappingPage0_t *config_page, u16 sz)
 {
 	MPI2_CONFIG_REQUEST *request;
-	MPI2_CONFIG_REPLY *reply;
+	MPI2_CONFIG_REPLY *reply = NULL;
 	struct mps_command *cm;
 	Mpi2DriverMappingPage0_t *page = NULL;
 	int error = 0;
@@ -561,12 +591,16 @@
 	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for header completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for header completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -575,7 +609,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: header read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -615,12 +652,16 @@
 		goto out;
 	}
 	cm->cm_data = page;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for page completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for page completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -629,7 +670,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: page read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -658,7 +702,7 @@
     Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
 {
 	MPI2_CONFIG_REQUEST *request;
-	MPI2_CONFIG_REPLY *reply;
+	MPI2_CONFIG_REPLY *reply = NULL;
 	struct mps_command *cm;
 	MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;	
 	int error = 0;
@@ -685,12 +729,16 @@
 	request->PageAddress |= htole16(entry_idx);
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for header completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for header completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -699,7 +747,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: header read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -741,12 +792,16 @@
 	bcopy(config_page, page, MIN(cm->cm_length, 
 	    (sizeof(Mpi2DriverMappingPage0_t))));
 	cm->cm_data = page;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for page completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request to write page completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -755,7 +810,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: page written with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -784,7 +842,7 @@
     *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
 {
 	MPI2_CONFIG_REQUEST *request;
-	MPI2_CONFIG_REPLY *reply;
+	MPI2_CONFIG_REPLY *reply = NULL;
 	struct mps_command *cm;
 	Mpi2SasDevicePage0_t *page = NULL;
 	int error = 0;
@@ -808,12 +866,16 @@
 	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for header completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for header completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -822,7 +884,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: header read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -862,12 +927,16 @@
 	}
 	cm->cm_data = page;
 
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for page completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for page completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -876,7 +945,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: page read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -905,7 +977,7 @@
     Mpi2BiosPage3_t *config_page)
 {
 	MPI2_CONFIG_REQUEST *request;
-	MPI2_CONFIG_REPLY *reply;
+	MPI2_CONFIG_REPLY *reply = NULL;
 	struct mps_command *cm;
 	Mpi2BiosPage3_t *page = NULL;
 	int error = 0;
@@ -928,12 +1000,16 @@
 	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for header completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for header completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -942,7 +1018,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: header read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -980,12 +1059,16 @@
 	}
 	cm->cm_data = page;
 
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for page completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for page completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -994,7 +1077,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: page read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -1023,7 +1109,7 @@
     *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address)
 {
 	MPI2_CONFIG_REQUEST *request;
-	MPI2_CONFIG_REPLY *reply;
+	MPI2_CONFIG_REPLY *reply = NULL;
 	struct mps_command *cm;
 	Mpi2RaidVolPage0_t *page = NULL;
 	int error = 0;
@@ -1046,8 +1132,14 @@
 	request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+
+	/*
+	 * This page must be polled because the IOC isn't ready yet when this
+	 * page is needed.
+	 */  
+	error = mps_wait_command(sc, &cm, 60, 0);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
 		/* If the poll returns error then we need to do diag reset */ 
@@ -1099,8 +1191,13 @@
 	}
 	cm->cm_data = page;
 
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	/*
+	 * This page must be polled because the IOC isn't ready yet when this
+	 * page is needed.
+	 */  
+	error = mps_wait_command(sc, &cm, 60, 0);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
 		/* If the poll returns error then we need to do diag reset */ 
@@ -1143,7 +1240,7 @@
     *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle)
 {
 	MPI2_CONFIG_REQUEST *request;
-	MPI2_CONFIG_REPLY *reply;
+	MPI2_CONFIG_REPLY *reply = NULL;
 	struct mps_command *cm;
 	Mpi2RaidVolPage1_t *page = NULL;
 	int error = 0;
@@ -1166,12 +1263,16 @@
 	request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for header completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for header completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -1180,7 +1281,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: header read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -1219,12 +1323,16 @@
 	}
 	cm->cm_data = page;
 
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for page completed with error %d",
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
+		printf("%s: request for page completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -1233,7 +1341,10 @@
 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
+		/*
+		 * If the request returns an error then we need to do a diag
+		 * reset
+		 */ 
 		printf("%s: page read with error; iocstatus = 0x%x\n",
 		    __func__, ioc_status);
 		error = ENXIO;
@@ -1288,7 +1399,7 @@
     Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address)
 {
 	MPI2_CONFIG_REQUEST *request;
-	MPI2_CONFIG_REPLY *reply;
+	MPI2_CONFIG_REPLY *reply = NULL;
 	struct mps_command *cm;
 	Mpi2RaidPhysDiskPage0_t *page = NULL;
 	int error = 0;
@@ -1311,8 +1422,14 @@
 	request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = NULL;
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+
+	/*
+	 * This page must be polled because the IOC isn't ready yet when this
+	 * page is needed.
+	 */  
+	error = mps_wait_command(sc, &cm, 60, 0);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
 		/* If the poll returns error then we need to do diag reset */ 
@@ -1364,8 +1481,13 @@
 	}
 	cm->cm_data = page;
 
-	error = mps_request_polled(sc, cm);
-	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+	/*
+	 * This page must be polled because the IOC isn't ready yet when this
+	 * page is needed.
+	 */  
+	error = mps_wait_command(sc, &cm, 60, 0);
+	if (cm != NULL)
+		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
 		/* If the poll returns error then we need to do diag reset */ 

Modified: trunk/sys/dev/mps/mps_ioctl.h
===================================================================
--- trunk/sys/dev/mps/mps_ioctl.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_ioctl.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2008 Yahoo!, Inc.
  * All rights reserved.
@@ -27,12 +28,13 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD userland interface
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD userland interface
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mps_ioctl.h 281564 2015-04-15 21:47:15Z slm $
  */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -56,9 +58,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mps_ioctl.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 #ifndef _MPS_IOCTL_H_

Modified: trunk/sys/dev/mps/mps_mapping.c
===================================================================
--- trunk/sys/dev/mps/mps_mapping.c	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_mapping.c	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,11 +25,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/mps/mps_mapping.c 319445 2017-06-01 16:54:10Z slm $");
 
 /* TODO Move headers to mpsvar */
 #include <sys/types.h>
@@ -42,6 +44,7 @@
 #include <sys/bus.h>
 #include <sys/endian.h>
 #include <sys/sysctl.h>
+#include <sys/sbuf.h>
 #include <sys/eventhandler.h>
 #include <sys/uio.h>
 #include <machine/bus.h>
@@ -58,7 +61,7 @@
 #include <dev/mps/mps_mapping.h>
 
 /**
- * _mapping_clear_entry - Clear a particular mapping entry.
+ * _mapping_clear_map_entry - Clear a particular mapping entry.
  * @map_entry: map table entry
  *
  * Returns nothing.
@@ -71,7 +74,6 @@
 	map_entry->phy_bits = 0;
 	map_entry->dpm_entry_num = MPS_DPM_BAD_IDX;
 	map_entry->dev_handle = 0;
-	map_entry->channel = -1;
 	map_entry->id = -1;
 	map_entry->missing_count = 0;
 	map_entry->init_complete = 0;
@@ -138,12 +140,15 @@
 	dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits);
 	dpm_entry->Reserved1 = 0;
 
+	mps_dprint(sc, MPS_MAPPING, "%s: Writing DPM entry %d for enclosure.\n",
+	    __func__, et_entry->dpm_entry_num);
 	memcpy(&config_page.Entry, (u8 *)dpm_entry,
 	    sizeof(Mpi2DriverMap0Entry_t));
 	if (mps_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
 	    et_entry->dpm_entry_num)) {
-		printf("%s: write of dpm entry %d for enclosure failed\n",
-		    __func__, et_entry->dpm_entry_num);
+		mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Write of DPM "
+		    "entry %d for enclosure failed.\n", __func__,
+		    et_entry->dpm_entry_num);
 		dpm_entry->MappingInformation = le16toh(dpm_entry->
 		    MappingInformation);
 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
@@ -162,7 +167,7 @@
 /**
  * _mapping_commit_map_entry - write a particular map table entry in DPM page0.
  * @sc: per adapter object
- * @enc_entry: enclosure table entry
+ * @mt_entry: mapping table entry
  *
  * Returns 0 for success, non-zero for failure.
  */
@@ -178,6 +183,19 @@
 	if (!sc->is_dpm_enable)
 		return 0;
 
+	/*
+	 * It's possible that this Map Entry points to a BAD DPM index. This
+	 * can happen if the Map Entry is a for a missing device and the DPM
+	 * entry that was being used by this device is now being used by some
+	 * new device. So, check for a BAD DPM index and just return if so.
+	 */
+	if (mt_entry->dpm_entry_num == MPS_DPM_BAD_IDX) {
+		mps_dprint(sc, MPS_MAPPING, "%s: DPM entry location for target "
+		    "%d is invalid. DPM will not be written.\n", __func__,
+		    mt_entry->id);
+		return 0;
+	}
+
 	memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
 	memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
@@ -191,13 +209,16 @@
 	dpm_entry->MappingInformation = htole16(mt_entry->missing_count);
 	dpm_entry->PhysicalBitsMapping = 0;
 	dpm_entry->Reserved1 = 0;
-	dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation);
 	memcpy(&config_page.Entry, (u8 *)dpm_entry,
 	    sizeof(Mpi2DriverMap0Entry_t));
+
+	mps_dprint(sc, MPS_MAPPING, "%s: Writing DPM entry %d for target %d.\n",
+	    __func__, mt_entry->dpm_entry_num, mt_entry->id);
 	if (mps_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
 	    mt_entry->dpm_entry_num)) {
-		printf("%s: write of dpm entry %d for device failed\n",
-		    __func__, mt_entry->dpm_entry_num);
+		mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Write of DPM "
+		    "entry %d for target %d failed.\n", __func__,
+		    mt_entry->dpm_entry_num, mt_entry->id);
 		dpm_entry->MappingInformation = le16toh(dpm_entry->
 		    MappingInformation);
 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
@@ -305,7 +326,7 @@
 		et_entry = &sc->enclosure_table[enc_idx];
 		if ((et_entry->missing_count > high_missing_count) &&
 		    !et_entry->skip_search) {
-			high_missing_count =  et_entry->missing_count;
+			high_missing_count = et_entry->missing_count;
 			high_idx = enc_idx;
 		}
 	}
@@ -324,7 +345,7 @@
 static u32
 _mapping_get_high_missing_mt_idx(struct mps_softc *sc)
 {
-	u32 map_idx, high_idx = MPS_ENCTABLE_BAD_IDX;
+	u32 map_idx, high_idx = MPS_MAPTABLE_BAD_IDX;
 	u8 high_missing_count = 0;
 	u32 start_idx, end_idx, start_idx_ir, end_idx_ir;
 	struct dev_mapping_table *mt_entry;
@@ -336,12 +357,13 @@
 	end_idx = sc->max_devices;
 	if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
 		start_idx = 1;
-	if (sc->ir_firmware)
+	if (sc->ir_firmware) {
 		_mapping_get_ir_maprange(sc, &start_idx_ir, &end_idx_ir);
-	if (start_idx == start_idx_ir)
-		start_idx = end_idx_ir + 1;
-	else
-		end_idx = start_idx_ir;
+		if (start_idx == start_idx_ir)
+			start_idx = end_idx_ir + 1;
+		else
+			end_idx = start_idx_ir;
+	}
 	mt_entry = &sc->mapping_table[start_idx];
 	for (map_idx = start_idx; map_idx < end_idx; map_idx++, mt_entry++) {
 		if (mt_entry->missing_count > high_missing_count) {
@@ -367,7 +389,7 @@
 
 	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
 	mt_entry = &sc->mapping_table[start_idx];
-	for (map_idx  = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
+	for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
 		if (mt_entry->physical_id == wwid)
 			return map_idx;
 
@@ -455,20 +477,32 @@
 	u32 high_idx = MPS_MAPTABLE_BAD_IDX;
 	struct dev_mapping_table *mt_entry;
 
+	/*
+	 * The IN_USE flag should be clear if the entry is available to use.
+	 * This flag is cleared on initialization and and when a volume is
+	 * deleted. All other times this flag should be set. If, for some
+	 * reason, a free entry cannot be found, look for the entry with the
+	 * highest missing count just in case there is one.
+	 */
 	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
 
 	mt_entry = &sc->mapping_table[start_idx];
-	for (map_idx  = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
+	for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) {
 		if (!(mt_entry->device_info & MPS_MAP_IN_USE))
 			return map_idx;
 
-	mt_entry = &sc->mapping_table[start_idx];
-	for (map_idx  = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) {
 		if (mt_entry->missing_count > high_missing_count) {
 			high_missing_count = mt_entry->missing_count;
 			high_idx = map_idx;
 		}
 	}
+
+	if (high_idx == MPS_MAPTABLE_BAD_IDX) {
+		mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Could not find a "
+		    "free entry in the mapping table for a Volume. The mapping "
+		    "table is probably corrupt.\n", __func__);
+	}
+	
 	return high_idx;
 }
 
@@ -491,6 +525,7 @@
 	if (sc->ir_firmware && (volume_mapping_flags ==
 	    MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING))
 		max_idx -= sc->max_volumes;
+
 	for (map_idx  = start_idx; map_idx < max_idx; map_idx++, mt_entry++)
 		if (!(mt_entry->device_info & (MPS_MAP_IN_USE |
 		    MPS_DEV_RESERVED)))
@@ -539,12 +574,66 @@
 _mapping_get_free_dpm_idx(struct mps_softc *sc)
 {
 	u16 entry_num;
+	Mpi2DriverMap0Entry_t *dpm_entry;
+	u16 current_entry = MPS_DPM_BAD_IDX, missing_cnt, high_missing_cnt = 0;
+	u64 physical_id;
+	struct dev_mapping_table *mt_entry;
+	u32 map_idx;
 
-	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
-		if (!sc->dpm_entry_used[entry_num])
-			return entry_num;
+ 	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
+		dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
+		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+		dpm_entry += entry_num;
+		missing_cnt = dpm_entry->MappingInformation &
+		    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
+
+		/*
+		 * If entry is used and not missing, then this entry can't be
+		 * used. Look at next one.
+		 */
+		if (sc->dpm_entry_used[entry_num] && !missing_cnt)
+			continue;
+
+		/*
+		 * If this entry is not used at all, then the missing count
+		 * doesn't matter. Just use this one. Otherwise, keep looking
+		 * and make sure the entry with the highest missing count is
+		 * used.
+		 */
+		if (!sc->dpm_entry_used[entry_num]) {
+			current_entry = entry_num;
+			break;
+		}
+		if ((current_entry == MPS_DPM_BAD_IDX) ||
+		    (missing_cnt > high_missing_cnt)) {
+			current_entry = entry_num;
+			high_missing_cnt = missing_cnt;
+		}
+ 	}
+
+	/*
+	 * If an entry has been found to use and it's already marked as used
+	 * it means that some device was already using this entry but it's
+	 * missing, and that means that the connection between the missing
+	 * device's DPM entry and the mapping table needs to be cleared. To do
+	 * this, use the Physical ID of the old device still in the DPM entry
+	 * to find its mapping table entry, then mark its DPM entry as BAD.
+	 */
+	if ((current_entry != MPS_DPM_BAD_IDX) &&
+	    sc->dpm_entry_used[current_entry]) {
+		dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
+		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
+		dpm_entry += current_entry;
+		physical_id = dpm_entry->PhysicalIdentifier.High;
+		physical_id = (physical_id << 32) |
+		    dpm_entry->PhysicalIdentifier.Low;
+		map_idx = _mapping_get_mt_idx_from_id(sc, physical_id);
+		if (map_idx != MPS_MAPTABLE_BAD_IDX) {
+			mt_entry = &sc->mapping_table[map_idx];
+			mt_entry->dpm_entry_num = MPS_DPM_BAD_IDX;
+		}
 	}
-	return MPS_DPM_BAD_IDX;
+	return current_entry;
 }
 
 /**
@@ -563,40 +652,57 @@
     Mpi2EventIrConfigElement_t *element, u64 wwid)
 {
 	struct dev_mapping_table *mt_entry;
-	u8 missing_cnt, reason = element->ReasonCode;
+	u8 missing_cnt, reason = element->ReasonCode, update_dpm = 1;
 	u16 dpm_idx;
 	Mpi2DriverMap0Entry_t *dpm_entry;
 
-	if (!sc->is_dpm_enable)
-		return;
+	/*
+	 * Depending on the reason code, update the missing count. Always set
+	 * the init_complete flag when here, so just do it first. That flag is
+	 * used for volumes to make sure that the DPM entry has been updated.
+	 * When a volume is deleted, clear the map entry's IN_USE flag so that
+	 * the entry can be used again if another volume is created. Also clear
+	 * its dev_handle entry so that other functions can't find this volume
+	 * by the handle, since it's not defined any longer.
+	 */
 	mt_entry = &sc->mapping_table[map_idx];
-	if (reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) {
+	mt_entry->init_complete = 1;
+	if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) ||
+	    (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED)) {
 		mt_entry->missing_count = 0;
-	} else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
-		mt_entry->missing_count = 0;
-		mt_entry->init_complete = 0;
-	} else if ((reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED) ||
-	    (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)) {
-		if (!mt_entry->init_complete) {
-			if (mt_entry->missing_count < MPS_MAX_MISSING_COUNT)
-				mt_entry->missing_count++;
-			else
-				mt_entry->init_complete = 1;
-		}
-		if (!mt_entry->missing_count)
+	} else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) {
+		if (mt_entry->missing_count < MPS_MAX_MISSING_COUNT)
 			mt_entry->missing_count++;
+
+		mt_entry->device_info &= ~MPS_MAP_IN_USE;
 		mt_entry->dev_handle = 0;
 	}
 
+	/*
+	 * If persistent mapping is enabled, update the DPM with the new missing
+	 * count for the volume. If the DPM index is bad, get a free one. If
+	 * it's bad for a volume that's being deleted do nothing because that
+	 * volume doesn't have a DPM entry. 
+	 */
+	if (!sc->is_dpm_enable)
+		return;
 	dpm_idx = mt_entry->dpm_entry_num;
 	if (dpm_idx == MPS_DPM_BAD_IDX) {
-		if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) ||
-		    (reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED))
-			dpm_idx = _mapping_get_dpm_idx_from_id(sc,
-			    mt_entry->physical_id, 0);
-		else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)
+		if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)
+		{
+			mps_dprint(sc, MPS_MAPPING, "%s: Volume being deleted "
+			    "is not in DPM so DPM missing count will not be "
+			    "updated.\n", __func__);
 			return;
+		}
 	}
+	if (dpm_idx == MPS_DPM_BAD_IDX)
+		dpm_idx = _mapping_get_free_dpm_idx(sc);
+
+	/*
+	 * Got the DPM entry for the volume or found a free DPM entry if this is
+	 * a new volume. Check if the current information is outdated.
+	 */
 	if (dpm_idx != MPS_DPM_BAD_IDX) {
 		dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
@@ -604,17 +710,25 @@
 		missing_cnt = dpm_entry->MappingInformation &
 		    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
 		if ((mt_entry->physical_id ==
-		    le64toh((u64)dpm_entry->PhysicalIdentifier.High |
-		    dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt ==
-		    mt_entry->missing_count))
-			mt_entry->init_complete = 1;
-	} else {
-		dpm_idx = _mapping_get_free_dpm_idx(sc);
-		mt_entry->init_complete = 0;
+		    le64toh(((u64)dpm_entry->PhysicalIdentifier.High << 32) |
+		    (u64)dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt ==
+		    mt_entry->missing_count)) {
+			mps_dprint(sc, MPS_MAPPING, "%s: DPM entry for volume "
+			   "with target ID %d does not require an update.\n",
+			    __func__, mt_entry->id);
+			update_dpm = 0;
+		}
 	}
 
-	if ((dpm_idx != MPS_DPM_BAD_IDX) && !mt_entry->init_complete) {
-		mt_entry->init_complete = 1;
+	/*
+	 * Update the volume's persistent info if it's new or the ID or missing
+	 * count has changed. If a good DPM index has not been found by now,
+	 * there is no space left in the DPM table.
+	 */
+	if ((dpm_idx != MPS_DPM_BAD_IDX) && update_dpm) {
+		mps_dprint(sc, MPS_MAPPING, "%s: Update DPM entry for volume "
+		    "with target ID %d.\n", __func__, mt_entry->id);
+
 		mt_entry->dpm_entry_num = dpm_idx;
 		dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
@@ -630,44 +744,47 @@
 		sc->dpm_flush_entry[dpm_idx] = 1;
 		sc->dpm_entry_used[dpm_idx] = 1;
 	} else if (dpm_idx == MPS_DPM_BAD_IDX) {
-		printf("%s: no space to add entry in DPM table\n", __func__);
-		mt_entry->init_complete = 1;
+		mps_dprint(sc, MPS_INFO | MPS_MAPPING, "%s: No space to add an "
+		    "entry in the DPM table for volume with target ID %d.\n",
+		    __func__, mt_entry->id);
 	}
 }
 
 /**
- * _mapping_add_to_removal_table - mark an entry for removal
+ * _mapping_add_to_removal_table - add DPM index to the removal table
  * @sc: per adapter object
- * @handle: Handle of enclosures/device/volume
+ * @dpm_idx: Index of DPM entry to remove
  *
- * Adds the handle or DPM entry number in removal table.
+ * Adds a DPM entry number to the removal table.
  *
  * Returns nothing.
  */
 static void
-_mapping_add_to_removal_table(struct mps_softc *sc, u16 handle,
-    u16 dpm_idx)
+_mapping_add_to_removal_table(struct mps_softc *sc, u16 dpm_idx)
 {
 	struct map_removal_table *remove_entry;
 	u32 i;
-	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
 
+	/*
+	 * This is only used to remove entries from the DPM in the controller.
+	 * If DPM is not enabled, just return.
+	 */
+	if (!sc->is_dpm_enable)
+		return;
+
+	/*
+	 * Find the first available removal_table entry and add the new entry
+	 * there.
+	 */
 	remove_entry = sc->removal_table;
 
 	for (i = 0; i < sc->max_devices; i++, remove_entry++) {
-		if (remove_entry->dev_handle || remove_entry->dpm_entry_num !=
-		    MPS_DPM_BAD_IDX)
+		if (remove_entry->dpm_entry_num != MPS_DPM_BAD_IDX)
 			continue;
-		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
-		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
-			if (dpm_idx)
-				remove_entry->dpm_entry_num = dpm_idx;
-			if (remove_entry->dpm_entry_num == MPS_DPM_BAD_IDX)
-				remove_entry->dev_handle = handle;
-		} else if ((ioc_pg8_flags &
-		    MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
-		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING)
-			remove_entry->dev_handle = handle;
+ 
+		mps_dprint(sc, MPS_MAPPING, "%s: Adding DPM entry %d to table "
+		    "for removal.\n", __func__, dpm_idx);
+		remove_entry->dpm_entry_num = dpm_idx;
 		break;
 	}
 
@@ -678,8 +795,13 @@
  * @sc: per adapter object
  * @topo_change: Topology change event entry
  *
- * Search through the topology change list and if any device is found not
- * responding it's associated map table entry and DPM entry is updated
+ * Increment the missing count in the mapping table for a device that is not
+ * responding. If Persitent Mapping is used, increment the DPM entry as well.
+ * Currently, this function only increments the missing count if the device 
+ * goes missing, so after initialization has completed. This means that the
+ * missing count can only go from 0 to 1 here. The missing count is incremented
+ * during initialization as well, so that's where a target's missing count can
+ * go past 1.
  *
  * Returns nothing.
  */
@@ -703,34 +825,45 @@
 		    dev_handle);
 		phy_change->is_processed = 1;
 		if (map_idx == MPS_MAPTABLE_BAD_IDX) {
-			printf("%s: device is already removed from mapping "
-			    "table\n", __func__);
+			mps_dprint(sc, MPS_INFO | MPS_MAPPING, "%s: device is "
+			    "already removed from mapping table\n", __func__);
 			continue;
 		}
 		mt_entry = &sc->mapping_table[map_idx];
-		if (!mt_entry->init_complete) {
-			if (mt_entry->missing_count < MPS_MAX_MISSING_COUNT)
-				mt_entry->missing_count++;
-			else
-				mt_entry->init_complete = 1;
-		}
-		if (!mt_entry->missing_count)
+		if (mt_entry->missing_count < MPS_MAX_MISSING_COUNT)
 			mt_entry->missing_count++;
-		_mapping_add_to_removal_table(sc, mt_entry->dev_handle, 0);
-		mt_entry->dev_handle = 0;
 
+		/*
+		 * When using Enc/Slot mapping, when a device is removed, it's
+		 * mapping table information should be cleared. Otherwise, the
+		 * target ID will be incorrect if this same device is re-added
+		 * to a different slot.
+		 */
+		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
+			_mapping_clear_map_entry(mt_entry);
+		}
+
+		/*
+		 * When using device mapping, update the missing count in the
+		 * DPM entry, but only if the missing count has changed.
+		 */
 		if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) &&
-		    sc->is_dpm_enable && !mt_entry->init_complete &&
+		    sc->is_dpm_enable &&
 		    mt_entry->dpm_entry_num != MPS_DPM_BAD_IDX) {
 			dpm_entry =
 			    (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
 			    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
 			dpm_entry += mt_entry->dpm_entry_num;
-			dpm_entry->MappingInformation = mt_entry->missing_count;
-			sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1;
+			if (dpm_entry->MappingInformation !=
+			    mt_entry->missing_count) {
+				dpm_entry->MappingInformation =
+				    mt_entry->missing_count;
+				sc->dpm_flush_entry[mt_entry->dpm_entry_num] =
+				    1;
+			}
 		}
-		mt_entry->init_complete = 1;
 	}
 }
 
@@ -763,6 +896,10 @@
 	vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
 
+	/*
+	 * The end of the mapping table depends on where volumes are kept, if
+	 * IR is enabled.
+	 */
 	if (!sc->ir_firmware)
 		end_of_table = sc->max_devices;
 	else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING)
@@ -770,6 +907,17 @@
 	else
 		end_of_table = sc->max_devices - sc->max_volumes;
 
+	/*
+	 * The skip_count is the number of entries that are reserved at the
+	 * beginning of the mapping table. But, it does not include the number
+	 * of Physical IDs that are reserved for direct attached devices. Look
+	 * through the mapping table after these reserved entries to see if 
+	 * the devices for this enclosure are already mapped. The PHY bit check
+	 * is used to make sure that at least one PHY bit is common between the
+	 * enclosure and the device that is already mapped.
+	 */
+	mps_dprint(sc, MPS_MAPPING, "%s: Looking for space in the mapping "
+	    "table for added enclosure.\n", __func__);
 	for (map_idx = (max_num_phy_ids + skip_count);
 	    map_idx < end_of_table; map_idx++) {
 		mt_entry = &sc->mapping_table[map_idx];
@@ -779,11 +927,21 @@
 			num_found += 1;
 			if (num_found == et_entry->num_slots) {
 				start_idx = (map_idx - num_found) + 1;
+				mps_dprint(sc, MPS_MAPPING, "%s: Found space "
+				    "in the mapping for enclosure at map index "
+				    "%d.\n", __func__, start_idx);
 				return start_idx;
 			}
 		} else
 			num_found = 0;
 	}
+
+	/*
+	 * If the enclosure's devices are not mapped already, look for
+	 * contiguous entries in the mapping table that are not reserved. If
+	 * enough entries are found, return the starting index for that space.
+	 */
+	num_found = 0;
 	for (map_idx = (max_num_phy_ids + skip_count);
 	    map_idx < end_of_table; map_idx++) {
 		mt_entry = &sc->mapping_table[map_idx];
@@ -791,6 +949,9 @@
 			num_found += 1;
 			if (num_found == et_entry->num_slots) {
 				start_idx = (map_idx - num_found) + 1;
+				mps_dprint(sc, MPS_MAPPING, "%s: Found space "
+				    "in the mapping for enclosure at map index "
+				    "%d.\n", __func__, start_idx);
 				return start_idx;
 			}
 		} else
@@ -797,21 +958,58 @@
 			num_found = 0;
 	}
 
+	/*
+	 * If here, it means that not enough space in the mapping table was
+	 * found to support this enclosure, so go through the enclosure table to
+	 * see if any enclosure entries have a missing count. If so, get the
+	 * enclosure with the highest missing count and check it to see if there
+	 * is enough space for the new enclosure.
+	 */
 	while (!done_flag) {
 		enc_idx = _mapping_get_high_missing_et_idx(sc);
-		if (enc_idx == MPS_ENCTABLE_BAD_IDX)
+		if (enc_idx == MPS_ENCTABLE_BAD_IDX) {
+			mps_dprint(sc, MPS_MAPPING, "%s: Not enough space was "
+			    "found in the mapping for the added enclosure.\n",
+			    __func__);
 			return MPS_MAPTABLE_BAD_IDX;
+		}
+
+		/*
+		 * Found a missing enclosure. Set the skip_search flag so this
+		 * enclosure is not checked again for a high missing count if
+		 * the loop continues. This way, all missing enclosures can
+		 * have their space added together to find enough space in the
+		 * mapping table for the added enclosure. The space must be
+		 * contiguous.
+		 */
+		mps_dprint(sc, MPS_MAPPING, "%s: Space from a missing "
+		    "enclosure was found.\n", __func__);
 		enc_entry = &sc->enclosure_table[enc_idx];
-		/*VSP FIXME*/
 		enc_entry->skip_search = 1;
+
+		/*
+		 * Unmark all of the missing enclosure's device's reserved
+		 * space. These will be remarked as reserved if this missing
+		 * enclosure's space is not used.
+		 */
+		mps_dprint(sc, MPS_MAPPING, "%s: Clear the reserved flag for "
+		    "all of the map entries for the enclosure.\n", __func__);
 		mt_entry = &sc->mapping_table[enc_entry->start_index];
 		for (map_idx = enc_entry->start_index; map_idx <
 		    (enc_entry->start_index + enc_entry->num_slots); map_idx++,
 		    mt_entry++)
-			mt_entry->device_info  &= ~MPS_DEV_RESERVED;
+			mt_entry->device_info &= ~MPS_DEV_RESERVED;
+
+		/*
+		 * Now that space has been unreserved, check again to see if
+		 * enough space is available for the new enclosure.
+		 */
+		mps_dprint(sc, MPS_MAPPING, "%s: Check if new mapping space is "
+		    "enough for the new enclosure.\n", __func__);
 		found_space = 0;
-		for (map_idx = (max_num_phy_ids +
-		    skip_count); map_idx < end_of_table; map_idx++) {
+		num_found = 0;
+		for (map_idx = (max_num_phy_ids + skip_count);
+		    map_idx < end_of_table; map_idx++) {
 			mt_entry = &sc->mapping_table[map_idx];
 			if (!(mt_entry->device_info & MPS_DEV_RESERVED)) {
 				num_found += 1;
@@ -818,13 +1016,24 @@
 				if (num_found == et_entry->num_slots) {
 					start_idx = (map_idx - num_found) + 1;
 					found_space = 1;
+					break;
 				}
 			} else
 				num_found = 0;
 		}
-
 		if (!found_space)
 			continue;
+
+		/*
+		 * If enough space was found, all of the missing enclosures that
+		 * will be used for the new enclosure must be added to the
+		 * removal table. Then all mappings for the enclosure's devices
+		 * and for the enclosure itself need to be cleared. There may be
+		 * more than one enclosure to add to the removal table and
+		 * clear.
+		 */
+		mps_dprint(sc, MPS_MAPPING, "%s: Found space in the mapping "
+		    "for enclosure at map index %d.\n", __func__, start_idx);
 		for (map_idx = start_idx; map_idx < (start_idx + num_found);
 		    map_idx++) {
 			enc_entry = sc->enclosure_table;
@@ -835,26 +1044,38 @@
 				    enc_entry->num_slots))
 					continue;
 				if (!enc_entry->removal_flag) {
+					mps_dprint(sc, MPS_MAPPING, "%s: "
+					    "Enclosure %d will be removed from "
+					    "the mapping table.\n", __func__,
+					    enc_idx);
 					enc_entry->removal_flag = 1;
-					_mapping_add_to_removal_table(sc, 0,
+					_mapping_add_to_removal_table(sc,
 					    enc_entry->dpm_entry_num);
 				}
 				mt_entry = &sc->mapping_table[map_idx];
-				if (mt_entry->device_info &
-				    MPS_MAP_IN_USE) {
-					_mapping_add_to_removal_table(sc,
-					    mt_entry->dev_handle, 0);
-					_mapping_clear_map_entry(mt_entry);
-				}
+				_mapping_clear_map_entry(mt_entry);
 				if (map_idx == (enc_entry->start_index +
 				    enc_entry->num_slots - 1))
 					_mapping_clear_enc_entry(et_entry);
 			}
 		}
+
+		/*
+		 * During the search for space for this enclosure, some entries
+		 * in the mapping table may have been unreserved. Go back and
+		 * change all of these to reserved again. Only the enclosures
+		 * with the removal_flag set should be left as unreserved. The
+		 * skip_search flag needs to be cleared as well so that the
+		 * enclosure's space will be looked at the next time space is
+		 * needed.
+		 */ 
 		enc_entry = sc->enclosure_table;
 		for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
 		    enc_idx++, enc_entry++) {
 			if (!enc_entry->removal_flag) {
+				mps_dprint(sc, MPS_MAPPING, "%s: Reset the "
+				    "reserved flag for all of the map entries "
+				    "for enclosure %d.\n", __func__, enc_idx);
 				mt_entry = &sc->mapping_table[enc_entry->
 				    start_index];
 				for (map_idx = enc_entry->start_index; map_idx <
@@ -895,7 +1116,7 @@
 	struct enc_mapping_table *et_entry;
 	struct dev_mapping_table *mt_entry;
 	u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED;
-	int rc;
+	int rc = 1;
 
 	for (entry = 0; entry < topo_change->num_entries; entry++) {
 		phy_change = &topo_change->phy_details[entry];
@@ -902,6 +1123,7 @@
 		if (phy_change->is_processed || !phy_change->dev_handle ||
 		    phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED)
 			continue;
+
 		if (mps_config_get_sas_device_pg0(sc, &mpi_reply,
 		    &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
 		    phy_change->dev_handle)) {
@@ -909,51 +1131,55 @@
 			continue;
 		}
 
+		/*
+		 * Always get SATA Identify information because this is used
+		 * to determine if Start/Stop Unit should be sent to the drive
+		 * when the system is shutdown.
+		 */
 		device_info = le32toh(sas_device_pg0.DeviceInfo);
-		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
-		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
-			if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
-			    (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) {
-				rc = mpssas_get_sas_address_for_sata_disk(sc,
-				    &sas_address, phy_change->dev_handle,
-				    device_info);
-				if (rc) {
-					printf("%s: failed to compute the "
-					    "hashed SAS Address for SATA "
-					    "device with handle 0x%04x\n",
-					    __func__, phy_change->dev_handle);
-					sas_address =
-					    sas_device_pg0.SASAddress.High;
-					sas_address = (sas_address << 32) |
-					    sas_device_pg0.SASAddress.Low;
-				}
+		sas_address = le32toh(sas_device_pg0.SASAddress.High);
+		sas_address = (sas_address << 32) |
+		    le32toh(sas_device_pg0.SASAddress.Low);
+		if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
+		    (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) {
+			rc = mpssas_get_sas_address_for_sata_disk(sc,
+			    &sas_address, phy_change->dev_handle, device_info,
+			    &phy_change->is_SATA_SSD);
+			if (rc) {
+				mps_dprint(sc, MPS_ERROR, "%s: failed to get "
+				    "disk type (SSD or HDD) and SAS Address "
+				    "for SATA device with handle 0x%04x\n",
+				    __func__, phy_change->dev_handle);
+			} else {
 				mps_dprint(sc, MPS_INFO, "SAS Address for SATA "
-					   "device = %jx\n", sas_address);
-			} else {
-				sas_address =
-					sas_device_pg0.SASAddress.High;
-				sas_address = (sas_address << 32) |
-					sas_device_pg0.SASAddress.Low;
+				    "device = %jx\n", sas_address);
 			}
-		} else {
-			sas_address = sas_device_pg0.SASAddress.High;
-			sas_address = (sas_address << 32) |
-			   sas_device_pg0.SASAddress.Low;
 		}
+
 		phy_change->physical_id = sas_address;
 		phy_change->slot = le16toh(sas_device_pg0.Slot);
-		phy_change->device_info =
-		    le32toh(sas_device_pg0.DeviceInfo);
+		phy_change->device_info = device_info;
 
+		/*
+		 * When using Enc/Slot mapping, if this device is an enclosure
+		 * make sure that all of its slots can fit into the mapping
+		 * table.
+		 */
 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
+			/*
+			 * The enclosure should already be in the enclosure
+			 * table due to the Enclosure Add event. If not, just
+			 * continue, nothing can be done.
+			 */
 			enc_idx = _mapping_get_enc_idx_from_handle(sc,
 			    topo_change->enc_handle);
 			if (enc_idx == MPS_ENCTABLE_BAD_IDX) {
 				phy_change->is_processed = 1;
-				printf("%s: failed to add the device with "
-				    "handle 0x%04x because the enclosure is "
-				    "not in the mapping table\n", __func__,
+				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
+				    "failed to add the device with handle "
+				    "0x%04x because the enclosure is not in "
+				    "the mapping table\n", __func__,
 				    phy_change->dev_handle);
 				continue;
 			}
@@ -967,8 +1193,20 @@
 				continue;
 			}
 			et_entry = &sc->enclosure_table[enc_idx];
+
+			/*
+			 * If the enclosure already has a start_index, it's been
+			 * mapped, so go to the next Topo change.
+			 */
 			if (et_entry->start_index != MPS_MAPTABLE_BAD_IDX)
 				continue;
+
+			/*
+			 * If the Expander Handle is 0, the devices are direct
+			 * attached. In that case, the start_index must be just 
+			 * after the reserved entries. Otherwise, find space in
+			 * the mapping table for the enclosure's devices.
+			 */ 
 			if (!topo_change->exp_handle) {
 				map_idx	= sc->num_rsvd_entries;
 				et_entry->start_index = map_idx;
@@ -976,8 +1214,26 @@
 				map_idx = _mapping_find_enc_map_space(sc,
 				    et_entry);
 				et_entry->start_index = map_idx;
+
+				/*
+				 * If space cannot be found to hold all of the
+				 * enclosure's devices in the mapping table,
+				 * there's no need to continue checking the
+				 * other devices in this event. Set all of the
+				 * phy_details for this event (if the change is
+				 * for an add) as already processed because none
+				 * of these devices can be added to the mapping
+				 * table.
+				 */
 				if (et_entry->start_index ==
 				    MPS_MAPTABLE_BAD_IDX) {
+					mps_dprint(sc, MPS_ERROR | MPS_MAPPING,
+					    "%s: failed to add the enclosure "
+					    "with ID 0x%016jx because there is "
+					    "no free space available in the "
+					    "mapping table for all of the "
+					    "enclosure's devices.\n", __func__,
+					    (uintmax_t)et_entry->enclosure_id);
 					phy_change->is_processed = 1;
 					for (phy_idx = 0; phy_idx <
 					    topo_change->num_entries;
@@ -993,6 +1249,15 @@
 					break;
 				}
 			}
+
+			/*
+			 * Found space in the mapping table for this enclosure.
+			 * Initialize each mapping table entry for the
+			 * enclosure.
+			 */
+			mps_dprint(sc, MPS_MAPPING, "%s: Initialize %d map "
+			    "entries for the enclosure, starting at map index "
+			    " %d.\n", __func__, et_entry->num_slots, map_idx);
 			mt_entry = &sc->mapping_table[map_idx];
 			for (index = map_idx; index < (et_entry->num_slots
 			    + map_idx); index++, mt_entry++) {
@@ -999,6 +1264,7 @@
 				mt_entry->device_info = MPS_DEV_RESERVED;
 				mt_entry->physical_id = et_entry->enclosure_id;
 				mt_entry->phy_bits = et_entry->phy_bits;
+				mt_entry->missing_count = 0;
 			}
 		}
 	}
@@ -1018,6 +1284,7 @@
 	struct dev_mapping_table *mt_entry;
 	u16 slots = et_entry->num_slots, map_idx;
 	u32 start_idx = et_entry->start_index;
+
 	if (start_idx != MPS_MAPTABLE_BAD_IDX) {
 		mt_entry = &sc->mapping_table[start_idx];
 		for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++)
@@ -1067,6 +1334,13 @@
 			}
 		}
 	}
+
+	/*
+	 * When using Enc/Slot mapping, if a new enclosure was added and old
+	 * enclosure space was needed, the enclosure table may now have gaps
+	 * that need to be closed. All enclosure mappings need to be contiguous
+	 * so that space can be reused correctly if available.
+	 */
 	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
 		num_entries = sc->num_enc_table_entries;
@@ -1109,8 +1383,8 @@
  * @sc: per adapter object
  * @topo_change: Topology change event entry
  *
- * Search through the topology change event list and updates map table,
- * enclosure table and DPM pages for for the newly added devices.
+ * Search through the topology change event list and update map table,
+ * enclosure table and DPM pages for the newly added devices.
  *
  * Returns nothing
  */
@@ -1147,30 +1421,41 @@
 			    (sc, topo_change->enc_handle);
 			if (enc_idx == MPS_ENCTABLE_BAD_IDX) {
 				phy_change->is_processed = 1;
-				printf("%s: failed to add the device with "
-				    "handle 0x%04x because the enclosure is "
-				    "not in the mapping table\n", __func__,
+				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
+				    "failed to add the device with handle "
+				    "0x%04x because the enclosure is not in "
+				    "the mapping table\n", __func__,
 				    phy_change->dev_handle);
 				continue;
 			}
+
+			/*
+			 * If the enclosure's start_index is BAD here, it means
+			 * that there is no room in the mapping table to cover
+			 * all of the devices that could be in the enclosure.
+			 * There's no reason to process any of the devices for
+			 * this enclosure since they can't be mapped.
+			 */
 			et_entry = &sc->enclosure_table[enc_idx];
 			if (et_entry->start_index == MPS_MAPTABLE_BAD_IDX) {
 				phy_change->is_processed = 1;
-				if (!sc->mt_full_retry) {
-					sc->mt_add_device_failed = 1;
-					continue;
-				}
-				printf("%s: failed to add the device with "
-				    "handle 0x%04x because there is no free "
-				    "space available in the mapping table\n",
+				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
+				    "failed to add the device with handle "
+				    "0x%04x because there is no free space "
+				    "available in the mapping table\n",
 				    __func__, phy_change->dev_handle);
 				continue;
 			}
+
+			/*
+			 * Add this device to the mapping table at the correct
+			 * offset where space was found to map the enclosure.
+			 * Then setup the DPM entry information if being used.
+			 */
 			map_idx = et_entry->start_index + phy_change->slot -
 			    et_entry->start_slot;
 			mt_entry = &sc->mapping_table[map_idx];
 			mt_entry->physical_id = phy_change->physical_id;
-			mt_entry->channel = 0;
 			mt_entry->id = map_idx;
 			mt_entry->dev_handle = phy_change->dev_handle;
 			mt_entry->missing_count = 0;
@@ -1197,12 +1482,12 @@
 						    et_entry->enclosure_id);
 						dpm_entry->
 						    PhysicalIdentifier.High =
-						    ( et_entry->enclosure_id
+						    (et_entry->enclosure_id
 						     >> 32);
 						dpm_entry->DeviceIndex =
 						    (U16)et_entry->start_index;
 						dpm_entry->MappingInformation =
-							et_entry->num_slots;
+						    et_entry->num_slots;
 						dpm_entry->MappingInformation
 						    <<= map_shift;
 						dpm_entry->PhysicalBitsMapping
@@ -1209,7 +1494,6 @@
 						    = et_entry->phy_bits;
 						et_entry->dpm_entry_num =
 						    dpm_idx;
-		/* FIXME Do I need to set the dpm_idxin mt_entry too */
 						sc->dpm_entry_used[dpm_idx] = 1;
 						sc->dpm_flush_entry[dpm_idx] =
 						    1;
@@ -1216,12 +1500,13 @@
 						phy_change->is_processed = 1;
 					} else {
 						phy_change->is_processed = 1;
-						printf("%s: failed to add the "
-						    "device with handle 0x%04x "
-						    "to persistent table "
-						    "because there is no free "
-						    "space available\n",
-						    __func__,
+						mps_dprint(sc, MPS_ERROR |
+						    MPS_MAPPING, "%s: failed "
+						    "to add the device with "
+						    "handle 0x%04x to "
+						    "persistent table because "
+						    "there is no free space "
+						    "available\n", __func__,
 						    phy_change->dev_handle);
 					}
 				} else {
@@ -1229,11 +1514,20 @@
 					mt_entry->dpm_entry_num = dpm_idx;
 				}
 			}
-			/* FIXME Why not mt_entry too? */
 			et_entry->init_complete = 1;
 		} else if ((ioc_pg8_flags &
 		    MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
+
+			/*
+			 * Get the mapping table index for this device. If it's
+			 * not in the mapping table yet, find a free entry if
+			 * one is available. If there are no free entries, look
+			 * for the entry that has the highest missing count. If
+			 * none of that works to find an entry in the mapping
+			 * table, there is a problem. Log a message and just
+			 * continue on.
+			 */
 			map_idx = _mapping_get_mt_idx_from_id
 			    (sc, phy_change->physical_id);
 			if (map_idx == MPS_MAPTABLE_BAD_IDX) {
@@ -1243,16 +1537,18 @@
 				map_idx = _mapping_get_free_mt_idx(sc,
 				    search_idx);
 			}
+
+			/*
+			 * If an entry will be used that has a missing device,
+			 * clear its entry from  the DPM in the controller.
+			 */
 			if (map_idx == MPS_MAPTABLE_BAD_IDX) {
 				map_idx = _mapping_get_high_missing_mt_idx(sc);
 				if (map_idx != MPS_MAPTABLE_BAD_IDX) {
 					mt_entry = &sc->mapping_table[map_idx];
-					if (mt_entry->dev_handle) {
-						_mapping_add_to_removal_table
-						    (sc, mt_entry->dev_handle,
-						     0);
-						is_removed = 1;
-					}
+					_mapping_add_to_removal_table(sc,
+					    mt_entry->dpm_entry_num);
+					is_removed = 1;
 					mt_entry->init_complete = 0;
 				}
 			}
@@ -1259,7 +1555,6 @@
 			if (map_idx != MPS_MAPTABLE_BAD_IDX) {
 				mt_entry = &sc->mapping_table[map_idx];
 				mt_entry->physical_id = phy_change->physical_id;
-				mt_entry->channel = 0;
 				mt_entry->id = map_idx;
 				mt_entry->dev_handle = phy_change->dev_handle;
 				mt_entry->missing_count = 0;
@@ -1267,13 +1562,10 @@
 				    | (MPS_DEV_RESERVED | MPS_MAP_IN_USE);
 			} else {
 				phy_change->is_processed = 1;
-				if (!sc->mt_full_retry) {
-					sc->mt_add_device_failed = 1;
-					continue;
-				}
-				printf("%s: failed to add the device with "
-				    "handle 0x%04x because there is no free "
-				    "space available in the mapping table\n",
+				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
+				    "failed to add the device with handle "
+				    "0x%04x because there is no free space "
+				    "available in the mapping table\n",
 				    __func__, phy_change->dev_handle);
 				continue;
 			}
@@ -1291,9 +1583,18 @@
 					    PhysicalIdentifier.High;
 					temp64_var = (temp64_var << 32) |
 					   dpm_entry->PhysicalIdentifier.Low;
+
+					/*
+					 * If the Mapping Table's info is not
+					 * the same as the DPM entry, clear the
+					 * init_complete flag so that it's
+					 * updated.
+					 */
 					if ((mt_entry->physical_id ==
 					    temp64_var) && !missing_cnt)
 						mt_entry->init_complete = 1;
+					else
+						mt_entry->init_complete = 0;
 				} else {
 					dpm_idx = _mapping_get_free_dpm_idx(sc);
 					mt_entry->init_complete = 0;
@@ -1300,7 +1601,6 @@
 				}
 				if (dpm_idx != MPS_DPM_BAD_IDX &&
 				    !mt_entry->init_complete) {
-					mt_entry->init_complete = 1;
 					mt_entry->dpm_entry_num = dpm_idx;
 					dpm_entry = (Mpi2DriverMap0Entry_t *)
 					    ((u8 *)sc->dpm_pg0 + hdr_sz);
@@ -1317,14 +1617,13 @@
 					sc->dpm_flush_entry[dpm_idx] = 1;
 					phy_change->is_processed = 1;
 				} else if (dpm_idx == MPS_DPM_BAD_IDX) {
-						phy_change->is_processed = 1;
-						printf("%s: failed to add the "
-						    "device with handle 0x%04x "
-						    "to persistent table "
-						    "because there is no free "
-						    "space available\n",
-						    __func__,
-						    phy_change->dev_handle);
+					phy_change->is_processed = 1;
+					mps_dprint(sc, MPS_ERROR | MPS_MAPPING,
+					    "%s: failed to add the device with "
+					    "handle 0x%04x to persistent table "
+					    "because there is no free space "
+					    "available\n", __func__,
+					    phy_change->dev_handle);
 				}
 			}
 			mt_entry->init_complete = 1;
@@ -1367,10 +1666,13 @@
 		memcpy(&config_page.Entry, (u8 *)dpm_entry,
 		    sizeof(Mpi2DriverMap0Entry_t));
 		/* TODO-How to handle failed writes? */
+		mps_dprint(sc, MPS_MAPPING, "%s: Flushing DPM entry %d.\n",
+		    __func__, entry_num);
 		if (mps_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
 		    entry_num)) {
-			printf("%s: write of dpm entry %d for device failed\n",
-			     __func__, entry_num);
+			mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Flush of "
+			    "DPM entry %d for device failed\n", __func__,
+			    entry_num);
 		} else
 			sc->dpm_flush_entry[entry_num] = 0;
 		dpm_entry->MappingInformation = le16toh(dpm_entry->
@@ -1460,7 +1762,6 @@
 	free(sc->dpm_pg0, M_MPT2);
 }
 
-
 static void
 _mapping_process_dpm_pg0(struct mps_softc *sc)
 {
@@ -1475,9 +1776,20 @@
 	u64 physical_id;
 	u32 phy_bits = 0;
 
+	/*
+	 * start_idx and end_idx are only used for IR.
+	 */
 	if (sc->ir_firmware)
 		_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
 
+	/*
+	 * Look through all of the DPM entries that were read from the
+	 * controller and copy them over to the driver's internal table if they
+	 * have a non-zero ID. At this point, any ID with a value of 0 would be
+	 * invalid, so don't copy it.
+	 */
+	mps_dprint(sc, MPS_MAPPING, "%s: Start copy of %d DPM entries into the "
+	    "mapping table.\n", __func__, sc->max_dpm_entries);
 	dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 +
 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
 	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++, 
@@ -1496,13 +1808,20 @@
 		    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
 		dev_idx = le16toh(dpm_entry->DeviceIndex);
 		phy_bits = le32toh(dpm_entry->PhysicalBitsMapping);
+
+		/*
+		 * Volumes are at special locations in the mapping table so
+		 * account for that. Volume mapping table entries do not depend
+		 * on the type of mapping, so continue the loop after adding
+		 * volumes to the mapping table.
+		 */
 		if (sc->ir_firmware && (dev_idx >= start_idx) &&
 		    (dev_idx <= end_idx)) {
 			mt_entry = &sc->mapping_table[dev_idx];
-			mt_entry->physical_id = dpm_entry->PhysicalIdentifier.High;
+			mt_entry->physical_id =
+			    dpm_entry->PhysicalIdentifier.High;
 			mt_entry->physical_id = (mt_entry->physical_id << 32) |
 			    dpm_entry->PhysicalIdentifier.Low;
-			mt_entry->channel = MPS_RAID_CHANNEL;
 			mt_entry->id = dev_idx;
 			mt_entry->missing_count = missing_cnt;
 			mt_entry->dpm_entry_num = entry_num;
@@ -1511,7 +1830,16 @@
 		}
 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
-			if (dev_idx <  (sc->num_rsvd_entries +
+
+			/*
+			 * The dev_idx for an enclosure is the start index. If
+			 * the start index is within the controller's default
+			 * enclosure area, set the number of slots for this
+			 * enclosure to the max allowed. Otherwise, it should be
+			 * a normal enclosure and the number of slots is in the
+			 * DPM entry's Mapping Information.
+			 */
+			if (dev_idx < (sc->num_rsvd_entries +
 			    max_num_phy_ids)) {
 				slot_id = 0;
 				if (ioc_pg8_flags &
@@ -1526,8 +1854,9 @@
 			}
 			enc_idx = sc->num_enc_table_entries;
 			if (enc_idx >= sc->max_enclosures) {
-				printf("%s: enclosure entries exceed max "
-				    "enclosures of %d\n", __func__,
+				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
+				    "Number of enclosure entries in DPM exceed "
+				    "the max allowed of %d.\n", __func__,
 				    sc->max_enclosures);
 				break;
 			}
@@ -1543,21 +1872,32 @@
 			et_entry->missing_count = missing_cnt;
 			et_entry->phy_bits = phy_bits;
 
+			/*
+			 * Initialize all entries for this enclosure in the
+			 * mapping table and mark them as reserved. The actual
+			 * devices have not been processed yet but when they are
+			 * they will use these entries. If an entry is found
+			 * that already has a valid DPM index, the mapping table
+			 * is corrupt. This can happen if the mapping type is
+			 * changed without clearing all of the DPM entries in
+			 * the controller.
+			 */
 			mt_entry = &sc->mapping_table[dev_idx];
 			for (map_idx = dev_idx; map_idx < (dev_idx + num_slots);
 			    map_idx++, mt_entry++) {
 				if (mt_entry->dpm_entry_num !=
 				    MPS_DPM_BAD_IDX) {
-					printf("%s: conflict in mapping table "
-					    "for enclosure %d\n", __func__,
+					mps_dprint(sc, MPS_ERROR | MPS_MAPPING,
+					    "%s: Conflict in mapping table for "
+					    " enclosure %d\n", __func__,
 					    enc_idx);
 					break;
 				}
-				physical_id = dpm_entry->PhysicalIdentifier.High;
+				physical_id =
+				    dpm_entry->PhysicalIdentifier.High;
 				mt_entry->physical_id = (physical_id << 32) |
 				    dpm_entry->PhysicalIdentifier.Low;
 				mt_entry->phy_bits = phy_bits;
-				mt_entry->channel = 0;
 				mt_entry->id = dev_idx;
 				mt_entry->dpm_entry_num = entry_num;
 				mt_entry->missing_count = missing_cnt;
@@ -1566,11 +1906,18 @@
 		} else if ((ioc_pg8_flags &
 		    MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
+
+			/*
+			 * Device mapping, so simply copy the DPM entries to the
+			 * mapping table, but check for a corrupt mapping table
+			 * (as described above in Enc/Slot mapping).
+			 */
 			map_idx = dev_idx;
 			mt_entry = &sc->mapping_table[map_idx];
 			if (mt_entry->dpm_entry_num != MPS_DPM_BAD_IDX) {
-				printf("%s: conflict in mapping table for "
-				    "device %d\n", __func__, map_idx);
+				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
+				    "Conflict in mapping table for device %d\n",
+				    __func__, map_idx);
 				break;
 			}
 			physical_id = dpm_entry->PhysicalIdentifier.High;
@@ -1577,7 +1924,6 @@
 			mt_entry->physical_id = (physical_id << 32) |
 			    dpm_entry->PhysicalIdentifier.Low;
 			mt_entry->phy_bits = phy_bits;
-			mt_entry->channel = 0;
 			mt_entry->id = dev_idx;
 			mt_entry->missing_count = missing_cnt;
 			mt_entry->dpm_entry_num = entry_num;
@@ -1589,43 +1935,91 @@
 /*
  * mps_mapping_check_devices - start of the day check for device availabilty
  * @sc: per adapter object
- * @sleep_flag: Flag indicating whether this function can sleep or not
  *
  * Returns nothing.
  */
 void
-mps_mapping_check_devices(struct mps_softc *sc, int sleep_flag)
+mps_mapping_check_devices(void *data)
 {
 	u32 i;
-/*	u32 cntdn, i;
-	u32 timeout = 60;*/
 	struct dev_mapping_table *mt_entry;
+	struct mps_softc *sc = (struct mps_softc *)data;
 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
 	struct enc_mapping_table *et_entry;
-	u32 start_idx, end_idx;
+	u32 start_idx = 0, end_idx = 0;
+	u8 stop_device_checks = 0;
 
-	/* We need to ucomment this when this function is called
-	 * from the port enable complete */
-#if 0
+	MPS_FUNCTRACE(sc);
+
+	/*
+	 * Clear this flag so that this function is never called again except
+	 * within this function if the check needs to be done again. The
+	 * purpose is to check for missing devices that are currently in the
+	 * mapping table so do this only at driver init after discovery.
+	 */
 	sc->track_mapping_events = 0;
-	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-	do {
-		if (!sc->pending_map_events)
-			break;
-		if (sleep_flag == CAN_SLEEP)
-			pause("mps_pause", (hz/1000));/* 1msec sleep */
-		else
-			DELAY(500); /* 500 useconds delay */
-	} while (--cntdn);
 
+	/*
+	 * callout synchronization
+	 * This is used to prevent race conditions for the callout. 
+	 */
+	mps_dprint(sc, MPS_MAPPING, "%s: Start check for missing devices.\n",
+	    __func__);
+	mtx_assert(&sc->mps_mtx, MA_OWNED);
+	if ((callout_pending(&sc->device_check_callout)) ||
+	    (!callout_active(&sc->device_check_callout))) {
+		mps_dprint(sc, MPS_MAPPING, "%s: Device Check Callout is "
+		    "already pending or not active.\n", __func__);
+		return;
+	}
+	callout_deactivate(&sc->device_check_callout);
 
-	if (!cntdn)
-		printf("%s: there are %d"
-		    " pending events after %d seconds of delay\n",
-		    __func__, sc->pending_map_events, timeout);
-#endif
-	sc->pending_map_events = 0;
+	/*
+	 * Use callout to check if any devices in the mapping table have been
+	 * processed yet. If ALL devices are marked as not init_complete, no
+	 * devices have been processed and mapped. Until devices are mapped
+	 * there's no reason to mark them as missing. Continue resetting this
+	 * callout until devices have been mapped.
+	 */
+	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
+		et_entry = sc->enclosure_table;
+		for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) {
+			if (et_entry->init_complete) {
+				stop_device_checks = 1;
+				break;
+			}
+		}
+	} else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
+	    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
+		mt_entry = sc->mapping_table;
+		for (i = 0; i < sc->max_devices; i++, mt_entry++) {
+			if (mt_entry->init_complete) {
+				stop_device_checks = 1;
+				break;
+			}
+		}
+	}
 
+	/*
+	 * Setup another callout check after a delay. Keep doing this until
+	 * devices are mapped.
+	 */
+	if (!stop_device_checks) {
+		mps_dprint(sc, MPS_MAPPING, "%s: No devices have been mapped. "
+		    "Reset callout to check again after a %d second delay.\n",
+		    __func__, MPS_MISSING_CHECK_DELAY);
+		callout_reset(&sc->device_check_callout,
+		    MPS_MISSING_CHECK_DELAY * hz, mps_mapping_check_devices,
+		    sc);
+		return;
+	}
+	mps_dprint(sc, MPS_MAPPING, "%s: Device check complete.\n", __func__);
+
+	/*
+	 * Depending on the mapping type, check if devices have been processed
+	 * and update their missing counts if not processed.
+	 */
 	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
 		et_entry = sc->enclosure_table;
@@ -1633,11 +2027,16 @@
 			if (!et_entry->init_complete) {
 				if (et_entry->missing_count <
 				    MPS_MAX_MISSING_COUNT) {
+					mps_dprint(sc, MPS_MAPPING, "%s: "
+					    "Enclosure %d is missing from the "
+					    "topology. Update its missing "
+					    "count.\n", __func__, i);
 					et_entry->missing_count++;
 					if (et_entry->dpm_entry_num !=
-					    MPS_DPM_BAD_IDX)
+					    MPS_DPM_BAD_IDX) {
 						_mapping_commit_enc_entry(sc,
 						    et_entry);
+					}
 				}
 				et_entry->init_complete = 1;
 			}
@@ -1646,70 +2045,46 @@
 			return;
 		_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
 		mt_entry = &sc->mapping_table[start_idx];
-		for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) {
-			if (mt_entry->device_info & MPS_DEV_RESERVED
-			    && !mt_entry->physical_id)
-				mt_entry->init_complete = 1;
-			else if (mt_entry->device_info & MPS_DEV_RESERVED) {
-				if (!mt_entry->init_complete) {
-					if (mt_entry->missing_count <
-					    MPS_MAX_MISSING_COUNT) {
-						mt_entry->missing_count++;
-						if (mt_entry->dpm_entry_num !=
-						    MPS_DPM_BAD_IDX)
-						_mapping_commit_map_entry(sc,
-						    mt_entry);
-					}
-					mt_entry->init_complete = 1;
-				}
-			}
-		}
 	} else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
 	    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
+		start_idx = 0;
+		end_idx = sc->max_devices - 1;
 		mt_entry = sc->mapping_table;
-		for (i = 0; i < sc->max_devices; i++, mt_entry++) {
-			if (mt_entry->device_info & MPS_DEV_RESERVED
-			    && !mt_entry->physical_id)
-				mt_entry->init_complete = 1;
-			else if (mt_entry->device_info & MPS_DEV_RESERVED) {
-				if (!mt_entry->init_complete) {
-					if (mt_entry->missing_count <
-					    MPS_MAX_MISSING_COUNT) {
-						mt_entry->missing_count++;
-						if (mt_entry->dpm_entry_num !=
-						    MPS_DPM_BAD_IDX)
+	}
+
+	/*
+	 * The start and end indices have been set above according to the
+	 * mapping type. Go through these mappings and update any entries that
+	 * do not have the init_complete flag set, which means they are missing.
+	 */
+	if (end_idx == 0)
+		return;
+	for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) {
+		if (mt_entry->device_info & MPS_DEV_RESERVED
+		    && !mt_entry->physical_id)
+			mt_entry->init_complete = 1;
+		else if (mt_entry->device_info & MPS_DEV_RESERVED) {
+			if (!mt_entry->init_complete) {
+				mps_dprint(sc, MPS_MAPPING, "%s: Device in "
+				    "mapping table at index %d is missing from "
+				    "topology. Update its missing count.\n",
+				    __func__, i);
+				if (mt_entry->missing_count <
+				    MPS_MAX_MISSING_COUNT) {
+					mt_entry->missing_count++;
+					if (mt_entry->dpm_entry_num !=
+					    MPS_DPM_BAD_IDX) {
 						_mapping_commit_map_entry(sc,
 						    mt_entry);
 					}
-					mt_entry->init_complete = 1;
 				}
+				mt_entry->init_complete = 1;
 			}
 		}
 	}
 }
 
-
 /**
- * mps_mapping_is_reinit_required - check whether event replay required
- * @sc: per adapter object
- *
- * Checks the per ioc flags and decide whether reinit of events required
- *
- * Returns 1 for reinit of ioc 0 for not.
- */
-int mps_mapping_is_reinit_required(struct mps_softc *sc)
-{
-	if (!sc->mt_full_retry && sc->mt_add_device_failed) {
-		sc->mt_full_retry = 1;
-		sc->mt_add_device_failed = 0;
-		_mapping_flush_dpm_pages(sc);
-		return 1;
-	}
-	sc->mt_full_retry = 1;
-	return 0;
-}
-
-/**
  * mps_mapping_initialize - initialize mapping tables
  * @sc: per adapter object
  *
@@ -1737,11 +2112,14 @@
 	sc->pending_map_events = 0;
 	sc->num_enc_table_entries = 0;
 	sc->num_rsvd_entries = 0;
-	sc->num_channels = 1;
 	sc->max_dpm_entries = sc->ioc_pg8.MaxPersistentEntries;
 	sc->is_dpm_enable = (sc->max_dpm_entries) ? 1 : 0;
 	sc->track_mapping_events = 0;
 	
+
+	mps_dprint(sc, MPS_MAPPING, "%s: Mapping table has a max of %d entries "
+	    "and DPM has a max of %d entries.\n", __func__, sc->max_devices,
+	    sc->max_dpm_entries);
 	if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING)
 		sc->is_dpm_enable = 0;
 
@@ -1781,8 +2159,8 @@
 retry_read_dpm:
 		if (mps_config_get_dpm_pg0(sc, &mpi_reply, sc->dpm_pg0,
 		    dpm_pg0_sz)) {
-			printf("%s: dpm page read failed; disabling dpm\n",
-			    __func__);
+			mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: DPM page "
+			    "read failed.\n", __func__);
 			if (retry_count < 3) {
 				retry_count++;
 				goto retry_read_dpm;
@@ -1793,6 +2171,11 @@
 
 	if (sc->is_dpm_enable)
 		_mapping_process_dpm_pg0(sc);
+	else {
+		mps_dprint(sc, MPS_MAPPING, "%s: DPM processing is disabled. "
+		    "Device mappings will not persist across reboots or "
+		    "resets.\n", __func__);
+	}
 
 	sc->track_mapping_events = 1;
 	return 0;
@@ -1812,15 +2195,15 @@
 }
 
 /**
- * mps_mapping_get_sas_id - assign a target id for sas device
+ * mps_mapping_get_tid - return the target id for sas device and handle
  * @sc: per adapter object
  * @sas_address: sas address of the device
  * @handle: device handle
  *
- * Returns valid ID on success or BAD_ID.
+ * Returns valid target ID on success or BAD_ID.
  */
 unsigned int
-mps_mapping_get_sas_id(struct mps_softc *sc, uint64_t sas_address, u16 handle)
+mps_mapping_get_tid(struct mps_softc *sc, uint64_t sas_address, u16 handle)
 {
 	u32 map_idx;
 	struct dev_mapping_table *mt_entry;
@@ -1836,38 +2219,39 @@
 }
 
 /**
- * mps_mapping_get_sas_id_from_handle - find a target id in mapping table using
+ * mps_mapping_get_tid_from_handle - find a target id in mapping table using
  * only the dev handle.  This is just a wrapper function for the local function
  * _mapping_get_mt_idx_from_handle.
  * @sc: per adapter object
  * @handle: device handle
  *
- * Returns valid ID on success or BAD_ID.
+ * Returns valid target ID on success or BAD_ID.
  */
 unsigned int
-mps_mapping_get_sas_id_from_handle(struct mps_softc *sc, u16 handle)
+mps_mapping_get_tid_from_handle(struct mps_softc *sc, u16 handle)
 {
 	return (_mapping_get_mt_idx_from_handle(sc, handle));
 }
 
 /**
- * mps_mapping_get_raid_id - assign a target id for raid device
+ * mps_mapping_get_raid_tid - return the target id for raid device
  * @sc: per adapter object
  * @wwid: world wide identifier for raid volume
- * @handle: device handle
+ * @volHandle: volume device handle
  *
- * Returns valid ID on success or BAD_ID.
+ * Returns valid target ID on success or BAD_ID.
  */
 unsigned int
-mps_mapping_get_raid_id(struct mps_softc *sc, u64 wwid, u16 handle)
+mps_mapping_get_raid_tid(struct mps_softc *sc, u64 wwid, u16 volHandle)
 {
-	u32 map_idx;
+	u32 start_idx, end_idx, map_idx;
 	struct dev_mapping_table *mt_entry;
 
-	for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
-		mt_entry = &sc->mapping_table[map_idx];
-		if (mt_entry->dev_handle == handle && mt_entry->physical_id ==
-		    wwid)
+	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
+	mt_entry = &sc->mapping_table[start_idx];
+	for (map_idx  = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) {
+		if (mt_entry->dev_handle == volHandle &&
+		    mt_entry->physical_id == wwid)
 			return mt_entry->id;
 	}
 
@@ -1875,16 +2259,16 @@
 }
 
 /**
- * mps_mapping_get_raid_id_from_handle - find raid device in mapping table
+ * mps_mapping_get_raid_tid_from_handle - find raid device in mapping table
  * using only the volume dev handle.  This is just a wrapper function for the
  * local function _mapping_get_ir_mt_idx_from_handle.
  * @sc: per adapter object
  * @volHandle: volume device handle
  *
- * Returns valid ID on success or BAD_ID.
+ * Returns valid target ID on success or BAD_ID.
  */
 unsigned int
-mps_mapping_get_raid_id_from_handle(struct mps_softc *sc, u16 volHandle)
+mps_mapping_get_raid_tid_from_handle(struct mps_softc *sc, u16 volHandle)
 {
 	return (_mapping_get_ir_mt_idx_from_handle(sc, volHandle));
 }
@@ -1918,8 +2302,8 @@
 
 	if (event_data->ReasonCode == MPI2_EVENT_SAS_ENCL_RC_ADDED) {
 		if (!event_data->NumSlots) {
-			printf("%s: enclosure with handle = 0x%x reported 0 "
-			    "slots\n", __func__,
+			mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Enclosure "
+			    "with handle = 0x%x reported 0 slots.\n", __func__,
 			    le16toh(event_data->EnclosureHandle));
 			goto out;
 		}
@@ -1928,13 +2312,22 @@
 		    event_data->EnclosureLogicalID.Low;
 		enc_idx = _mapping_get_enc_idx_from_id(sc, temp64_var,
 		    event_data->PhyBits);
+
+		/*
+		 * If the Added enclosure is already in the Enclosure Table,
+		 * make sure that all the the enclosure info is up to date. If
+		 * the enclosure was missing and has just been added back, or if
+		 * the enclosure's Phy Bits have changed, clear the missing
+		 * count and update the Phy Bits in the mapping table and in the
+		 * DPM, if it's being used.
+		 */
 		if (enc_idx != MPS_ENCTABLE_BAD_IDX) {
 			et_entry = &sc->enclosure_table[enc_idx];
 			if (et_entry->init_complete &&
 			    !et_entry->missing_count) {
-				printf("%s: enclosure %d is already present "
-				    "with handle = 0x%x\n",__func__, enc_idx,
-				    et_entry->enc_handle);
+				mps_dprint(sc, MPS_MAPPING, "%s: Enclosure %d "
+				    "is already present with handle = 0x%x\n",
+				    __func__, enc_idx, et_entry->enc_handle);
 				goto out;
 			}
 			et_entry->enc_handle = le16toh(event_data->
@@ -1953,8 +2346,7 @@
 					missing_count =
 					    (u8)(dpm_entry->MappingInformation &
 					    MPI2_DRVMAP0_MAPINFO_MISSING_MASK);
-					if (!et_entry->init_complete && (
-					    missing_count || update_phy_bits)) {
+					if (missing_count || update_phy_bits) {
 						dpm_entry->MappingInformation
 						    = et_entry->num_slots;
 						dpm_entry->MappingInformation
@@ -1967,10 +2359,18 @@
 				}
 			}
 		} else {
+			/*
+			 * This is a new enclosure that is being added.
+			 * Initialize the Enclosure Table entry. It will be
+			 * finalized when a device is added for the enclosure
+			 * and the enclosure has enough space in the Mapping
+			 * Table to map its devices.
+			 */
 			enc_idx = sc->num_enc_table_entries;
 			if (enc_idx >= sc->max_enclosures) {
-				printf("%s: enclosure can not be added; "
-				    "mapping table is full\n", __func__);
+				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
+				    "Enclosure cannot be added to mapping "
+				    "table because it's full.\n", __func__);
 				goto out;
 			}
 			sc->num_enc_table_entries++;
@@ -1977,10 +2377,11 @@
 			et_entry = &sc->enclosure_table[enc_idx];
 			et_entry->enc_handle = le16toh(event_data->
 			    EnclosureHandle);
-			et_entry->enclosure_id = event_data->
-			    EnclosureLogicalID.High;
-			et_entry->enclosure_id = ( et_entry->enclosure_id << 
-			    32) | event_data->EnclosureLogicalID.Low;
+			et_entry->enclosure_id = le64toh(event_data->
+			    EnclosureLogicalID.High);
+			et_entry->enclosure_id =
+			    ((et_entry->enclosure_id << 32) |
+			    le64toh(event_data->EnclosureLogicalID.Low));
 			et_entry->start_index = MPS_MAPTABLE_BAD_IDX;
 			et_entry->dpm_entry_num = MPS_DPM_BAD_IDX;
 			et_entry->num_slots = le16toh(event_data->NumSlots);
@@ -1990,23 +2391,23 @@
 		et_entry->init_complete = 1;
 	} else if (event_data->ReasonCode ==
 	    MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING) {
+		/*
+		 * An enclosure was removed. Update its missing count and then
+		 * update the DPM entry with the new missing count for the
+		 * enclosure.
+		 */
 		enc_idx = _mapping_get_enc_idx_from_handle(sc,
 		    le16toh(event_data->EnclosureHandle));
 		if (enc_idx == MPS_ENCTABLE_BAD_IDX) {
-			printf("%s: cannot unmap enclosure %d because it has "
-			    "already been deleted", __func__, enc_idx);
+			mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Cannot "
+			    "unmap enclosure %d because it has already been "
+			    "deleted.\n", __func__, enc_idx);
 			goto out;
 		}
 		et_entry = &sc->enclosure_table[enc_idx];
-		if (!et_entry->init_complete) {
-			if (et_entry->missing_count < MPS_MAX_MISSING_COUNT)
-				et_entry->missing_count++;
-			else
-				et_entry->init_complete = 1;
-		}
-		if (!et_entry->missing_count)
+		if (et_entry->missing_count < MPS_MAX_MISSING_COUNT)
 			et_entry->missing_count++;
-		if (sc->is_dpm_enable && !et_entry->init_complete &&
+		if (sc->is_dpm_enable &&
 		    et_entry->dpm_entry_num != MPS_DPM_BAD_IDX) {
 			dpm_entry += et_entry->dpm_entry_num;
 			dpm_entry->MappingInformation = et_entry->num_slots;
@@ -2076,66 +2477,6 @@
 }
 
 /**
- * _mapping_check_update_ir_mt_idx - Check and update IR map table index
- * @sc: per adapter object
- * @event_data: event data payload
- * @evt_idx: current event index
- * @map_idx: current index and the place holder for new map table index
- * @wwid_table: world wide name for volumes in the element table
- *
- * pass through IR events and find whether any events matches and if so
- * tries to find new index if not returns failure
- *
- * Returns 0 on success and 1 on failure
- */
-static int
-_mapping_check_update_ir_mt_idx(struct mps_softc *sc,
-    Mpi2EventDataIrConfigChangeList_t *event_data, int evt_idx, u32 *map_idx,
-    u64 *wwid_table)
-{
-	struct dev_mapping_table *mt_entry;
-	u32 st_idx, end_idx, mt_idx = *map_idx;
-	u8 match = 0;
-	Mpi2EventIrConfigElement_t *element;
-	u16 element_flags;
-	int i;
-
-	mt_entry = &sc->mapping_table[mt_idx];
-	_mapping_get_ir_maprange(sc, &st_idx, &end_idx);
-search_again:
-	match = 0;
-	for (i = evt_idx + 1; i < event_data->NumElements; i++) {
-		element = (Mpi2EventIrConfigElement_t *)
-		    &event_data->ConfigElement[i];
-		element_flags = le16toh(element->ElementFlags);
-		if ((element_flags &
-		    MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) !=
-		    MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT)
-			continue;
-		if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_ADDED ||
-		    element->ReasonCode ==
-		    MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
-			if (mt_entry->physical_id == wwid_table[i]) {
-				match = 1;
-				break;
-			}
-		}
-	}
-
-	if (match) {
-		do {
-			mt_idx++;
-			if (mt_idx > end_idx)
-				return 1;
-			mt_entry = &sc->mapping_table[mt_idx];
-		} while (mt_entry->device_info & MPS_MAP_IN_USE);
-		goto search_again;
-	}
-	*map_idx = mt_idx;
-	return 0;
-}
-
-/**
  * mps_mapping_ir_config_change_event - handle IR config change list events
  * @sc: per adapter object
  * @event_data: event data payload
@@ -2152,7 +2493,6 @@
 	u32 map_idx, flags;
 	struct dev_mapping_table *mt_entry;
 	u16 element_flags;
-	u8 log_full_error = 0;
 
 	wwid_table = malloc(sizeof(u64) * event_data->NumElements, M_MPT2,
 	    M_NOWAIT | M_ZERO);
@@ -2160,6 +2500,11 @@
 		goto out;
 	element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
 	flags = le32toh(event_data->Flags);
+
+	/*
+	 * For volume changes, get the WWID for the volume and put it in a
+	 * table to be used in the processing of the IR change event.
+	 */
 	for (i = 0; i < event_data->NumElements; i++, element++) {
 		element_flags = le16toh(element->ElementFlags);
 		if ((element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_ADDED) &&
@@ -2173,14 +2518,14 @@
 		    MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) {
 			mps_config_get_volume_wwid(sc,
 			    le16toh(element->VolDevHandle), &wwid_table[i]);
-			map_idx = _mapping_get_ir_mt_idx_from_wwid(sc,
-			    wwid_table[i]);
-			if (map_idx != MPS_MAPTABLE_BAD_IDX) {
-				mt_entry = &sc->mapping_table[map_idx];
-				mt_entry->device_info |= MPS_MAP_IN_USE;
-			}
 		}
 	}
+
+	/*
+	 * Check the ReasonCode for each element in the IR event and Add/Remove
+	 * Volumes or Physical Disks of Volumes to/from the mapping table. Use
+	 * the WWIDs gotten above in wwid_table.
+	 */
 	if (flags == MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
 		goto out;
 	else {
@@ -2194,8 +2539,11 @@
 				map_idx = _mapping_get_ir_mt_idx_from_wwid
 				    (sc, wwid_table[i]);
 				if (map_idx != MPS_MAPTABLE_BAD_IDX) {
+					/*
+					 * The volume is already in the mapping
+					 * table. Just update it's info.
+					 */
 					mt_entry = &sc->mapping_table[map_idx];
-					mt_entry->channel = MPS_RAID_CHANNEL;
 					mt_entry->id = map_idx;
 					mt_entry->dev_handle = le16toh
 					    (element->VolDevHandle);
@@ -2205,31 +2553,33 @@
 					    map_idx, element, wwid_table[i]);
 					continue;
 				}
+
+				/*
+				 * Volume is not in mapping table yet. Find a
+				 * free entry in the mapping table at the
+				 * volume mapping locations. If no entries are
+				 * available, this is an error because it means
+				 * there are more volumes than can be mapped
+				 * and that should never happen for volumes.
+				 */
 				map_idx = _mapping_get_free_ir_mt_idx(sc);
 				if (map_idx == MPS_MAPTABLE_BAD_IDX)
-					log_full_error = 1;
-				else if (i < (event_data->NumElements - 1)) {
-					log_full_error =
-					    _mapping_check_update_ir_mt_idx
-					    (sc, event_data, i, &map_idx,
-					     wwid_table);
-				}
-				if (log_full_error) {
-					printf("%s: no space to add the RAID "
-					    "volume with handle 0x%04x in "
-					    "mapping table\n", __func__, le16toh
-					    (element->VolDevHandle));
+				{
+					mps_dprint(sc, MPS_ERROR | MPS_MAPPING,
+					    "%s: failed to add the volume with "
+					    "handle 0x%04x because there is no "
+					    "free space available in the "
+					    "mapping table\n", __func__,
+					    le16toh(element->VolDevHandle));
 					continue;
 				}
 				mt_entry = &sc->mapping_table[map_idx];
 				mt_entry->physical_id = wwid_table[i];
-				mt_entry->channel = MPS_RAID_CHANNEL;
 				mt_entry->id = map_idx;
 				mt_entry->dev_handle = le16toh(element->
 				    VolDevHandle);
 				mt_entry->device_info = MPS_DEV_RESERVED |
 				    MPS_MAP_IN_USE;
-				mt_entry->init_complete = 0;
 				_mapping_update_ir_missing_cnt(sc, map_idx,
 				    element, wwid_table[i]);
 			} else if (element->ReasonCode ==
@@ -2237,9 +2587,10 @@
 				map_idx = _mapping_get_ir_mt_idx_from_wwid(sc,
 				    wwid_table[i]);
 				if (map_idx == MPS_MAPTABLE_BAD_IDX) {
-					printf("%s: failed to remove a volume "
-					    "because it has already been "
-					    "removed\n", __func__);
+					mps_dprint(sc, MPS_MAPPING,"%s: Failed "
+					    "to remove a volume because it has "
+					    "already been removed.\n",
+					    __func__);
 					continue;
 				}
 				_mapping_update_ir_missing_cnt(sc, map_idx,
@@ -2249,9 +2600,10 @@
 				map_idx = _mapping_get_mt_idx_from_handle(sc,
 				    le16toh(element->VolDevHandle));
 				if (map_idx == MPS_MAPTABLE_BAD_IDX) {
-					printf("%s: failed to remove volume "
-					    "with handle 0x%04x because it has "
-					    "already been removed\n", __func__,
+					mps_dprint(sc, MPS_MAPPING,"%s: Failed "
+					    "to remove volume with handle "
+					    "0x%04x because it has already "
+					    "been removed.\n", __func__,
 					    le16toh(element->VolDevHandle));
 					continue;
 				}
@@ -2268,3 +2620,61 @@
 	if (sc->pending_map_events)
 		sc->pending_map_events--;
 }
+
+int
+mps_mapping_dump(SYSCTL_HANDLER_ARGS)
+{
+	struct mps_softc *sc;
+	struct dev_mapping_table *mt_entry;
+	struct sbuf sbuf;
+	int i, error;
+
+	sc = (struct mps_softc *)arg1;
+
+	error = sysctl_wire_old_buffer(req, 0);
+	if (error != 0)
+		return (error);
+	sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
+
+	sbuf_printf(&sbuf, "\nindex physical_id       handle id\n");
+	for (i = 0; i < sc->max_devices; i++) {
+		mt_entry = &sc->mapping_table[i];
+		if (mt_entry->physical_id == 0)
+			continue;
+		sbuf_printf(&sbuf, "%4d  %jx  %04x   %hd\n",
+		    i, mt_entry->physical_id, mt_entry->dev_handle,
+		    mt_entry->id);
+	}
+	error = sbuf_finish(&sbuf);
+	sbuf_delete(&sbuf);
+	return (error);
+}
+
+int
+mps_mapping_encl_dump(SYSCTL_HANDLER_ARGS)
+{
+	struct mps_softc *sc;
+	struct enc_mapping_table *enc_entry;
+	struct sbuf sbuf;
+	int i, error;
+
+	sc = (struct mps_softc *)arg1;
+
+	error = sysctl_wire_old_buffer(req, 0);
+	if (error != 0)
+		return (error);
+	sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
+
+	sbuf_printf(&sbuf, "\nindex enclosure_id      handle map_index\n");
+	for (i = 0; i < sc->max_enclosures; i++) {
+		enc_entry = &sc->enclosure_table[i];
+		if (enc_entry->enclosure_id == 0)
+			continue;
+		sbuf_printf(&sbuf, "%4d  %jx  %04x   %d\n",
+		    i, enc_entry->enclosure_id, enc_entry->enc_handle,
+		    enc_entry->start_index);
+	}
+	error = sbuf_finish(&sbuf);
+	sbuf_delete(&sbuf);
+	return (error);
+}

Modified: trunk/sys/dev/mps/mps_mapping.h
===================================================================
--- trunk/sys/dev/mps/mps_mapping.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_mapping.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,9 +25,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mps_mapping.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 #ifndef _MPS_MAPPING_H
@@ -38,6 +40,7 @@
  * @dev_handle: device handle for the device pointed by this entry
  * @slot: slot ID
  * @is_processed: Flag to indicate whether this entry is processed or not
+ * @is_SATA_SSD: 1 if this is a SATA device AND an SSD, 0 otherwise
  */
 struct _map_phy_change {
 	uint64_t	physical_id;
@@ -46,6 +49,8 @@
 	uint16_t	slot;
 	uint8_t	reason;
 	uint8_t	is_processed;
+	uint8_t	is_SATA_SSD;
+	uint8_t reserved;
 };
 
 /**
@@ -66,6 +71,6 @@
 
 extern int
 mpssas_get_sas_address_for_sata_disk(struct mps_softc *ioc,
-    u64 *sas_address, u16 handle, u32 device_info);
+    u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD);
 
 #endif

Modified: trunk/sys/dev/mps/mps_pci.c
===================================================================
--- trunk/sys/dev/mps/mps_pci.c	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_pci.c	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009 Yahoo! Inc.
  * All rights reserved.
@@ -25,9 +26,9 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/mps/mps_pci.c 322661 2017-08-18 15:38:08Z ken $");
 
-/* PCI/PCI-X/PCIe bus interface for the LSI MPT2 controllers */
+/* PCI/PCI-X/PCIe bus interface for the Avago Tech (LSI) MPT2 controllers */
 
 /* TODO Move headers to mpsvar */
 #include <sys/types.h>
@@ -68,6 +69,7 @@
 static void	mps_pci_free(struct mps_softc *);
 static int	mps_alloc_msix(struct mps_softc *sc, int msgs);
 static int	mps_alloc_msi(struct mps_softc *sc, int msgs);
+static int	mps_pci_alloc_interrupts(struct mps_softc *sc);
 
 static device_method_t mps_methods[] = {
 	DEVMETHOD(device_probe,		mps_pci_probe),
@@ -98,33 +100,33 @@
 	const char	*desc;
 } mps_identifiers[] = {
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
-	    0xffff, 0xffff, 0, "LSI SAS2004" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2004" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
-	    0xffff, 0xffff, 0, "LSI SAS2008" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2008" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
-	    0xffff, 0xffff, 0, "LSI SAS2108" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2108" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
-	    0xffff, 0xffff, 0, "LSI SAS2108" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2108" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
-	    0xffff, 0xffff, 0, "LSI SAS2108" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2108" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
-	    0xffff, 0xffff, 0, "LSI SAS2116" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2116" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
-	    0xffff, 0xffff, 0, "LSI SAS2116" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2116" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
-	    0xffff, 0xffff, 0, "LSI SAS2208" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
-	    0xffff, 0xffff, 0, "LSI SAS2208" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
-	    0xffff, 0xffff, 0, "LSI SAS2208" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
-	    0xffff, 0xffff, 0, "LSI SAS2208" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
-	    0xffff, 0xffff, 0, "LSI SAS2208" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
-	    0xffff, 0xffff, 0, "LSI SAS2208" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2208" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
-	    0xffff, 0xffff, 0, "LSI SAS2308" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2308" },
 	// Add Customer specific vender/subdevice id before generic
 	// (0xffff) vender/subdevice id.
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
@@ -136,11 +138,11 @@
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
 	    0x8086, 0x3519, 0, "Intel(R) Integrated RAID Module RMS25KB040" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
-	    0xffff, 0xffff, 0, "LSI SAS2308" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2308" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
-	    0xffff, 0xffff, 0, "LSI SAS2308" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS2308" },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
-	    0xffff, 0xffff, MPS_FLAGS_WD_AVAILABLE, "LSI SSS6200" },
+	    0xffff, 0xffff, 0, "Avago Technologies (LSI) SSS6200" },
 	{ 0, 0, 0, 0, 0, NULL }
 };
 
@@ -183,7 +185,6 @@
 {
 	struct mps_softc *sc;
 	struct mps_ident *m;
-	uint16_t command;
 	int error;
 
 	sc = device_get_softc(dev);
@@ -192,25 +193,16 @@
 	m = mps_find_ident(dev);
 	sc->mps_flags = m->flags;
 
+	mps_get_tunables(sc);
+
 	/* Twiddle basic PCI config bits for a sanity check */
-	command = pci_read_config(dev, PCIR_COMMAND, 2);
-	command |= PCIM_CMD_BUSMASTEREN;
-	pci_write_config(dev, PCIR_COMMAND, command, 2);
-	command = pci_read_config(dev, PCIR_COMMAND, 2);
-	if ((command & PCIM_CMD_BUSMASTEREN) == 0) {
-		device_printf(dev, "Cannot enable PCI busmaster\n");
-		return (ENXIO);
-	}
-	if ((command & PCIM_CMD_MEMEN) == 0) {
-		device_printf(dev, "PCI memory window not available\n");
-		return (ENXIO);
-	}
+	pci_enable_busmaster(dev);
 
 	/* Allocate the System Interface Register Set */
 	sc->mps_regs_rid = PCIR_BAR(1);
 	if ((sc->mps_regs_resource = bus_alloc_resource_any(dev,
 	    SYS_RES_MEMORY, &sc->mps_regs_rid, RF_ACTIVE)) == NULL) {
-		device_printf(dev, "Cannot allocate PCI registers\n");
+		mps_printf(sc, "Cannot allocate PCI registers\n");
 		return (ENXIO);
 	}
 	sc->mps_btag = rman_get_bustag(sc->mps_regs_resource);
@@ -228,25 +220,34 @@
 				0,			/* flags */
 				NULL, NULL,		/* lockfunc, lockarg */
 				&sc->mps_parent_dmat)) {
-		device_printf(dev, "Cannot allocate parent DMA tag\n");
+		mps_printf(sc, "Cannot allocate parent DMA tag\n");
 		mps_pci_free(sc);
 		return (ENOMEM);
 	}
 
-	if ((error = mps_attach(sc)) != 0)
+	if (((error = mps_pci_alloc_interrupts(sc)) != 0) ||
+	    ((error = mps_attach(sc)) != 0))
 		mps_pci_free(sc);
 
 	return (error);
 }
 
-int
-mps_pci_setup_interrupts(struct mps_softc *sc)
+/*
+ * Allocate, but don't assign interrupts early.  Doing it before requesting
+ * the IOCFacts message informs the firmware that we want to do MSI-X
+ * multiqueue.  We might not use all of the available messages, but there's
+ * no reason to re-alloc if we don't.
+ */
+static int
+mps_pci_alloc_interrupts(struct mps_softc *sc)
 {
 	device_t dev;
-	int i, error, msgs;
+	int error, msgs;
 
 	dev = sc->mps_dev;
-	error = ENXIO;
+	error = 0;
+	msgs = 0;
+
 	if ((sc->disable_msix == 0) &&
 	    ((msgs = pci_msix_count(dev)) >= MPS_MSI_COUNT))
 		error = mps_alloc_msix(sc, MPS_MSI_COUNT);
@@ -253,14 +254,29 @@
 	if ((error != 0) && (sc->disable_msi == 0) &&
 	    ((msgs = pci_msi_count(dev)) >= MPS_MSI_COUNT))
 		error = mps_alloc_msi(sc, MPS_MSI_COUNT);
+	if (error != 0)
+		msgs = 0;
 
-	if (error != 0) {
+	sc->msi_msgs = msgs;
+	return (error);
+}
+
+int
+mps_pci_setup_interrupts(struct mps_softc *sc)
+{
+	device_t dev;
+	int i, error;
+
+	dev = sc->mps_dev;
+	error = ENXIO;
+
+	if (sc->msi_msgs == 0) {
 		sc->mps_flags |= MPS_FLAGS_INTX;
 		sc->mps_irq_rid[0] = 0;
 		sc->mps_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ,
 		    &sc->mps_irq_rid[0],  RF_SHAREABLE | RF_ACTIVE);
 		if (sc->mps_irq[0] == NULL) {
-			device_printf(dev, "Cannot allocate INTx interrupt\n");
+			mps_printf(sc, "Cannot allocate INTx interrupt\n");
 			return (ENXIO);
 		}
 		error = bus_setup_intr(dev, sc->mps_irq[0],
@@ -267,7 +283,7 @@
 		    INTR_TYPE_BIO | INTR_MPSAFE, NULL, mps_intr, sc,
 		    &sc->mps_intrhand[0]);
 		if (error)
-			device_printf(dev, "Cannot setup INTx interrupt\n");
+			mps_printf(sc, "Cannot setup INTx interrupt\n");
 	} else {
 		sc->mps_flags |= MPS_FLAGS_MSI;
 		for (i = 0; i < MPS_MSI_COUNT; i++) {
@@ -275,7 +291,7 @@
 			sc->mps_irq[i] = bus_alloc_resource_any(dev,
 			    SYS_RES_IRQ, &sc->mps_irq_rid[i], RF_ACTIVE);
 			if (sc->mps_irq[i] == NULL) {
-				device_printf(dev,
+				mps_printf(sc,
 				    "Cannot allocate MSI interrupt\n");
 				return (ENXIO);
 			}
@@ -283,7 +299,7 @@
 			    INTR_TYPE_BIO | INTR_MPSAFE, NULL, mps_intr_msi,
 			    sc, &sc->mps_intrhand[i]);
 			if (error) {
-				device_printf(dev,
+				mps_printf(sc,
 				    "Cannot setup MSI interrupt %d\n", i);
 				break;
 			}

Modified: trunk/sys/dev/mps/mps_sas.c
===================================================================
--- trunk/sys/dev/mps/mps_sas.c	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_sas.c	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,6 +1,8 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009 Yahoo! Inc.
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -24,15 +26,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mps_sas.c 322661 2017-08-18 15:38:08Z ken $
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/mps/mps_sas.c 322661 2017-08-18 15:38:08Z ken $");
 
-/* Communications core for LSI MPT2 */
+/* Communications core for Avago Technologies (LSI) MPT2 */
 
 /* TODO Move headers to mpsvar */
 #include <sys/types.h>
@@ -115,11 +117,12 @@
 
 MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory");
 
-static void mpssas_discovery_timeout(void *data);
 static void mpssas_remove_device(struct mps_softc *, struct mps_command *);
 static void mpssas_remove_complete(struct mps_softc *, struct mps_command *);
 static void mpssas_action(struct cam_sim *sim, union ccb *ccb);
 static void mpssas_poll(struct cam_sim *sim);
+static int mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm,
+    struct mps_command *cm);
 static void mpssas_scsiio_timeout(void *data);
 static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm);
 static void mpssas_direct_drive_io(struct mpssas_softc *sassc,
@@ -134,16 +137,12 @@
 static void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb);
 #endif //FreeBSD_version >= 900026
 static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *);
-static int  mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm);
-static int  mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type);
-static void mpssas_rescan(struct mpssas_softc *sassc, union ccb *ccb);
-static void mpssas_rescan_done(struct cam_periph *periph, union ccb *done_ccb);
-static void mpssas_scanner_thread(void *arg);
-#if __FreeBSD_version >= 1000006
 static void mpssas_async(void *callback_arg, uint32_t code,
 			 struct cam_path *path, void *arg);
-#else
-static void mpssas_check_eedp(struct mpssas_softc *sassc);
+#if (__FreeBSD_version < 901503) || \
+    ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
+static void mpssas_check_eedp(struct mps_softc *sc, struct cam_path *path,
+			      struct ccb_getdev *cgd);
 static void mpssas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb);
 #endif
 static int mpssas_send_portenable(struct mps_softc *sc);
@@ -156,7 +155,7 @@
 	struct mpssas_target *target;
 	int i;
 
-	for (i = start; i < sassc->sc->facts->MaxTargets; i++) {
+	for (i = start; i < sassc->maxtargets; i++) {
 		target = &sassc->targets[i];
 		if (target->handle == handle)
 			return (target);
@@ -175,38 +174,59 @@
 void
 mpssas_startup_increment(struct mpssas_softc *sassc)
 {
+	MPS_FUNCTRACE(sassc->sc);
+
 	if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
 		if (sassc->startup_refcount++ == 0) {
 			/* just starting, freeze the simq */
-			mps_dprint(sassc->sc, MPS_INFO,
+			mps_dprint(sassc->sc, MPS_INIT,
 			    "%s freezing simq\n", __func__);
+#if __FreeBSD_version >= 1000039
+			xpt_hold_boot();
+#endif
 			xpt_freeze_simq(sassc->sim, 1);
 		}
-		mps_dprint(sassc->sc, MPS_TRACE, "%s refcount %u\n", __func__,
+		mps_dprint(sassc->sc, MPS_INIT, "%s refcount %u\n", __func__,
 		    sassc->startup_refcount);
 	}
 }
 
 void
+mpssas_release_simq_reinit(struct mpssas_softc *sassc)
+{
+	if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
+		sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
+		xpt_release_simq(sassc->sim, 1);
+		mps_dprint(sassc->sc, MPS_INFO, "Unfreezing SIM queue\n");
+	}
+}
+
+void
 mpssas_startup_decrement(struct mpssas_softc *sassc)
 {
+	MPS_FUNCTRACE(sassc->sc);
+
 	if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
 		if (--sassc->startup_refcount == 0) {
 			/* finished all discovery-related actions, release
 			 * the simq and rescan for the latest topology.
 			 */
-			mps_dprint(sassc->sc, MPS_INFO,
+			mps_dprint(sassc->sc, MPS_INIT,
 			    "%s releasing simq\n", __func__);
 			sassc->flags &= ~MPSSAS_IN_STARTUP;
 			xpt_release_simq(sassc->sim, 1);
+#if __FreeBSD_version >= 1000039
+			xpt_release_boot();
+#else
 			mpssas_rescan_target(sassc->sc, NULL);
+#endif
 		}
-		mps_dprint(sassc->sc, MPS_TRACE, "%s refcount %u\n", __func__,
+		mps_dprint(sassc->sc, MPS_INIT, "%s refcount %u\n", __func__,
 		    sassc->startup_refcount);
 	}
 }
 
-/* LSI's firmware requires us to stop sending commands when we're doing task
+/* The firmware requires us to stop sending commands when we're doing task
  * management, so refcount the TMs and keep the simq frozen when any are in
  * use.
  */
@@ -216,14 +236,6 @@
 	struct mps_command *tm;
 
 	tm = mps_alloc_high_priority_command(sc);
-	if (tm != NULL) {
-		if (sc->sassc->tm_count++ == 0) {
-			mps_printf(sc, "%s freezing simq\n", __func__);
-			xpt_freeze_simq(sc->sassc->sim, 1);
-		}
-		mps_dprint(sc, MPS_TRACE, "%s tm_count %u\n", __func__,
-		    sc->sassc->tm_count);
-	}
 	return tm;
 }
 
@@ -230,24 +242,31 @@
 void
 mpssas_free_tm(struct mps_softc *sc, struct mps_command *tm)
 {
+	int target_id = 0xFFFFFFFF;
+ 
 	if (tm == NULL)
 		return;
 
-	/* if there are no TMs in use, we can release the simq.  We use our
-	 * own refcount so that it's easier for a diag reset to cleanup and
-	 * release the simq.
+	/*
+	 * For TM's the devq is frozen for the device.  Unfreeze it here and
+	 * free the resources used for freezing the devq.  Must clear the
+	 * INRESET flag as well or scsi I/O will not work.
 	 */
-	if (--sc->sassc->tm_count == 0) {
-		mps_printf(sc, "%s releasing simq\n", __func__);
-		xpt_release_simq(sc->sassc->sim, 1);
+	if (tm->cm_targ != NULL) {
+		tm->cm_targ->flags &= ~MPSSAS_TARGET_INRESET;
+		target_id = tm->cm_targ->tid;
 	}
-	mps_dprint(sc, MPS_TRACE, "%s tm_count %u\n", __func__,
-	    sc->sassc->tm_count);
+	if (tm->cm_ccb) {
+		mps_dprint(sc, MPS_INFO, "Unfreezing devq for target ID %d\n",
+		    target_id);
+		xpt_release_devq(tm->cm_ccb->ccb_h.path, 1, TRUE);
+		xpt_free_path(tm->cm_ccb->ccb_h.path);
+		xpt_free_ccb(tm->cm_ccb);
+	}
 
 	mps_free_high_priority_command(sc, tm);
 }
 
-
 void
 mpssas_rescan_target(struct mps_softc *sc, struct mpssas_target *targ)
 {
@@ -256,6 +275,7 @@
 	target_id_t targetid;
 	union ccb *ccb;
 
+	MPS_FUNCTRACE(sc);
 	pathid = cam_sim_path(sassc->sim);
 	if (targ == NULL)
 		targetid = CAM_TARGET_WILDCARD;
@@ -267,13 +287,13 @@
 	 */
 	ccb = xpt_alloc_ccb_nowait();
 	if (ccb == NULL) {
-		mps_dprint(sc, MPS_FAULT, "unable to alloc CCB for rescan\n");
+		mps_dprint(sc, MPS_ERROR, "unable to alloc CCB for rescan\n");
 		return;
 	}
 
-	if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, pathid,
-		            targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
-		mps_dprint(sc, MPS_FAULT, "unable to create path for rescan\n");
+	if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid,
+	    targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+		mps_dprint(sc, MPS_ERROR, "unable to create path for rescan\n");
 		xpt_free_ccb(ccb);
 		return;
 	}
@@ -284,11 +304,11 @@
 		ccb->ccb_h.func_code = XPT_SCAN_TGT;     
 
 	mps_dprint(sc, MPS_TRACE, "%s targetid %u\n", __func__, targetid);
-	mpssas_rescan(sassc, ccb);
+	xpt_rescan(ccb);
 }
 
 static void
-mpssas_log_command(struct mps_command *cm, const char *fmt, ...)
+mpssas_log_command(struct mps_command *cm, u_int level, const char *fmt, ...)
 {
 	struct sbuf sb;
 	va_list ap;
@@ -298,6 +318,10 @@
 	if (cm == NULL)
 		return;
 
+	/* No need to be in here if debugging isn't enabled */
+	if ((cm->cm_sc->mps_debug & level) == 0)
+		return;
+
 	sbuf_new(&sb, str, sizeof(str), 0);
 
 	va_start(ap, fmt);
@@ -324,7 +348,7 @@
 	sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID);
 	sbuf_vprintf(&sb, fmt, ap);
 	sbuf_finish(&sb);
-	printf("%s", sbuf_data(&sb));
+	mps_print_field(cm->cm_sc, "%s", sbuf_data(&sb));
 
 	va_end(ap);
 }
@@ -337,7 +361,7 @@
 	struct mpssas_target *targ;
 	uint16_t handle;
 
-	mps_dprint(sc, MPS_INFO, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
@@ -345,24 +369,27 @@
 
 	if (reply == NULL) {
 		/* XXX retry the remove after the diag reset completes? */
-		mps_printf(sc, "%s NULL reply reseting device 0x%04x\n", 
-		    __func__, handle);
+		mps_dprint(sc, MPS_FAULT,
+		    "%s NULL reply resetting device 0x%04x\n", __func__,
+		    handle);
 		mpssas_free_tm(sc, tm);
 		return;
 	}
 
-	if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
-		mps_printf(sc, "IOCStatus = 0x%x while resetting device 0x%x\n",
-		   reply->IOCStatus, handle);
-		mpssas_free_tm(sc, tm);
-		return;
+	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
+	    MPI2_IOCSTATUS_SUCCESS) {
+		mps_dprint(sc, MPS_ERROR,
+		   "IOCStatus = 0x%x while resetting device 0x%x\n",
+		   le16toh(reply->IOCStatus), handle);
 	}
 
-	mps_printf(sc, "Reset aborted %u commands\n", reply->TerminationCount);
+	mps_dprint(sc, MPS_XINFO,
+	    "Reset aborted %u commands\n", reply->TerminationCount);
 	mps_free_reply(sc, tm->cm_reply_data);
 	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
 
-	mps_printf(sc, "clearing target %u handle 0x%04x\n", targ->tid, handle);
+	mps_dprint(sc, MPS_XINFO,
+	    "clearing target %u handle 0x%04x\n", targ->tid, handle);
 	
 	/*
 	 * Don't clear target if remove fails because things will get confusing.
@@ -370,7 +397,8 @@
 	 * this target id if possible, and so we can assign the same target id
 	 * to this device if it comes back in the future.
 	 */
-	if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) {
+	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
+	    MPI2_IOCSTATUS_SUCCESS) {
 		targ = tm->cm_targ;
 		targ->handle = 0x0;
 		targ->encl_handle = 0x0;
@@ -398,7 +426,7 @@
 	struct mps_command *cm;
 	struct mpssas_target *targ = NULL;
 
-	mps_dprint(sassc->sc, MPS_INFO, "%s\n", __func__);
+	MPS_FUNCTRACE(sassc->sc);
 	sc = sassc->sc;
 
 #ifdef WD_SUPPORT
@@ -417,7 +445,8 @@
 	if (targ == NULL) {
 		/* FIXME: what is the action? */
 		/* We don't know about this device? */
-		printf("%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle);
+		mps_dprint(sc, MPS_ERROR,
+		   "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle);
 		return;
 	}
 
@@ -425,7 +454,8 @@
 
 	cm = mpssas_alloc_tm(sc);
 	if (cm == NULL) {
-		mps_printf(sc, "%s: command alloc failure\n", __func__);
+		mps_dprint(sc, MPS_ERROR,
+		    "%s: command alloc failure\n", __func__);
 		return;
 	}
 
@@ -445,6 +475,11 @@
 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
 	cm->cm_complete = mpssas_remove_volume;
 	cm->cm_complete_data = (void *)(uintptr_t)handle;
+
+	mps_dprint(sc, MPS_INFO, "%s: Sending reset for target ID %d\n",
+	    __func__, targ->tid);
+	mpssas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD);
+
 	mps_map_command(sc, cm);
 }
 
@@ -465,7 +500,7 @@
 	struct mps_command *cm;
 	struct mpssas_target *targ = NULL;
 
-	mps_dprint(sassc->sc, MPS_INFO, "%s\n", __func__);
+	MPS_FUNCTRACE(sassc->sc);
 
 	sc = sassc->sc;
 
@@ -473,7 +508,8 @@
 	if (targ == NULL) {
 		/* FIXME: what is the action? */
 		/* We don't know about this device? */
-		printf("%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle);
+		mps_dprint(sc, MPS_ERROR,
+		    "%s : invalid handle 0x%x \n", __func__, handle);
 		return;
 	}
 
@@ -481,7 +517,8 @@
 
 	cm = mpssas_alloc_tm(sc);
 	if (cm == NULL) {
-		mps_printf(sc, "%s: command alloc failure\n", __func__);
+		mps_dprint(sc, MPS_ERROR,
+		    "%s: command alloc failure\n", __func__);
 		return;
 	}
 
@@ -501,6 +538,11 @@
 	cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
 	cm->cm_complete = mpssas_remove_device;
 	cm->cm_complete_data = (void *)(uintptr_t)handle;
+
+	mps_dprint(sc, MPS_INFO, "%s: Sending reset for target ID %d\n",
+	    __func__, targ->tid);
+	mpssas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD);
+
 	mps_map_command(sc, cm);
 }
 
@@ -513,7 +555,7 @@
 	struct mps_command *next_cm;
 	uint16_t handle;
 
-	mps_dprint(sc, MPS_INFO, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
@@ -525,29 +567,29 @@
 	 * task management commands don't have S/G lists.
 	 */
 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
-		mps_printf(sc, "%s: cm_flags = %#x for remove of handle %#04x! "
-			   "This should not happen!\n", __func__, tm->cm_flags,
-			   handle);
-		mpssas_free_tm(sc, tm);
-		return;
+		mps_dprint(sc, MPS_ERROR,
+		    "%s: cm_flags = %#x for remove of handle %#04x! "
+		    "This should not happen!\n", __func__, tm->cm_flags,
+		    handle);
 	}
 
 	if (reply == NULL) {
 		/* XXX retry the remove after the diag reset completes? */
-		mps_printf(sc, "%s NULL reply reseting device 0x%04x\n", 
-		    __func__, handle);
+		mps_dprint(sc, MPS_FAULT,
+		    "%s NULL reply resetting device 0x%04x\n", __func__,
+		    handle);
 		mpssas_free_tm(sc, tm);
 		return;
 	}
 
-	if (le16toh(reply->IOCStatus) != MPI2_IOCSTATUS_SUCCESS) {
-		mps_printf(sc, "IOCStatus = 0x%x while resetting device 0x%x\n",
+	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
+	    MPI2_IOCSTATUS_SUCCESS) {
+		mps_dprint(sc, MPS_ERROR,
+		   "IOCStatus = 0x%x while resetting device 0x%x\n",
 		   le16toh(reply->IOCStatus), handle);
-		mpssas_free_tm(sc, tm);
-		return;
 	}
 
-	mps_dprint(sc, MPS_INFO, "Reset aborted %u commands\n",
+	mps_dprint(sc, MPS_XINFO, "Reset aborted %u commands\n",
 	    le32toh(reply->TerminationCount));
 	mps_free_reply(sc, tm->cm_reply_data);
 	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
@@ -565,14 +607,14 @@
 
 	mps_map_command(sc, tm);
 
-	mps_dprint(sc, MPS_INFO, "clearing target %u handle 0x%04x\n",
+	mps_dprint(sc, MPS_XINFO, "clearing target %u handle 0x%04x\n",
 		   targ->tid, handle);
 	TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) {
 		union ccb *ccb;
 
-		mps_dprint(sc, MPS_INFO, "Completing missed command %p\n", tm);
+		mps_dprint(sc, MPS_XINFO, "Completing missed command %p\n", tm);
 		ccb = tm->cm_complete_data;
-		ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 		mpssas_scsiio_complete(sc, tm);
 	}
 }
@@ -585,7 +627,7 @@
 	struct mpssas_target *targ;
 	struct mpssas_lun *lun;
 
-	mps_dprint(sc, MPS_INFO, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply;
 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
@@ -596,7 +638,8 @@
 	 * task management commands don't have S/G lists.
 	 */
 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
-		mps_printf(sc, "%s: cm_flags = %#x for remove of handle %#04x! "
+		mps_dprint(sc, MPS_XINFO,
+			   "%s: cm_flags = %#x for remove of handle %#04x! "
 			   "This should not happen!\n", __func__, tm->cm_flags,
 			   handle);
 		mpssas_free_tm(sc, tm);
@@ -605,13 +648,14 @@
 
 	if (reply == NULL) {
 		/* most likely a chip reset */
-		mps_printf(sc, "%s NULL reply removing device 0x%04x\n",
-		    __func__, handle);
+		mps_dprint(sc, MPS_FAULT,
+		    "%s NULL reply removing device 0x%04x\n", __func__, handle);
 		mpssas_free_tm(sc, tm);
 		return;
 	}
 
-	mps_printf(sc, "%s on handle 0x%04x, IOCStatus= 0x%x\n", __func__, 
+	mps_dprint(sc, MPS_XINFO,
+	    "%s on handle 0x%04x, IOCStatus= 0x%x\n", __func__, 
 	    handle, le16toh(reply->IOCStatus));
 
 	/*
@@ -620,7 +664,8 @@
 	 * this target id if possible, and so we can assign the same target id
 	 * to this device if it comes back in the future.
 	 */
-	if (le16toh(reply->IOCStatus) == MPI2_IOCSTATUS_SUCCESS) {
+	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
+	    MPI2_IOCSTATUS_SUCCESS) {
 		targ = tm->cm_targ;
 		targ->handle = 0x0;
 		targ->encl_handle = 0x0;
@@ -671,12 +716,10 @@
 mps_attach_sas(struct mps_softc *sc)
 {
 	struct mpssas_softc *sassc;
-#if __FreeBSD_version >= 1000006
 	cam_status status;
-#endif
 	int unit, error = 0;
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	sassc = malloc(sizeof(struct mpssas_softc), M_MPT2, M_WAITOK|M_ZERO);
 	if(!sassc) {
@@ -684,8 +727,16 @@
 		__func__, __LINE__);
 		return (ENOMEM);
 	}
+
+	/*
+	 * XXX MaxTargets could change during a reinit.  Since we don't
+	 * resize the targets[] array during such an event, cache the value
+	 * of MaxTargets here so that we don't get into trouble later.  This
+	 * should move into the reinit logic.
+	 */
+	sassc->maxtargets = sc->facts->MaxTargets + sc->facts->MaxVolumes;
 	sassc->targets = malloc(sizeof(struct mpssas_target) *
-	    sc->facts->MaxTargets, M_MPT2, M_WAITOK|M_ZERO);
+	    sassc->maxtargets, M_MPT2, M_WAITOK|M_ZERO);
 	if(!sassc->targets) {
 		device_printf(sc->mps_dev, "Cannot allocate memory %s %d\n",
 		__func__, __LINE__);
@@ -696,7 +747,7 @@
 	sassc->sc = sc;
 
 	if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) {
-		mps_dprint(sc, MPS_FAULT, "Cannot allocate SIMQ\n");
+		mps_dprint(sc, MPS_ERROR, "Cannot allocate SIMQ\n");
 		error = ENOMEM;
 		goto out;
 	}
@@ -705,7 +756,7 @@
 	sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc,
 	    unit, &sc->mps_mtx, sc->num_reqs, sc->num_reqs, sassc->devq);
 	if (sassc->sim == NULL) {
-		mps_dprint(sc, MPS_FAULT, "Cannot allocate SIM\n");
+		mps_dprint(sc, MPS_ERROR, "Cannot allocate SIM\n");
 		error = EINVAL;
 		goto out;
 	}
@@ -716,21 +767,10 @@
 	TASK_INIT(&sassc->ev_task, 0, mpssas_firmware_event_work, sc);
 	sassc->ev_tq = taskqueue_create("mps_taskq", M_NOWAIT | M_ZERO,
 	    taskqueue_thread_enqueue, &sassc->ev_tq);
-
-	/* Run the task queue with lowest priority */
-	taskqueue_start_threads(&sassc->ev_tq, 1, 255, "%s taskq", 
+	taskqueue_start_threads(&sassc->ev_tq, 1, PRIBIO, "%s taskq", 
 	    device_get_nameunit(sc->mps_dev));
 
-	TAILQ_INIT(&sassc->ccb_scanq);
-	error = mps_kproc_create(mpssas_scanner_thread, sassc,
-	    &sassc->rescan_thread, 0, 0, "mps_scan%d", unit);
-	if (error) {
-		mps_printf(sc, "Error %d starting rescan thread\n", error);
-		goto out;
-	}
-
 	mps_lock(sc);
-	sassc->flags |= MPSSAS_SCANTHREAD;
 
 	/*
 	 * XXX There should be a bus for every port on the adapter, but since
@@ -738,7 +778,7 @@
 	 * everything is just a target on a single bus.
 	 */
 	if ((error = xpt_bus_register(sassc->sim, sc->mps_dev, 0)) != 0) {
-		mps_dprint(sc, MPS_FAULT, "Error %d registering SCSI bus\n",
+		mps_dprint(sc, MPS_ERROR, "Error %d registering SCSI bus\n",
 		    error);
 		mps_unlock(sc);
 		goto out;
@@ -745,26 +785,52 @@
 	}
 
 	/*
-	 * Assume that discovery events will start right away.  Freezing
-	 * the simq will prevent the CAM boottime scanner from running
-	 * before discovery is complete.
+	 * Assume that discovery events will start right away.
+	 *
+	 * Hold off boot until discovery is complete.
 	 */
 	sassc->flags |= MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY;
-	xpt_freeze_simq(sassc->sim, 1);
 	sc->sassc->startup_refcount = 0;
+	mpssas_startup_increment(sassc);
 
 	callout_init(&sassc->discovery_callout, 1 /*mpsafe*/);
-	sassc->discovery_timeouts = 0;
 
-	sassc->tm_count = 0;
+	/*
+	 * Register for async events so we can determine the EEDP
+	 * capabilities of devices.
+	 */
+	status = xpt_create_path(&sassc->path, /*periph*/NULL,
+	    cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD,
+	    CAM_LUN_WILDCARD);
+	if (status != CAM_REQ_CMP) {
+		mps_printf(sc, "Error %#x creating sim path\n", status);
+		sassc->path = NULL;
+	} else {
+		int event;
 
-#if __FreeBSD_version >= 1000006
-	status = xpt_register_async(AC_ADVINFO_CHANGED, mpssas_async, sc, NULL);
+#if (__FreeBSD_version >= 1000006) || \
+    ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
+		event = AC_ADVINFO_CHANGED;
+#else
+		event = AC_FOUND_DEVICE;
+#endif
+		status = xpt_register_async(event, mpssas_async, sc,
+					    sassc->path);
+		if (status != CAM_REQ_CMP) {
+			mps_dprint(sc, MPS_ERROR,
+			    "Error %#x registering async handler for "
+			    "AC_ADVINFO_CHANGED events\n", status);
+			xpt_free_path(sassc->path);
+			sassc->path = NULL;
+		}
+	}
 	if (status != CAM_REQ_CMP) {
-		mps_printf(sc, "Error %#x registering async handler for "
-			   "AC_ADVINFO_CHANGED events\n", status);
+		/*
+		 * EEDP use is the exception, not the rule.
+		 * Warn the user, but do not fail to attach.
+		 */
+		mps_printf(sc, "EEDP capabilities disabled.\n");
 	}
-#endif
 
 	mps_unlock(sc);
 
@@ -783,7 +849,7 @@
 	struct mpssas_target *targ;
 	int i;
 
-	mps_dprint(sc, MPS_INFO, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	if (sc->sassc == NULL)
 		return (0);
@@ -803,9 +869,11 @@
 	mps_lock(sc);
 
 	/* Deregister our async handler */
-#if __FreeBSD_version >= 1000006
-	xpt_register_async(0, mpssas_async, sc, NULL);
-#endif
+	if (sassc->path != NULL) {
+		xpt_register_async(0, mpssas_async, sc, sassc->path);
+		xpt_free_path(sassc->path);
+		sassc->path = NULL;
+	}
 
 	if (sassc->flags & MPSSAS_IN_STARTUP)
 		xpt_release_simq(sassc->sim, 1);
@@ -815,22 +883,12 @@
 		cam_sim_free(sassc->sim, FALSE);
 	}
 
-	if (sassc->flags & MPSSAS_SCANTHREAD) {
-		sassc->flags |= MPSSAS_SHUTDOWN;
-		wakeup(&sassc->ccb_scanq);
-		
-		if (sassc->flags & MPSSAS_SCANTHREAD) {
-			msleep(&sassc->flags, &sc->mps_mtx, PRIBIO,
-			       "mps_shutdown", 30 * hz);
-		}
-	}
 	mps_unlock(sc);
 
-	mps_dprint(sc, MPS_INFO, "%s:%d\n", __func__,__LINE__);
 	if (sassc->devq != NULL)
 		cam_simq_free(sassc->devq);
 
-	for(i=0; i< sc->facts->MaxTargets ;i++) {
+	for(i=0; i< sassc->maxtargets ;i++) {
 		targ = &sassc->targets[i];
 		SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
 			free(lun, M_MPT2);
@@ -848,51 +906,30 @@
 {
 	struct mps_softc *sc = sassc->sc;
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	if (sassc->flags & MPSSAS_DISCOVERY_TIMEOUT_PENDING)
 		callout_stop(&sassc->discovery_callout);
 
-}
-
-static void
-mpssas_discovery_timeout(void *data)
-{
-	struct mpssas_softc *sassc = data;
-	struct mps_softc *sc;
-
-	sc = sassc->sc;
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-	mps_lock(sc);
-	mps_printf(sc,
-	    "Timeout waiting for discovery, interrupts may not be working!\n");
-	sassc->flags &= ~MPSSAS_DISCOVERY_TIMEOUT_PENDING;
-
-	/* Poll the hardware for events in case interrupts aren't working */
-	mps_intr_locked(sc);
-
-	mps_printf(sassc->sc,
-	    "Finished polling after discovery timeout at %d\n", ticks);
-
-	if ((sassc->flags & MPSSAS_IN_DISCOVERY) == 0) {
-		mpssas_discovery_end(sassc);
-	} else {
-		if (sassc->discovery_timeouts < MPSSAS_MAX_DISCOVERY_TIMEOUTS) {
-			sassc->flags |= MPSSAS_DISCOVERY_TIMEOUT_PENDING;
-			callout_reset(&sassc->discovery_callout,
-			    MPSSAS_DISCOVERY_TIMEOUT * hz,
-			    mpssas_discovery_timeout, sassc);
-			sassc->discovery_timeouts++;
-		} else {
-			mps_dprint(sassc->sc, MPS_FAULT,
-			    "Discovery timed out, continuing.\n");
-			sassc->flags &= ~MPSSAS_IN_DISCOVERY;
-			mpssas_discovery_end(sassc);
-		}
+	/*
+	 * After discovery has completed, check the mapping table for any
+	 * missing devices and update their missing counts. Only do this once
+	 * whenever the driver is initialized so that missing counts aren't
+	 * updated unnecessarily. Note that just because discovery has
+	 * completed doesn't mean that events have been processed yet. The
+	 * check_devices function is a callout timer that checks if ALL devices
+	 * are missing. If so, it will wait a little longer for events to
+	 * complete and keep resetting itself until some device in the mapping
+	 * table is not missing, meaning that event processing has started.
+	 */
+	if (sc->track_mapping_events) {
+		mps_dprint(sc, MPS_XINFO | MPS_MAPPING, "Discovery has "
+		    "completed. Check for missing devices in the mapping "
+		    "table.\n");
+		callout_reset(&sc->device_check_callout,
+		    MPS_MISSING_CHECK_DELAY * hz, mps_mapping_check_devices,
+		    sc);
 	}
-
-	mps_unlock(sc);
 }
 
 static void
@@ -902,7 +939,8 @@
 
 	sassc = cam_sim_softc(sim);
 
-	mps_dprint(sassc->sc, MPS_TRACE, "%s func 0x%x\n", __func__, 
+	MPS_FUNCTRACE(sassc->sc);
+	mps_dprint(sassc->sc, MPS_TRACE, "ccb func_code 0x%x\n",
 	    ccb->ccb_h.func_code);
 	mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
 
@@ -910,18 +948,29 @@
 	case XPT_PATH_INQ:
 	{
 		struct ccb_pathinq *cpi = &ccb->cpi;
+		struct mps_softc *sc = sassc->sc;
+		uint8_t sges_per_frame;
 
 		cpi->version_num = 1;
 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
 		cpi->target_sprt = 0;
-		cpi->hba_misc = PIM_NOBUSRESET;
+#if __FreeBSD_version >= 1000039
+		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN;
+#else
+		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED;
+#endif
 		cpi->hba_eng_cnt = 0;
-		cpi->max_target = sassc->sc->facts->MaxTargets - 1;
+		cpi->max_target = sassc->maxtargets - 1;
 		cpi->max_lun = 255;
-		cpi->initiator_id = 255;
-		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
-		strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN);
-		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+
+		/*
+		 * initiator_id is set here to an ID outside the set of valid
+		 * target IDs (including volumes).
+		 */
+		cpi->initiator_id = sassc->maxtargets;
+		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+		strlcpy(cpi->hba_vid, "Avago Tech", HBA_IDLEN);
+		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
 		cpi->unit_number = cam_sim_unit(sim);
 		cpi->bus_id = cam_sim_bus(sim);
 		cpi->base_transfer_speed = 150000;
@@ -929,13 +978,24 @@
 		cpi->transport_version = 0;
 		cpi->protocol = PROTO_SCSI;
 		cpi->protocol_version = SCSI_REV_SPC;
-#if __FreeBSD_version >= 800001
+
 		/*
-		 * XXX KDM where does this number come from?
+		 * Max IO Size is Page Size * the following:
+		 * ((SGEs per frame - 1 for chain element) *
+		 * Max Chain Depth) + 1 for no chain needed in last frame
+		 *
+		 * If user suggests a Max IO size to use, use the smaller of the
+		 * user's value and the calculated value as long as the user's
+		 * value is larger than 0. The user's value is in pages.
 		 */
-		cpi->maxio = 256 * 1024;
-#endif
-		cpi->ccb_h.status = CAM_REQ_CMP;
+		sges_per_frame = ((sc->facts->IOCRequestFrameSize * 4) /
+		    sizeof(MPI2_SGE_SIMPLE64)) - 1;
+		cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1;
+		cpi->maxio *= PAGE_SIZE;
+		if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE <
+		    cpi->maxio))
+			cpi->maxio = sc->max_io_pages * PAGE_SIZE;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		break;
 	}
 	case XPT_GET_TRAN_SETTINGS:
@@ -949,9 +1009,12 @@
 		sas = &cts->xport_specific.sas;
 		scsi = &cts->proto_specific.scsi;
 
+		KASSERT(cts->ccb_h.target_id < sassc->maxtargets,
+		    ("Target %d out of bounds in XPT_GET_TRANS_SETTINGS\n",
+		    cts->ccb_h.target_id));
 		targ = &sassc->targets[cts->ccb_h.target_id];
 		if (targ->handle == 0x0) {
-			cts->ccb_h.status = CAM_SEL_TIMEOUT;
+			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 			break;
 		}
 
@@ -978,23 +1041,23 @@
 		scsi->valid = CTS_SCSI_VALID_TQ;
 		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
 
-		cts->ccb_h.status = CAM_REQ_CMP;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		break;
 	}
 	case XPT_CALC_GEOMETRY:
 		cam_calc_geometry(&ccb->ccg, /*extended*/1);
-		ccb->ccb_h.status = CAM_REQ_CMP;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		break;
 	case XPT_RESET_DEV:
-		mps_printf(sassc->sc, "mpssas_action XPT_RESET_DEV\n");
+		mps_dprint(sassc->sc, MPS_XINFO, "mpssas_action XPT_RESET_DEV\n");
 		mpssas_action_resetdev(sassc, ccb);
 		return;
 	case XPT_RESET_BUS:
 	case XPT_ABORT:
 	case XPT_TERM_IO:
-		mps_printf(sassc->sc, "mpssas_action faking success for "
-			   "abort or reset\n");
-		ccb->ccb_h.status = CAM_REQ_CMP;
+		mps_dprint(sassc->sc, MPS_XINFO,
+		    "mpssas_action faking success for abort or reset\n");
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		break;
 	case XPT_SCSI_IO:
 		mpssas_action_scsiio(sassc, ccb);
@@ -1005,7 +1068,7 @@
 		return;
 #endif
 	default:
-		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+		mpssas_set_ccbstatus(ccb, CAM_FUNC_NOTAVAIL);
 		break;
 	}
 	xpt_done(ccb);
@@ -1019,12 +1082,12 @@
 	path_id_t path_id = cam_sim_path(sc->sassc->sim);
 	struct cam_path *path;
 
-	mps_printf(sc, "%s code %x target %d lun %d\n", __func__,
-	    ac_code, target_id, lun_id);
+	mps_dprint(sc, MPS_XINFO, "%s code %x target %d lun %jx\n", __func__,
+	    ac_code, target_id, (uintmax_t)lun_id);
 
 	if (xpt_create_path(&path, NULL, 
 		path_id, target_id, lun_id) != CAM_REQ_CMP) {
-		mps_printf(sc, "unable to create path for reset "
+		mps_dprint(sc, MPS_ERROR, "unable to create path for reset "
 			   "notification\n");
 		return;
 	}
@@ -1040,7 +1103,7 @@
 	int i;
 	int completed;
 
-	mps_printf(sc, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 	mtx_assert(&sc->mps_mtx, MA_OWNED);
 
 	/* complete all commands with a NULL reply */
@@ -1053,7 +1116,7 @@
 			cm->cm_flags |= MPS_CM_FLAGS_COMPLETE;
 
 		if (cm->cm_complete != NULL) {
-			mpssas_log_command(cm, 
+			mpssas_log_command(cm, MPS_RECOVERY,
 			    "completing cm %p state %x ccb %p for diag reset\n", 
 			    cm, cm->cm_state, cm->cm_ccb);
 
@@ -1062,16 +1125,19 @@
 		}
 
 		if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) {
-			mpssas_log_command(cm, 
+			mpssas_log_command(cm, MPS_RECOVERY,
 			    "waking up cm %p state %x ccb %p for diag reset\n", 
 			    cm, cm->cm_state, cm->cm_ccb);
 			wakeup(cm);
 			completed = 1;
 		}
+
+		if (cm->cm_sc->io_cmds_active != 0)
+			cm->cm_sc->io_cmds_active--;
 		
 		if ((completed == 0) && (cm->cm_state != MPS_CM_STATE_FREE)) {
 			/* this should never happen, but if it does, log */
-			mpssas_log_command(cm, 
+			mpssas_log_command(cm, MPS_RECOVERY,
 			    "cm %p state %x flags 0x%x ccb %p during diag "
 			    "reset\n", cm, cm->cm_state, cm->cm_flags,
 			    cm->cm_ccb);
@@ -1092,10 +1158,10 @@
 	 * discovery-related activities have finished, the simq will be
 	 * released.
 	 */
-	mps_printf(sc, "%s startup\n", __func__);
+	mps_dprint(sc, MPS_INIT, "%s startup\n", __func__);
 	sc->sassc->flags |= MPSSAS_IN_STARTUP;
 	sc->sassc->flags |= MPSSAS_IN_DISCOVERY;
-	xpt_freeze_simq(sc->sassc->sim, 1);
+	mpssas_startup_increment(sc->sassc);
 
 	/* notify CAM of a bus reset */
 	mpssas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD, 
@@ -1104,22 +1170,17 @@
 	/* complete and cleanup after all outstanding commands */
 	mpssas_complete_all_commands(sc);
 
-	mps_printf(sc, "%s startup %u tm %u after command completion\n",
-	    __func__, sc->sassc->startup_refcount, sc->sassc->tm_count);
+	mps_dprint(sc, MPS_INIT,
+	    "%s startup %u after command completion\n", __func__,
+	    sc->sassc->startup_refcount);
 
-	/*
-	 * The simq was explicitly frozen above, so set the refcount to 0.
-	 * The simq will be explicitly released after port enable completes.
-	 */
-	sc->sassc->startup_refcount = 0;
-
 	/* zero all the target handles, since they may change after the
 	 * reset, and we have to rediscover all the targets and use the new
 	 * handles.  
 	 */
-	for (i = 0; i < sc->facts->MaxTargets; i++) {
+	for (i = 0; i < sc->sassc->maxtargets; i++) {
 		if (sc->sassc->targets[i].outstanding != 0)
-			mps_printf(sc, "target %u outstanding %u\n", 
+			mps_dprint(sc, MPS_INIT, "target %u outstanding %u\n", 
 			    i, sc->sassc->targets[i].outstanding);
 		sc->sassc->targets[i].handle = 0x0;
 		sc->sassc->targets[i].exp_dev_handle = 0x0;
@@ -1127,6 +1188,7 @@
 		sc->sassc->targets[i].flags = MPSSAS_TARGET_INDIAGRESET;
 	}
 }
+
 static void
 mpssas_tm_timeout(void *data)
 {
@@ -1135,7 +1197,8 @@
 
 	mtx_assert(&sc->mps_mtx, MA_OWNED);
 
-	mpssas_log_command(tm, "task mgmt %p timed out\n", tm);
+	mpssas_log_command(tm, MPS_INFO|MPS_RECOVERY,
+	    "task mgmt %p timed out\n", tm);
 	mps_reinit(sc);
 }
 
@@ -1158,9 +1221,10 @@
 	 * Currently there should be no way we can hit this case.  It only
 	 * happens when we have a failure to allocate chain frames, and
 	 * task management commands don't have S/G lists.
+	 * XXXSL So should it be an assertion?
 	 */
 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
-		mps_printf(sc, "%s: cm_flags = %#x for LUN reset! "
+		mps_dprint(sc, MPS_ERROR, "%s: cm_flags = %#x for LUN reset! "
 			   "This should not happen!\n", __func__, tm->cm_flags);
 		mpssas_free_tm(sc, tm);
 		return;
@@ -1167,10 +1231,10 @@
 	}
 
 	if (reply == NULL) {
-		mpssas_log_command(tm, "NULL reset reply for tm %p\n", tm);
+		mpssas_log_command(tm, MPS_RECOVERY,
+		    "NULL reset reply for tm %p\n", tm);
 		if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
 			/* this completion was due to a reset, just cleanup */
-			targ->flags &= ~MPSSAS_TARGET_INRESET;
 			targ->tm = NULL;
 			mpssas_free_tm(sc, tm);
 		}
@@ -1181,7 +1245,7 @@
 		return;
 	}
 
-	mpssas_log_command(tm, 
+	mpssas_log_command(tm, MPS_RECOVERY,
 	    "logical unit reset status 0x%x code 0x%x count %u\n",
 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
 	    le32toh(reply->TerminationCount));
@@ -1196,7 +1260,7 @@
 	}
 
 	if (cm_count == 0) {
-		mpssas_log_command(tm, 
+		mpssas_log_command(tm, MPS_RECOVERY|MPS_INFO,
 		    "logical unit %u finished recovery after reset\n",
 		    tm->cm_lun, tm);
 
@@ -1221,7 +1285,7 @@
 		 * effectively failed, regardless of the status reported.
 		 * Escalate to a target reset.
 		 */
-		mpssas_log_command(tm, 
+		mpssas_log_command(tm, MPS_RECOVERY,
 		    "logical unit reset complete for tm %p, but still have %u command(s)\n",
 		    tm, cm_count);
 		mpssas_send_reset(sc, tm,
@@ -1248,7 +1312,7 @@
 	 * task management commands don't have S/G lists.
 	 */
 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
-		mps_printf(sc, "%s: cm_flags = %#x for target reset! "
+		mps_dprint(sc, MPS_ERROR,"%s: cm_flags = %#x for target reset! "
 			   "This should not happen!\n", __func__, tm->cm_flags);
 		mpssas_free_tm(sc, tm);
 		return;
@@ -1255,10 +1319,10 @@
 	}
 
 	if (reply == NULL) {
-		mpssas_log_command(tm, "NULL reset reply for tm %p\n", tm);
+		mpssas_log_command(tm, MPS_RECOVERY,
+		    "NULL reset reply for tm %p\n", tm);
 		if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
 			/* this completion was due to a reset, just cleanup */
-			targ->flags &= ~MPSSAS_TARGET_INRESET;
 			targ->tm = NULL;
 			mpssas_free_tm(sc, tm);
 		}
@@ -1269,18 +1333,16 @@
 		return;
 	}
 
-	mpssas_log_command(tm, 
+	mpssas_log_command(tm, MPS_RECOVERY,
 	    "target reset status 0x%x code 0x%x count %u\n",
 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
 	    le32toh(reply->TerminationCount));
 
-	targ->flags &= ~MPSSAS_TARGET_INRESET;
-
 	if (targ->outstanding == 0) {
 		/* we've finished recovery for this target and all
 		 * of its logical units.
 		 */
-		mpssas_log_command(tm, 
+		mpssas_log_command(tm, MPS_RECOVERY|MPS_INFO,
 		    "recovery finished after target reset\n");
 
 		mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
@@ -1294,7 +1356,7 @@
 		 * outstanding commands, the reset effectively failed,
 		 * regardless of the status reported.  escalate.
 		 */
-		mpssas_log_command(tm, 
+		mpssas_log_command(tm, MPS_RECOVERY,
 		    "target reset complete for tm %p, but still have %u command(s)\n", 
 		    tm, targ->outstanding);
 		mps_reinit(sc);
@@ -1303,7 +1365,7 @@
 
 #define MPS_RESET_TIMEOUT 30
 
-static int
+int
 mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type)
 {
 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
@@ -1312,7 +1374,7 @@
 
 	target = tm->cm_targ;
 	if (target->handle == 0) {
-		mps_printf(sc, "%s null devhandle for target_id %d\n",
+		mps_dprint(sc, MPS_ERROR,"%s null devhandle for target_id %d\n",
 		    __func__, target->tid);
 		return -1;
 	}
@@ -1326,19 +1388,25 @@
 		/* XXX Need to handle invalid LUNs */
 		MPS_SET_LUN(req->LUN, tm->cm_lun);
 		tm->cm_targ->logical_unit_resets++;
-		mpssas_log_command(tm, "sending logical unit reset\n");
+		mpssas_log_command(tm, MPS_RECOVERY|MPS_INFO,
+		    "sending logical unit reset\n");
 		tm->cm_complete = mpssas_logical_unit_reset_complete;
+		mpssas_prepare_for_tm(sc, tm, target, tm->cm_lun);
 	}
 	else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
-		/* Target reset method =  SAS Hard Link Reset / SATA Link Reset */
+		/*
+		 * Target reset method =
+		 * 	SAS Hard Link Reset / SATA Link Reset
+		 */
 		req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
 		tm->cm_targ->target_resets++;
-		tm->cm_targ->flags |= MPSSAS_TARGET_INRESET;
-		mpssas_log_command(tm, "sending target reset\n");
+		mpssas_log_command(tm, MPS_RECOVERY|MPS_INFO,
+		    "sending target reset\n");
 		tm->cm_complete = mpssas_target_reset_complete;
+		mpssas_prepare_for_tm(sc, tm, target, CAM_LUN_WILDCARD);
 	}
 	else {
-		mps_printf(sc, "unexpected reset type 0x%x\n", type);
+		mps_dprint(sc, MPS_ERROR, "unexpected reset type 0x%x\n", type);
 		return -1;
 	}
 
@@ -1351,7 +1419,7 @@
 
 	err = mps_map_command(sc, tm);
 	if (err)
-		mpssas_log_command(tm,
+		mpssas_log_command(tm, MPS_RECOVERY,
 		    "error %d sending reset type %u\n",
 		    err, type);
 
@@ -1379,7 +1447,7 @@
 	 * task management commands don't have S/G lists.
 	 */
 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
-		mpssas_log_command(tm,
+		mpssas_log_command(tm, MPS_RECOVERY,
 		    "cm_flags = %#x for abort %p TaskMID %u!\n", 
 		    tm->cm_flags, tm, le16toh(req->TaskMID));
 		mpssas_free_tm(sc, tm);
@@ -1387,7 +1455,7 @@
 	}
 
 	if (reply == NULL) {
-		mpssas_log_command(tm,
+		mpssas_log_command(tm, MPS_RECOVERY,
 		    "NULL abort reply for tm %p TaskMID %u\n", 
 		    tm, le16toh(req->TaskMID));
 		if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
@@ -1402,7 +1470,7 @@
 		return;
 	}
 
-	mpssas_log_command(tm,
+	mpssas_log_command(tm, MPS_RECOVERY,
 	    "abort TaskMID %u status 0x%x code 0x%x count %u\n",
 	    le16toh(req->TaskMID),
 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
@@ -1413,7 +1481,7 @@
 		/* if there are no more timedout commands, we're done with
 		 * error recovery for this target.
 		 */
-		mpssas_log_command(tm, 
+		mpssas_log_command(tm, MPS_RECOVERY,
 		    "finished recovery after aborting TaskMID %u\n",
 		    le16toh(req->TaskMID));
 
@@ -1422,7 +1490,7 @@
 	}
 	else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) {
 		/* abort success, but we have more timedout commands to abort */
-		mpssas_log_command(tm, 
+		mpssas_log_command(tm, MPS_RECOVERY,
 		    "continuing recovery after aborting TaskMID %u\n",
 		    le16toh(req->TaskMID));
 		
@@ -1432,7 +1500,7 @@
 		/* we didn't get a command completion, so the abort
 		 * failed as far as we're concerned.  escalate.
 		 */
-		mpssas_log_command(tm, 
+		mpssas_log_command(tm, MPS_RECOVERY,
 		    "abort failed for TaskMID %u tm %p\n",
 		    le16toh(req->TaskMID), tm);
 
@@ -1452,11 +1520,14 @@
 
 	targ = cm->cm_targ;
 	if (targ->handle == 0) {
-		mps_printf(sc, "%s null devhandle for target_id %d\n",
+		mps_dprint(sc, MPS_ERROR,"%s null devhandle for target_id %d\n",
 		    __func__, cm->cm_ccb->ccb_h.target_id);
 		return -1;
 	}
 
+	mpssas_log_command(cm, MPS_RECOVERY|MPS_INFO,
+	    "Aborting command %p\n", cm);
+
 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
 	req->DevHandle = htole16(targ->handle);
 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
@@ -1479,15 +1550,18 @@
 
 	targ->aborts++;
 
+	mps_dprint(sc, MPS_INFO, "Sending reset from %s for target ID %d\n",
+	    __func__, targ->tid);
+	mpssas_prepare_for_tm(sc, tm, targ, tm->cm_lun);
+
 	err = mps_map_command(sc, tm);
 	if (err)
-		mpssas_log_command(tm,
+		mps_dprint(sc, MPS_RECOVERY,
 		    "error %d sending abort for cm %p SMID %u\n",
 		    err, cm, req->TaskMID);
 	return err;
 }
 
-
 static void
 mpssas_scsiio_timeout(void *data)
 {
@@ -1498,9 +1572,10 @@
 	cm = (struct mps_command *)data;
 	sc = cm->cm_sc;
 
+	MPS_FUNCTRACE(sc);
 	mtx_assert(&sc->mps_mtx, MA_OWNED);
 
-	mps_printf(sc, "%s checking sc %p cm %p\n", __func__, sc, cm);
+	mps_dprint(sc, MPS_XINFO, "Timeout checking cm %p\n", sc);
 
 	/*
 	 * Run the interrupt handler to make sure it's not pending.  This
@@ -1509,26 +1584,27 @@
 	 */
 	mps_intr_locked(sc);
 	if (cm->cm_state == MPS_CM_STATE_FREE) {
-		mps_printf(sc, "SCSI command %p sc %p almost timed out\n", cm, sc);
+		mpssas_log_command(cm, MPS_XINFO,
+		    "SCSI command %p almost timed out\n", cm);
 		return;
 	}
 
 	if (cm->cm_ccb == NULL) {
-		mps_printf(sc, "command timeout with NULL ccb\n");
+		mps_dprint(sc, MPS_ERROR, "command timeout with NULL ccb\n");
 		return;
 	}
 
-	mpssas_log_command(cm, "command timeout cm %p ccb %p\n", 
-	    cm, cm->cm_ccb);
-
 	targ = cm->cm_targ;
 	targ->timeouts++;
 
+	mpssas_log_command(cm, MPS_ERROR, "command timeout %d cm %p target "
+	    "%u, handle(0x%04x)\n", cm->cm_ccb->ccb_h.timeout, cm,  targ->tid,
+	    targ->handle);
+
 	/* XXX first, check the firmware state, to see if it's still
 	 * operational.  if not, do a diag reset.
 	 */
-
-	cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT;
+	mpssas_set_ccbstatus(cm->cm_ccb, CAM_CMD_TIMEOUT);
 	cm->cm_state = MPS_CM_STATE_TIMEDOUT;
 	TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery);
 
@@ -1536,11 +1612,12 @@
 		/* target already in recovery, just queue up another
 		 * timedout command to be processed later.
 		 */
-		mps_printf(sc, "queued timedout cm %p for processing by tm %p\n",
+		mps_dprint(sc, MPS_RECOVERY,
+		    "queued timedout cm %p for processing by tm %p\n",
 		    cm, targ->tm);
 	}
 	else if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) {
-		mps_printf(sc, "timedout cm %p allocated tm %p\n",
+		mps_dprint(sc, MPS_RECOVERY, "timedout cm %p allocated tm %p\n",
 		    cm, targ->tm);
 
 		/* start recovery by aborting the first timedout command */
@@ -1556,8 +1633,8 @@
 		 * more credits than disks in an enclosure, and limit
 		 * ourselves to one TM per target for recovery.
 		 */
-		mps_printf(sc, "timedout cm %p failed to allocate a tm\n",
-		    cm);
+		mps_dprint(sc, MPS_RECOVERY,
+		    "timedout cm %p failed to allocate a tm\n", cm);
 	}
 
 }
@@ -1576,26 +1653,41 @@
 	uint32_t mpi_control;
 
 	sc = sassc->sc;
+	MPS_FUNCTRACE(sc);
 	mtx_assert(&sc->mps_mtx, MA_OWNED);
 
 	csio = &ccb->csio;
+	KASSERT(csio->ccb_h.target_id < sassc->maxtargets,
+	    ("Target %d out of bounds in XPT_SCSI_IO\n",
+	     csio->ccb_h.target_id));
 	targ = &sassc->targets[csio->ccb_h.target_id];
-	mps_dprint(sc, MPS_TRACE, "%s ccb %p target flag %x\n", __func__, ccb, targ->flags);
+	mps_dprint(sc, MPS_TRACE, "ccb %p target flag %x\n", ccb, targ->flags);
 	if (targ->handle == 0x0) {
-		mps_dprint(sc, MPS_TRACE, "%s NULL handle for target %u\n", 
+		mps_dprint(sc, MPS_ERROR, "%s NULL handle for target %u\n", 
 		    __func__, csio->ccb_h.target_id);
-		csio->ccb_h.status = CAM_SEL_TIMEOUT;
+		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 		xpt_done(ccb);
 		return;
 	}
 	if (targ->flags & MPS_TARGET_FLAGS_RAID_COMPONENT) {
-		mps_dprint(sc, MPS_TRACE, "%s Raid component no SCSI IO supported %u\n", 
-		    __func__, csio->ccb_h.target_id);
-		csio->ccb_h.status = CAM_TID_INVALID;
+		mps_dprint(sc, MPS_ERROR, "%s Raid component no SCSI IO "
+		    "supported %u\n", __func__, csio->ccb_h.target_id);
+		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 		xpt_done(ccb);
 		return;
 	}
 	/*
+	 * Sometimes, it is possible to get a command that is not "In
+	 * Progress" and was actually aborted by the upper layer.  Check for
+	 * this here and complete the command without error.
+	 */
+	if (mpssas_get_ccbstatus(ccb) != CAM_REQ_INPROG) {
+		mps_dprint(sc, MPS_TRACE, "%s Command is not in progress for "
+		    "target %u\n", __func__, csio->ccb_h.target_id);
+		xpt_done(ccb);
+		return;
+	}
+	/*
 	 * If devinfo is 0 this will be a volume.  In that case don't tell CAM
 	 * that the volume has timed out.  We want volumes to be enumerated
 	 * until they are deleted/removed, not just failed.
@@ -1602,22 +1694,38 @@
 	 */
 	if (targ->flags & MPSSAS_TARGET_INREMOVAL) {
 		if (targ->devinfo == 0)
-			csio->ccb_h.status = CAM_REQ_CMP;
+			mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		else
-			csio->ccb_h.status = CAM_SEL_TIMEOUT;
+			mpssas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT);
 		xpt_done(ccb);
 		return;
 	}
 
 	if ((sc->mps_flags & MPS_FLAGS_SHUTDOWN) != 0) {
-		mps_dprint(sc, MPS_TRACE, "%s shutting down\n", __func__);
-		csio->ccb_h.status = CAM_TID_INVALID;
+		mps_dprint(sc, MPS_INFO, "%s shutting down\n", __func__);
+		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 		xpt_done(ccb);
 		return;
 	}
 
+	/*
+	 * If target has a reset in progress, freeze the devq and return.  The
+	 * devq will be released when the TM reset is finished.
+	 */
+	if (targ->flags & MPSSAS_TARGET_INRESET) {
+		ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
+		mps_dprint(sc, MPS_INFO, "%s: Freezing devq for target ID %d\n",
+		    __func__, targ->tid);
+		xpt_freeze_devq(ccb->ccb_h.path, 1);
+		xpt_done(ccb);
+		return;
+	}
+
 	cm = mps_alloc_command(sc);
-	if (cm == NULL) {
+	if (cm == NULL || (sc->mps_flags & MPS_FLAGS_DIAGRESET)) {
+		if (cm != NULL) {
+			mps_free_command(sc, cm);
+		}
 		if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
 			xpt_freeze_simq(sassc->sim, 1);
 			sassc->flags |= MPSSAS_QUEUE_FROZEN;
@@ -1663,7 +1771,7 @@
 		break;
 	}
  
-  if (csio->cdb_len == 32)
+	if (csio->cdb_len == 32)
                 mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
 	/*
 	 * It looks like the hardware doesn't require an explicit tag
@@ -1690,7 +1798,7 @@
 	req->Control = htole32(mpi_control);
 	if (MPS_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) {
 		mps_free_command(sc, cm);
-		ccb->ccb_h.status = CAM_LUN_INVALID;
+		mpssas_set_ccbstatus(ccb, CAM_LUN_INVALID);
 		xpt_done(ccb);
 		return;
 	}
@@ -1755,8 +1863,13 @@
 		}
 	}
 
-	cm->cm_data = csio->data_ptr;
 	cm->cm_length = csio->dxfer_len;
+	if (cm->cm_length != 0) {
+		cm->cm_data = ccb;
+		cm->cm_flags |= MPS_CM_FLAGS_USE_CCB;
+	} else {
+		cm->cm_data = NULL;
+	}
 	cm->cm_sge = &req->SGL;
 	cm->cm_sglsize = (32 - 24) * 4;
 	cm->cm_desc.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
@@ -1773,23 +1886,23 @@
 	 * the I/O to the IR volume itself.
 	 */
 	if (sc->WD_valid_config) {
-		if (ccb->ccb_h.status != MPS_WD_RETRY) {
+		if (ccb->ccb_h.sim_priv.entries[0].field == MPS_WD_RETRY) {
 			mpssas_direct_drive_io(sassc, cm, ccb);
 		} else {
-			ccb->ccb_h.status = CAM_REQ_INPROG;
+			mpssas_set_ccbstatus(ccb, CAM_REQ_INPROG);
 		}
 	}
 
-	callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000,
-	   mpssas_scsiio_timeout, cm);
+	callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0,
+	    mpssas_scsiio_timeout, cm, 0);
 
 	targ->issued++;
 	targ->outstanding++;
 	TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link);
+	ccb->ccb_h.status |= CAM_SIM_QUEUED;
 
-	if ((sc->mps_debug & MPS_TRACE) != 0)
-		mpssas_log_command(cm, "%s cm %p ccb %p outstanding %u\n",
-		    __func__, cm, ccb, targ->outstanding);
+	mpssas_log_command(cm, MPS_XINFO, "%s cm %p ccb %p outstanding %u\n",
+	    __func__, cm, ccb, targ->outstanding);
 
 	mps_map_command(sc, cm);
 	return;
@@ -1829,7 +1942,7 @@
                 desc = "unknown";
                 break;
         }
-		mps_dprint(sc, MPS_INFO, "response_code(0x%01x): %s\n",
+		mps_dprint(sc, MPS_XINFO, "response_code(0x%01x): %s\n",
                 response_code, desc);
 }
 /**
@@ -1963,21 +2076,20 @@
 	if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
 		strcat(desc_scsi_state, "autosense valid ");
 
-	mps_dprint(sc, MPS_INFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x), \n",
-		le16toh(mpi_reply->DevHandle),
-	    desc_ioc_state, ioc_status);
+	mps_dprint(sc, MPS_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n",
+	    le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status);
 	/* We can add more detail about underflow data here
 	 * TO-DO
 	 * */
-	mps_dprint(sc, MPS_INFO, "\tscsi_status(%s)(0x%02x), "
-	    "scsi_state(%s)(0x%02x)\n", desc_scsi_status,
-	    scsi_status, desc_scsi_state, scsi_state);
+	mps_dprint(sc, MPS_XINFO, "\tscsi_status(%s)(0x%02x), "
+	    "scsi_state(%s)(0x%02x)\n", desc_scsi_status, scsi_status,
+	    desc_scsi_state, scsi_state);
 
-	if (sc->mps_debug & MPS_INFO &&
+	if (sc->mps_debug & MPS_XINFO &&
 		scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
-		mps_dprint(sc, MPS_INFO, "-> Sense Buffer Data : Start :\n");
+		mps_dprint(sc, MPS_XINFO, "-> Sense Buffer Data : Start :\n");
 		scsi_sense_print(csio);
-		mps_dprint(sc, MPS_INFO, "-> Sense Buffer Data : End :\n");
+		mps_dprint(sc, MPS_XINFO, "-> Sense Buffer Data : End :\n");
 	}
 
 	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
@@ -1998,10 +2110,13 @@
 	u8 *TLR_bits, TLR_on;
 	int dir = 0, i;
 	u16 alloc_len;
+	struct mpssas_target *target;
+	target_id_t target_id;
 
+	MPS_FUNCTRACE(sc);
 	mps_dprint(sc, MPS_TRACE,
-	    "%s cm %p SMID %u ccb %p reply %p outstanding %u\n",
-	    __func__, cm, cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply,
+	    "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm,
+	    cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply,
 	    cm->cm_targ->outstanding);
 
 	callout_stop(&cm->cm_callout);
@@ -2010,6 +2125,7 @@
 	sassc = sc->sassc;
 	ccb = cm->cm_complete_data;
 	csio = &ccb->csio;
+	target_id = csio->ccb_h.target_id;
 	rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply;
 	/*
 	 * XXX KDM if the chain allocation fails, does it matter if we do
@@ -2028,11 +2144,12 @@
 	cm->cm_targ->completed++;
 	cm->cm_targ->outstanding--;
 	TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link);
+	ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED);
 
 	if (cm->cm_state == MPS_CM_STATE_TIMEDOUT) {
 		TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery);
 		if (cm->cm_reply != NULL)
-			mpssas_log_command(cm, 
+			mpssas_log_command(cm, MPS_RECOVERY,
 			    "completed timedout cm %p ccb %p during recovery "
 			    "ioc %x scsi %x state %x xfer %u\n",
 			    cm, cm->cm_ccb,
@@ -2039,12 +2156,12 @@
 			    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
 			    le32toh(rep->TransferCount));
 		else
-			mpssas_log_command(cm, 
+			mpssas_log_command(cm, MPS_RECOVERY,
 			    "completed timedout cm %p ccb %p during recovery\n",
 			    cm, cm->cm_ccb);
 	} else if (cm->cm_targ->tm != NULL) {
 		if (cm->cm_reply != NULL)
-			mpssas_log_command(cm, 
+			mpssas_log_command(cm, MPS_RECOVERY,
 			    "completed cm %p ccb %p during recovery "
 			    "ioc %x scsi %x state %x xfer %u\n",
 			    cm, cm->cm_ccb,
@@ -2051,11 +2168,11 @@
 			    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
 			    le32toh(rep->TransferCount));
 		else
-			mpssas_log_command(cm, 
+			mpssas_log_command(cm, MPS_RECOVERY,
 			    "completed cm %p ccb %p during recovery\n",
 			    cm, cm->cm_ccb);
 	} else if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
-		mpssas_log_command(cm, 
+		mpssas_log_command(cm, MPS_RECOVERY,
 		    "reset completed cm %p ccb %p\n",
 		    cm, cm->cm_ccb);
 	}
@@ -2069,7 +2186,7 @@
 		 * because there can be no reply when we haven't actually
 		 * gone out to the hardware.
 		 */
-		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+		mpssas_set_ccbstatus(ccb, CAM_REQUEUE_REQ);
 
 		/*
 		 * Currently the only error included in the mask is
@@ -2085,25 +2202,37 @@
 		if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
 			xpt_freeze_simq(sassc->sim, 1);
 			sassc->flags |= MPSSAS_QUEUE_FROZEN;
-			mps_dprint(sc, MPS_INFO, "Error sending command, "
+			mps_dprint(sc, MPS_XINFO, "Error sending command, "
 				   "freezing SIM queue\n");
 		}
 	}
 
+	/*
+	 * If this is a Start Stop Unit command and it was issued by the driver
+	 * during shutdown, decrement the refcount to account for all of the
+	 * commands that were sent.  All SSU commands should be completed before
+	 * shutdown completes, meaning SSU_refcount will be 0 after SSU_started
+	 * is TRUE.
+	 */
+	if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) {
+		mps_dprint(sc, MPS_INFO, "Decrementing SSU count.\n");
+		sc->SSU_refcount--;
+	}
+
 	/* Take the fast path to completion */
 	if (cm->cm_reply == NULL) {
-		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
+		if (mpssas_get_ccbstatus(ccb) == CAM_REQ_INPROG) {
 			if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0)
-				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
+				mpssas_set_ccbstatus(ccb, CAM_SCSI_BUS_RESET);
 			else {
-				ccb->ccb_h.status = CAM_REQ_CMP;
+				mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 				ccb->csio.scsi_status = SCSI_STATUS_OK;
 			}
 			if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
 				ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
 				sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
-				mps_dprint(sc, MPS_INFO,
-					   "Unfreezing SIM queue\n");
+				mps_dprint(sc, MPS_XINFO,
+				    "Unfreezing SIM queue\n");
 			}
 		} 
 
@@ -2112,10 +2241,10 @@
 		 * CAM_REQ_CMP.  The first is if MPS_CM_FLAGS_ERROR_MASK is
 		 * set, the second is in the MPS_FLAGS_DIAGRESET above.
 		 */
-		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+		if (mpssas_get_ccbstatus(ccb) != CAM_REQ_CMP) {
 			/*
 			 * Freeze the dev queue so that commands are
-			 * executed in the correct order with after error
+			 * executed in the correct order after error
 			 * recovery.
 			 */
 			ccb->ccb_h.status |= CAM_DEV_QFRZN;
@@ -2126,11 +2255,10 @@
 		return;
 	}
 
-	if (sc->mps_debug & MPS_TRACE)
-		mpssas_log_command(cm, 
-		    "ioc %x scsi %x state %x xfer %u\n",
-			le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
-			le32toh(rep->TransferCount));
+	mpssas_log_command(cm, MPS_XINFO,
+	    "ioc %x scsi %x state %x xfer %u\n",
+	    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
+	    le32toh(rep->TransferCount));
 
 	/*
 	 * If this is a Direct Drive I/O, reissue the I/O to the original IR
@@ -2140,10 +2268,11 @@
 	 */
 	if (cm->cm_flags & MPS_CM_FLAGS_DD_IO) {
 		mps_free_command(sc, cm);
-		ccb->ccb_h.status = MPS_WD_RETRY;
+		ccb->ccb_h.sim_priv.entries[0].field = MPS_WD_RETRY;
 		mpssas_action_scsiio(sassc, ccb);
 		return;
-	}
+	} else
+		ccb->ccb_h.sim_priv.entries[0].field = 0;
 
 	switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) {
 	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
@@ -2154,12 +2283,12 @@
 
 		if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
 		    MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR)
-			mpssas_log_command(cm, "recovered error\n");
+			mpssas_log_command(cm, MPS_XINFO, "recovered error\n");
 
 		/* Completion failed at the transport level. */
 		if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS |
 		    MPI2_SCSI_STATE_TERMINATED)) {
-			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+			mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
 			break;
 		}
 
@@ -2168,7 +2297,7 @@
 		 * recover the command.
 		 */
 		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) {
-			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
+			mpssas_set_ccbstatus(ccb, CAM_AUTOSENSE_FAIL);
 			break;
 		}
 
@@ -2178,9 +2307,10 @@
 		 * TLR_bits for the target.
 		 */
 		if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) &&
-		    ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE) ==
+		    ((le32toh(rep->ResponseInfo) &
+		    MPI2_SCSI_RI_MASK_REASONCODE) ==
 		    MPS_SCSI_RI_INVALID_FRAME)) {
-			sc->mapping_table[csio->ccb_h.target_id].TLR_bits =
+			sc->mapping_table[target_id].TLR_bits =
 			    (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
 		}
 
@@ -2192,7 +2322,7 @@
 		 */
 		if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) ||
 		    (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) {
-			ccb->ccb_h.status = CAM_REQ_ABORTED;
+			mpssas_set_ccbstatus(ccb, CAM_REQ_ABORTED);
 			break;
 		}
 
@@ -2199,9 +2329,9 @@
 		/* Handle normal status and sense */
 		csio->scsi_status = rep->SCSIStatus;
 		if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD)
-			ccb->ccb_h.status = CAM_REQ_CMP;
+			mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		else
-			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+			mpssas_set_ccbstatus(ccb, CAM_SCSI_STATUS_ERROR);
 
 		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
 			int sense_len, returned_sense_len;
@@ -2233,18 +2363,20 @@
 		if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
 		    (csio->cdb_io.cdb_bytes[1] & SI_EVPD) &&
 		    (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) &&
-		    (csio->data_ptr != NULL) && (((uint8_t *)cm->cm_data)[0] ==
-		    T_SEQUENTIAL) && (sc->control_TLR) &&
-		    (sc->mapping_table[csio->ccb_h.target_id].device_info &
+		    ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) &&
+		    (csio->data_ptr != NULL) &&
+		    ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) &&
+		    (sc->control_TLR) &&
+		    (sc->mapping_table[target_id].device_info &
 		    MPI2_SAS_DEVICE_INFO_SSP_TARGET)) {
 			vpd_list = (struct scsi_vpd_supported_page_list *)
 			    csio->data_ptr;
-			TLR_bits = &sc->mapping_table[csio->ccb_h.target_id].
-			    TLR_bits;
+			TLR_bits = &sc->mapping_table[target_id].TLR_bits;
 			*TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
 			TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON;
 			alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) +
 			    csio->cdb_io.cdb_bytes[4];
+			alloc_len -= csio->resid;
 			for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) {
 				if (vpd_list->list[i] == 0x90) {
 					*TLR_bits = TLR_on;
@@ -2252,6 +2384,24 @@
 				}
 			}
 		}
+
+		/*
+		 * If this is a SATA direct-access end device, mark it so that
+		 * a SCSI StartStopUnit command will be sent to it when the
+		 * driver is being shutdown.
+		 */
+		if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
+		    ((csio->data_ptr[0] & 0x1f) == T_DIRECT) &&
+		    (sc->mapping_table[target_id].device_info &
+		    MPI2_SAS_DEVICE_INFO_SATA_DEVICE) &&
+		    ((sc->mapping_table[target_id].device_info &
+		    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
+		    MPI2_SAS_DEVICE_INFO_END_DEVICE)) {
+			target = &sassc->targets[target_id];
+			target->supports_SSU = TRUE;
+			mps_dprint(sc, MPS_XINFO, "Target %d supports SSU\n",
+			    target_id);
+		}
 		break;
 	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
 	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
@@ -2262,13 +2412,13 @@
 		 * failed.
 		 */
 		if (cm->cm_targ->devinfo == 0)
-			ccb->ccb_h.status = CAM_REQ_CMP;
+			mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		else
-			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 		break;
 	case MPI2_IOCSTATUS_INVALID_SGL:
 		mps_print_scsiio_cmd(sc, cm);
-		ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
+		mpssas_set_ccbstatus(ccb, CAM_UNREC_HBA_ERROR);
 		break;
 	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
 		/*
@@ -2281,27 +2431,37 @@
 		 * on the console.
 		 */
 		if (cm->cm_state == MPS_CM_STATE_TIMEDOUT)
-			ccb->ccb_h.status = CAM_CMD_TIMEOUT;
+			mpssas_set_ccbstatus(ccb, CAM_CMD_TIMEOUT);
 		else
-			ccb->ccb_h.status = CAM_REQ_ABORTED;
+			mpssas_set_ccbstatus(ccb, CAM_REQ_ABORTED);
 		break;
 	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
 		/* resid is ignored for this condition */
 		csio->resid = 0;
-		ccb->ccb_h.status = CAM_DATA_RUN_ERR;
+		mpssas_set_ccbstatus(ccb, CAM_DATA_RUN_ERR);
 		break;
 	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
 	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
 		/*
-		 * Since these are generally external (i.e. hopefully
-		 * transient transport-related) errors, retry these without
-		 * decrementing the retry count.
+		 * These can sometimes be transient transport-related
+		 * errors, and sometimes persistent drive-related errors.
+		 * We used to retry these without decrementing the retry
+		 * count by returning CAM_REQUEUE_REQ.  Unfortunately, if
+		 * we hit a persistent drive problem that returns one of
+		 * these error codes, we would retry indefinitely.  So,
+		 * return CAM_REQ_CMP_ERROR so that we decrement the retry
+		 * count and avoid infinite retries.  We're taking the
+		 * potential risk of flagging false failures in the event
+		 * of a topology-related error (e.g. a SAS expander problem
+		 * causes a command addressed to a drive to fail), but
+		 * avoiding getting into an infinite retry loop.
 		 */
-		ccb->ccb_h.status = CAM_REQUEUE_REQ;
-		mpssas_log_command(cm, 
-		    "terminated ioc %x scsi %x state %x xfer %u\n",
-			le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
-			le32toh(rep->TransferCount));
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
+		mpssas_log_command(cm, MPS_INFO,
+		    "terminated ioc %x loginfo %x scsi %x state %x xfer %u\n",
+		    le16toh(rep->IOCStatus), le32toh(rep->IOCLogInfo),
+		    rep->SCSIStatus, rep->SCSIState,
+		    le32toh(rep->TransferCount));
 		break;
 	case MPI2_IOCSTATUS_INVALID_FUNCTION:
 	case MPI2_IOCSTATUS_INTERNAL_ERROR:
@@ -2314,12 +2474,13 @@
 	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
 	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
 	default:
-		mpssas_log_command(cm, 
-		    "completed ioc %x scsi %x state %x xfer %u\n",
-			le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
-			le32toh(rep->TransferCount));
+		mpssas_log_command(cm, MPS_XINFO,
+		    "completed ioc %x loginfo %x scsi %x state %x xfer %u\n",
+		    le16toh(rep->IOCStatus), le32toh(rep->IOCLogInfo),
+		    rep->SCSIStatus, rep->SCSIState,
+		    le32toh(rep->TransferCount));
 		csio->resid = cm->cm_length;
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
 		break;
 	}
 	
@@ -2328,11 +2489,11 @@
 	if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
 		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
 		sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
-		mps_dprint(sc, MPS_INFO, "Command completed, "
-			   "unfreezing SIM queue\n");
+		mps_dprint(sc, MPS_XINFO, "Command completed, "
+		    "unfreezing SIM queue\n");
 	}
 
-	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+	if (mpssas_get_ccbstatus(ccb) != CAM_REQ_CMP) {
 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
 		xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
 	}
@@ -2628,16 +2789,16 @@
 	 * in the standard request size.
 	 */
 	if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
-		mps_printf(sc, "%s: cm_flags = %#x on SMP request!\n",
+		mps_dprint(sc, MPS_ERROR,"%s: cm_flags = %#x on SMP request!\n",
 			   __func__, cm->cm_flags);
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
 		goto bailout;
         }
 
 	rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply;
 	if (rpl == NULL) {
-		mps_dprint(sc, MPS_INFO, "%s: NULL cm_reply!\n", __func__);
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+		mps_dprint(sc, MPS_ERROR, "%s: NULL cm_reply!\n", __func__);
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
 		goto bailout;
 	}
 
@@ -2645,22 +2806,23 @@
 	sasaddr = le32toh(req->SASAddress.Low);
 	sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32;
 
-	if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS ||
+	if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
+	    MPI2_IOCSTATUS_SUCCESS ||
 	    rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) {
-		mps_dprint(sc, MPS_INFO, "%s: IOCStatus %04x SASStatus %02x\n",
+		mps_dprint(sc, MPS_XINFO, "%s: IOCStatus %04x SASStatus %02x\n",
 		    __func__, le16toh(rpl->IOCStatus), rpl->SASStatus);
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
 		goto bailout;
 	}
 
-	mps_dprint(sc, MPS_INFO, "%s: SMP request to SAS address "
+	mps_dprint(sc, MPS_XINFO, "%s: SMP request to SAS address "
 		   "%#jx completed successfully\n", __func__,
 		   (uintmax_t)sasaddr);
 
 	if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED)
-		ccb->ccb_h.status = CAM_REQ_CMP;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 	else
-		ccb->ccb_h.status = CAM_SMP_STATUS_ERROR;
+		mpssas_set_ccbstatus(ccb, CAM_SMP_STATUS_ERROR);
 
 bailout:
 	/*
@@ -2681,29 +2843,23 @@
 	uint8_t *request, *response;
 	MPI2_SMP_PASSTHROUGH_REQUEST *req;
 	struct mps_softc *sc;
-	struct sglist *sg;
 	int error;
 
 	sc = sassc->sc;
-	sg = NULL;
 	error = 0;
 
 	/*
 	 * XXX We don't yet support physical addresses here.
 	 */
-	if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) {
-		mps_printf(sc, "%s: physical addresses not supported\n",
-			   __func__);
-		ccb->ccb_h.status = CAM_REQ_INVALID;
+	switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
+	case CAM_DATA_PADDR:
+	case CAM_DATA_SG_PADDR:
+		mps_dprint(sc, MPS_ERROR,
+			   "%s: physical addresses not supported\n", __func__);
+		mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID);
 		xpt_done(ccb);
 		return;
-	}
-
-	/*
-	 * If the user wants to send an S/G list, check to make sure they
-	 * have single buffers.
-	 */
-	if (ccb->ccb_h.flags & CAM_SCATTER_VALID) {
+	case CAM_DATA_SG:
 		/*
 		 * The chip does not support more than one buffer for the
 		 * request or response.
@@ -2710,10 +2866,11 @@
 		 */
 	 	if ((ccb->smpio.smp_request_sglist_cnt > 1)
 		  || (ccb->smpio.smp_response_sglist_cnt > 1)) {
-			mps_printf(sc, "%s: multiple request or response "
+			mps_dprint(sc, MPS_ERROR,
+				   "%s: multiple request or response "
 				   "buffer segments not supported for SMP\n",
 				   __func__);
-			ccb->ccb_h.status = CAM_REQ_INVALID;
+			mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID);
 			xpt_done(ccb);
 			return;
 		}
@@ -2730,7 +2887,7 @@
 			bus_dma_segment_t *req_sg;
 
 			req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
-			request = (uint8_t *)req_sg[0].ds_addr;
+			request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr;
 		} else
 			request = ccb->smpio.smp_request;
 
@@ -2738,18 +2895,25 @@
 			bus_dma_segment_t *rsp_sg;
 
 			rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
-			response = (uint8_t *)rsp_sg[0].ds_addr;
+			response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr;
 		} else
 			response = ccb->smpio.smp_response;
-	} else {
+		break;
+	case CAM_DATA_VADDR:
 		request = ccb->smpio.smp_request;
 		response = ccb->smpio.smp_response;
+		break;
+	default:
+		mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID);
+		xpt_done(ccb);
+		return;
 	}
 
 	cm = mps_alloc_command(sc);
 	if (cm == NULL) {
-		mps_printf(sc, "%s: cannot allocate command\n", __func__);
-		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+		mps_dprint(sc, MPS_ERROR,
+		    "%s: cannot allocate command\n", __func__);
+		mpssas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
 		xpt_done(ccb);
 		return;
 	}
@@ -2765,8 +2929,8 @@
 	req->SGLFlags = 
 	    MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI;
 
-	mps_dprint(sc, MPS_INFO, "%s: sending SMP request to SAS "
-		   "address %#jx\n", __func__, (uintmax_t)sasaddr);
+	mps_dprint(sc, MPS_XINFO, "%s: sending SMP request to SAS "
+	    "address %#jx\n", __func__, (uintmax_t)sasaddr);
 
 	mpi_init_sge(cm, req, &req->SGL);
 
@@ -2827,7 +2991,8 @@
 	 */
 	error = mps_map_command(sc, cm);
 	if ((error != 0) && (error != EINPROGRESS)) {
-		mps_printf(sc, "%s: error %d returned from mps_map_command()\n",
+		mps_dprint(sc, MPS_ERROR,
+			   "%s: error %d returned from mps_map_command()\n",
 			   __func__, error);
 		goto bailout_error;
 	}
@@ -2836,7 +3001,7 @@
 
 bailout_error:
 	mps_free_command(sc, cm);
-	ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+	mpssas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
 	xpt_done(ccb);
 	return;
 
@@ -2854,11 +3019,14 @@
 	/*
 	 * Make sure the target exists.
 	 */
+	KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
+	    ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id));
 	targ = &sassc->targets[ccb->ccb_h.target_id];
 	if (targ->handle == 0x0) {
-		mps_printf(sc, "%s: target %d does not exist!\n", __func__,
+		mps_dprint(sc, MPS_ERROR,
+			   "%s: target %d does not exist!\n", __func__,
 			   ccb->ccb_h.target_id);
-		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+		mpssas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT);
 		xpt_done(ccb);
 		return;
 	}
@@ -2904,9 +3072,10 @@
 #endif
 
 		if (targ->parent_handle == 0x0) {
-			mps_printf(sc, "%s: handle %d does not have a valid "
+			mps_dprint(sc, MPS_ERROR,
+				   "%s: handle %d does not have a valid "
 				   "parent handle!\n", __func__, targ->handle);
-			ccb->ccb_h.status = CAM_REQ_INVALID;
+			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 			goto bailout;
 		}
 #ifdef OLD_MPS_PROBE
@@ -2914,18 +3083,20 @@
 			targ->parent_handle);
 
 		if (parent_target == NULL) {
-			mps_printf(sc, "%s: handle %d does not have a valid "
+			mps_dprint(sc, MPS_ERROR,
+				   "%s: handle %d does not have a valid "
 				   "parent target!\n", __func__, targ->handle);
-			ccb->ccb_h.status = CAM_REQ_INVALID;
+			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 			goto bailout;
 		}
 
 		if ((parent_target->devinfo &
 		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
-			mps_printf(sc, "%s: handle %d parent %d does not "
+			mps_dprint(sc, MPS_ERROR,
+				   "%s: handle %d parent %d does not "
 				   "have an SMP target!\n", __func__,
 				   targ->handle, parent_target->handle);
-			ccb->ccb_h.status = CAM_REQ_INVALID;
+			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 			goto bailout;
 
 		}
@@ -2934,18 +3105,20 @@
 #else /* OLD_MPS_PROBE */
 		if ((targ->parent_devinfo &
 		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
-			mps_printf(sc, "%s: handle %d parent %d does not "
+			mps_dprint(sc, MPS_ERROR,
+				   "%s: handle %d parent %d does not "
 				   "have an SMP target!\n", __func__,
 				   targ->handle, targ->parent_handle);
-			ccb->ccb_h.status = CAM_REQ_INVALID;
+			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 			goto bailout;
 
 		}
 		if (targ->parent_sasaddr == 0x0) {
-			mps_printf(sc, "%s: handle %d parent handle %d does "
+			mps_dprint(sc, MPS_ERROR,
+				   "%s: handle %d parent handle %d does "
 				   "not have a valid SAS address!\n",
 				   __func__, targ->handle, targ->parent_handle);
-			ccb->ccb_h.status = CAM_REQ_INVALID;
+			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 			goto bailout;
 		}
 
@@ -2955,9 +3128,10 @@
 	}
 
 	if (sasaddr == 0) {
-		mps_printf(sc, "%s: unable to find SAS address for handle %d\n",
+		mps_dprint(sc, MPS_INFO,
+			   "%s: unable to find SAS address for handle %d\n",
 			   __func__, targ->handle);
-		ccb->ccb_h.status = CAM_REQ_INVALID;
+		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
 		goto bailout;
 	}
 	mpssas_send_smpcmd(sassc, ccb, sasaddr);
@@ -2978,14 +3152,18 @@
 	struct mps_command *tm;
 	struct mpssas_target *targ;
 
-	mps_dprint(sassc->sc, MPS_TRACE, __func__);
+	MPS_FUNCTRACE(sassc->sc);
 	mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
 
+	KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
+	    ("Target %d out of bounds in XPT_RESET_DEV\n",
+	     ccb->ccb_h.target_id));
 	sc = sassc->sc;
 	tm = mps_alloc_command(sc);
 	if (tm == NULL) {
-		mps_printf(sc, "comand alloc failure in mpssas_action_resetdev\n");
-		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+		mps_dprint(sc, MPS_ERROR,
+		    "command alloc failure in mpssas_action_resetdev\n");
+		mpssas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
 		xpt_done(ccb);
 		return;
 	}
@@ -3004,6 +3182,8 @@
 	tm->cm_complete = mpssas_resetdev_complete;
 	tm->cm_complete_data = ccb;
 	tm->cm_targ = targ;
+	targ->flags |= MPSSAS_TARGET_INRESET;
+
 	mps_map_command(sc, tm);
 }
 
@@ -3013,7 +3193,7 @@
 	MPI2_SCSI_TASK_MANAGE_REPLY *resp;
 	union ccb *ccb;
 
-	mps_dprint(sc, MPS_TRACE, __func__);
+	MPS_FUNCTRACE(sc);
 	mtx_assert(&sc->mps_mtx, MA_OWNED);
 
 	resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
@@ -3029,23 +3209,25 @@
 
 		req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
 
-		mps_printf(sc, "%s: cm_flags = %#x for reset of handle %#04x! "
+		mps_dprint(sc, MPS_ERROR,
+			   "%s: cm_flags = %#x for reset of handle %#04x! "
 			   "This should not happen!\n", __func__, tm->cm_flags,
 			   req->DevHandle);
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
 		goto bailout;
 	}
 
-	printf("%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__,
+	mps_dprint(sc, MPS_XINFO,
+	    "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__,
 	    le16toh(resp->IOCStatus), le32toh(resp->ResponseCode));
 
 	if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) {
-		ccb->ccb_h.status = CAM_REQ_CMP;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
 		    CAM_LUN_WILDCARD);
 	}
 	else
-		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
 
 bailout:
 
@@ -3072,114 +3254,6 @@
 }
 
 static void
-mpssas_rescan_done(struct cam_periph *periph, union ccb *done_ccb)
-{
-	struct mpssas_softc *sassc;
-	char path_str[64];
-
-	if (done_ccb == NULL)
-		return;
-
-	sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1;
-
-	mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
-
-	xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str));
-	mps_dprint(sassc->sc, MPS_INFO, "Completing rescan for %s\n", path_str);
-
-	xpt_free_path(done_ccb->ccb_h.path);
-	xpt_free_ccb(done_ccb);
-
-#if __FreeBSD_version < 1000006
-	/*
-	 * Before completing scan, get EEDP stuff for all of the existing
-	 * targets.
-	 */
-	mpssas_check_eedp(sassc);
-#endif
-
-}
-
-/* thread to handle bus rescans */
-static void
-mpssas_scanner_thread(void *arg)
-{
-	struct mpssas_softc *sassc;
-	struct mps_softc *sc;
-	union ccb	*ccb;
-
-	sassc = (struct mpssas_softc *)arg;
-	sc = sassc->sc;
-
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
-	mps_lock(sc);
-	for (;;) {
-		/* Sleep for 1 second and check the queue status*/
-		msleep(&sassc->ccb_scanq, &sc->mps_mtx, PRIBIO,
-		       "mps_scanq", 1 * hz);
-		if (sassc->flags & MPSSAS_SHUTDOWN) {
-			mps_dprint(sc, MPS_TRACE, "Scanner shutting down\n");
-			break;
-		}
-next_work:
-		// Get first work.
-		ccb = (union ccb *)TAILQ_FIRST(&sassc->ccb_scanq);
-		if (ccb == NULL)
-			continue;
-		// Got first work.
-		TAILQ_REMOVE(&sassc->ccb_scanq, &ccb->ccb_h, sim_links.tqe);
-		xpt_action(ccb);
-		if (sassc->flags & MPSSAS_SHUTDOWN) {
-			mps_dprint(sc, MPS_TRACE, "Scanner shutting down\n");
-			break;
-		}
-		goto next_work;
-	}
-
-	sassc->flags &= ~MPSSAS_SCANTHREAD;
-	wakeup(&sassc->flags);
-	mps_unlock(sc);
-	mps_dprint(sc, MPS_TRACE, "Scanner exiting\n");
-	mps_kproc_exit(0);
-}
-
-/*
- * This function will send READ_CAP_16 to find out EEDP protection mode.
- * It will check inquiry data before sending READ_CAP_16.
- * Callback for READ_CAP_16 is "mpssas_read_cap_done".
- * This is insternal scsi command and we need to take care release of devq, if
- * CAM_DEV_QFRZN is set. Driver needs to release devq if it has frozen any.
- * xpt_release_devq is called from mpssas_read_cap_done.
- *
- * All other commands will be handled by periph layer and there it will 
- * check for "CAM_DEV_QFRZN" and release of devq will be done.
- */
-static void
-mpssas_rescan(struct mpssas_softc *sassc, union ccb *ccb)
-{
-	char path_str[64];
-
-	mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
-	mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
-
-	if (ccb == NULL)
-		return;
-
-	xpt_path_string(ccb->ccb_h.path, path_str, sizeof(path_str));
-	mps_dprint(sassc->sc, MPS_INFO, "Queueing rescan for %s\n", path_str);
-
-	/* Prepare request */
-	ccb->ccb_h.ppriv_ptr1 = sassc;
-	ccb->ccb_h.cbfcnp = mpssas_rescan_done;
-	xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, MPS_PRIORITY_XPT);
-	TAILQ_INSERT_TAIL(&sassc->ccb_scanq, &ccb->ccb_h, sim_links.tqe);
-	wakeup(&sassc->ccb_scanq);
-}
-
-#if __FreeBSD_version >= 1000006
-static void
 mpssas_async(void *callback_arg, uint32_t code, struct cam_path *path,
 	     void *arg)
 {
@@ -3188,6 +3262,8 @@
 	sc = (struct mps_softc *)callback_arg;
 
 	switch (code) {
+#if (__FreeBSD_version >= 1000006) || \
+    ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
 	case AC_ADVINFO_CHANGED: {
 		struct mpssas_target *target;
 		struct mpssas_softc *sassc;
@@ -3210,15 +3286,11 @@
 			break;
 
 		/*
-		 * We're only interested in devices that are attached to
-		 * this controller.
-		 */
-		if (xpt_path_path_id(path) != sassc->sim->path_id)
-			break;
-
-		/*
 		 * We should have a handle for this, but check to make sure.
 		 */
+		KASSERT(xpt_path_target_id(path) < sassc->maxtargets,
+		    ("Target %d out of bounds in mpssas_async\n",
+		    xpt_path_target_id(path)));
 		target = &sassc->targets[xpt_path_target_id(path)];
 		if (target->handle == 0)
 			break;
@@ -3236,7 +3308,7 @@
 			lun = malloc(sizeof(struct mpssas_lun), M_MPT2,
 				     M_NOWAIT | M_ZERO);
 			if (lun == NULL) {
-				mps_dprint(sc, MPS_FAULT, "Unable to alloc "
+				mps_dprint(sc, MPS_ERROR, "Unable to alloc "
 					   "LUN for EEDP support.\n");
 				break;
 			}
@@ -3249,7 +3321,12 @@
 		cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
 		cdai.ccb_h.flags = CAM_DIR_IN;
 		cdai.buftype = CDAI_TYPE_RCAPLONG;
+#if (__FreeBSD_version >= 1100061) || \
+    ((__FreeBSD_version >= 1001510) && (__FreeBSD_version < 1100000))
+		cdai.flags = CDAI_FLAG_NONE;
+#else
 		cdai.flags = 0;
+#endif
 		cdai.bufsiz = sizeof(rcap_buf);
 		cdai.buf = (uint8_t *)&rcap_buf;
 		xpt_action((union ccb *)&cdai);
@@ -3257,7 +3334,7 @@
 			cam_release_devq(cdai.ccb_h.path,
 					 0, 0, 0, FALSE);
 
-		if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
+		if ((mpssas_get_ccbstatus((union ccb *)&cdai) == CAM_REQ_CMP)
 		 && (rcap_buf.prot & SRC16_PROT_EN)) {
 			lun->eedp_formatted = TRUE;
 			lun->eedp_block_size = scsi_4btoul(rcap_buf.length);
@@ -3267,178 +3344,152 @@
 		}
 		break;
 	}
+#else
+	case AC_FOUND_DEVICE: {
+		struct ccb_getdev *cgd;
+
+		cgd = arg;
+		mpssas_check_eedp(sc, path, cgd);
+		break;
+	}
+#endif
 	default:
 		break;
 	}
 }
-#else /* __FreeBSD_version >= 1000006 */
 
+#if (__FreeBSD_version < 901503) || \
+    ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
 static void
-mpssas_check_eedp(struct mpssas_softc *sassc)
+mpssas_check_eedp(struct mps_softc *sc, struct cam_path *path,
+		  struct ccb_getdev *cgd)
 {
-	struct mps_softc *sc = sassc->sc;
+	struct mpssas_softc *sassc = sc->sassc;
 	struct ccb_scsiio *csio;
 	struct scsi_read_capacity_16 *scsi_cmd;
 	struct scsi_read_capacity_eedp *rcap_buf;
-	union ccb *ccb;
-	path_id_t pathid = cam_sim_path(sassc->sim);
+	path_id_t pathid;
 	target_id_t targetid;
 	lun_id_t lunid;
-	struct cam_periph *found_periph;
+	union ccb *ccb;
+	struct cam_path *local_path;
 	struct mpssas_target *target;
 	struct mpssas_lun *lun;
 	uint8_t	found_lun;
-	struct ccb_getdev cgd;
 	char path_str[64];
 
+	sassc = sc->sassc;
+	pathid = cam_sim_path(sassc->sim);
+	targetid = xpt_path_target_id(path);
+	lunid = xpt_path_lun_id(path);
+
+	KASSERT(targetid < sassc->maxtargets,
+	    ("Target %d out of bounds in mpssas_check_eedp\n",
+	     targetid));
+	target = &sassc->targets[targetid];
+	if (target->handle == 0x0)
+		return;
+
 	/*
-	 * Issue a READ CAPACITY 16 command to each LUN of each target.  This
-	 * info is used to determine if the LUN is formatted for EEDP support.
+	 * Determine if the device is EEDP capable.
+	 *
+	 * If this flag is set in the inquiry data, 
+	 * the device supports protection information,
+	 * and must support the 16 byte read
+	 * capacity command, otherwise continue without
+	 * sending read cap 16
 	 */
-	for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) {
-		target = &sassc->targets[targetid];
-		if (target->handle == 0x0) {
-			continue;
-		}
+	if ((cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) == 0)
+		return;
 
-		lunid = 0;
-		do {
-			ccb = xpt_alloc_ccb_nowait();
-			if (ccb == NULL) {
-				mps_dprint(sc, MPS_FAULT, "Unable to alloc CCB "
-				    "for EEDP support.\n");
-				return;
-			}
+	/*
+	 * Issue a READ CAPACITY 16 command.  This info
+	 * is used to determine if the LUN is formatted
+	 * for EEDP support.
+	 */
+	ccb = xpt_alloc_ccb_nowait();
+	if (ccb == NULL) {
+		mps_dprint(sc, MPS_ERROR, "Unable to alloc CCB "
+		    "for EEDP support.\n");
+		return;
+	}
 
-			if (xpt_create_path(&ccb->ccb_h.path, xpt_periph,
-			    pathid, targetid, lunid) != CAM_REQ_CMP) {
-				mps_dprint(sc, MPS_FAULT, "Unable to create "
-				    "path for EEDP support\n");
-				xpt_free_ccb(ccb);
-				return;
-			}
+	if (xpt_create_path(&local_path, xpt_periph,
+	    pathid, targetid, lunid) != CAM_REQ_CMP) {
+		mps_dprint(sc, MPS_ERROR, "Unable to create "
+		    "path for EEDP support\n");
+		xpt_free_ccb(ccb);
+		return;
+	}
 
-			/*
-			 * If a periph is returned, the LUN exists.  Create an
-			 * entry in the target's LUN list.
-			 */
-			if ((found_periph = cam_periph_find(ccb->ccb_h.path,
-			    NULL)) != NULL) {
-				/*
-				 * If LUN is already in list, don't create a new
-				 * one.
-				 */
-				found_lun = FALSE;
-				SLIST_FOREACH(lun, &target->luns, lun_link) {
-					if (lun->lun_id == lunid) {
-						found_lun = TRUE;
-						break;
-					}
-				}
-				if (!found_lun) {
-					lun = malloc(sizeof(struct mpssas_lun),
-					    M_MPT2, M_NOWAIT | M_ZERO);
-					if (lun == NULL) {
-						mps_dprint(sc, MPS_FAULT,
-						    "Unable to alloc LUN for "
-						    "EEDP support.\n");
-						xpt_free_path(ccb->ccb_h.path);
-						xpt_free_ccb(ccb);
-						return;
-					}
-					lun->lun_id = lunid;
-					SLIST_INSERT_HEAD(&target->luns, lun,
-					    lun_link);
-				}
-				lunid++;
-				/* Before Issuing READ CAPACITY 16, 
-				 * check Device type. 
- 				 */
-				xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path, 
-					CAM_PRIORITY_NORMAL);
-				cgd.ccb_h.func_code = XPT_GDEV_TYPE;
-				xpt_action((union ccb *)&cgd);
+	/*
+	 * If LUN is already in list, don't create a new
+	 * one.
+	 */
+	found_lun = FALSE;
+	SLIST_FOREACH(lun, &target->luns, lun_link) {
+		if (lun->lun_id == lunid) {
+			found_lun = TRUE;
+			break;
+		}
+	}
+	if (!found_lun) {
+		lun = malloc(sizeof(struct mpssas_lun), M_MPT2,
+		    M_NOWAIT | M_ZERO);
+		if (lun == NULL) {
+			mps_dprint(sc, MPS_ERROR,
+			    "Unable to alloc LUN for EEDP support.\n");
+			xpt_free_path(local_path);
+			xpt_free_ccb(ccb);
+			return;
+		}
+		lun->lun_id = lunid;
+		SLIST_INSERT_HEAD(&target->luns, lun,
+		    lun_link);
+	}
 
-				/*
-				 * If this flag is set in the inquiry data, 
-				 * the device supports protection information,
-				 * and must support the 16 byte read
-				 * capacity command, otherwise continue without
-				 * sending read cap 16
-				 */
+	xpt_path_string(local_path, path_str, sizeof(path_str));
 
-				xpt_path_string(ccb->ccb_h.path, path_str, 
-					sizeof(path_str));
+	mps_dprint(sc, MPS_INFO, "Sending read cap: path %s handle %d\n",
+	    path_str, target->handle);
 
-				if ((cgd.inq_data.spc3_flags & 
-				SPC3_SID_PROTECT) == 0) {
-					xpt_free_path(ccb->ccb_h.path);
-					xpt_free_ccb(ccb);
-					continue;
-				}
-				
-				mps_dprint(sc, MPS_INFO,
-				"Sending read cap: path %s"
-				" handle %d\n", path_str, target->handle );
-			
-				/*
-				 * Issue a READ CAPACITY 16 command for the LUN.
-				 * The mpssas_read_cap_done function will load
-				 * the read cap info into the LUN struct.
-				 */
-				rcap_buf =
-					malloc(sizeof(struct scsi_read_capacity_eedp),
-					M_MPT2, M_NOWAIT| M_ZERO);
-				if (rcap_buf == NULL) {
-					mps_dprint(sc, MPS_FAULT, "Unable to alloc read "
-						"capacity buffer for EEDP support.\n");
-					xpt_free_path(ccb->ccb_h.path);
-					xpt_free_ccb(ccb);
-					return;
-				}
-				csio = &ccb->csio;
-				csio->ccb_h.func_code = XPT_SCSI_IO;
-				csio->ccb_h.flags = CAM_DIR_IN;
-				csio->ccb_h.retry_count = 4;	
-				csio->ccb_h.cbfcnp = mpssas_read_cap_done;
-				csio->ccb_h.timeout = 60000;
-				csio->data_ptr = (uint8_t *)rcap_buf;
-				csio->dxfer_len = sizeof(struct
-				    scsi_read_capacity_eedp);
-				csio->sense_len = MPS_SENSE_LEN;
-				csio->cdb_len = sizeof(*scsi_cmd);
-				csio->tag_action = MSG_SIMPLE_Q_TAG;
+	/*
+	 * Issue a READ CAPACITY 16 command for the LUN.
+	 * The mpssas_read_cap_done function will load
+	 * the read cap info into the LUN struct.
+	 */
+	rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp),
+	    M_MPT2, M_NOWAIT | M_ZERO);
+	if (rcap_buf == NULL) {
+		mps_dprint(sc, MPS_FAULT,
+		    "Unable to alloc read capacity buffer for EEDP support.\n");
+		xpt_free_path(ccb->ccb_h.path);
+		xpt_free_ccb(ccb);
+		return;
+	}
+	xpt_setup_ccb(&ccb->ccb_h, local_path, CAM_PRIORITY_XPT);
+	csio = &ccb->csio;
+	csio->ccb_h.func_code = XPT_SCSI_IO;
+	csio->ccb_h.flags = CAM_DIR_IN;
+	csio->ccb_h.retry_count = 4;	
+	csio->ccb_h.cbfcnp = mpssas_read_cap_done;
+	csio->ccb_h.timeout = 60000;
+	csio->data_ptr = (uint8_t *)rcap_buf;
+	csio->dxfer_len = sizeof(struct scsi_read_capacity_eedp);
+	csio->sense_len = MPS_SENSE_LEN;
+	csio->cdb_len = sizeof(*scsi_cmd);
+	csio->tag_action = MSG_SIMPLE_Q_TAG;
 
-				scsi_cmd = (struct scsi_read_capacity_16 *)
-				    &csio->cdb_io.cdb_bytes;
-				bzero(scsi_cmd, sizeof(*scsi_cmd));
-				scsi_cmd->opcode = 0x9E;
-				scsi_cmd->service_action = SRC16_SERVICE_ACTION;
-				((uint8_t *)scsi_cmd)[13] = sizeof(struct
-				    scsi_read_capacity_eedp);
+	scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes;
+	bzero(scsi_cmd, sizeof(*scsi_cmd));
+	scsi_cmd->opcode = 0x9E;
+	scsi_cmd->service_action = SRC16_SERVICE_ACTION;
+	((uint8_t *)scsi_cmd)[13] = sizeof(struct scsi_read_capacity_eedp);
 
-				/*
-				 * Set the path, target and lun IDs for the READ
-				 * CAPACITY request.
-				 */
-				ccb->ccb_h.path_id =
-				    xpt_path_path_id(ccb->ccb_h.path);
-				ccb->ccb_h.target_id =
-				    xpt_path_target_id(ccb->ccb_h.path);
-				ccb->ccb_h.target_lun =
-				    xpt_path_lun_id(ccb->ccb_h.path);
-
-				ccb->ccb_h.ppriv_ptr1 = sassc;
-				xpt_action(ccb);
-			} else {
-				xpt_free_path(ccb->ccb_h.path);
-				xpt_free_ccb(ccb);
-			}
-		} while (found_periph);
-	}
+	ccb->ccb_h.ppriv_ptr1 = sassc;
+	xpt_action(ccb);
 }
 
-
 static void
 mpssas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb)
 {
@@ -3471,6 +3522,9 @@
 	 * target.
 	 */
 	sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1;
+	KASSERT(done_ccb->ccb_h.target_id < sassc->maxtargets,
+	    ("Target %d out of bounds in mpssas_read_cap_done\n",
+	     done_ccb->ccb_h.target_id));
 	target = &sassc->targets[done_ccb->ccb_h.target_id];
 	SLIST_FOREACH(lun, &target->luns, lun_link) {
 		if (lun->lun_id != done_ccb->ccb_h.target_lun)
@@ -3483,7 +3537,7 @@
 		 * the lun as not supporting EEDP and set the block size
 		 * to 0.
 		 */
-		if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+		if ((mpssas_get_ccbstatus(done_ccb) != CAM_REQ_CMP)
 		 || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) {
 			lun->eedp_formatted = FALSE;
 			lun->eedp_block_size = 0;
@@ -3491,6 +3545,10 @@
 		}
 
 		if (rcap_buf->protect & 0x01) {
+			mps_dprint(sassc->sc, MPS_INFO, "LUN %d for "
+ 			    "target ID %d is formatted for EEDP "
+ 			    "support.\n", done_ccb->ccb_h.target_lun,
+ 			    done_ccb->ccb_h.target_id);
 			lun->eedp_formatted = TRUE;
 			lun->eedp_block_size = scsi_4btoul(rcap_buf->length);
 		}
@@ -3502,12 +3560,40 @@
 	xpt_free_path(done_ccb->ccb_h.path);
 	xpt_free_ccb(done_ccb);
 }
-#endif /* __FreeBSD_version >= 1000006 */
+#endif /* (__FreeBSD_version < 901503) || \
+          ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */
 
+void
+mpssas_prepare_for_tm(struct mps_softc *sc, struct mps_command *tm,
+    struct mpssas_target *target, lun_id_t lun_id)
+{
+	union ccb *ccb;
+	path_id_t path_id;
+
+	/*
+	 * Set the INRESET flag for this target so that no I/O will be sent to
+	 * the target until the reset has completed.  If an I/O request does
+	 * happen, the devq will be frozen.  The CCB holds the path which is
+	 * used to release the devq.  The devq is released and the CCB is freed
+	 * when the TM completes.
+	 */
+	ccb = xpt_alloc_ccb_nowait();
+	if (ccb) {
+		path_id = cam_sim_path(sc->sassc->sim);
+		if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, path_id,
+		    target->tid, lun_id) != CAM_REQ_CMP) {
+			xpt_free_ccb(ccb);
+		} else {
+			tm->cm_ccb = ccb;
+			tm->cm_targ = target;
+			target->flags |= MPSSAS_TARGET_INRESET;
+		}
+	}
+}
+
 int
 mpssas_startup(struct mps_softc *sc)
 {
-	struct mpssas_softc *sassc;
 
 	/*
 	 * Send the port enable message and set the wait_for_port_enable flag.
@@ -3514,8 +3600,6 @@
 	 * This flag helps to keep the simq frozen until all discovery events
 	 * are processed.
 	 */
-	sassc = sc->sassc;
-	mpssas_startup_increment(sassc);
 	sc->wait_for_port_enable = 1;
 	mpssas_send_portenable(sc);
 	return (0);
@@ -3527,7 +3611,7 @@
 	MPI2_PORT_ENABLE_REQUEST *request;
 	struct mps_command *cm;
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 
 	if ((cm = mps_alloc_command(sc)) == NULL)
 		return (EBUSY);
@@ -3541,7 +3625,7 @@
 	cm->cm_sge = NULL;
 
 	mps_map_command(sc, cm);
-	mps_dprint(sc, MPS_TRACE, 
+	mps_dprint(sc, MPS_XINFO, 
 	    "mps_send_portenable finished cm %p req %p complete %p\n",
 	    cm, cm->cm_req, cm->cm_complete);
 	return (0);
@@ -3553,7 +3637,7 @@
 	MPI2_PORT_ENABLE_REPLY *reply;
 	struct mpssas_softc *sassc;
 
-	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+	MPS_FUNCTRACE(sc);
 	sassc = sc->sassc;
 
 	/*
@@ -3562,7 +3646,7 @@
 	 * port enable commands don't have S/G lists.
 	 */
 	if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
-		mps_printf(sc, "%s: cm_flags = %#x for port enable! "
+		mps_dprint(sc, MPS_ERROR, "%s: cm_flags = %#x for port enable! "
 			   "This should not happen!\n", __func__, cm->cm_flags);
 	}
 
@@ -3575,7 +3659,7 @@
 
 	mps_free_command(sc, cm);
 	if (sc->mps_ich.ich_arg != NULL) {
-		mps_dprint(sc, MPS_INFO, "disestablish config intrhook\n");
+		mps_dprint(sc, MPS_XINFO, "disestablish config intrhook\n");
 		config_intrhook_disestablish(&sc->mps_ich);
 		sc->mps_ich.ich_arg = NULL;
 	}
@@ -3600,6 +3684,52 @@
 	sc->port_enable_complete = 1;
 	wakeup(&sc->port_enable_complete);
 	mpssas_startup_decrement(sassc);
-	xpt_release_simq(sassc->sim, 1);
 }
 
+int
+mpssas_check_id(struct mpssas_softc *sassc, int id)
+{
+	struct mps_softc *sc = sassc->sc;
+	char *ids;
+	char *name;
+
+	ids = &sc->exclude_ids[0];
+	while((name = strsep(&ids, ",")) != NULL) {
+		if (name[0] == '\0')
+			continue;
+		if (strtol(name, NULL, 0) == (long)id)
+			return (1);
+	}
+
+	return (0);
+}
+
+void
+mpssas_realloc_targets(struct mps_softc *sc, int maxtargets)
+{
+	struct mpssas_softc *sassc;
+	struct mpssas_lun *lun, *lun_tmp;
+	struct mpssas_target *targ;
+	int i;
+
+	sassc = sc->sassc;
+	/*
+	 * The number of targets is based on IOC Facts, so free all of
+	 * the allocated LUNs for each target and then the target buffer
+	 * itself.
+	 */
+	for (i=0; i< maxtargets; i++) {
+		targ = &sassc->targets[i];
+		SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
+			free(lun, M_MPT2);
+		}
+	}
+	free(sassc->targets, M_MPT2);
+
+	sassc->targets = malloc(sizeof(struct mpssas_target) * maxtargets,
+	    M_MPT2, M_WAITOK|M_ZERO);
+	if (!sassc->targets) {
+		panic("%s failed to alloc targets with error %d\n",
+		    __func__, ENOMEM);
+	}
+}

Modified: trunk/sys/dev/mps/mps_sas.h
===================================================================
--- trunk/sys/dev/mps/mps_sas.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_sas.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,9 +25,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mps_sas.h 281564 2015-04-15 21:47:15Z slm $
  */
 
 struct mps_fw_event_work;
@@ -51,11 +53,10 @@
 #define MPSSAS_TARGET_INREMOVAL	(1 << 3)
 #define MPS_TARGET_FLAGS_RAID_COMPONENT (1 << 4)
 #define MPS_TARGET_FLAGS_VOLUME         (1 << 5)
+#define MPS_TARGET_IS_SATA_SSD	(1 << 6)
 #define MPSSAS_TARGET_INRECOVERY (MPSSAS_TARGET_INABORT | \
     MPSSAS_TARGET_INRESET | MPSSAS_TARGET_INCHIPRESET)
 
-#define MPSSAS_TARGET_ADD       (1 << 29)
-#define MPSSAS_TARGET_REMOVE    (1 << 30)
 	uint16_t	tid;
 	SLIST_HEAD(, mpssas_lun) luns;
 	TAILQ_HEAD(, mps_command) commands;
@@ -77,6 +78,8 @@
 	unsigned int    aborts;
 	unsigned int    logical_unit_resets;
 	unsigned int    target_resets;
+	uint8_t		stop_at_shutdown;
+	uint8_t		supports_SSU;
 };
 
 struct mpssas_softc {
@@ -87,7 +90,7 @@
 #define MPSSAS_DISCOVERY_TIMEOUT_PENDING	(1 << 2)
 #define MPSSAS_QUEUE_FROZEN	(1 << 3)
 #define	MPSSAS_SHUTDOWN		(1 << 4)
-#define	MPSSAS_SCANTHREAD	(1 << 5)
+	u_int			maxtargets;
 	struct mpssas_target	*targets;
 	struct cam_devq		*devq;
 	struct cam_sim		*sim;
@@ -94,16 +97,11 @@
 	struct cam_path		*path;
 	struct intr_config_hook	sas_ich;
 	struct callout		discovery_callout;
-	u_int			discovery_timeouts;
 	struct mps_event_handle	*mpssas_eh;
 
 	u_int                   startup_refcount;
-	u_int                   tm_count;
 	struct proc             *sysctl_proc;
 
-	TAILQ_HEAD(, ccb_hdr) ccb_scanq;
-	struct proc		*rescan_thread;
-
 	struct taskqueue	*ev_tq;
 	struct task		ev_task;
 	TAILQ_HEAD(, mps_fw_event_work)	ev_queue;
@@ -148,6 +146,19 @@
 	return (0);
 }
 
+static __inline void
+mpssas_set_ccbstatus(union ccb *ccb, int status)
+{
+	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+	ccb->ccb_h.status |= status;
+}
+
+static __inline int
+mpssas_get_ccbstatus(union ccb *ccb)
+{
+	return (ccb->ccb_h.status & CAM_STATUS_MASK);
+}
+
 #define MPS_SET_SINGLE_LUN(req, lun)	\
 do {					\
 	bzero((req)->LUN, 8);		\
@@ -156,9 +167,10 @@
 
 void mpssas_rescan_target(struct mps_softc *sc, struct mpssas_target *targ);
 void mpssas_discovery_end(struct mpssas_softc *sassc);
+void mpssas_prepare_for_tm(struct mps_softc *sc, struct mps_command *tm,
+    struct mpssas_target *target, lun_id_t lun_id);
 void mpssas_startup_increment(struct mpssas_softc *sassc);
 void mpssas_startup_decrement(struct mpssas_softc *sassc);
 
-struct mps_command * mpssas_alloc_tm(struct mps_softc *sc);
-void mpssas_free_tm(struct mps_softc *sc, struct mps_command *tm);
 void mpssas_firmware_event_work(void *arg, int pending);
+int mpssas_check_id(struct mpssas_softc *sassc, int id);

Modified: trunk/sys/dev/mps/mps_sas_lsi.c
===================================================================
--- trunk/sys/dev/mps/mps_sas_lsi.c	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_sas_lsi.c	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,5 +1,7 @@
+/* $MidnightBSD$ */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,13 +25,13 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/mps/mps_sas_lsi.c 322661 2017-08-18 15:38:08Z ken $");
 
-/* Communications core for LSI MPT2 */
+/* Communications core for Avago Technologies (LSI) MPT2 */
 
 /* TODO Move headers to mpsvar */
 #include <sys/types.h>
@@ -105,7 +107,9 @@
 	u16 serial_number[10];	/* 10-19 */
 	u16 reserved2[7];	/* 20-26 */
 	u16 model_number[20];	/* 27-46*/
-	u16 reserved3[209];	/* 47-255*/
+	u16 reserved3[170];	/* 47-216 */
+	u16 rotational_speed;	/* 217 */
+	u16 reserved4[38];	/* 218-255 */
 };
 static u32 event_count;
 static void mpssas_fw_work(struct mps_softc *sc,
@@ -116,10 +120,14 @@
 static int mpssas_get_sata_identify(struct mps_softc *sc, u16 handle,
     Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz,
     u32 devinfo);
+static void mpssas_ata_id_timeout(void *data);
 int mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc,
-    u64 *sas_address, u16 handle, u32 device_info);
+    u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD);
 static int mpssas_volume_add(struct mps_softc *sc,
     u16 handle);
+static void mpssas_SSU_to_SATA_devices(struct mps_softc *sc);
+static void mpssas_stop_unit_done(struct cam_periph *periph,
+    union ccb *done_ccb);
 
 void
 mpssas_evt_handler(struct mps_softc *sc, uintptr_t data,
@@ -129,7 +137,7 @@
 	u16 sz;
 
 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-	mps_print_evt_sas(sc, event);
+	MPS_DPRINT_EVENT(sc, sas, event);
 	mpssas_record_event(sc, event);
 
 	fw_event = malloc(sizeof(struct mps_fw_event_work), M_MPT2,
@@ -191,7 +199,7 @@
 	struct mpssas_softc *sassc;
 	sassc = sc->sassc;
 
-	mps_dprint(sc, MPS_INFO, "(%d)->(%s) Working on  Event: [%x]\n",
+	mps_dprint(sc, MPS_EVENT, "(%d)->(%s) Working on  Event: [%x]\n",
 			event_count++,__func__,fw_event->event);
 	switch (fw_event->event) {
 	case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 
@@ -210,9 +218,11 @@
 			switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
 			case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
 				if (mpssas_add_device(sc,
-				    le16toh(phy->AttachedDevHandle), phy->LinkRate)){
-					printf("%s: failed to add device with "
-					    "handle 0x%x\n", __func__,
+				    le16toh(phy->AttachedDevHandle),
+				    phy->LinkRate)){
+					mps_dprint(sc, MPS_ERROR, "%s: "
+					    "failed to add device with handle "
+					    "0x%x\n", __func__,
 					    le16toh(phy->AttachedDevHandle));
 					mpssas_prepare_remove(sassc, le16toh(
 						phy->AttachedDevHandle));
@@ -276,8 +286,8 @@
 
 		element =
 		    (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
-		id = mps_mapping_get_raid_id_from_handle
-		    (sc, element->VolDevHandle);
+		id = mps_mapping_get_raid_tid_from_handle(sc,
+		    element->VolDevHandle);
 
 		mps_mapping_ir_config_change_event(sc, event_data);
 
@@ -286,7 +296,8 @@
 			case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
 			case MPI2_EVENT_IR_CHANGE_RC_ADDED:
 				if (!foreign_config) {
-					if (mpssas_volume_add(sc, le16toh(element->VolDevHandle))){
+					if (mpssas_volume_add(sc,
+					    le16toh(element->VolDevHandle))){
 						printf("%s: failed to add RAID "
 						    "volume with handle 0x%x\n",
 						    __func__, le16toh(element->
@@ -326,12 +337,16 @@
 				 * Phys Disk of a volume has been created.  Hide
 				 * it from the OS.
 				 */
-				targ = mpssas_find_target_by_handle(sassc, 0, element->PhysDiskDevHandle);
+				targ = mpssas_find_target_by_handle(sassc, 0,
+				    element->PhysDiskDevHandle);
 				if (targ == NULL) 
 					break;
 				
-				/* Set raid component flags only if it is not WD.
-				 * OR WrapDrive with WD_HIDE_ALWAYS/WD_HIDE_IF_VOLUME is set in NVRAM
+				/*
+				 * Set raid component flags only if it is not
+				 * WD. OR WrapDrive with
+				 * WD_HIDE_ALWAYS/WD_HIDE_IF_VOLUME is set in
+				 * NVRAM
 				 */
 				if((!sc->WD_available) ||
 				((sc->WD_available && 
@@ -374,10 +389,10 @@
 		/*
 		 * Informational only.
 		 */
-		mps_dprint(sc, MPS_INFO, "Received IR Volume event:\n");
+		mps_dprint(sc, MPS_EVENT, "Received IR Volume event:\n");
 		switch (event_data->ReasonCode) {
 		case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED:
-  			mps_dprint(sc, MPS_INFO, "   Volume Settings "
+  			mps_dprint(sc, MPS_EVENT, "   Volume Settings "
   			    "changed from 0x%x to 0x%x for Volome with "
  			    "handle 0x%x", le32toh(event_data->PreviousValue),
  			    le32toh(event_data->NewValue),
@@ -384,7 +399,7 @@
  			    le16toh(event_data->VolDevHandle));
 			break;
 		case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED:
-  			mps_dprint(sc, MPS_INFO, "   Volume Status "
+  			mps_dprint(sc, MPS_EVENT, "   Volume Status "
   			    "changed from 0x%x to 0x%x for Volome with "
  			    "handle 0x%x", le32toh(event_data->PreviousValue),
  			    le32toh(event_data->NewValue),
@@ -391,7 +406,7 @@
  			    le16toh(event_data->VolDevHandle));
 			break;
 		case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED:
-  			mps_dprint(sc, MPS_INFO, "   Volume State "
+  			mps_dprint(sc, MPS_EVENT, "   Volume State "
   			    "changed from 0x%x to 0x%x for Volome with "
  			    "handle 0x%x", le32toh(event_data->PreviousValue),
  			    le32toh(event_data->NewValue),
@@ -440,10 +455,10 @@
 		/*
 		 * Informational only.
 		 */
-		mps_dprint(sc, MPS_INFO, "Received IR Phys Disk event:\n");
+		mps_dprint(sc, MPS_EVENT, "Received IR Phys Disk event:\n");
 		switch (event_data->ReasonCode) {
 		case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED:
-  			mps_dprint(sc, MPS_INFO, "   Phys Disk Settings "
+  			mps_dprint(sc, MPS_EVENT, "   Phys Disk Settings "
   			    "changed from 0x%x to 0x%x for Phys Disk Number "
   			    "%d and handle 0x%x at Enclosure handle 0x%x, Slot "
  			    "%d", le32toh(event_data->PreviousValue),
@@ -453,7 +468,7 @@
  			    le16toh(event_data->EnclosureHandle), le16toh(event_data->Slot));
 			break;
 		case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED:
-  			mps_dprint(sc, MPS_INFO, "   Phys Disk Status changed "
+  			mps_dprint(sc, MPS_EVENT, "   Phys Disk Status changed "
   			    "from 0x%x to 0x%x for Phys Disk Number %d and "
   			    "handle 0x%x at Enclosure handle 0x%x, Slot %d",
  				le32toh(event_data->PreviousValue),
@@ -462,7 +477,7 @@
  			    le16toh(event_data->EnclosureHandle), le16toh(event_data->Slot));
 			break;
 		case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED:
-  			mps_dprint(sc, MPS_INFO, "   Phys Disk State changed "
+  			mps_dprint(sc, MPS_EVENT, "   Phys Disk State changed "
   			    "from 0x%x to 0x%x for Phys Disk Number %d and "
   			    "handle 0x%x at Enclosure handle 0x%x, Slot %d",
  				le32toh(event_data->PreviousValue),
@@ -518,8 +533,8 @@
 		/*
 		 * Informational only.
 		 */
-		mps_dprint(sc, MPS_INFO, "Received IR Op Status event:\n");
-		mps_dprint(sc, MPS_INFO, "   RAID Operation of %d is %d "
+		mps_dprint(sc, MPS_EVENT, "Received IR Op Status event:\n");
+		mps_dprint(sc, MPS_EVENT, "   RAID Operation of %d is %d "
 		    "percent complete for Volume with handle 0x%x",
 		    event_data->RAIDOperation, event_data->PercentComplete,
 		    le16toh(event_data->VolDevHandle));
@@ -577,7 +592,7 @@
 		break;
 
 	}
-	mps_dprint(sc, MPS_INFO, "(%d)->(%s) Event Free: [%x]\n",event_count,__func__, fw_event->event);
+	mps_dprint(sc, MPS_EVENT, "(%d)->(%s) Event Free: [%x]\n",event_count,__func__, fw_event->event);
 	mpssas_fw_event_free(sc, fw_event);
 }
 
@@ -603,14 +618,14 @@
 	struct mpssas_target *targ;
 	Mpi2ConfigReply_t mpi_reply;
 	Mpi2SasDevicePage0_t config_page;
-	uint64_t sas_address, sata_sas_address;
+	uint64_t sas_address;
 	uint64_t parent_sas_address = 0;
-	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
 	u32 device_info, parent_devinfo = 0;
 	unsigned int id;
-	int ret;
-	int error = 0;
+	int ret = 1, error = 0, i;
 	struct mpssas_lun *lun;
+	u8 is_SATA_SSD = 0;
+	struct mps_command *cm;
 
 	sassc = sc->sassc;
 	mpssas_startup_increment(sassc);
@@ -642,36 +657,81 @@
 	}
 	/* TODO Check proper endianess */
 	sas_address = config_page.SASAddress.High;
-	sas_address = (sas_address << 32) | 
-	    config_page.SASAddress.Low;
+	sas_address = (sas_address << 32) | config_page.SASAddress.Low;
 
-	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE)
-		    == MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
-		if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) {
-			ret = mpssas_get_sas_address_for_sata_disk(sc,
-			    &sata_sas_address, handle, device_info);
-			if (!ret)
-				id = mps_mapping_get_sas_id(sc,
-				    sata_sas_address, handle);
-			else
-				id = mps_mapping_get_sas_id(sc,
-				    sas_address, handle);
-		} else
-			id = mps_mapping_get_sas_id(sc, sas_address,
-			    handle);
-	} else
-		id = mps_mapping_get_sas_id(sc, sas_address, handle);
+	/*
+	 * Always get SATA Identify information because this is used to
+	 * determine if Start/Stop Unit should be sent to the drive when the
+	 * system is shutdown.
+	 */
+	if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) {
+		ret = mpssas_get_sas_address_for_sata_disk(sc, &sas_address,
+		    handle, device_info, &is_SATA_SSD);
+		if (ret) {
+			mps_dprint(sc, MPS_INFO, "%s: failed to get disk type "
+			    "(SSD or HDD) for SATA device with handle 0x%04x\n",
+			    __func__, handle);
+		} else {
+			mps_dprint(sc, MPS_INFO, "SAS Address from SATA "
+			    "device = %jx\n", sas_address);
+		}
+	}
 
+	/*
+	 * use_phynum:
+	 *  1 - use the PhyNum field as a fallback to the mapping logic
+	 *  0 - never use the PhyNum field
+	 * -1 - only use the PhyNum field
+	 *
+	 * Note that using the Phy number to map a device can cause device adds
+	 * to fail if multiple enclosures/expanders are in the topology. For
+	 * example, if two devices are in the same slot number in two different
+	 * enclosures within the topology, only one of those devices will be
+	 * added. PhyNum mapping should not be used if multiple enclosures are
+	 * in the topology.
+	 */
+	id = MPS_MAP_BAD_ID;
+	if (sc->use_phynum != -1) 
+		id = mps_mapping_get_tid(sc, sas_address, handle);
 	if (id == MPS_MAP_BAD_ID) {
-		printf("failure at %s:%d/%s()! Could not get ID for device "
-		    "with handle 0x%04x\n", __FILE__, __LINE__, __func__,
-		    handle);
-		error = ENXIO;
-		goto out;
+		if ((sc->use_phynum == 0)
+		 || ((id = config_page.PhyNum) > sassc->maxtargets)) {
+			mps_dprint(sc, MPS_INFO, "failure at %s:%d/%s()! "
+			    "Could not get ID for device with handle 0x%04x\n",
+			    __FILE__, __LINE__, __func__, handle);
+			error = ENXIO;
+			goto out;
+		}
 	}
-	mps_dprint(sc, MPS_INFO, "SAS Address from SAS device page0 = %jx\n",
+	mps_dprint(sc, MPS_MAPPING, "%s: Target ID for added device is %d.\n",
+	    __func__, id);
+
+	/*
+	 * Only do the ID check and reuse check if the target is not from a
+	 * RAID Component. For Physical Disks of a Volume, the ID will be reused
+	 * when a volume is deleted because the mapping entry for the PD will
+	 * still be in the mapping table. The ID check should not be done here
+	 * either since this PD is already being used.
+	 */
+	targ = &sassc->targets[id];
+	if (!(targ->flags & MPS_TARGET_FLAGS_RAID_COMPONENT)) {
+		if (mpssas_check_id(sassc, id) != 0) {
+			device_printf(sc->mps_dev, "Excluding target id %d\n",
+			    id);
+			error = ENXIO;
+			goto out;
+		}
+
+		if (targ->handle != 0x0) {
+			mps_dprint(sc, MPS_MAPPING, "Attempting to reuse "
+			    "target id %d handle 0x%04x\n", id, targ->handle);
+			error = ENXIO;
+			goto out;
+		}
+	}
+
+	mps_dprint(sc, MPS_MAPPING, "SAS Address from SAS device page0 = %jx\n",
 	    sas_address);
-	targ = &sassc->targets[id];
 	targ->devinfo = device_info;
 	targ->devname = le32toh(config_page.DeviceName.High);
 	targ->devname = (targ->devname << 32) | 
@@ -686,6 +746,9 @@
 	targ->tid = id;
 	targ->linkrate = (linkrate>>4);
 	targ->flags = 0;
+	if (is_SATA_SSD) {
+		targ->flags = MPS_TARGET_IS_SATA_SSD;
+	}
 	TAILQ_INIT(&targ->commands);
 	TAILQ_INIT(&targ->timedout_commands);
 	while(!SLIST_EMPTY(&targ->luns)) {
@@ -696,21 +759,66 @@
 	SLIST_INIT(&targ->luns);
 
 	mps_describe_devinfo(targ->devinfo, devstring, 80);
-	mps_dprint(sc, MPS_INFO, "Found device <%s> <%s> <0x%04x> <%d/%d>\n", devstring,
-	    mps_describe_table(mps_linkrate_names, targ->linkrate),
+	mps_dprint(sc, MPS_MAPPING, "Found device <%s> <%s> <0x%04x> <%d/%d>\n",
+	    devstring, mps_describe_table(mps_linkrate_names, targ->linkrate),
 	    targ->handle, targ->encl_handle, targ->encl_slot);
+
+#if __FreeBSD_version < 1000039
 	if ((sassc->flags & MPSSAS_IN_STARTUP) == 0)
+#endif
 		mpssas_rescan_target(sc, targ);
-	mps_dprint(sc, MPS_INFO, "Target id 0x%x added\n", targ->tid);
+	mps_dprint(sc, MPS_MAPPING, "Target id 0x%x added\n", targ->tid);
+
+	/*
+	 * Check all commands to see if the SATA_ID_TIMEOUT flag has been set.
+	 * If so, send a Target Reset TM to the target that was just created.
+	 * An Abort Task TM should be used instead of a Target Reset, but that
+	 * would be much more difficult because targets have not been fully
+	 * discovered yet, and LUN's haven't been setup.  So, just reset the
+	 * target instead of the LUN.
+	 */
+	for (i = 1; i < sc->num_reqs; i++) {
+		cm = &sc->commands[i];
+		if (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) {
+			targ->timeouts++;
+			cm->cm_state = MPS_CM_STATE_TIMEDOUT;
+
+			if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) {
+				mps_dprint(sc, MPS_INFO, "%s: sending Target "
+				    "Reset for stuck SATA identify command "
+				    "(cm = %p)\n", __func__, cm);
+				targ->tm->cm_targ = targ;
+				mpssas_send_reset(sc, targ->tm,
+				    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
+			} else {
+				mps_dprint(sc, MPS_ERROR, "Failed to allocate "
+				    "tm for Target Reset after SATA ID command "
+				    "timed out (cm %p)\n", cm);
+			}
+			/*
+			 * No need to check for more since the target is
+			 * already being reset.
+			 */
+			break;
+		}
+	}
 out:
+	/*
+	 * Free the commands that may not have been freed from the SATA ID call
+	 */
+	for (i = 1; i < sc->num_reqs; i++) {
+		cm = &sc->commands[i];
+		if (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) {
+			mps_free_command(sc, cm);
+		}
+	}
 	mpssas_startup_decrement(sassc);
 	return (error);
-	
 }
 	
 int
 mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc,
-    u64 *sas_address, u16 handle, u32 device_info)
+    u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD)
 {
 	Mpi2SataPassthroughReply_t mpi_reply;
 	int i, rc, try_count;
@@ -730,16 +838,33 @@
 		ioc_status = le16toh(mpi_reply.IOCStatus)
 		    & MPI2_IOCSTATUS_MASK;
 		sas_status = mpi_reply.SASStatus;
-	} while ((rc == -EAGAIN || ioc_status || sas_status) &&
-	    (try_count < 5));
+		switch (ioc_status) {
+		case MPI2_IOCSTATUS_SUCCESS:
+			break;
+		case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+			/* No sense sleeping.  this error won't get better */
+			break;
+		default:
+			if (sc->spinup_wait_time > 0) {
+				mps_dprint(sc, MPS_INFO, "Sleeping %d seconds "
+				    "after SATA ID error to wait for spinup\n",
+				    sc->spinup_wait_time);
+				msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0,
+				    "mpsid", sc->spinup_wait_time * hz);
+			}
+		}
+	} while (((rc && (rc != EWOULDBLOCK)) ||
+	    	 (ioc_status && 
+		  (ioc_status != MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR))
+	       || sas_status) && (try_count < 5));
 
 	if (rc == 0 && !ioc_status && !sas_status) {
-		mps_dprint(sc, MPS_INFO, "%s: got SATA identify successfully "
-			   "for handle = 0x%x with try_count = %d\n",
-			   __func__, handle, try_count);
+		mps_dprint(sc, MPS_MAPPING, "%s: got SATA identify "
+		    "successfully for handle = 0x%x with try_count = %d\n",
+		    __func__, handle, try_count);
 	} else {
-		mps_dprint(sc, MPS_INFO, "%s: handle = 0x%x failed\n",
-			   __func__, handle);
+		mps_dprint(sc, MPS_MAPPING, "%s: handle = 0x%x failed\n",
+		    __func__, handle);
 		return -1;
 	}
 	/* Copy & byteswap the 40 byte model number to a buffer */
@@ -750,9 +875,9 @@
 	/* Copy & byteswap the 20 byte serial number to a buffer */
 	for (i = 0; i < MPT2SAS_SN_LEN; i += 2) {
 		buffer[MPT2SAS_MN_LEN + i] =
-			((u8 *)ata_identify.serial_number)[i + 1];
+		    ((u8 *)ata_identify.serial_number)[i + 1];
 		buffer[MPT2SAS_MN_LEN + i + 1] =
-			((u8 *)ata_identify.serial_number)[i];
+		    ((u8 *)ata_identify.serial_number)[i];
 	}
 	bufferptr = (u32 *)buffer;
 	/* There are 60 bytes to hash down to 8. 60 isn't divisible by 8,
@@ -779,6 +904,10 @@
 	    (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 |
 	    (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] <<  8 |
 	    (u64)hash_address.wwid[7];
+	if (ata_identify.rotational_speed == 1) {
+		*is_SATA_SSD = 1;
+	}
+
 	return 0;
 }
 
@@ -787,7 +916,7 @@
     Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo)
 {
 	Mpi2SataPassthroughRequest_t *mpi_request;
-	Mpi2SataPassthroughReply_t *reply;
+	Mpi2SataPassthroughReply_t *reply = NULL;
 	struct mps_command *cm;
 	char *buffer;
 	int error = 0;
@@ -818,12 +947,32 @@
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_data = buffer;
 	cm->cm_length = htole32(sz);
-	error = mps_request_polled(sc, cm);
-	reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply;
+
+	/*
+	 * Start a timeout counter specifically for the SATA ID command. This
+	 * is used to fix a problem where the FW does not send a reply sometimes
+	 * when a bad disk is in the topology. So, this is used to timeout the
+	 * command so that processing can continue normally.
+	 */
+	mps_dprint(sc, MPS_XINFO, "%s start timeout counter for SATA ID "
+	    "command\n", __func__);
+	callout_reset(&cm->cm_callout, MPS_ATA_ID_TIMEOUT * hz,
+	    mpssas_ata_id_timeout, cm);
+	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
+	mps_dprint(sc, MPS_XINFO, "%s stop timeout counter for SATA ID "
+	    "command\n", __func__);
+	/* XXX KDM need to fix the case where this command is destroyed */
+	callout_stop(&cm->cm_callout);
+
+	if (cm != NULL)
+		reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply;
 	if (error || (reply == NULL)) {
 		/* FIXME */
-		/* If the poll returns error then we need to do diag reset */ 
-		printf("%s: poll for page completed with error %d",
+ 		/*
+ 		 * If the request returns an error then we need to do a diag
+ 		 * reset
+ 		 */ 
+ 		printf("%s: request for page completed with error %d",
 		    __func__, error);
 		error = ENXIO;
 		goto out;
@@ -838,11 +987,67 @@
 		goto out;
 	}
 out:
-	mps_free_command(sc, cm);
-	free(buffer, M_MPT2);	
+	/*
+	 * If the SATA_ID_TIMEOUT flag has been set for this command, don't free
+	 * it.  The command will be freed after sending a target reset TM. If
+	 * the command did timeout, use EWOULDBLOCK.
+	 */
+	if ((cm != NULL)
+	 && (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) == 0)
+		mps_free_command(sc, cm);
+	else if (error == 0)
+		error = EWOULDBLOCK;
+	free(buffer, M_MPT2);
 	return (error);
 }
 
+static void
+mpssas_ata_id_timeout(void *data)
+{
+	struct mps_softc *sc;
+	struct mps_command *cm;
+
+	cm = (struct mps_command *)data;
+	sc = cm->cm_sc;
+	mtx_assert(&sc->mps_mtx, MA_OWNED);
+
+	mps_dprint(sc, MPS_INFO, "%s checking ATA ID command %p sc %p\n",
+	    __func__, cm, sc);
+	if ((callout_pending(&cm->cm_callout)) ||
+	    (!callout_active(&cm->cm_callout))) {
+		mps_dprint(sc, MPS_INFO, "%s ATA ID command almost timed out\n",
+		    __func__);
+		return;
+	}
+	callout_deactivate(&cm->cm_callout);
+
+	/*
+	 * Run the interrupt handler to make sure it's not pending.  This
+	 * isn't perfect because the command could have already completed
+	 * and been re-used, though this is unlikely.
+	 */
+	mps_intr_locked(sc);
+	if (cm->cm_state == MPS_CM_STATE_FREE) {
+		mps_dprint(sc, MPS_INFO, "%s ATA ID command almost timed out\n",
+		    __func__);
+		return;
+	}
+
+	mps_dprint(sc, MPS_INFO, "ATA ID command timeout cm %p\n", cm);
+
+	/*
+	 * Send wakeup() to the sleeping thread that issued this ATA ID command.
+	 * wakeup() will cause msleep to return a 0 (not EWOULDBLOCK), and this
+	 * will keep reinit() from being called. This way, an Abort Task TM can
+	 * be issued so that the timed out command can be cleared.  The Abort
+	 * Task cannot be sent from here because the driver has not completed
+	 * setting up targets.  Instead, the command is flagged so that special
+	 * handling will be used to send the abort.
+	 */
+	cm->cm_flags |= MPS_CM_FLAGS_SATA_ID_TIMEOUT;
+	wakeup(cm);
+}
+
 static int
 mpssas_volume_add(struct mps_softc *sc, u16 handle)
 {
@@ -864,7 +1069,7 @@
 		goto out;
 	}
 
-	id = mps_mapping_get_raid_id(sc, wwid, handle);
+	id = mps_mapping_get_raid_tid(sc, wwid, handle);
 	if (id == MPS_MAP_BAD_ID) {
 		printf("%s: could not get ID for volume with handle 0x%04x and "
 		    "WWID 0x%016llx\n", __func__, handle,
@@ -885,9 +1090,11 @@
 		free(lun, M_MPT2);
 	}
 	SLIST_INIT(&targ->luns);
+#if __FreeBSD_version < 1000039
 	if ((sassc->flags & MPSSAS_IN_STARTUP) == 0)
+#endif
 		mpssas_rescan_target(sc, targ);
-	mps_dprint(sc, MPS_INFO, "RAID target id %d added (WWID = 0x%jx)\n",
+	mps_dprint(sc, MPS_MAPPING, "RAID target id %d added (WWID = 0x%jx)\n",
 	    targ->tid, wwid);
 out:
 	mpssas_startup_decrement(sassc);
@@ -895,6 +1102,131 @@
 }
 
 /**
+ * mpssas_SSU_to_SATA_devices 
+ * @sc: per adapter object
+ *
+ * Looks through the target list and issues a StartStopUnit SCSI command to each
+ * SATA direct-access device.  This helps to ensure that data corruption is
+ * avoided when the system is being shut down.  This must be called after the IR
+ * System Shutdown RAID Action is sent if in IR mode.
+ *
+ * Return nothing.
+ */
+static void
+mpssas_SSU_to_SATA_devices(struct mps_softc *sc)
+{
+	struct mpssas_softc *sassc = sc->sassc;
+	union ccb *ccb;
+	path_id_t pathid = cam_sim_path(sassc->sim);
+	target_id_t targetid;
+	struct mpssas_target *target;
+	char path_str[64];
+	struct timeval cur_time, start_time;
+
+	/*
+	 * For each target, issue a StartStopUnit command to stop the device.
+	 */
+	sc->SSU_started = TRUE;
+	sc->SSU_refcount = 0;
+	for (targetid = 0; targetid < sc->max_devices; targetid++) {
+		target = &sassc->targets[targetid];
+		if (target->handle == 0x0) {
+			continue;
+		}
+
+		ccb = xpt_alloc_ccb_nowait();
+		if (ccb == NULL) {
+			mps_dprint(sc, MPS_FAULT, "Unable to alloc CCB to stop "
+			    "unit.\n");
+			return;
+		}
+
+		/*
+		 * The stop_at_shutdown flag will be set if this device is
+		 * a SATA direct-access end device.
+		 */
+		if (target->stop_at_shutdown) {
+			if (xpt_create_path(&ccb->ccb_h.path,
+			    xpt_periph, pathid, targetid,
+			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+				mps_dprint(sc, MPS_FAULT, "Unable to create "
+				    "LUN path to stop unit.\n");
+				xpt_free_ccb(ccb);
+				return;
+			}
+			xpt_path_string(ccb->ccb_h.path, path_str,
+			    sizeof(path_str));
+
+			mps_dprint(sc, MPS_INFO, "Sending StopUnit: path %s "
+			    "handle %d\n", path_str, target->handle);
+			
+			/*
+			 * Issue a START STOP UNIT command for the target.
+			 * Increment the SSU counter to be used to count the
+			 * number of required replies.
+			 */
+			mps_dprint(sc, MPS_INFO, "Incrementing SSU count\n");
+			sc->SSU_refcount++;
+			ccb->ccb_h.target_id =
+			    xpt_path_target_id(ccb->ccb_h.path);
+			ccb->ccb_h.ppriv_ptr1 = sassc;
+			scsi_start_stop(&ccb->csio,
+			    /*retries*/0,
+			    mpssas_stop_unit_done,
+			    MSG_SIMPLE_Q_TAG,
+			    /*start*/FALSE,
+			    /*load/eject*/0,
+			    /*immediate*/FALSE,
+			    MPS_SENSE_LEN,
+			    /*timeout*/10000);
+			xpt_action(ccb);
+		}
+	}
+
+	/*
+	 * Wait until all of the SSU commands have completed or time has
+	 * expired (60 seconds).  Pause for 100ms each time through.  If any
+	 * command times out, the target will be reset in the SCSI command
+	 * timeout routine.
+	 */
+	getmicrotime(&start_time);
+	while (sc->SSU_refcount) {
+		pause("mpswait", hz/10);
+		
+		getmicrotime(&cur_time);
+		if ((cur_time.tv_sec - start_time.tv_sec) > 60) {
+			mps_dprint(sc, MPS_FAULT, "Time has expired waiting "
+			    "for SSU commands to complete.\n");
+			break;
+		}
+	}
+}
+
+static void
+mpssas_stop_unit_done(struct cam_periph *periph, union ccb *done_ccb)
+{
+	struct mpssas_softc *sassc;
+	char path_str[64];
+
+	if (done_ccb == NULL)
+		return;
+
+	sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1;
+
+	xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str));
+	mps_dprint(sassc->sc, MPS_INFO, "Completing stop unit for %s\n",
+	    path_str);
+
+	/*
+	 * Nothing more to do except free the CCB and path.  If the command
+	 * timed out, an abort reset, then target reset will be issued during
+	 * the SCSI Command process.
+	 */
+	xpt_free_path(done_ccb->ccb_h.path);
+	xpt_free_ccb(done_ccb);
+}
+
+/**
  * mpssas_ir_shutdown - IR shutdown notification
  * @sc: per adapter object
  *
@@ -913,12 +1245,14 @@
 	unsigned int id, found_volume = 0;
 	struct mps_command *cm;
 	Mpi2RaidActionRequest_t	*action;
+	target_id_t targetid;
+	struct mpssas_target *target;
 
 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
 
 	/* is IR firmware build loaded? */
 	if (!sc->ir_firmware)
-		return;
+		goto out;
 
 	/* are there any volumes?  Look at IR target IDs. */
 	// TODO-later, this should be looked up in the RAID config structure
@@ -943,11 +1277,11 @@
 	}
 
 	if (!found_volume)
-		return;
+		goto out;
 
 	if ((cm = mps_alloc_command(sc)) == NULL) {
 		printf("%s: command alloc failed\n", __func__);
-		return;
+		goto out;
 	}
 
 	action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req;
@@ -955,7 +1289,7 @@
 	action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	mps_lock(sc);
-	mps_request_polled(sc, cm);
+	mps_wait_command(sc, &cm, 5, CAN_SLEEP);
 	mps_unlock(sc);
 
 	/*
@@ -963,4 +1297,49 @@
 	 */
 	if (cm)
 		mps_free_command(sc, cm);
+
+out:
+	/*
+	 * All of the targets must have the correct value set for
+	 * 'stop_at_shutdown' for the current 'enable_ssu' sysctl variable.
+	 *
+	 * The possible values for the 'enable_ssu' variable are:
+	 * 0: disable to SSD and HDD
+	 * 1: disable only to HDD (default)
+	 * 2: disable only to SSD
+	 * 3: enable to SSD and HDD
+	 * anything else will default to 1.
+	 */
+	for (targetid = 0; targetid < sc->max_devices; targetid++) {
+		target = &sc->sassc->targets[targetid];
+		if (target->handle == 0x0) {
+			continue;
+		}
+
+		if (target->supports_SSU) {
+			switch (sc->enable_ssu) {
+			case MPS_SSU_DISABLE_SSD_DISABLE_HDD:
+				target->stop_at_shutdown = FALSE;
+				break;
+			case MPS_SSU_DISABLE_SSD_ENABLE_HDD:
+				target->stop_at_shutdown = TRUE;
+				if (target->flags & MPS_TARGET_IS_SATA_SSD) {
+					target->stop_at_shutdown = FALSE;
+				}
+				break;
+			case MPS_SSU_ENABLE_SSD_ENABLE_HDD:
+				target->stop_at_shutdown = TRUE;
+				break;
+			case MPS_SSU_ENABLE_SSD_DISABLE_HDD:
+			default:
+				target->stop_at_shutdown = TRUE;
+				if ((target->flags &
+				    MPS_TARGET_IS_SATA_SSD) == 0) {
+					target->stop_at_shutdown = FALSE;
+				}
+				break;
+			}
+		}
+	}
+	mpssas_SSU_to_SATA_devices(sc);
 }

Modified: trunk/sys/dev/mps/mps_table.c
===================================================================
--- trunk/sys/dev/mps/mps_table.c	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_table.c	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009 Yahoo! Inc.
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/mps/mps_table.c 322661 2017-08-18 15:38:08Z ken $");
 
 /* Debugging tables for MPT2 */
 
@@ -205,17 +206,18 @@
 	MPS_PRINTFIELD(sc, facts, IOCNumber, %d);
 	MPS_PRINTFIELD(sc, facts, IOCExceptions, 0x%x);
 	MPS_PRINTFIELD(sc, facts, MaxChainDepth, %d);
-	mps_dprint_field(sc, MPS_INFO, "WhoInit: %s\n",
+	mps_print_field(sc, "WhoInit: %s\n",
 	    mps_describe_table(mps_whoinit_names, facts->WhoInit));
 	MPS_PRINTFIELD(sc, facts, NumberOfPorts, %d);
+	MPS_PRINTFIELD(sc, facts, MaxMSIxVectors, %d);
 	MPS_PRINTFIELD(sc, facts, RequestCredit, %d);
 	MPS_PRINTFIELD(sc, facts, ProductID, 0x%x);
-	mps_dprint_field(sc, MPS_INFO, "IOCCapabilities: %b\n",
+	mps_print_field(sc, "IOCCapabilities: %b\n",
 	    facts->IOCCapabilities, "\20" "\3ScsiTaskFull" "\4DiagTrace"
 	    "\5SnapBuf" "\6ExtBuf" "\7EEDP" "\10BiDirTarg" "\11Multicast"
 	    "\14TransRetry" "\15IR" "\16EventReplay" "\17RaidAccel"
 	    "\20MSIXIndex" "\21HostDisc");
-	mps_dprint_field(sc, MPS_INFO, "FWVersion= %d-%d-%d-%d\n",
+	mps_print_field(sc, "FWVersion= %d-%d-%d-%d\n",
 	    facts->FWVersion.Struct.Major,
 	    facts->FWVersion.Struct.Minor,
 	    facts->FWVersion.Struct.Unit,
@@ -225,7 +227,7 @@
 	MPS_PRINTFIELD(sc, facts, MaxTargets, %d);
 	MPS_PRINTFIELD(sc, facts, MaxSasExpanders, %d);
 	MPS_PRINTFIELD(sc, facts, MaxEnclosures, %d);
-	mps_dprint_field(sc, MPS_INFO, "ProtocolFlags: %b\n",
+	mps_print_field(sc, "ProtocolFlags: %b\n",
 	    facts->ProtocolFlags, "\20" "\1ScsiTarg" "\2ScsiInit");
 	MPS_PRINTFIELD(sc, facts, HighPriorityCredit, %d);
 	MPS_PRINTFIELD(sc, facts, MaxReplyDescriptorPostQueueDepth, %d);
@@ -246,15 +248,15 @@
 }
 
 void
-mps_print_event(struct mps_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event)
+mps_print_evt_generic(struct mps_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event)
 {
 
-	MPS_EVENTFIELD_START(sc, "EventReply");
-	MPS_EVENTFIELD(sc, event, EventDataLength, %d);
-	MPS_EVENTFIELD(sc, event, AckRequired, %d);
-	mps_dprint_field(sc, MPS_EVENT, "Event: %s (0x%x)\n",
+	MPS_PRINTFIELD_START(sc, "EventReply");
+	MPS_PRINTFIELD(sc, event, EventDataLength, %d);
+	MPS_PRINTFIELD(sc, event, AckRequired, %d);
+	mps_print_field(sc, "Event: %s (0x%x)\n",
 	    mps_describe_table(mps_event_names, event->Event), event->Event);
-	MPS_EVENTFIELD(sc, event, EventContext, 0x%x);
+	MPS_PRINTFIELD(sc, event, EventContext, 0x%x);
 }
 
 void
@@ -263,7 +265,7 @@
 	MPS_PRINTFIELD_START(sc, "SAS Device Page 0");
 	MPS_PRINTFIELD(sc, buf, Slot, %d);
 	MPS_PRINTFIELD(sc, buf, EnclosureHandle, 0x%x);
-	mps_dprint_field(sc, MPS_INFO, "SASAddress: 0x%jx\n",
+	mps_print_field(sc, "SASAddress: 0x%jx\n",
 	    mps_to_u64(&buf->SASAddress));
 	MPS_PRINTFIELD(sc, buf, ParentDevHandle, 0x%x);
 	MPS_PRINTFIELD(sc, buf, PhyNum, %d);
@@ -271,7 +273,7 @@
 	MPS_PRINTFIELD(sc, buf, DevHandle, 0x%x);
 	MPS_PRINTFIELD(sc, buf, AttachedPhyIdentifier, 0x%x);
 	MPS_PRINTFIELD(sc, buf, ZoneGroup, %d);
-	mps_dprint_field(sc, MPS_INFO, "DeviceInfo: %b,%s\n", buf->DeviceInfo,
+	mps_print_field(sc, "DeviceInfo: %b,%s\n", buf->DeviceInfo,
 	    "\20" "\4SataHost" "\5SmpInit" "\6StpInit" "\7SspInit"
 	    "\10SataDev" "\11SmpTarg" "\12StpTarg" "\13SspTarg" "\14Direct"
 	    "\15LsiDev" "\16AtapiDev" "\17SepDev",
@@ -279,7 +281,7 @@
 	MPS_PRINTFIELD(sc, buf, Flags, 0x%x);
 	MPS_PRINTFIELD(sc, buf, PhysicalPort, %d);
 	MPS_PRINTFIELD(sc, buf, MaxPortConnections, %d);
-	mps_dprint_field(sc, MPS_INFO, "DeviceName: 0x%jx\n",
+	mps_print_field(sc, "DeviceName: 0x%jx\n",
 	    mps_to_u64(&buf->DeviceName));
 	MPS_PRINTFIELD(sc, buf, PortGroups, %d);
 	MPS_PRINTFIELD(sc, buf, DmaGroup, %d);
@@ -290,7 +292,7 @@
 mps_print_evt_sas(struct mps_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event)
 {
 
-	mps_print_event(sc, event);
+	mps_print_evt_generic(sc, event);
 
 	switch(event->Event) {
 	case MPI2_EVENT_SAS_DISCOVERY:
@@ -298,12 +300,12 @@
 		MPI2_EVENT_DATA_SAS_DISCOVERY *data;
 
 		data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)&event->EventData;
-		mps_dprint_field(sc, MPS_EVENT, "Flags: %b\n", data->Flags,
+		mps_print_field(sc, "Flags: %b\n", data->Flags,
 		    "\20" "\1InProgress" "\2DeviceChange");
-		mps_dprint_field(sc, MPS_EVENT, "ReasonCode: %s\n",
+		mps_print_field(sc, "ReasonCode: %s\n",
 		    mps_describe_table(mps_sasdisc_reason, data->ReasonCode));
-		MPS_EVENTFIELD(sc, data, PhysicalPort, %d);
-		mps_dprint_field(sc, MPS_EVENT, "DiscoveryStatus: %b\n",
+		MPS_PRINTFIELD(sc, data, PhysicalPort, %d);
+		mps_print_field(sc, "DiscoveryStatus: %b\n",
 		    data->DiscoveryStatus,  "\20"
 		    "\1Loop" "\2UnaddressableDev" "\3DupSasAddr" "\5SmpTimeout"
 		    "\6ExpRouteFull" "\7RouteIndexError" "\10SmpFailed"
@@ -322,26 +324,26 @@
 
 		data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
 		    &event->EventData;
-		MPS_EVENTFIELD(sc, data, EnclosureHandle, 0x%x);
-		MPS_EVENTFIELD(sc, data, ExpanderDevHandle, 0x%x);
-		MPS_EVENTFIELD(sc, data, NumPhys, %d);
-		MPS_EVENTFIELD(sc, data, NumEntries, %d);
-		MPS_EVENTFIELD(sc, data, StartPhyNum, %d);
-		mps_dprint_field(sc, MPS_EVENT, "ExpStatus: %s (0x%x)\n",
+		MPS_PRINTFIELD(sc, data, EnclosureHandle, 0x%x);
+		MPS_PRINTFIELD(sc, data, ExpanderDevHandle, 0x%x);
+		MPS_PRINTFIELD(sc, data, NumPhys, %d);
+		MPS_PRINTFIELD(sc, data, NumEntries, %d);
+		MPS_PRINTFIELD(sc, data, StartPhyNum, %d);
+		mps_print_field(sc, "ExpStatus: %s (0x%x)\n",
 		    mps_describe_table(mps_sastopo_exp, data->ExpStatus),
 		    data->ExpStatus);
-		MPS_EVENTFIELD(sc, data, PhysicalPort, %d);
+		MPS_PRINTFIELD(sc, data, PhysicalPort, %d);
 		for (i = 0; i < data->NumEntries; i++) {
 			phy = &data->PHY[i];
 			phynum = data->StartPhyNum + i;
-			mps_dprint_field(sc, MPS_EVENT,
+			mps_print_field(sc,
 			    "PHY[%d].AttachedDevHandle: 0x%04x\n", phynum,
 			    phy->AttachedDevHandle);
-			mps_dprint_field(sc, MPS_EVENT,
+			mps_print_field(sc,
 			    "PHY[%d].LinkRate: %s (0x%x)\n", phynum,
 			    mps_describe_table(mps_linkrate_names,
 			    (phy->LinkRate >> 4) & 0xf), phy->LinkRate);
-			mps_dprint_field(sc,MPS_EVENT,"PHY[%d].PhyStatus: %s\n",
+			mps_print_field(sc, "PHY[%d].PhyStatus: %s\n",
 			    phynum, mps_describe_table(mps_phystatus_names,
 			    phy->PhyStatus));
 		}
@@ -353,13 +355,13 @@
 
 		data = (MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE *)
 		    &event->EventData;
-		MPS_EVENTFIELD(sc, data, EnclosureHandle, 0x%x);
-		mps_dprint_field(sc, MPS_EVENT, "ReasonCode: %s\n",
+		MPS_PRINTFIELD(sc, data, EnclosureHandle, 0x%x);
+		mps_print_field(sc, "ReasonCode: %s\n",
 		    mps_describe_table(mps_sastopo_exp, data->ReasonCode));
-		MPS_EVENTFIELD(sc, data, PhysicalPort, %d);
-		MPS_EVENTFIELD(sc, data, NumSlots, %d);
-		MPS_EVENTFIELD(sc, data, StartSlot, %d);
-		MPS_EVENTFIELD(sc, data, PhyBits, 0x%x);
+		MPS_PRINTFIELD(sc, data, PhysicalPort, %d);
+		MPS_PRINTFIELD(sc, data, NumSlots, %d);
+		MPS_PRINTFIELD(sc, data, StartSlot, %d);
+		MPS_PRINTFIELD(sc, data, PhyBits, 0x%x);
 		break;
 	}
 	case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
@@ -368,13 +370,13 @@
 
 		data = (MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
 		    &event->EventData;
-		MPS_EVENTFIELD(sc, data, TaskTag, 0x%x);
-		mps_dprint_field(sc, MPS_EVENT, "ReasonCode: %s\n",
+		MPS_PRINTFIELD(sc, data, TaskTag, 0x%x);
+		mps_print_field(sc, "ReasonCode: %s\n",
 		    mps_describe_table(mps_sasdev_reason, data->ReasonCode));
-		MPS_EVENTFIELD(sc, data, ASC, 0x%x);
-		MPS_EVENTFIELD(sc, data, ASCQ, 0x%x);
-		MPS_EVENTFIELD(sc, data, DevHandle, 0x%x);
-		mps_dprint_field(sc, MPS_EVENT, "SASAddress: 0x%jx\n",
+		MPS_PRINTFIELD(sc, data, ASC, 0x%x);
+		MPS_PRINTFIELD(sc, data, ASCQ, 0x%x);
+		MPS_PRINTFIELD(sc, data, DevHandle, 0x%x);
+		mps_print_field(sc, "SASAddress: 0x%jx\n",
 		    mps_to_u64(&data->SASAddress));
 	}
 	default:
@@ -390,17 +392,17 @@
 	MPS_PRINTFIELD(sc, buf, NumPhys, %d);
 	MPS_PRINTFIELD(sc, buf, Phy, %d);
 	MPS_PRINTFIELD(sc, buf, NumTableEntriesProgrammed, %d);
-	mps_dprint_field(sc, MPS_INFO, "ProgrammedLinkRate: %s (0x%x)\n",
+	mps_print_field(sc, "ProgrammedLinkRate: %s (0x%x)\n",
 	    mps_describe_table(mps_linkrate_names,
 	    (buf->ProgrammedLinkRate >> 4) & 0xf), buf->ProgrammedLinkRate);
-	mps_dprint_field(sc, MPS_INFO, "HwLinkRate: %s (0x%x)\n",
+	mps_print_field(sc, "HwLinkRate: %s (0x%x)\n",
 	    mps_describe_table(mps_linkrate_names,
 	    (buf->HwLinkRate >> 4) & 0xf), buf->HwLinkRate);
 	MPS_PRINTFIELD(sc, buf, AttachedDevHandle, 0x%04x);
-	mps_dprint_field(sc, MPS_INFO, "PhyInfo Reason: %s (0x%x)\n",
+	mps_print_field(sc, "PhyInfo Reason: %s (0x%x)\n",
 	    mps_describe_table(mps_phyinfo_reason_names,
 	    (buf->PhyInfo >> 16) & 0xf), buf->PhyInfo);
-	mps_dprint_field(sc, MPS_INFO, "AttachedDeviceInfo: %b,%s\n",
+	mps_print_field(sc, "AttachedDeviceInfo: %b,%s\n",
 	    buf->AttachedDeviceInfo, "\20" "\4SATAhost" "\5SMPinit" "\6STPinit"
 	    "\7SSPinit" "\10SATAdev" "\11SMPtarg" "\12STPtarg" "\13SSPtarg"
 	    "\14Direct" "\15LSIdev" "\16ATAPIdev" "\17SEPdev",
@@ -408,7 +410,7 @@
 	    buf->AttachedDeviceInfo & 0x03));
 	MPS_PRINTFIELD(sc, buf, ExpanderDevHandle, 0x%04x);
 	MPS_PRINTFIELD(sc, buf, ChangeCount, %d);
-	mps_dprint_field(sc, MPS_INFO, "NegotiatedLinkRate: %s (0x%x)\n",
+	mps_print_field(sc, "NegotiatedLinkRate: %s (0x%x)\n",
 	    mps_describe_table(mps_linkrate_names,
 	    buf->NegotiatedLinkRate & 0xf), buf->NegotiatedLinkRate);
 	MPS_PRINTFIELD(sc, buf, PhyIdentifier, %d);
@@ -415,7 +417,7 @@
 	MPS_PRINTFIELD(sc, buf, AttachedPhyIdentifier, %d);
 	MPS_PRINTFIELD(sc, buf, DiscoveryInfo, 0x%x);
 	MPS_PRINTFIELD(sc, buf, AttachedPhyInfo, 0x%x);
-	mps_dprint_field(sc, MPS_INFO, "AttachedPhyInfo Reason: %s (0x%x)\n",
+	mps_print_field(sc, "AttachedPhyInfo Reason: %s (0x%x)\n",
 	    mps_describe_table(mps_phyinfo_reason_names,
 	    buf->AttachedPhyInfo & 0xf), buf->AttachedPhyInfo);
 	MPS_PRINTFIELD(sc, buf, ZoneGroup, %d);
@@ -429,21 +431,21 @@
 	MPS_PRINTFIELD(sc, buf, OwnerDevHandle, 0x%04x);
 	MPS_PRINTFIELD(sc, buf, AttachedDevHandle, 0x%04x);
 	MPS_PRINTFIELD(sc, buf, AttachedPhyIdentifier, %d);
-	mps_dprint_field(sc, MPS_INFO, "AttachedPhyInfo Reason: %s (0x%x)\n",
+	mps_print_field(sc, "AttachedPhyInfo Reason: %s (0x%x)\n",
 	    mps_describe_table(mps_phyinfo_reason_names,
 	    buf->AttachedPhyInfo & 0xf), buf->AttachedPhyInfo);
-	mps_dprint_field(sc, MPS_INFO, "ProgrammedLinkRate: %s (0x%x)\n",
+	mps_print_field(sc, "ProgrammedLinkRate: %s (0x%x)\n",
 	    mps_describe_table(mps_linkrate_names,
 	    (buf->ProgrammedLinkRate >> 4) & 0xf), buf->ProgrammedLinkRate);
-	mps_dprint_field(sc, MPS_INFO, "HwLinkRate: %s (0x%x)\n",
+	mps_print_field(sc, "HwLinkRate: %s (0x%x)\n",
 	    mps_describe_table(mps_linkrate_names,
 	    (buf->HwLinkRate >> 4) & 0xf), buf->HwLinkRate);
 	MPS_PRINTFIELD(sc, buf, ChangeCount, %d);
 	MPS_PRINTFIELD(sc, buf, Flags, 0x%x);
-	mps_dprint_field(sc, MPS_INFO, "PhyInfo Reason: %s (0x%x)\n",
+	mps_print_field(sc, "PhyInfo Reason: %s (0x%x)\n",
 	    mps_describe_table(mps_phyinfo_reason_names,
 	    (buf->PhyInfo >> 16) & 0xf), buf->PhyInfo);
-	mps_dprint_field(sc, MPS_INFO, "NegotiatedLinkRate: %s (0x%x)\n",
+	mps_print_field(sc, "NegotiatedLinkRate: %s (0x%x)\n",
 	    mps_describe_table(mps_linkrate_names,
 	    buf->NegotiatedLinkRate & 0xf), buf->NegotiatedLinkRate);
 }
@@ -463,10 +465,12 @@
 	sge = (MPI2_SGE_SIMPLE64 *)&frame[offset * 4];
 	printf("SGL for command %p\n", cm);
 
+	hexdump(frame, 128, NULL, 0);
 	while (frame != NULL) {
-		flags = sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT;
-		printf("seg%d flags=0x%x len=0x%x addr=0x%jx\n", i, flags,
-		    sge->FlagsLength & 0xffffff, mps_to_u64(&sge->Address));
+		flags = le32toh(sge->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT;
+		printf("seg%d flags=0x%02x len=0x%06x addr=0x%016jx\n",
+		    i, flags, le32toh(sge->FlagsLength) & 0xffffff,
+		    mps_to_u64(&sge->Address));
 		if (flags & (MPI2_SGE_FLAGS_END_OF_LIST |
 		    MPI2_SGE_FLAGS_END_OF_BUFFER))
 			break;
@@ -475,8 +479,8 @@
 		if (flags & MPI2_SGE_FLAGS_LAST_ELEMENT) {
 			sgc = (MPI2_SGE_CHAIN32 *)sge;
 			printf("chain flags=0x%x len=0x%x Offset=0x%x "
-			    "Address=0x%x\n", sgc->Flags, sgc->Length,
-			    sgc->NextChainOffset, sgc->Address);
+			    "Address=0x%x\n", sgc->Flags, le16toh(sgc->Length),
+			    sgc->NextChainOffset, le32toh(sgc->Address));
 			if (chain == NULL)
 				chain = TAILQ_FIRST(&cm->cm_chain_list);
 			else

Modified: trunk/sys/dev/mps/mps_table.h
===================================================================
--- trunk/sys/dev/mps/mps_table.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_table.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009 Yahoo! Inc.
  * All rights reserved.
@@ -23,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mps_table.h 322661 2017-08-18 15:38:08Z ken $
  */
 
 #ifndef _MPS_TABLE_H
@@ -43,7 +44,7 @@
 
 void mps_print_iocfacts(struct mps_softc *, MPI2_IOC_FACTS_REPLY *);
 void mps_print_portfacts(struct mps_softc *, MPI2_PORT_FACTS_REPLY *);
-void mps_print_event(struct mps_softc *, MPI2_EVENT_NOTIFICATION_REPLY *);
+void mps_print_evt_generic(struct mps_softc *, MPI2_EVENT_NOTIFICATION_REPLY *);
 void mps_print_sasdev0(struct mps_softc *, MPI2_CONFIG_PAGE_SAS_DEV_0 *);
 void mps_print_evt_sas(struct mps_softc *, MPI2_EVENT_NOTIFICATION_REPLY *);
 void mps_print_expander1(struct mps_softc *, MPI2_CONFIG_PAGE_EXPANDER_1 *);
@@ -50,4 +51,14 @@
 void mps_print_sasphy0(struct mps_softc *, MPI2_CONFIG_PAGE_SAS_PHY_0 *);
 void mps_print_sgl(struct mps_softc *, struct mps_command *, int);
 void mps_print_scsiio_cmd(struct mps_softc *, struct mps_command *);
+
+#define MPS_DPRINT_PAGE(sc, level, func, buf)		\
+do {							\
+	if ((sc)->mps_debug & level)			\
+		mps_print_##func((sc), buf);		\
+} while (0)
+
+#define MPS_DPRINT_EVENT(sc, func, buf)			\
+	MPS_DPRINT_PAGE(sc, MPS_EVENT, evt_##func, buf)
+
 #endif

Modified: trunk/sys/dev/mps/mps_user.c
===================================================================
--- trunk/sys/dev/mps/mps_user.c	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mps_user.c	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2008 Yahoo!, Inc.
  * All rights reserved.
@@ -27,10 +28,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD userland interface
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD userland interface
  */
 /*-
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,13 +56,13 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mps_user.c 322661 2017-08-18 15:38:08Z ken $
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/dev/mps/mps_user.c 322661 2017-08-18 15:38:08Z ken $");
 
 #include "opt_compat.h"
 
@@ -90,6 +92,7 @@
 #include <sys/rman.h>
 
 #include <cam/cam.h>
+#include <cam/cam_ccb.h>
 #include <cam/scsi/scsi_all.h>
 
 #include <dev/mps/mpi/mpi2_type.h>
@@ -310,6 +313,10 @@
 	hdr->PageNumber = ext_page_req->header.PageNumber;
 	hdr->ExtPageType = ext_page_req->header.ExtPageType;
 	params.page_address = le32toh(ext_page_req->page_address);
+	params.buffer = NULL;
+	params.length = 0;
+	params.callback = NULL;
+
 	if ((error = mps_read_config_page(sc, &params)) != 0) {
 		/*
 		 * Leave the request. Without resetting the chip, it's
@@ -536,11 +543,6 @@
 		return (EINVAL);
 
 	mpi_init_sge(cm, req, &req->SGL);
-	if (cmd->len == 0) {
-		/* Perhaps just asking what the size of the fw is? */
-		return (0);
-	}
-
 	bzero(&tc, sizeof tc);
 
 	/*
@@ -556,6 +558,8 @@
 	tc.ImageOffset = 0;
 	tc.ImageSize = cmd->len;
 
+	cm->cm_flags |= MPS_CM_FLAGS_DATAIN;
+
 	return (mps_push_sge(cm, &tc, sizeof tc, 0));
 }
 
@@ -672,16 +676,16 @@
 	cm = mps_alloc_command(sc);
 
 	if (cm == NULL) {
-		mps_printf(sc, "mps_user_command: no mps requests\n");
+		mps_printf(sc, "%s: no mps requests\n", __func__);
 		err = ENOMEM;
-		goto Ret;
+		goto RetFree;
 	}
 	mps_unlock(sc);
 
 	hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
 
-	mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d  rpl %p %d\n",
-		    cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len );
+	mps_dprint(sc, MPS_USER, "%s: req %p %d  rpl %p %d\n", __func__,
+	    cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len);
 
 	if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) {
 		err = EINVAL;
@@ -691,23 +695,11 @@
 	if (err != 0)
 		goto RetFreeUnlocked;
 
-	mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X  "
-	    "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags );
+	mps_dprint(sc, MPS_USER, "%s: Function %02X MsgFlags %02X\n", __func__,
+	    hdr->Function, hdr->MsgFlags);
 
-	err = mps_user_setup_request(cm, cmd);
-	if (err != 0) {
-		mps_printf(sc, "mps_user_command: unsupported function 0x%X\n",
-		    hdr->Function );
-		goto RetFreeUnlocked;
-	}
-
 	if (cmd->len > 0) {
 		buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO);
-		if(!buf) {
-			mps_printf(sc, "Cannot allocate memory %s %d\n",
-			 __func__, __LINE__);
-			return (ENOMEM);
-    	}
 		cm->cm_data = buf;
 		cm->cm_length = cmd->len;
 	} else {
@@ -718,23 +710,33 @@
 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 
+	err = mps_user_setup_request(cm, cmd);
+	if (err == EINVAL) {
+		mps_printf(sc, "%s: unsupported parameter or unsupported "
+		    "function in request (function = 0x%X)\n", __func__,
+		    hdr->Function);
+	}
+	if (err != 0)
+		goto RetFreeUnlocked;
+
 	mps_lock(sc);
-	err = mps_wait_command(sc, cm, 30);
+	err = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
 
-	if (err) {
+	if (err || (cm == NULL)) {
 		mps_printf(sc, "%s: invalid request: error %d\n",
 		    __func__, err);
-		goto Ret;
+		goto RetFree;
 	}
 
 	rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
-	sz = rpl->MsgLength * 4;
+	if (rpl != NULL)
+		sz = rpl->MsgLength * 4;
+	else
+		sz = 0;
 	
 	if (sz > cmd->rpl_len) {
-		mps_printf(sc,
-		    "mps_user_command: reply buffer too small %d required %d\n",
-		    cmd->rpl_len, sz );
-		err = EINVAL;
+		mps_printf(sc, "%s: user reply buffer (%d) smaller than "
+		    "returned buffer (%d)\n", __func__, cmd->rpl_len, sz);
 		sz = cmd->rpl_len;
 	}	
 
@@ -742,13 +744,13 @@
 	copyout(rpl, cmd->rpl, sz);
 	if (buf != NULL)
 		copyout(buf, cmd->buf, cmd->len);
-	mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz );
+	mps_dprint(sc, MPS_USER, "%s: reply size %d\n", __func__, sz);
 
 RetFreeUnlocked:
 	mps_lock(sc);
+RetFree:
 	if (cm != NULL)
 		mps_free_command(sc, cm);
-Ret:
 	mps_unlock(sc);
 	if (buf != NULL)
 		free(buf, M_MPSUSER);
@@ -759,11 +761,12 @@
 mps_user_pass_thru(struct mps_softc *sc, mps_pass_thru_t *data)
 {
 	MPI2_REQUEST_HEADER	*hdr, tmphdr;	
-	MPI2_DEFAULT_REPLY	*rpl;
+	MPI2_DEFAULT_REPLY	*rpl = NULL;
 	struct mps_command	*cm = NULL;
 	int			err = 0, dir = 0, sz;
 	uint8_t			function = 0;
 	u_int			sense_len;
+	struct mpssas_target	*targ = NULL;
 
 	/*
 	 * Only allow one passthru command at a time.  Use the MPS_FLAGS_BUSY
@@ -771,7 +774,7 @@
 	 */
 	mps_lock(sc);
 	if (sc->mps_flags & MPS_FLAGS_BUSY) {
-		mps_dprint(sc, MPS_INFO, "%s: Only one passthru command "
+		mps_dprint(sc, MPS_USER, "%s: Only one passthru command "
 		    "allowed at a single time.", __func__);
 		mps_unlock(sc);
 		return (EBUSY);
@@ -803,7 +806,7 @@
 	} else
 		return (EINVAL);
 
-	mps_dprint(sc, MPS_INFO, "%s: req 0x%jx %d  rpl 0x%jx %d "
+	mps_dprint(sc, MPS_USER, "%s: req 0x%jx %d  rpl 0x%jx %d "
 	    "data in 0x%jx %d data out 0x%jx %d data dir %d\n", __func__,
 	    data->PtrRequest, data->RequestSize, data->PtrReply,
 	    data->ReplySize, data->PtrData, data->DataSize,
@@ -823,7 +826,7 @@
 	}
 
 	function = tmphdr.Function;
-	mps_dprint(sc, MPS_INFO, "%s: Function %02X MsgFlags %02X\n", __func__,
+	mps_dprint(sc, MPS_USER, "%s: Function %02X MsgFlags %02X\n", __func__,
 	    function, tmphdr.MsgFlags);
 
 	/*
@@ -845,11 +848,22 @@
 		task->TaskMID = cm->cm_desc.Default.SMID;
 
 		cm->cm_data = NULL;
-		cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+		cm->cm_desc.HighPriority.RequestFlags =
+		    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
 		cm->cm_complete = NULL;
 		cm->cm_complete_data = NULL;
 
-		err = mps_wait_command(sc, cm, 30);
+		targ = mpssas_find_target_by_handle(sc->sassc, 0,
+		    task->DevHandle);
+		if (targ == NULL) {
+			mps_dprint(sc, MPS_INFO,
+			   "%s %d : invalid handle for requested TM 0x%x \n",
+			   __func__, __LINE__, task->DevHandle);
+			err = 1;
+		} else {
+			mpssas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD);
+			err = mps_wait_command(sc, &cm, 30, CAN_SLEEP);
+		}
 
 		if (err != 0) {
 			err = EIO;
@@ -859,20 +873,19 @@
 		/*
 		 * Copy the reply data and sense data to user space.
 		 */
-		if (cm->cm_reply != NULL) {
+		if ((cm != NULL) && (cm->cm_reply != NULL)) {
 			rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
 			sz = rpl->MsgLength * 4;
 	
 			if (sz > data->ReplySize) {
-				mps_printf(sc, "%s: reply buffer too small: %d, "
-				    "required: %d\n", __func__, data->ReplySize, sz);
-				err = EINVAL;
-			} else {
-				mps_unlock(sc);
-				copyout(cm->cm_reply, PTRIN(data->PtrReply),
-				    data->ReplySize);
-				mps_lock(sc);
+				mps_printf(sc, "%s: user reply buffer (%d) "
+				    "smaller than returned buffer (%d)\n",
+				    __func__, data->ReplySize, sz);
 			}
+			mps_unlock(sc);
+			copyout(cm->cm_reply, PTRIN(data->PtrReply),
+			    data->ReplySize);
+			mps_lock(sc);
 		}
 		mpssas_free_tm(sc, cm);
 		goto Ret;
@@ -913,25 +926,20 @@
 	if (cm->cm_length != 0) {
 		cm->cm_data = malloc(cm->cm_length, M_MPSUSER, M_WAITOK |
 		    M_ZERO);
-		if (cm->cm_data == NULL) {
-			mps_dprint(sc, MPS_FAULT, "%s: alloc failed for IOCTL "
-			    "passthru length %d\n", __func__, cm->cm_length);
-		} else {
-			cm->cm_flags = MPS_CM_FLAGS_DATAIN;
-			if (data->DataOutSize) {
-				cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
-				err = copyin(PTRIN(data->PtrDataOut),
-				    cm->cm_data, data->DataOutSize);
-			} else if (data->DataDirection ==
-			    MPS_PASS_THRU_DIRECTION_WRITE) {
-				cm->cm_flags = MPS_CM_FLAGS_DATAOUT;
-				err = copyin(PTRIN(data->PtrData),
-				    cm->cm_data, data->DataSize);
-			}
-			if (err != 0)
-				mps_dprint(sc, MPS_FAULT, "%s: failed to copy "
-				    "IOCTL data from user space\n", __func__);
+		cm->cm_flags = MPS_CM_FLAGS_DATAIN;
+		if (data->DataOutSize) {
+			cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
+			err = copyin(PTRIN(data->PtrDataOut),
+			    cm->cm_data, data->DataOutSize);
+		} else if (data->DataDirection ==
+		    MPS_PASS_THRU_DIRECTION_WRITE) {
+			cm->cm_flags = MPS_CM_FLAGS_DATAOUT;
+			err = copyin(PTRIN(data->PtrData),
+			    cm->cm_data, data->DataSize);
 		}
+		if (err != 0)
+			mps_dprint(sc, MPS_FAULT, "%s: failed to copy "
+			    "IOCTL data from user space\n", __func__);
 	}
 	cm->cm_flags |= MPS_CM_FLAGS_SGE_SIMPLE;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
@@ -986,9 +994,9 @@
 
 	mps_lock(sc);
 
-	err = mps_wait_command(sc, cm, 30);
+	err = mps_wait_command(sc, &cm, 30, CAN_SLEEP);
 
-	if (err) {
+	if (err || (cm == NULL)) {
 		mps_printf(sc, "%s: invalid request: error %d\n", __func__,
 		    err);
 		mps_unlock(sc);
@@ -1025,15 +1033,13 @@
 		sz = rpl->MsgLength * 4;
 
 		if (sz > data->ReplySize) {
-			mps_printf(sc, "%s: reply buffer too small: %d, "
-			    "required: %d\n", __func__, data->ReplySize, sz);
-			err = EINVAL;
-		} else {
-			mps_unlock(sc);
-			copyout(cm->cm_reply, PTRIN(data->PtrReply),
-			    data->ReplySize);
-			mps_lock(sc);
+			mps_printf(sc, "%s: user reply buffer (%d) smaller "
+			    "than returned buffer (%d)\n", __func__,
+			    data->ReplySize, sz);
 		}
+		mps_unlock(sc);
+		copyout(cm->cm_reply, PTRIN(data->PtrReply), data->ReplySize);
+		mps_lock(sc);
 
 		if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) ||
 		    (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
@@ -1156,7 +1162,7 @@
     mps_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code)
 {
 	MPI2_DIAG_BUFFER_POST_REQUEST	*req;
-	MPI2_DIAG_BUFFER_POST_REPLY	*reply;
+	MPI2_DIAG_BUFFER_POST_REPLY	*reply = NULL;
 	struct mps_command		*cm = NULL;
 	int				i, status;
 
@@ -1203,8 +1209,8 @@
 	/*
 	 * Send command synchronously.
 	 */
-	status = mps_wait_command(sc, cm, 30);
-	if (status) {
+	status = mps_wait_command(sc, &cm, 30, CAN_SLEEP);
+	if (status || (cm == NULL)) {
 		mps_printf(sc, "%s: invalid request: error %d\n", __func__,
 		    status);
 		status = MPS_DIAG_FAILURE;
@@ -1215,12 +1221,14 @@
 	 * Process POST reply.
 	 */
 	reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply;
-	if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
+	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
+	    MPI2_IOCSTATUS_SUCCESS) {
 		status = MPS_DIAG_FAILURE;
 		mps_dprint(sc, MPS_FAULT, "%s: post of FW  Diag Buffer failed "
 		    "with IOCStatus = 0x%x, IOCLogInfo = 0x%x and "
-		    "TransferLength = 0x%x\n", __func__, reply->IOCStatus,
-		    reply->IOCLogInfo, reply->TransferLength);
+		    "TransferLength = 0x%x\n", __func__,
+		    le16toh(reply->IOCStatus), le32toh(reply->IOCLogInfo),
+		    le32toh(reply->TransferLength));
 		goto done;
 	}
 
@@ -1233,7 +1241,8 @@
 	status = MPS_DIAG_SUCCESS;
 
 done:
-	mps_free_command(sc, cm);
+	if (cm != NULL)
+		mps_free_command(sc, cm);
 	return (status);
 }
 
@@ -1243,7 +1252,7 @@
     uint32_t diag_type)
 {
 	MPI2_DIAG_RELEASE_REQUEST	*req;
-	MPI2_DIAG_RELEASE_REPLY		*reply;
+	MPI2_DIAG_RELEASE_REPLY		*reply = NULL;
 	struct mps_command		*cm = NULL;
 	int				status;
 
@@ -1252,8 +1261,8 @@
 	 */
 	*return_code = MPS_FW_DIAG_ERROR_RELEASE_FAILED;
 	if (!pBuffer->enabled) {
-		mps_dprint(sc, MPS_INFO, "%s: This buffer type is not supported "
-		    "by the IOC", __func__);
+		mps_dprint(sc, MPS_USER, "%s: This buffer type is not "
+		    "supported by the IOC", __func__);
 		return (MPS_DIAG_FAILURE);
 	}
 
@@ -1287,8 +1296,8 @@
 	/*
 	 * Send command synchronously.
 	 */
-	status = mps_wait_command(sc, cm, 30);
-	if (status) {
+	status = mps_wait_command(sc, &cm, 30, CAN_SLEEP);
+	if (status || (cm == NULL)) {
 		mps_printf(sc, "%s: invalid request: error %d\n", __func__,
 		    status);
 		status = MPS_DIAG_FAILURE;
@@ -1299,12 +1308,13 @@
 	 * Process RELEASE reply.
 	 */
 	reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply;
-	if ((reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) ||
-	    pBuffer->owned_by_firmware) {
+	if (((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
+	    MPI2_IOCSTATUS_SUCCESS) || pBuffer->owned_by_firmware) {
 		status = MPS_DIAG_FAILURE;
 		mps_dprint(sc, MPS_FAULT, "%s: release of FW Diag Buffer "
 		    "failed with IOCStatus = 0x%x and IOCLogInfo = 0x%x\n",
-		    __func__, reply->IOCStatus, reply->IOCLogInfo);
+		    __func__, le16toh(reply->IOCStatus),
+		    le32toh(reply->IOCLogInfo));
 		goto done;
 	}
 
@@ -1322,6 +1332,9 @@
 	}
 
 done:
+	if (cm != NULL)
+		mps_free_command(sc, cm);
+
 	return (status);
 }
 
@@ -1795,7 +1808,7 @@
 	 * Only allow one diag action at one time.
 	 */
 	if (sc->mps_flags & MPS_FLAGS_BUSY) {
-		mps_dprint(sc, MPS_INFO, "%s: Only one FW diag command "
+		mps_dprint(sc, MPS_USER, "%s: Only one FW diag command "
 		    "allowed at a single time.", __func__);
 		return (EBUSY);
 	}
@@ -1982,7 +1995,7 @@
 		 */
 		case REG_IO_READ:
 		case REG_IO_WRITE:
-			mps_dprint(sc, MPS_INFO, "IO access is not supported. "
+			mps_dprint(sc, MPS_USER, "IO access is not supported. "
 			    "Use memory access.");
 			status = EINVAL;
 			break;
@@ -2044,7 +2057,7 @@
 			data->DevHandle = dev_handle;
 	} else {
 		bus = 0;
-		target = mps_mapping_get_sas_id_from_handle(sc, dev_handle);
+		target = mps_mapping_get_tid_from_handle(sc, dev_handle);
 		data->Bus = bus;
 		data->TargetID = target;
 	}
@@ -2075,11 +2088,6 @@
 		break;
 	case MPSIO_READ_CFG_PAGE:
 		mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO);
-		if(!mps_page) {
-			mps_printf(sc, "Cannot allocate memory %s %d\n",
-			 __func__, __LINE__);
-			return (ENOMEM);
-    	}
 		error = copyin(page_req->buf, mps_page,
 		    sizeof(MPI2_CONFIG_PAGE_HEADER));
 		if (error)
@@ -2098,11 +2106,6 @@
 		break;
 	case MPSIO_READ_EXT_CFG_PAGE:
 		mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
-		if(!mps_page) {
-			mps_printf(sc, "Cannot allocate memory %s %d\n",
-			 __func__, __LINE__);
-			return (ENOMEM);
-	}
 		error = copyin(ext_page_req->buf, mps_page,
 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
 		if (error)
@@ -2116,11 +2119,6 @@
 		break;
 	case MPSIO_WRITE_CFG_PAGE:
 		mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
-		if(!mps_page) {
-			mps_printf(sc, "Cannot allocate memory %s %d\n",
-			 __func__, __LINE__);
-			return (ENOMEM);
-	}
 		error = copyin(page_req->buf, mps_page, page_req->len);
 		if (error)
 			break;
@@ -2170,7 +2168,7 @@
 			printf("Port Enable did not complete after Diag "
 			    "Reset msleep error %d.\n", msleep_ret);
 		else
-			mps_dprint(sc, MPS_INFO,
+			mps_dprint(sc, MPS_USER,
 				"Hard Reset with Port Enable completed in %d seconds.\n",
 				 (uint32_t) (time_uptime - reinit_start));
 		break;

Modified: trunk/sys/dev/mps/mpsvar.h
===================================================================
--- trunk/sys/dev/mps/mpsvar.h	2018-05-27 23:34:03 UTC (rev 10093)
+++ trunk/sys/dev/mps/mpsvar.h	2018-05-27 23:35:39 UTC (rev 10094)
@@ -1,6 +1,8 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009 Yahoo! Inc.
- * Copyright (c) 2011, 2012 LSI Corp.
+ * Copyright (c) 2011-2015 LSI Corp.
+ * Copyright (c) 2013-2015 Avago Technologies
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -24,15 +26,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * LSI MPT-Fusion Host Adapter FreeBSD
+ * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/dev/mps/mpsvar.h 322661 2017-08-18 15:38:08Z ken $
  */
 
 #ifndef _MPSVAR_H
 #define _MPSVAR_H
 
-#define MPS_DRIVER_VERSION	"14.00.00.01-fbsd"
+#define MPS_DRIVER_VERSION	"21.02.00.00-fbsd"
 
 #define MPS_DB_MAX_WAIT		2500
 
@@ -40,6 +42,7 @@
 #define MPS_EVT_REPLY_FRAMES	32
 #define MPS_REPLY_FRAMES	MPS_REQ_FRAMES
 #define MPS_CHAIN_FRAMES	2048
+#define MPS_MAXIO_PAGES		(-1)
 #define MPS_SENSE_LEN		SSD_FULL_SIZE
 #define MPS_MSI_COUNT		1
 #define MPS_SGE64_SIZE		12
@@ -50,10 +53,14 @@
 #define  NO_SLEEP			0
 
 #define MPS_PERIODIC_DELAY	1	/* 1 second heartbeat/watchdog check */
+#define MPS_ATA_ID_TIMEOUT	5	/* 5 second timeout for SATA ID cmd */
+#define MPS_MISSING_CHECK_DELAY	10	/* 10 seconds between missing check */
 
 #define MPS_SCSI_RI_INVALID_FRAME	(0x00000002)
 #define MPS_STRING_LENGTH               64
 
+#define DEFAULT_SPINUP_WAIT	3	/* seconds to wait for spinup */
+
 #include <sys/endian.h>
 
 /*
@@ -65,7 +72,6 @@
 #define MPS_MAX_MISSING_COUNT	0x0F
 #define MPS_DEV_RESERVED	0x20000000
 #define MPS_MAP_IN_USE		0x10000000
-#define MPS_RAID_CHANNEL	1
 #define MPS_MAP_BAD_ID		0xFFFFFFFF
 
 /*
@@ -102,7 +108,6 @@
  * @phy_bits: bitfields indicating controller phys
  * @dpm_entry_num: index of this device in device persistent map table
  * @dev_handle: device handle for the device pointed by this entry
- * @channel: target channel
  * @id: target id
  * @missing_count: number of times the device not detected by driver
  * @hide_flag: Hide this physical disk/not (foreign configuration)
@@ -114,8 +119,7 @@
 	u32	phy_bits;
 	u16	dpm_entry_num;
 	u16	dev_handle;
-	u8	reserved1;
-	u8	channel;
+	u16	reserved1;
 	u16	id;
 	u8	missing_count;
 	u8	init_complete;
@@ -231,6 +235,8 @@
 #define MPS_CM_FLAGS_SMP_PASS		(1 << 8)
 #define	MPS_CM_FLAGS_CHAIN_FAILED	(1 << 9)
 #define	MPS_CM_FLAGS_ERROR_MASK		MPS_CM_FLAGS_CHAIN_FAILED
+#define	MPS_CM_FLAGS_USE_CCB		(1 << 10)
+#define	MPS_CM_FLAGS_SATA_ID_TIMEOUT	(1 << 11)
 	u_int				cm_state;
 #define MPS_CM_STATE_FREE		0
 #define MPS_CM_STATE_BUSY		1
@@ -266,18 +272,22 @@
 #define MPS_FLAGS_DIAGRESET	(1 << 4)
 #define	MPS_FLAGS_ATTACH_DONE	(1 << 5)
 #define	MPS_FLAGS_WD_AVAILABLE	(1 << 6)
+#define	MPS_FLAGS_REALLOCATED	(1 << 7)
 	u_int				mps_debug;
 	u_int				disable_msix;
 	u_int				disable_msi;
+	u_int				msi_msgs;
 	int				tm_cmds_active;
 	int				io_cmds_active;
 	int				io_cmds_highwater;
 	int				chain_free;
 	int				max_chains;
+	int				max_io_pages;
 	int				chain_free_lowwater;
-#if __FreeBSD_version >= 900030
+	u_int				enable_ssu;
+	int				spinup_wait_time;
+	int				use_phynum;
 	uint64_t			chain_alloc_fail;
-#endif
 	struct sysctl_ctx_list		sysctl_ctx;
 	struct sysctl_oid		*sysctl_tree;
 	char                            fw_version[16];
@@ -284,6 +294,7 @@
 	struct mps_command		*commands;
 	struct mps_chain		*chains;
 	struct callout			periodic;
+	struct callout			device_check_callout;
 
 	struct mpssas_softc		*sassc;
 	char            tmp_string[MPS_STRING_LENGTH];
@@ -303,7 +314,6 @@
 	bus_dma_tag_t			buffer_dmat;
 
 	MPI2_IOC_FACTS_REPLY		*facts;
-	MPI2_PORT_FACTS_REPLY		*pfacts;
 	int				num_reqs;
 	int				num_replies;
 	int				fqdepth;	/* Free queue */
@@ -369,13 +379,10 @@
 	uint8_t				max_volumes;
 	uint8_t				num_enc_table_entries;
 	uint8_t				num_rsvd_entries;
-	uint8_t				num_channels;
 	uint16_t			max_dpm_entries;
 	uint8_t				is_dpm_enable;
 	uint8_t				track_mapping_events;
 	uint32_t			pending_map_events;
-	uint8_t				mt_full_retry;
-	uint8_t				mt_add_device_failed;
 
 	/* FW diag Buffer List */
 	mps_fw_diagnostic_buffer_t
@@ -414,6 +421,13 @@
 	uint16_t			DD_block_exponent;
 	uint64_t			DD_max_lba;
 	struct mps_column_map		DD_column_map[MPS_MAX_DISKS_IN_VOL];
+
+	char				exclude_ids[80];
+	struct timeval			lastfail;
+
+	/* StartStopUnit command handling at shutdown */
+	uint32_t			SSU_refcount;
+	uint8_t				SSU_started;
 };
 
 struct mps_config_params {
@@ -469,11 +483,8 @@
 		sc->chain_free--;
 		if (sc->chain_free < sc->chain_free_lowwater)
 			sc->chain_free_lowwater = sc->chain_free;
-	}
-#if __FreeBSD_version >= 900030
-	else
+	} else
 		sc->chain_alloc_fail++;
-#endif
 	return (chain);
 }
 
@@ -480,9 +491,6 @@
 static __inline void
 mps_free_chain(struct mps_softc *sc, struct mps_chain *chain)
 {
-#if 0
-	bzero(chain->chain, 128);
-#endif
 	sc->chain_free++;
 	TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link);
 }
@@ -580,15 +588,29 @@
 	mtx_unlock(&sc->mps_mtx);
 }
 
-#define MPS_INFO	(1 << 0)
-#define MPS_TRACE	(1 << 1)
-#define MPS_FAULT	(1 << 2)
-#define MPS_EVENT	(1 << 3)
-#define MPS_LOG		(1 << 4)
+#define MPS_INFO	(1 << 0)	/* Basic info */
+#define MPS_FAULT	(1 << 1)	/* Hardware faults */
+#define MPS_EVENT	(1 << 2)	/* Event data from the controller */
+#define MPS_LOG		(1 << 3)	/* Log data from the controller */
+#define MPS_RECOVERY	(1 << 4)	/* Command error recovery tracing */
+#define MPS_ERROR	(1 << 5)	/* Parameter errors, programming bugs */
+#define MPS_INIT	(1 << 6)	/* Things related to system init */
+#define MPS_XINFO	(1 << 7)	/* More detailed/noisy info */
+#define MPS_USER	(1 << 8)	/* Trace user-generated commands */
+#define MPS_MAPPING	(1 << 9)	/* Trace device mappings */
+#define MPS_TRACE	(1 << 10)	/* Function-by-function trace */
 
+#define	MPS_SSU_DISABLE_SSD_DISABLE_HDD	0
+#define	MPS_SSU_ENABLE_SSD_DISABLE_HDD	1
+#define	MPS_SSU_DISABLE_SSD_ENABLE_HDD	2
+#define	MPS_SSU_ENABLE_SSD_ENABLE_HDD	3
+
 #define mps_printf(sc, args...)				\
 	device_printf((sc)->mps_dev, ##args)
 
+#define mps_print_field(sc, msg, args...)		\
+	printf("\t" msg, ##args)
+
 #define mps_vprintf(sc, args...)			\
 do {							\
 	if (bootverbose)				\
@@ -597,29 +619,20 @@
 
 #define mps_dprint(sc, level, msg, args...)		\
 do {							\
-	if (sc->mps_debug & level)			\
-		device_printf(sc->mps_dev, msg, ##args);	\
+	if ((sc)->mps_debug & (level))			\
+		device_printf((sc)->mps_dev, msg, ##args);	\
 } while (0)
 
-#define mps_dprint_field(sc, level, msg, args...)		\
-do {								\
-	if (sc->mps_debug & level)				\
-		printf("\t" msg, ##args);			\
-} while (0)
-
 #define MPS_PRINTFIELD_START(sc, tag...)	\
-	mps_dprint((sc), MPS_INFO, ##tag);	\
-	mps_dprint_field((sc), MPS_INFO, ":\n")
+	mps_printf((sc), ##tag);			\
+	mps_print_field((sc), ":\n")
 #define MPS_PRINTFIELD_END(sc, tag)		\
-	mps_dprint((sc), MPS_INFO, tag "\n")
+	mps_printf((sc), tag "\n")
 #define MPS_PRINTFIELD(sc, facts, attr, fmt)	\
-	mps_dprint_field((sc), MPS_INFO, #attr ": " #fmt "\n", (facts)->attr)
+	mps_print_field((sc), #attr ": " #fmt "\n", (facts)->attr)
 
-#define MPS_EVENTFIELD_START(sc, tag...)	\
-	mps_dprint((sc), MPS_EVENT, ##tag);	\
-	mps_dprint_field((sc), MPS_EVENT, ":\n")
-#define MPS_EVENTFIELD(sc, facts, attr, fmt)	\
-	mps_dprint_field((sc), MPS_EVENT, #attr ": " #fmt "\n", (facts)->attr)
+#define MPS_FUNCTRACE(sc)			\
+	mps_dprint((sc), MPS_TRACE, "%s\n", __func__)
 
 #define  CAN_SLEEP                      1
 #define  NO_SLEEP                       0
@@ -627,8 +640,8 @@
 static __inline void
 mps_from_u64(uint64_t data, U64 *mps)
 {
-	(mps)->High = (uint32_t)((data) >> 32);
-	(mps)->Low = (uint32_t)((data) & 0xffffffff);
+	(mps)->High = htole32((uint32_t)((data) >> 32));
+	(mps)->Low = htole32((uint32_t)((data) & 0xffffffff));
 }
 
 static __inline uint64_t
@@ -635,7 +648,7 @@
 mps_to_u64(U64 *data)
 {
 
-	return (((uint64_t)data->High << 32) | data->Low);
+	return (((uint64_t)le32toh(data->High) << 32) | le32toh(data->Low));
 }
 
 static __inline void
@@ -661,6 +674,7 @@
 int mps_pci_setup_interrupts(struct mps_softc *sc);
 int mps_pci_restore(struct mps_softc *sc);
 
+void mps_get_tunables(struct mps_softc *sc);
 int mps_attach(struct mps_softc *sc);
 int mps_free(struct mps_softc *sc);
 void mps_intr(void *);
@@ -685,8 +699,8 @@
     MPI2_EVENT_NOTIFICATION_REPLY *event_reply);
 
 int mps_map_command(struct mps_softc *sc, struct mps_command *cm);
-int mps_wait_command(struct mps_softc *sc, struct mps_command *cm, int timeout);
-int mps_request_polled(struct mps_softc *sc, struct mps_command *cm);
+int mps_wait_command(struct mps_softc *sc, struct mps_command **cm, int timeout,
+    int sleep_flag);
 
 int mps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t
     *mpi_reply, Mpi2BiosPage3_t *config_page);
@@ -718,24 +732,25 @@
 int mps_mapping_initialize(struct mps_softc *);
 void mps_mapping_topology_change_event(struct mps_softc *,
     Mpi2EventDataSasTopologyChangeList_t *);
-int mps_mapping_is_reinit_required(struct mps_softc *);
 void mps_mapping_free_memory(struct mps_softc *sc);
 int mps_config_set_dpm_pg0(struct mps_softc *, Mpi2ConfigReply_t *,
     Mpi2DriverMappingPage0_t *, u16 );
 void mps_mapping_exit(struct mps_softc *);
-void mps_mapping_check_devices(struct mps_softc *, int);
+void mps_mapping_check_devices(void *);
 int mps_mapping_allocate_memory(struct mps_softc *sc);
-unsigned int mps_mapping_get_sas_id(struct mps_softc *, uint64_t , u16);
-unsigned int mps_mapping_get_sas_id_from_handle(struct mps_softc *sc,
+unsigned int mps_mapping_get_tid(struct mps_softc *, uint64_t , u16);
+unsigned int mps_mapping_get_tid_from_handle(struct mps_softc *sc,
     u16 handle);
-unsigned int mps_mapping_get_raid_id(struct mps_softc *sc, u64 wwid,
-    u16 handle);
-unsigned int mps_mapping_get_raid_id_from_handle(struct mps_softc *sc,
+unsigned int mps_mapping_get_raid_tid(struct mps_softc *sc, u64 wwid,
+     u16 volHandle);
+unsigned int mps_mapping_get_raid_tid_from_handle(struct mps_softc *sc,
     u16 volHandle);
 void mps_mapping_enclosure_dev_status_change_event(struct mps_softc *,
     Mpi2EventDataSasEnclDevStatusChange_t *event_data);
 void mps_mapping_ir_config_change_event(struct mps_softc *sc,
     Mpi2EventDataIrConfigChangeList_t *event_data);
+int mps_mapping_dump(SYSCTL_HANDLER_ARGS);
+int mps_mapping_encl_dump(SYSCTL_HANDLER_ARGS);
 
 void mpssas_evt_handler(struct mps_softc *sc, uintptr_t data,
     MPI2_EVENT_NOTIFICATION_REPLY *event);
@@ -743,6 +758,12 @@
 void mpssas_prepare_volume_remove(struct mpssas_softc *sassc, uint16_t handle);
 int mpssas_startup(struct mps_softc *sc);
 struct mpssas_target * mpssas_find_target_by_handle(struct mpssas_softc *, int, uint16_t);
+void mpssas_realloc_targets(struct mps_softc *sc, int maxtargets);
+struct mps_command * mpssas_alloc_tm(struct mps_softc *sc);
+void mpssas_free_tm(struct mps_softc *sc, struct mps_command *tm);
+void mpssas_release_simq_reinit(struct mpssas_softc *sassc);
+int mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm,
+    uint8_t type);
 
 SYSCTL_DECL(_hw_mps);
 



More information about the Midnightbsd-cvs mailing list