changeset 11964:4f2b629aa67f

6932434 AAC adapter GUI hang when creating or deleting RAID
author Xin Chen - Sun Microsystems - Beijing China <Xin.Chen@Sun.COM>
date Sun, 21 Mar 2010 12:30:24 +0800
parents 061945695ce1
children a7d9676a9f85
files usr/src/uts/common/io/aac/aac.c usr/src/uts/common/io/aac/aac.h usr/src/uts/common/io/aac/aac_ioctl.c usr/src/uts/common/io/warlock/aac.wlcmd
diffstat 4 files changed, 545 insertions(+), 318 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/aac/aac.c	Sat Mar 20 13:03:54 2010 -0700
+++ b/usr/src/uts/common/io/aac/aac.c	Sun Mar 21 12:30:24 2010 +0800
@@ -339,12 +339,16 @@
 /*
  * Adapter Initiated FIB handling function
  */
-static int aac_handle_aif(struct aac_softstate *, struct aac_fib *);
+static void aac_save_aif(struct aac_softstate *, ddi_acc_handle_t,
+    struct aac_fib *, int);
+static int aac_handle_aif(struct aac_softstate *, struct aac_aif_command *);
 
 /*
- * Timeout handling thread function
+ * Event handling related functions
  */
-static void aac_daemon(void *);
+static void aac_timer(void *);
+static void aac_event_thread(struct aac_softstate *);
+static void aac_event_disp(struct aac_softstate *, int);
 
 /*
  * IOCTL interface related functions
@@ -370,7 +374,9 @@
 static dev_info_t *aac_find_child(struct aac_softstate *, uint16_t, uint8_t);
 static int aac_tran_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t,
     void *, dev_info_t **);
-static int aac_dr_event(struct aac_softstate *, int, int, int);
+static int aac_handle_dr(struct aac_softstate *, int, int, int);
+
+extern pri_t minclsyspri;
 
 #ifdef DEBUG
 /*
@@ -659,16 +665,8 @@
 	0		/* DMA transfer flags */
 };
 
-struct aac_drinfo {
-	struct aac_softstate *softs;
-	int tgt;
-	int lun;
-	int event;
-};
-
 static int aac_tick = AAC_DEFAULT_TICK;	/* tick for the internal timer */
 static uint32_t aac_timebase = 0;	/* internal timer in seconds */
-static uint32_t aac_sync_time = 0;	/* next time to sync. with firmware */
 
 /*
  * Warlock directives
@@ -690,7 +688,6 @@
     aac_sg_table aac_srb))
 _NOTE(SCHEME_PROTECTS_DATA("unique to sync fib and cdb", scsi_inquiry))
 _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device scsi_address))
-_NOTE(SCHEME_PROTECTS_DATA("unique to dr event", aac_drinfo))
 _NOTE(SCHEME_PROTECTS_DATA("unique to scsi_transport", buf))
 
 int
@@ -825,16 +822,22 @@
 	AAC_DISABLE_INTR(softs);
 
 	/* Init mutexes and condvars */
-	mutex_init(&softs->q_comp_mutex, NULL,
+	mutex_init(&softs->io_lock, NULL, MUTEX_DRIVER,
+	    DDI_INTR_PRI(softs->intr_pri));
+	mutex_init(&softs->q_comp_mutex, NULL, MUTEX_DRIVER,
+	    DDI_INTR_PRI(softs->intr_pri));
+	mutex_init(&softs->time_mutex, NULL, MUTEX_DRIVER,
+	    DDI_INTR_PRI(softs->intr_pri));
+	mutex_init(&softs->ev_lock, NULL, MUTEX_DRIVER,
+	    DDI_INTR_PRI(softs->intr_pri));
+	mutex_init(&softs->aifq_mutex, NULL,
 	    MUTEX_DRIVER, DDI_INTR_PRI(softs->intr_pri));
 	cv_init(&softs->event, NULL, CV_DRIVER, NULL);
 	cv_init(&softs->sync_fib_cv, NULL, CV_DRIVER, NULL);
-	mutex_init(&softs->aifq_mutex, NULL,
-	    MUTEX_DRIVER, DDI_INTR_PRI(softs->intr_pri));
-	cv_init(&softs->aifv, NULL, CV_DRIVER, NULL);
 	cv_init(&softs->drain_cv, NULL, CV_DRIVER, NULL);
-	mutex_init(&softs->io_lock, NULL, MUTEX_DRIVER,
-	    DDI_INTR_PRI(softs->intr_pri));
+	cv_init(&softs->event_wait_cv, NULL, CV_DRIVER, NULL);
+	cv_init(&softs->event_disp_cv, NULL, CV_DRIVER, NULL);
+	cv_init(&softs->aifq_cv, NULL, CV_DRIVER, NULL);
 	attach_state |= AAC_ATTACH_KMUTEX_INITED;
 
 	/* Init the cmd queues */
@@ -907,19 +910,23 @@
 		goto error;
 	}
 
-	/* Create a taskq for dealing with dr events */
-	if ((softs->taskq = ddi_taskq_create(dip, "aac_dr_taskq", 1,
-	    TASKQ_DEFAULTPRI, 0)) == NULL) {
-		AACDB_PRINT(softs, CE_WARN, "ddi_taskq_create failed");
+	/* Common attach is OK, so we are attached! */
+	softs->state |= AAC_STATE_RUN;
+
+	/* Create event thread */
+	softs->fibctx_p = &softs->aifctx;
+	if ((softs->event_thread = thread_create(NULL, 0, aac_event_thread,
+	    softs, 0, &p0, TS_RUN, minclsyspri)) == NULL) {
+		AACDB_PRINT(softs, CE_WARN, "aif thread create failed");
+		softs->state &= ~AAC_STATE_RUN;
 		goto error;
 	}
 
 	aac_unhold_bus(softs, AAC_IOCMD_SYNC | AAC_IOCMD_ASYNC);
-	softs->state |= AAC_STATE_RUN;
 
 	/* Create a thread for command timeout */
-	softs->timeout_id = timeout(aac_daemon, (void *)softs,
-	    (60 * drv_usectohz(1000000)));
+	softs->timeout_id = timeout(aac_timer, (void *)softs,
+	    (aac_tick * drv_usectohz(1000000)));
 
 	/* Common attach is OK, so we are attached! */
 	ddi_report_dev(dip);
@@ -927,8 +934,6 @@
 	return (DDI_SUCCESS);
 
 error:
-	if (softs && softs->taskq)
-		ddi_taskq_destroy(softs->taskq);
 	if (attach_state & AAC_ATTACH_CREATE_SCSI)
 		ddi_remove_minor_node(dip, "scsi");
 	if (attach_state & AAC_ATTACH_CREATE_DEVCTL)
@@ -940,13 +945,17 @@
 		scsi_hba_tran_free(AAC_DIP2TRAN(dip));
 	}
 	if (attach_state & AAC_ATTACH_KMUTEX_INITED) {
+		mutex_destroy(&softs->io_lock);
 		mutex_destroy(&softs->q_comp_mutex);
+		mutex_destroy(&softs->time_mutex);
+		mutex_destroy(&softs->ev_lock);
+		mutex_destroy(&softs->aifq_mutex);
 		cv_destroy(&softs->event);
 		cv_destroy(&softs->sync_fib_cv);
-		mutex_destroy(&softs->aifq_mutex);
-		cv_destroy(&softs->aifv);
 		cv_destroy(&softs->drain_cv);
-		mutex_destroy(&softs->io_lock);
+		cv_destroy(&softs->event_wait_cv);
+		cv_destroy(&softs->event_disp_cv);
+		cv_destroy(&softs->aifq_cv);
 	}
 	if (attach_state & AAC_ATTACH_PCI_MEM_MAPPED)
 		ddi_regs_map_free(&softs->pci_mem_handle);
@@ -979,17 +988,9 @@
 	AAC_DISABLE_INTR(softs);
 	softs->state = AAC_STATE_STOPPED;
 
-	mutex_exit(&softs->io_lock);
-	(void) untimeout(softs->timeout_id);
-	mutex_enter(&softs->io_lock);
-	softs->timeout_id = 0;
-
-	ddi_taskq_destroy(softs->taskq);
-
 	ddi_remove_minor_node(dip, "aac");
 	ddi_remove_minor_node(dip, "scsi");
 	ddi_remove_minor_node(dip, "devctl");
-
 	mutex_exit(&softs->io_lock);
 
 	aac_common_detach(softs);
@@ -999,12 +1000,34 @@
 	scsi_hba_tran_free(tran);
 	mutex_exit(&softs->io_lock);
 
-	mutex_destroy(&softs->q_comp_mutex);
-	cv_destroy(&softs->event);
+	/* Stop timer */
+	mutex_enter(&softs->time_mutex);
+	if (softs->timeout_id) {
+		timeout_id_t tid = softs->timeout_id;
+		softs->timeout_id = 0;
+
+		mutex_exit(&softs->time_mutex);
+		(void) untimeout(tid);
+		mutex_enter(&softs->time_mutex);
+	}
+	mutex_exit(&softs->time_mutex);
+
+	/* Destroy event thread */
+	mutex_enter(&softs->ev_lock);
+	cv_signal(&softs->event_disp_cv);
+	cv_wait(&softs->event_wait_cv, &softs->ev_lock);
+	mutex_exit(&softs->ev_lock);
+
+	cv_destroy(&softs->aifq_cv);
+	cv_destroy(&softs->event_disp_cv);
+	cv_destroy(&softs->event_wait_cv);
+	cv_destroy(&softs->drain_cv);
 	cv_destroy(&softs->sync_fib_cv);
+	cv_destroy(&softs->event);
 	mutex_destroy(&softs->aifq_mutex);
-	cv_destroy(&softs->aifv);
-	cv_destroy(&softs->drain_cv);
+	mutex_destroy(&softs->ev_lock);
+	mutex_destroy(&softs->time_mutex);
+	mutex_destroy(&softs->q_comp_mutex);
 	mutex_destroy(&softs->io_lock);
 
 	ddi_regs_map_free(&softs->pci_mem_handle);
@@ -1050,6 +1073,7 @@
 	if (softs == NULL)
 		return (DDI_FAILURE);
 
+	_NOTE(ASSUMING_PROTECTED(softs->state))
 	AAC_DISABLE_INTR(softs);
 
 	return (DDI_SUCCESS);
@@ -1352,7 +1376,7 @@
 				aac_handle_io(softs, index);
 			} else if (index != 0xfffffffeul) {
 				struct aac_fib *fibp;	/* FIB in AIF queue */
-				uint16_t fib_size, fib_size0;
+				uint16_t fib_size;
 
 				/*
 				 * 0xfffffffe means that the controller wants
@@ -1361,25 +1385,13 @@
 				 */
 				index &= ~2;
 
-				mutex_enter(&softs->aifq_mutex);
-				/*
-				 * Copy AIF from adapter to the empty AIF slot
-				 */
-				fibp = &softs->aifq[softs->aifq_idx].d;
-				fib_size0 = PCI_MEM_GET16(softs, index + \
+				fibp = (struct aac_fib *)(softs-> \
+				    pci_mem_base_vaddr + index);
+				fib_size = PCI_MEM_GET16(softs, index + \
 				    offsetof(struct aac_fib, Header.Size));
-				fib_size = (fib_size0 > AAC_FIB_SIZE) ?
-				    AAC_FIB_SIZE : fib_size0;
-				PCI_MEM_REP_GET8(softs, index, fibp,
-				    fib_size);
-
-				if (aac_check_acc_handle(softs-> \
-				    pci_mem_handle) == DDI_SUCCESS)
-					(void) aac_handle_aif(softs, fibp);
-				else
-					ddi_fm_service_impact(softs->devinfo_p,
-					    DDI_SERVICE_UNAFFECTED);
-				mutex_exit(&softs->aifq_mutex);
+
+				aac_save_aif(softs, softs->pci_mem_handle,
+				    fibp, fib_size);
 
 				/*
 				 * AIF memory is owned by the adapter, so let it
@@ -1460,9 +1472,8 @@
 		if (aac_fib_dequeue(softs, AAC_HOST_NORM_CMD_Q, &aif_idx) ==
 		    AACOK) {
 			ddi_acc_handle_t acc = softs->comm_space_acc_handle;
-			struct aac_fib *fibp;	/* FIB in AIF queue */
-			struct aac_fib *fibp0;	/* FIB in communication space */
-			uint16_t fib_size, fib_size0;
+			struct aac_fib *fibp;	/* FIB in communication space */
+			uint16_t fib_size;
 			uint32_t fib_xfer_state;
 			uint32_t addr, size;
 
@@ -1474,28 +1485,21 @@
 	    adapter_fibs[(aif_idx)]), AAC_FIB_SIZE, \
 	    (type)); }
 
-			mutex_enter(&softs->aifq_mutex);
 			/* Copy AIF from adapter to the empty AIF slot */
-			fibp = &softs->aifq[softs->aifq_idx].d;
 			AAC_SYNC_AIF(softs, aif_idx, DDI_DMA_SYNC_FORCPU);
-			fibp0 = &softs->comm_space->adapter_fibs[aif_idx];
-			fib_size0 = ddi_get16(acc, &fibp0->Header.Size);
-			fib_size = (fib_size0 > AAC_FIB_SIZE) ?
-			    AAC_FIB_SIZE : fib_size0;
-			ddi_rep_get8(acc, (uint8_t *)fibp, (uint8_t *)fibp0,
-			    fib_size, DDI_DEV_AUTOINCR);
-
-			(void) aac_handle_aif(softs, fibp);
-			mutex_exit(&softs->aifq_mutex);
+			fibp = &softs->comm_space->adapter_fibs[aif_idx];
+			fib_size = ddi_get16(acc, &fibp->Header.Size);
+
+			aac_save_aif(softs, acc, fibp, fib_size);
 
 			/* Complete AIF back to adapter with good status */
 			fib_xfer_state = LE_32(fibp->Header.XferState);
 			if (fib_xfer_state & AAC_FIBSTATE_FROMADAP) {
-				ddi_put32(acc, &fibp0->Header.XferState,
+				ddi_put32(acc, &fibp->Header.XferState,
 				    fib_xfer_state | AAC_FIBSTATE_DONEHOST);
-				ddi_put32(acc, (void *)&fibp0->data[0], ST_OK);
-				if (fib_size0 > AAC_FIB_SIZE)
-					ddi_put16(acc, &fibp0->Header.Size,
+				ddi_put32(acc, (void *)&fibp->data[0], ST_OK);
+				if (fib_size > AAC_FIB_SIZE)
+					ddi_put16(acc, &fibp->Header.Size,
 					    AAC_FIB_SIZE);
 				AAC_SYNC_AIF(softs, aif_idx,
 				    DDI_DMA_SYNC_FORDEV);
@@ -2773,6 +2777,7 @@
 {
 	uint32_t status;
 	int i;
+	struct aac_supplement_adapter_info sinf;
 
 	DBCALLED(softs, 1);
 
@@ -2852,13 +2857,10 @@
 	AAC_STATUS_CLR(softs, ~0); /* Clear out all interrupts */
 	AAC_ENABLE_INTR(softs); /* Enable the interrupts we can handle */
 
-	/* Get adapter names */
-	if (CARD_IS_UNKNOWN(softs->card)) {
-		struct aac_supplement_adapter_info sinf;
-
-		if (aac_get_adapter_info(softs, NULL, &sinf) != AACOK) {
-			cmn_err(CE_CONT, "?Query adapter information failed");
-		} else {
+	if (aac_get_adapter_info(softs, NULL, &sinf) == AACOK) {
+		/* Get adapter names */
+		if (CARD_IS_UNKNOWN(softs->card)) {
+
 			softs->feature_bits = sinf.FeatureBits;
 			softs->support_opt2 = sinf.SupportedOptions2;
 
@@ -2900,7 +2902,10 @@
 					    p0, AAC_PRODUCT_LEN);
 			}
 		}
-	}
+	} else {
+		cmn_err(CE_CONT, "?Query adapter information failed");
+	}
+
 
 	cmn_err(CE_NOTE,
 	    "!aac driver %d.%02d.%02d-%d, found card: " \
@@ -3428,22 +3433,20 @@
 	return (mir);
 }
 
-static int
+static enum aac_cfg_event
 aac_probe_container(struct aac_softstate *softs, uint32_t cid)
 {
+	enum aac_cfg_event event = AAC_CFG_NULL_NOEXIST;
 	struct aac_container *dvp = &softs->containers[cid];
+	struct aac_mntinforesp *mir;
 	ddi_acc_handle_t acc;
-	struct aac_mntinforesp *mir;
-	uint64_t size;
-	uint32_t uid;
-	int rval;
 
 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
 	acc = softs->sync_ac.slotp->fib_acc_handle;
 
 	/* Get container basic info */
 	if ((mir = aac_get_container_info(softs, cid)) == NULL) {
-		rval = AACERR;
+		/* AAC_CFG_NULL_NOEXIST */
 		goto finish;
 	}
 
@@ -3452,10 +3455,15 @@
 			AACDB_PRINT(softs, CE_NOTE,
 			    ">>> Container %d deleted", cid);
 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
-			(void) aac_dr_event(softs, dvp->cid, -1,
-			    AAC_EVT_OFFLINE);
-		}
+			event = AAC_CFG_DELETE;
+		}
+		/* AAC_CFG_NULL_NOEXIST */
 	} else {
+		uint64_t size;
+		uint32_t uid;
+
+		event = AAC_CFG_NULL_EXIST;
+
 		size = AAC_MIR_SIZE(softs, acc, mir);
 		uid = ddi_get32(acc, &mir->Status);
 		if (AAC_DEV_IS_VALID(&dvp->dev)) {
@@ -3464,12 +3472,14 @@
 				    ">>> Container %u uid changed to %d",
 				    cid, uid);
 				dvp->uid = uid;
+				event = AAC_CFG_CHANGE;
 			}
 			if (dvp->size != size) {
 				AACDB_PRINT(softs, CE_NOTE,
 				    ">>> Container %u size changed to %"PRIu64,
 				    cid, size);
 				dvp->size = size;
+				event = AAC_CFG_CHANGE;
 			}
 		} else { /* Init new container */
 			AACDB_PRINT(softs, CE_NOTE,
@@ -3488,15 +3498,14 @@
 			dvp->size = size;
 			dvp->locked = 0;
 			dvp->deleted = 0;
-			(void) aac_dr_event(softs, dvp->cid, -1,
-			    AAC_EVT_ONLINE);
-		}
-	}
-	rval = AACOK;
+
+			event = AAC_CFG_ADD;
+		}
+	}
 
 finish:
 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
-	return (rval);
+	return (event);
 }
 
 /*
@@ -3512,10 +3521,16 @@
 	count = softs->container_count;
 	if (aac_get_container_count(softs, &count) == AACERR)
 		return (AACERR);
+
 	for (i = total = 0; i < count; i++) {
-		if (aac_probe_container(softs, i) == AACOK)
+		enum aac_cfg_event event = aac_probe_container(softs, i);
+		if ((event != AAC_CFG_NULL_NOEXIST) &&
+		    (event != AAC_CFG_NULL_EXIST)) {
+			(void) aac_handle_dr(softs, i, -1, event);
 			total++;
-	}
+		}
+	}
+
 	if (count < softs->container_count) {
 		struct aac_container *dvp;
 
@@ -3526,10 +3541,11 @@
 			AACDB_PRINT(softs, CE_NOTE, ">>> Container %d deleted",
 			    dvp->cid);
 			dvp->dev.flags &= ~AAC_DFLAG_VALID;
-			(void) aac_dr_event(softs, dvp->cid, -1,
-			    AAC_EVT_OFFLINE);
-		}
-	}
+			(void) aac_handle_dr(softs, dvp->cid, -1,
+			    AAC_CFG_DELETE);
+		}
+	}
+
 	softs->container_count = count;
 	AACDB_PRINT(softs, CE_CONT, "?Total %d container(s) found", total);
 	return (AACOK);
@@ -5494,15 +5510,13 @@
 	    AAC_FIBSTATE_HOSTOWNED |
 	    AAC_FIBSTATE_INITIALISED |
 	    AAC_FIBSTATE_EMPTY |
+	    AAC_FIBSTATE_FAST_RESPONSE | /* enable fast io */
 	    AAC_FIBSTATE_FROMHOST |
 	    AAC_FIBSTATE_REXPECTED |
 	    AAC_FIBSTATE_NORM;
 
-	if (!(acp->flags & AAC_CMD_SYNC)) {
-		xfer_state |=
-		    AAC_FIBSTATE_ASYNC |
-		    AAC_FIBSTATE_FAST_RESPONSE; /* enable fast io */
-	}
+	if (!(acp->flags & AAC_CMD_SYNC))
+		xfer_state |= AAC_FIBSTATE_ASYNC;
 
 	ddi_put32(acc, &fibp->Header.XferState, xfer_state);
 	ddi_put16(acc, &fibp->Header.Command, cmd);
@@ -6265,6 +6279,115 @@
 }
 
 /*
+ * Copy AIF from adapter to the empty AIF slot and inform AIF threads
+ */
+static void
+aac_save_aif(struct aac_softstate *softs, ddi_acc_handle_t acc,
+    struct aac_fib *fibp0, int fib_size0)
+{
+	struct aac_fib *fibp;	/* FIB in AIF queue */
+	int fib_size;
+	uint16_t fib_command;
+	int current, next;
+
+	/* Ignore non AIF messages */
+	fib_command = ddi_get16(acc, &fibp0->Header.Command);
+	if (fib_command != AifRequest) {
+		cmn_err(CE_WARN, "!Unknown command from controller");
+		return;
+	}
+
+	mutex_enter(&softs->aifq_mutex);
+
+	/* Save AIF */
+	fibp = &softs->aifq[softs->aifq_idx].d;
+	fib_size = (fib_size0 > AAC_FIB_SIZE) ? AAC_FIB_SIZE : fib_size0;
+	ddi_rep_get8(acc, (uint8_t *)fibp, (uint8_t *)fibp0, fib_size,
+	    DDI_DEV_AUTOINCR);
+
+	if (aac_check_acc_handle(softs->pci_mem_handle) != DDI_SUCCESS) {
+		ddi_fm_service_impact(softs->devinfo_p,
+		    DDI_SERVICE_UNAFFECTED);
+		mutex_exit(&softs->aifq_mutex);
+		return;
+	}
+
+	AACDB_PRINT_AIF(softs, (struct aac_aif_command *)&fibp->data[0]);
+
+	/* Modify AIF contexts */
+	current = softs->aifq_idx;
+	next = (current + 1) % AAC_AIFQ_LENGTH;
+	if (next == 0) {
+		struct aac_fib_context *ctx_p;
+
+		softs->aifq_wrap = 1;
+		for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
+			if (next == ctx_p->ctx_idx) {
+				ctx_p->ctx_flags |= AAC_CTXFLAG_FILLED;
+			} else if (current == ctx_p->ctx_idx &&
+			    (ctx_p->ctx_flags & AAC_CTXFLAG_FILLED)) {
+				ctx_p->ctx_idx = next;
+				ctx_p->ctx_overrun++;
+			}
+		}
+	}
+	softs->aifq_idx = next;
+
+	/* Wakeup AIF threads */
+	cv_broadcast(&softs->aifq_cv);
+	mutex_exit(&softs->aifq_mutex);
+
+	/* Wakeup event thread to handle aif */
+	aac_event_disp(softs, AAC_EVENT_AIF);
+}
+
+static int
+aac_return_aif_common(struct aac_softstate *softs, struct aac_fib_context *ctx,
+    struct aac_fib **fibpp)
+{
+	int current;
+
+	current = ctx->ctx_idx;
+	if (current == softs->aifq_idx &&
+	    !(ctx->ctx_flags & AAC_CTXFLAG_FILLED))
+		return (EAGAIN); /* Empty */
+
+	*fibpp = &softs->aifq[current].d;
+
+	ctx->ctx_flags &= ~AAC_CTXFLAG_FILLED;
+	ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
+	return (0);
+}
+
+int
+aac_return_aif(struct aac_softstate *softs, struct aac_fib_context *ctx,
+    struct aac_fib **fibpp)
+{
+	int rval;
+
+	mutex_enter(&softs->aifq_mutex);
+	rval = aac_return_aif_common(softs, ctx, fibpp);
+	mutex_exit(&softs->aifq_mutex);
+	return (rval);
+}
+
+int
+aac_return_aif_wait(struct aac_softstate *softs, struct aac_fib_context *ctx,
+    struct aac_fib **fibpp)
+{
+	int rval;
+
+	mutex_enter(&softs->aifq_mutex);
+	rval = aac_return_aif_common(softs, ctx, fibpp);
+	if (rval == EAGAIN) {
+		AACDB_PRINT(softs, CE_NOTE, "Waiting for AIF");
+		rval = cv_wait_sig(&softs->aifq_cv, &softs->aifq_mutex);
+	}
+	mutex_exit(&softs->aifq_mutex);
+	return ((rval > 0) ? 0 : EINTR);
+}
+
+/*
  * The following function comes from Adaptec:
  *
  * When driver sees a particular event that means containers are changed, it
@@ -6275,26 +6398,12 @@
  * another particular event. When sees that events come in, it will do rescan.
  */
 static int
-aac_handle_aif(struct aac_softstate *softs, struct aac_fib *fibp)
+aac_handle_aif(struct aac_softstate *softs, struct aac_aif_command *aif)
 {
 	ddi_acc_handle_t acc = softs->comm_space_acc_handle;
-	uint16_t fib_command;
-	struct aac_aif_command *aif;
 	int en_type;
 	int devcfg_needed;
-	int current, next;
-
-	fib_command = LE_16(fibp->Header.Command);
-	if (fib_command != AifRequest) {
-		cmn_err(CE_NOTE, "!Unknown command from controller: 0x%x",
-		    fib_command);
-		return (AACERR);
-	}
-
-	/* Update internal container state */
-	aif = (struct aac_aif_command *)&fibp->data[0];
-
-	AACDB_PRINT_AIF(softs, aif);
+
 	devcfg_needed = 0;
 	en_type = LE_32((uint32_t)aif->data.EN.type);
 
@@ -6353,37 +6462,45 @@
 		break;
 	}
 
-	mutex_exit(&softs->aifq_mutex);
 	if (devcfg_needed) {
 		softs->devcfg_wait_on = 0;
 		(void) aac_probe_containers(softs);
 	}
-	mutex_enter(&softs->aifq_mutex);
-
-	/* Modify AIF contexts */
-	current = softs->aifq_idx;
-	next = (current + 1) % AAC_AIFQ_LENGTH;
-	if (next == 0) {
-		struct aac_fib_context *ctx;
-
-		softs->aifq_wrap = 1;
-		for (ctx = softs->fibctx; ctx; ctx = ctx->next) {
-			if (next == ctx->ctx_idx) {
-				ctx->ctx_filled = 1;
-			} else if (current == ctx->ctx_idx && ctx->ctx_filled) {
-				ctx->ctx_idx = next;
-				AACDB_PRINT(softs, CE_NOTE,
-				    "-- AIF queue(%x) overrun", ctx->unique);
-			}
-		}
-	}
-	softs->aifq_idx = next;
-
-	/* Wakeup applications */
-	cv_broadcast(&softs->aifv);
+
 	return (AACOK);
 }
 
+
+/*
+ * Check and handle AIF events
+ */
+static void
+aac_aif_event(struct aac_softstate *softs)
+{
+	struct aac_fib *fibp;
+
+	/*CONSTCOND*/
+	while (1) {
+		if (aac_return_aif(softs, &softs->aifctx, &fibp) != 0)
+			break; /* No more AIFs to handle, end loop */
+
+		/* AIF overrun, array create/delete may missed. */
+		if (softs->aifctx.ctx_overrun) {
+			softs->aifctx.ctx_overrun = 0;
+		}
+
+		/* AIF received, handle it */
+		struct aac_aif_command *aifp =
+		    (struct aac_aif_command *)&fibp->data[0];
+		uint32_t aif_command = LE_32((uint32_t)aifp->command);
+
+		if (aif_command == AifCmdDriverNotify ||
+		    aif_command == AifCmdEventNotify ||
+		    aif_command == AifCmdJobProgress)
+			(void) aac_handle_aif(softs, aifp);
+	}
+}
+
 /*
  * Timeout recovery
  */
@@ -6426,12 +6543,17 @@
  * Time sync. command added to synchronize time with firmware every 30
  * minutes (required for correct AIF timestamps etc.)
  */
-static int
+static void
 aac_sync_tick(struct aac_softstate *softs)
 {
 	ddi_acc_handle_t acc;
 	int rval;
 
+	mutex_enter(&softs->time_mutex);
+	ASSERT(softs->time_sync <= softs->timebase);
+	softs->time_sync = 0;
+	mutex_exit(&softs->time_mutex);
+
 	/* Time sync. with firmware every AAC_SYNC_TICK */
 	(void) aac_sync_fib_slot_bind(softs, &softs->sync_ac);
 	acc = softs->sync_ac.slotp->fib_acc_handle;
@@ -6440,43 +6562,158 @@
 	    ddi_get_time());
 	rval = aac_sync_fib(softs, SendHostTime, AAC_FIB_SIZEOF(uint32_t));
 	aac_sync_fib_slot_release(softs, &softs->sync_ac);
-	return (rval);
-}
-
+
+	mutex_enter(&softs->time_mutex);
+	softs->time_sync = softs->timebase;
+	if (rval != AACOK)
+		/* retry shortly */
+		softs->time_sync += aac_tick << 1;
+	else
+		softs->time_sync += AAC_SYNC_TICK;
+	mutex_exit(&softs->time_mutex);
+}
+
+/*
+ * Timeout checking and handling
+ */
 static void
-aac_daemon(void *arg)
-{
-	struct aac_softstate *softs = (struct aac_softstate *)arg;
-	struct aac_cmd *acp;
-
-	DBCALLED(softs, 2);
-
-	mutex_enter(&softs->io_lock);
-	/* Check slot for timeout pkts */
-	aac_timebase += aac_tick;
-	for (acp = softs->q_busy.q_head; acp; acp = acp->next) {
-		if (acp->timeout) {
-			if (acp->timeout <= aac_timebase) {
+aac_daemon(struct aac_softstate *softs)
+{
+	int time_out; /* set if timeout happened */
+	int time_adjust;
+	uint32_t softs_timebase;
+
+	mutex_enter(&softs->time_mutex);
+	ASSERT(softs->time_out <= softs->timebase);
+	softs->time_out = 0;
+	softs_timebase = softs->timebase;
+	mutex_exit(&softs->time_mutex);
+
+	/* Check slots for timeout pkts */
+	time_adjust = 0;
+	do {
+		struct aac_cmd *acp;
+
+		time_out = 0;
+		for (acp = softs->q_busy.q_head; acp; acp = acp->next) {
+			if (acp->timeout == 0)
+				continue;
+
+			/*
+			 * If timeout happened, update outstanding cmds
+			 * to be checked later again.
+			 */
+			if (time_adjust) {
+				acp->timeout += time_adjust;
+				continue;
+			}
+
+			if (acp->timeout <= softs_timebase) {
 				aac_cmd_timeout(softs, acp);
-				ddi_trigger_softintr(softs->softint_id);
+				time_out = 1;
+				time_adjust = aac_tick * drv_usectohz(1000000);
+				break; /* timeout happened */
+			} else {
+				break; /* no timeout */
 			}
-			break;
-		}
-	}
-
-	/* Time sync. with firmware every AAC_SYNC_TICK */
-	if (aac_sync_time <= aac_timebase) {
-		aac_sync_time = aac_timebase;
-		if (aac_sync_tick(softs) != AACOK)
-			aac_sync_time += aac_tick << 1; /* retry shortly */
-		else
-			aac_sync_time += AAC_SYNC_TICK;
-	}
-
-	if ((softs->state & AAC_STATE_RUN) && (softs->timeout_id != 0))
-		softs->timeout_id = timeout(aac_daemon, (void *)softs,
+		}
+	} while (time_out);
+
+	mutex_enter(&softs->time_mutex);
+	softs->time_out = softs->timebase + aac_tick;
+	mutex_exit(&softs->time_mutex);
+}
+
+/*
+ * The event thread handles various tasks serially for the other parts of
+ * the driver, so that they can run fast.
+ */
+static void
+aac_event_thread(struct aac_softstate *softs)
+{
+	int run = 1;
+
+	DBCALLED(softs, 1);
+
+	mutex_enter(&softs->ev_lock);
+	while (run) {
+		int events;
+
+		if ((events = softs->events) == 0) {
+			cv_wait(&softs->event_disp_cv, &softs->ev_lock);
+			events = softs->events;
+		}
+		softs->events = 0;
+		mutex_exit(&softs->ev_lock);
+
+		mutex_enter(&softs->io_lock);
+		if ((softs->state & AAC_STATE_RUN) &&
+		    (softs->state & AAC_STATE_DEAD) == 0) {
+			if (events & AAC_EVENT_TIMEOUT)
+				aac_daemon(softs);
+			if (events & AAC_EVENT_SYNCTICK)
+				aac_sync_tick(softs);
+			if (events & AAC_EVENT_AIF)
+				aac_aif_event(softs);
+		} else {
+			run = 0;
+		}
+		mutex_exit(&softs->io_lock);
+
+		mutex_enter(&softs->ev_lock);
+	}
+
+	cv_signal(&softs->event_wait_cv);
+	mutex_exit(&softs->ev_lock);
+}
+
+/*
+ * Internal timer. It is only responsbile for time counting and report time
+ * related events. Events handling is done by aac_event_thread(), so that
+ * the timer itself could be as precise as possible.
+ */
+static void
+aac_timer(void *arg)
+{
+	struct aac_softstate *softs = arg;
+	int events = 0;
+
+	mutex_enter(&softs->time_mutex);
+
+	/* If timer is being stopped, exit */
+	if (softs->timeout_id) {
+		softs->timeout_id = timeout(aac_timer, (void *)softs,
 		    (aac_tick * drv_usectohz(1000000)));
-	mutex_exit(&softs->io_lock);
+	} else {
+		mutex_exit(&softs->time_mutex);
+		return;
+	}
+
+	/* Time counting */
+	softs->timebase += aac_tick;
+
+	/* Check time related events */
+	if (softs->time_out && softs->time_out <= softs->timebase)
+		events |= AAC_EVENT_TIMEOUT;
+	if (softs->time_sync && softs->time_sync <= softs->timebase)
+		events |= AAC_EVENT_SYNCTICK;
+
+	mutex_exit(&softs->time_mutex);
+
+	if (events)
+		aac_event_disp(softs, events);
+}
+
+/*
+ * Dispatch events to daemon thread for handling
+ */
+static void
+aac_event_disp(struct aac_softstate *softs, int events)
+{
+	mutex_enter(&softs->ev_lock);
+	softs->events |= events;
+	cv_broadcast(&softs->event_disp_cv);
+	mutex_exit(&softs->ev_lock);
 }
 
 /*
@@ -6898,13 +7135,14 @@
 	DBCALLED(softs, 2);
 
 	if (tgt < AAC_MAX_LD) {
-		int rval;
+		enum aac_cfg_event event;
 
 		if (lun == 0) {
 			mutex_enter(&softs->io_lock);
-			rval = aac_probe_container(softs, tgt);
+			event = aac_probe_container(softs, tgt);
 			mutex_exit(&softs->io_lock);
-			if (rval == AACOK) {
+			if ((event != AAC_CFG_NULL_NOEXIST) &&
+			    (event != AAC_CFG_DELETE)) {
 				if (scsi_hba_probe(sd, NULL) ==
 				    SCSIPROBE_EXISTS)
 					return (NDI_SUCCESS);
@@ -7162,10 +7400,10 @@
 	return (rval);
 }
 
-static void
-aac_handle_dr(struct aac_drinfo *drp)
-{
-	struct aac_softstate *softs = drp->softs;
+/*ARGSUSED*/
+static int
+aac_handle_dr(struct aac_softstate *softs, int tgt, int lun, int event)
+{
 	struct aac_device *dvp;
 	dev_info_t *dip;
 	int valid;
@@ -7174,21 +7412,22 @@
 	DBCALLED(softs, 1);
 
 	/* Hold the nexus across the bus_config */
-	mutex_enter(&softs->io_lock);
-	dvp = AAC_DEV(softs, drp->tgt);
+	dvp = AAC_DEV(softs, tgt);
 	valid = AAC_DEV_IS_VALID(dvp);
 	dip = dvp->dip;
+	if (!(softs->state & AAC_STATE_RUN))
+		return (AACERR);
 	mutex_exit(&softs->io_lock);
 
-	switch (drp->event) {
-	case AAC_EVT_ONLINE:
-	case AAC_EVT_OFFLINE:
+	switch (event) {
+	case AAC_CFG_ADD:
+	case AAC_CFG_DELETE:
 		/* Device onlined */
 		if (dip == NULL && valid) {
 			ndi_devi_enter(softs->devinfo_p, &circ1);
-			(void) aac_config_lun(softs, drp->tgt, 0, NULL);
+			(void) aac_config_lun(softs, tgt, 0, NULL);
 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d onlined",
-			    softs->instance, drp->tgt, drp->lun);
+			    softs->instance, tgt, lun);
 			ndi_devi_exit(softs->devinfo_p, circ1);
 		}
 		/* Device offlined */
@@ -7199,34 +7438,12 @@
 
 			(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
 			AACDB_PRINT(softs, CE_NOTE, "c%dt%dL%d offlined",
-			    softs->instance, drp->tgt, drp->lun);
+			    softs->instance, tgt, lun);
 		}
 		break;
 	}
-	kmem_free(drp, sizeof (struct aac_drinfo));
-}
-
-static int
-aac_dr_event(struct aac_softstate *softs, int tgt, int lun, int event)
-{
-	struct aac_drinfo *drp;
-
-	DBCALLED(softs, 1);
-
-	if (softs->taskq == NULL ||
-	    (drp = kmem_zalloc(sizeof (struct aac_drinfo), KM_NOSLEEP)) == NULL)
-		return (AACERR);
-
-	drp->softs = softs;
-	drp->tgt = tgt;
-	drp->lun = lun;
-	drp->event = event;
-	if ((ddi_taskq_dispatch(softs->taskq, (void (*)(void *))aac_handle_dr,
-	    drp, DDI_NOSLEEP)) != DDI_SUCCESS) {
-		AACDB_PRINT(softs, CE_WARN, "DR task start failed");
-		kmem_free(drp, sizeof (struct aac_drinfo));
-		return (AACERR);
-	}
+
+	mutex_enter(&softs->io_lock);
 	return (AACOK);
 }
 
--- a/usr/src/uts/common/io/aac/aac.h	Sat Mar 20 13:03:54 2010 -0700
+++ b/usr/src/uts/common/io/aac/aac.h	Sun Mar 21 12:30:24 2010 +0800
@@ -55,7 +55,7 @@
 
 #define	AAC_DRIVER_MAJOR_VERSION	2
 #define	AAC_DRIVER_MINOR_VERSION	2
-#define	AAC_DRIVER_BUGFIX_LEVEL		9
+#define	AAC_DRIVER_BUGFIX_LEVEL		10
 #define	AAC_DRIVER_TYPE			AAC_TYPE_RELEASE
 
 #define	STR(s)				# s
@@ -113,6 +113,13 @@
 #define	AAC_HI32(p64)			((uint32_t *)(p64) + 1)
 
 /*
+ * Internal events that will be handled serially by aac_event_thread()
+ */
+#define	AAC_EVENT_AIF			(1 << 0)
+#define	AAC_EVENT_TIMEOUT		(1 << 1)
+#define	AAC_EVENT_SYNCTICK		(1 << 2)
+
+/*
  * AAC_CMDQ_SYNC should be 0 and AAC_CMDQ_ASYNC be 1 for Sync FIB io
  * to be served before async FIB io, see aac_start_waiting_io().
  * So that io requests sent by interactive userland commands get
@@ -154,17 +161,23 @@
 #define	AAC_DEV_LD		0	/* logical device */
 #define	AAC_DEV_PD		1	/* physical device */
 
-/* DR events */
-#define	AAC_EVT_NONE		0
-#define	AAC_EVT_ONLINE		1
-#define	AAC_EVT_OFFLINE		2
-
 /* Device flags */
 #define	AAC_DFLAG_VALID		(1 << 0)
 #define	AAC_DFLAG_CONFIGURING	(1 << 1)
 
 #define	AAC_DEV_IS_VALID(dvp)	((dvp)->flags & AAC_DFLAG_VALID)
 
+/*
+ * Device config change events
+ */
+enum aac_cfg_event {
+	AAC_CFG_NULL_NOEXIST = 0,	/* No change with no device */
+	AAC_CFG_NULL_EXIST,		/* No change but have device */
+	AAC_CFG_ADD,			/* Device added */
+	AAC_CFG_DELETE,			/* Device deleted */
+	AAC_CFG_CHANGE			/* Device changed */
+};
+
 struct aac_device {
 	int flags;
 
@@ -333,10 +346,15 @@
 	    uint32_t, uint32_t, uint32_t, uint32_t);
 };
 
+#define	AAC_CTXFLAG_FILLED	0x01	/* aifq's full for this ctx */
+#define	AAC_CTXFLAG_RESETED	0x02
+
 struct aac_fib_context {
 	uint32_t unique;
 	int ctx_idx;
 	int ctx_filled;		/* aifq is full for this fib context */
+	int ctx_flags;
+	int ctx_overrun;
 	struct aac_fib_context *next, *prev;
 };
 
@@ -428,8 +446,6 @@
 	struct aac_slot *io_slot;	/* static list for allocated slots */
 	struct aac_slot *free_io_slot_head;
 
-	timeout_id_t timeout_id;	/* for timeout daemon */
-
 	kcondvar_t event;		/* for ioctl_send_fib() and sync IO */
 	kcondvar_t sync_fib_cv;		/* for sync_fib_slot_bind/release */
 
@@ -439,17 +455,32 @@
 	timeout_id_t drain_timeid;	/* for outstanding cmd drain */
 	kcondvar_t drain_cv;		/* for quiesce drain */
 
+	/* Internal timer */
+	kmutex_t time_mutex;
+	timeout_id_t timeout_id;	/* for timeout daemon */
+	uint32_t timebase;		/* internal timer in seconds */
+	uint32_t time_sync;		/* next time to sync with firmware */
+	uint32_t time_out;		/* next time to check timeout */
+	uint32_t time_throttle;		/* next time to restore throttle */
+
+	/* Internal events handling */
+	kmutex_t ev_lock;
+	int events;
+	kthread_t *event_thread;	/* for AIF & timeout */
+	kcondvar_t event_wait_cv;
+	kcondvar_t event_disp_cv;
+
 	/* AIF */
 	kmutex_t aifq_mutex;		/* for AIF queue aifq */
-	kcondvar_t aifv;
+	kcondvar_t aifq_cv;
 	union aac_fib_align aifq[AAC_AIFQ_LENGTH];
 	int aifq_idx;			/* slot for next new AIF */
 	int aifq_wrap;			/* AIF queue has ever been wrapped */
-	struct aac_fib_context *fibctx;
+	struct aac_fib_context aifctx;	/* sys aif ctx */
+	struct aac_fib_context *fibctx_p;
 	int devcfg_wait_on;		/* AIF event waited for rescan */
 
 	int fm_capabilities;
-	ddi_taskq_t *taskq;
 
 	/* MSI specific fields */
 	ddi_intr_handle_t *htable;	/* For array of interrupts */
--- a/usr/src/uts/common/io/aac/aac_ioctl.c	Sat Mar 20 13:03:54 2010 -0700
+++ b/usr/src/uts/common/io/aac/aac_ioctl.c	Sun Mar 21 12:30:24 2010 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -66,6 +66,10 @@
 extern int aac_do_io(struct aac_softstate *, struct aac_cmd *);
 extern void aac_cmd_fib_copy(struct aac_softstate *, struct aac_cmd *);
 extern void aac_ioctl_complete(struct aac_softstate *, struct aac_cmd *);
+extern int aac_return_aif_wait(struct aac_softstate *, struct aac_fib_context *,
+    struct aac_fib **);
+extern int aac_return_aif(struct aac_softstate *, struct aac_fib_context *,
+    struct aac_fib **);
 
 extern ddi_device_acc_attr_t aac_acc_attr;
 extern int aac_check_dma_handle(ddi_dma_handle_t);
@@ -305,45 +309,45 @@
 static int
 aac_open_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
 {
-	struct aac_fib_context *fibctx, *ctx;
+	struct aac_fib_context *fibctx_p, *ctx_p;
 
 	DBCALLED(softs, 2);
 
-	fibctx = kmem_zalloc(sizeof (struct aac_fib_context), KM_NOSLEEP);
-	if (fibctx == NULL)
+	fibctx_p = kmem_zalloc(sizeof (struct aac_fib_context), KM_NOSLEEP);
+	if (fibctx_p == NULL)
 		return (ENOMEM);
 
 	mutex_enter(&softs->aifq_mutex);
 	/* All elements are already 0, add to queue */
-	if (softs->fibctx == NULL) {
-		softs->fibctx = fibctx;
+	if (softs->fibctx_p == NULL) {
+		softs->fibctx_p = fibctx_p;
 	} else {
-		for (ctx = softs->fibctx; ctx->next; ctx = ctx->next)
+		for (ctx_p = softs->fibctx_p; ctx_p->next; ctx_p = ctx_p->next)
 			;
-		ctx->next = fibctx;
-		fibctx->prev = ctx;
+		ctx_p->next = fibctx_p;
+		fibctx_p->prev = ctx_p;
 	}
 
 	/* Evaluate unique value */
-	fibctx->unique = (unsigned long)fibctx & 0xfffffffful;
-	ctx = softs->fibctx;
-	while (ctx != fibctx) {
-		if (ctx->unique == fibctx->unique) {
-			fibctx->unique++;
-			ctx = softs->fibctx;
+	fibctx_p->unique = (unsigned long)fibctx_p & 0xfffffffful;
+	ctx_p = softs->fibctx_p;
+	while (ctx_p != fibctx_p) {
+		if (ctx_p->unique == fibctx_p->unique) {
+			fibctx_p->unique++;
+			ctx_p = softs->fibctx_p;
 		} else {
-			ctx = ctx->next;
+			ctx_p = ctx_p->next;
 		}
 	}
 
 	/* Set ctx_idx to the oldest AIF */
 	if (softs->aifq_wrap) {
-		fibctx->ctx_idx = softs->aifq_idx;
-		fibctx->ctx_filled = 1;
+		fibctx_p->ctx_idx = softs->aifq_idx;
+		fibctx_p->ctx_filled = 1;
 	}
 	mutex_exit(&softs->aifq_mutex);
 
-	if (ddi_copyout(&fibctx->unique, (void *)arg,
+	if (ddi_copyout(&fibctx_p->unique, (void *)arg,
 	    sizeof (uint32_t), mode) != 0)
 		return (EFAULT);
 
@@ -351,30 +355,12 @@
 }
 
 static int
-aac_return_aif(struct aac_softstate *softs,
-    struct aac_fib_context *ctx, caddr_t uptr, int mode)
-{
-	int current;
-
-	current = ctx->ctx_idx;
-	if (current == softs->aifq_idx && !ctx->ctx_filled)
-		return (EAGAIN); /* Empty */
-	if (ddi_copyout(&softs->aifq[current].d, (void *)uptr,
-	    sizeof (struct aac_fib), mode) != 0)
-		return (EFAULT);
-
-	ctx->ctx_filled = 0;
-	ctx->ctx_idx = (current + 1) % AAC_AIFQ_LENGTH;
-
-	return (0);
-}
-
-static int
 aac_next_getadapter_fib(struct aac_softstate *softs, intptr_t arg, int mode)
 {
 	union aac_get_adapter_fib_align un;
 	struct aac_get_adapter_fib *af = &un.d;
-	struct aac_fib_context *ctx;
+	struct aac_fib_context *ctx_p;
+	struct aac_fib *fibp;
 	int rval;
 
 	DBCALLED(softs, 2);
@@ -383,65 +369,58 @@
 		return (EFAULT);
 
 	mutex_enter(&softs->aifq_mutex);
-	for (ctx = softs->fibctx; ctx; ctx = ctx->next) {
-		if (af->context == ctx->unique)
+	for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
+		if (af->context == ctx_p->unique)
 			break;
 	}
-	if (ctx) {
-#ifdef	_LP64
-		rval = aac_return_aif(softs, ctx,
-		    (caddr_t)(uint64_t)af->aif_fib, mode);
-#else
-		rval = aac_return_aif(softs, ctx,
-		    (caddr_t)af->aif_fib, mode);
-#endif
-		if (rval == EAGAIN && af->wait) {
-			AACDB_PRINT(softs, CE_NOTE,
-			    "aac_next_getadapter_fib(): waiting for AIF");
-			rval = cv_wait_sig(&softs->aifv, &softs->aifq_mutex);
-			if (rval > 0) {
-#ifdef	_LP64
-				rval = aac_return_aif(softs, ctx,
-				    (caddr_t)(uint64_t)af->aif_fib, mode);
-#else
-				rval = aac_return_aif(softs, ctx,
-				    (caddr_t)af->aif_fib, mode);
-#endif
-			} else {
-				rval = EINTR;
-			}
-		}
-	} else {
-		rval = EFAULT;
-	}
 	mutex_exit(&softs->aifq_mutex);
 
+	if (ctx_p) {
+		if (af->wait)
+			rval = aac_return_aif_wait(softs, ctx_p, &fibp);
+		else
+			rval = aac_return_aif(softs, ctx_p, &fibp);
+	}
+	else
+		rval = EFAULT;
+
+finish:
+	if (rval == 0) {
+		if (ddi_copyout(fibp,
+#ifdef _LP64
+		    (void *)(uint64_t)af->aif_fib,
+#else
+		    (void *)af->aif_fib,
+#endif
+		    sizeof (struct aac_fib), mode) != 0)
+			rval = EFAULT;
+	}
 	return (rval);
 }
 
 static int
 aac_close_getadapter_fib(struct aac_softstate *softs, intptr_t arg)
 {
-	struct aac_fib_context *ctx;
+	struct aac_fib_context *ctx_p;
 
 	DBCALLED(softs, 2);
 
 	mutex_enter(&softs->aifq_mutex);
-	for (ctx = softs->fibctx; ctx; ctx = ctx->next) {
-		if (ctx->unique != (uint32_t)arg)
+	for (ctx_p = softs->fibctx_p; ctx_p; ctx_p = ctx_p->next) {
+		if (ctx_p->unique != (uint32_t)arg)
 			continue;
 
-		if (ctx == softs->fibctx)
-			softs->fibctx = ctx->next;
+		if (ctx_p == softs->fibctx_p)
+			softs->fibctx_p = ctx_p->next;
 		else
-			ctx->prev->next = ctx->next;
-		if (ctx->next)
-			ctx->next->prev = ctx->prev;
+			ctx_p->prev->next = ctx_p->next;
+		if (ctx_p->next)
+			ctx_p->next->prev = ctx_p->prev;
 		break;
 	}
 	mutex_exit(&softs->aifq_mutex);
-	if (ctx)
-		kmem_free(ctx, sizeof (struct aac_fib_context));
+	if (ctx_p)
+		kmem_free(ctx_p, sizeof (struct aac_fib_context));
 
 	return (0);
 }
--- a/usr/src/uts/common/io/warlock/aac.wlcmd	Sat Mar 20 13:03:54 2010 -0700
+++ b/usr/src/uts/common/io/warlock/aac.wlcmd	Sun Mar 21 12:30:24 2010 +0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 one aac_softstate
@@ -45,7 +45,7 @@
 	aac_cmd_fib_scsi32 \
 	aac_cmd_fib_scsi64
 
-root aac_intr_old aac_intr_new aac_fm_error_cb aac_handle_dr aac_name_node aac_quiesce
+root aac_intr_old aac_intr_new aac_fm_error_cb aac_name_node aac_quiesce
 
 add scsi_pkt::pkt_comp target \
 	aac_tran_destroy_pkt \