kern/149968: Kernel panic with ZFS and twa version 3.80.06.002

Tom Couch tom.couch at lsi.com
Wed Aug 25 18:30:08 UTC 2010


>Number:         149968
>Category:       kern
>Synopsis:       Kernel panic with ZFS and twa version 3.80.06.002
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Aug 25 18:30:06 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     Tom Couch
>Release:        8.1-RELEASE-amd64-all
>Organization:
LSI Corporation
>Environment:
FreeBSD MacSolaris4 8.1-RELEASE FreeBSD 8.1-RELEASE #14: Thu Jul 29 17:28:47 PDT 2010     tcouch at MacSolaris4:/usr/obj/usr/src/sys/MACSOLARIS4  amd64
>Description:
Kernel panic on ZFS using twa driver 3.80.06.002 under heavy IO.
>How-To-Repeat:
  Create a unit (single drive is OK) with the CLI tool:
  % tw_cli /c0 add type=single drive=3

  Create a zpool on the unit:
  % zpool create my_zpool /dev/da0

  Trigger the kernel panic:
  % dd if=/dev/urandom of=/my_zpool/testfile bs=1M count=3000; sync

  Kernel panic happens at this point.
  The system may need a hard reboot to recover.
>Fix:
For FreeBSD HEAD, use twa driver version 3.80.06.003
For FreeBSD 8.x,  use twa driver version 3.80.06.003
For FreeBSD 7.x,  use twa driver version 3.70.05.010
                -OR-
Apply the attached driver patch.

Patch attached with submission follows:

diff -u FreeBSD_HEAD_twa_cvs/tw_cl.h FreeBSD_HEAD_twa_3_80_06_003/tw_cl.h
--- FreeBSD_HEAD_twa_cvs/tw_cl.h	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_cl.h	2010-08-24 18:02:12.000000000 -0700
@@ -88,7 +88,8 @@
 #define TW_CLI_BUSY_Q		1	/* q of reqs submitted to fw */
 #define TW_CLI_PENDING_Q	2	/* q of reqs deferred due to 'q full' */
 #define TW_CLI_COMPLETE_Q	3	/* q of reqs completed by fw */
-#define TW_CLI_Q_COUNT		4	/* total number of queues */
+#define TW_CLI_RESET_Q		4	/* q of reqs reset by timeout */
+#define TW_CLI_Q_COUNT		5	/* total number of queues */
 
 
 /* CL's internal request context. */
@@ -133,6 +134,7 @@
 	TW_UINT8 		interrupts_enabled;	  /* Interrupts on controller enabled. */
 	TW_UINT8 		internal_req_busy;	  /* Data buffer for internal requests in use. */
 	TW_UINT8 		get_more_aens;		  /* More AEN's need to be retrieved. */
+	TW_UINT8 		reset_needed;		  /* Controller needs a soft reset. */
 	TW_UINT8 		reset_in_progress;	  /* Controller is being reset. */
 	TW_UINT8 		reset_phase1_in_progress; /* In 'phase 1' of reset. */
 	TW_UINT32		flags;		/* controller settings */
diff -u FreeBSD_HEAD_twa_cvs/tw_cl_externs.h FreeBSD_HEAD_twa_3_80_06_003/tw_cl_externs.h
--- FreeBSD_HEAD_twa_cvs/tw_cl_externs.h	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_cl_externs.h	2010-08-24 18:02:12.000000000 -0700
@@ -86,6 +86,8 @@
 
 /* Soft reset the controller. */
 extern TW_INT32	tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr);
+extern int twa_setup_intr(struct twa_softc *sc);
+extern int twa_teardown_intr(struct twa_softc *sc);
 
 /* Send down a SCSI command to the firmware (usually, an internal Req Sense. */
 extern TW_INT32	tw_cli_send_scsi_cmd(struct tw_cli_req_context *req,
diff -u FreeBSD_HEAD_twa_cvs/tw_cl_fwif.h FreeBSD_HEAD_twa_3_80_06_003/tw_cl_fwif.h
--- FreeBSD_HEAD_twa_cvs/tw_cl_fwif.h	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_cl_fwif.h	2010-08-24 18:02:12.000000000 -0700
@@ -89,7 +89,7 @@
 #define TWA_STATUS_MINOR_VERSION_MASK		0x0F000000
 #define TWA_STATUS_MAJOR_VERSION_MASK		0xF0000000
 
-#define TWA_STATUS_UNEXPECTED_BITS		0x00F00000
+#define TWA_STATUS_UNEXPECTED_BITS		0x00D00000
 
 
 /* PCI related defines. */
diff -u FreeBSD_HEAD_twa_cvs/tw_cl_init.c FreeBSD_HEAD_twa_3_80_06_003/tw_cl_init.c
--- FreeBSD_HEAD_twa_cvs/tw_cl_init.c	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_cl_init.c	2010-08-24 18:02:12.000000000 -0700
@@ -315,6 +315,7 @@
 	tw_cli_req_q_init(ctlr, TW_CLI_BUSY_Q);
 	tw_cli_req_q_init(ctlr, TW_CLI_PENDING_Q);
 	tw_cli_req_q_init(ctlr, TW_CLI_COMPLETE_Q);
+	tw_cli_req_q_init(ctlr, TW_CLI_RESET_Q);
 
 	/* Initialize all locks used by CL. */
 	ctlr->gen_lock = &(ctlr->gen_lock_handle);
@@ -675,15 +676,14 @@
 	/* Submit the command, and wait for it to complete. */
 	error = tw_cli_submit_and_poll_request(req,
 		TW_CLI_REQUEST_TIMEOUT_PERIOD);
-	if (error == TW_OSL_ETIMEDOUT)
-		/* Clean-up done by tw_cli_submit_and_poll_request. */
-		return(error);
 	if (error)
 		goto out;
 	if ((error = init_connect->status)) {
+#if       0
 		tw_cli_create_ctlr_event(ctlr,
 			TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
 			&(req->cmd_pkt->cmd_hdr));
+#endif // 0
 		goto out;
 	}
 	if (set_features & TWA_EXTENDED_INIT_CONNECT) {
diff -u FreeBSD_HEAD_twa_cvs/tw_cl_intr.c FreeBSD_HEAD_twa_3_80_06_003/tw_cl_intr.c
--- FreeBSD_HEAD_twa_cvs/tw_cl_intr.c	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_cl_intr.c	2010-08-24 18:02:12.000000000 -0700
@@ -248,8 +248,7 @@
 #ifdef TW_OSL_DEBUG
 			tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
 #endif /* TW_OSL_DEBUG */
-			tw_cl_reset_ctlr(ctlr->ctlr_handle);
-			return(TW_OSL_EIO);
+			continue;
 		}
 
 		/*
@@ -402,9 +401,7 @@
 #ifdef TW_OSL_DEBUG
 		tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
 #endif /* TW_OSL_DEBUG */
-		tw_cl_reset_ctlr(ctlr->ctlr_handle);
-		req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
-		goto out;
+		return;
 	}
 
 	if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
@@ -483,6 +480,7 @@
 			cdb[8], cdb[9], cdb[10], cdb[11],
 			cdb[12], cdb[13], cdb[14], cdb[15]);
 
+#if       0
 		/* 
 		 * Print the error. Firmware doesn't yet support
 		 * the 'Mode Sense' cmd.  Don't print if the cmd
@@ -493,6 +491,7 @@
 			tw_cli_create_ctlr_event(req->ctlr,
 				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
 				cmd_hdr);
+#endif // 0
 	}
 
 	if (scsi_req->sense_data) {
@@ -530,9 +529,11 @@
 	 */
 	if (! req->error_code)
 		if (cmd->param.status) {
+#if       0
 			tw_cli_create_ctlr_event(ctlr,
 				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
 				&(req->cmd_pkt->cmd_hdr));
+#endif // 0
 			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
 				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
 				0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING,
@@ -590,9 +591,11 @@
 		if ((error = cmd->status)) {
 			cmd_hdr = (struct tw_cl_command_header *)
 				(&(req->cmd_pkt->cmd_hdr));
+#if       0
 			tw_cli_create_ctlr_event(ctlr,
 				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
 				cmd_hdr);
+#endif // 0
 			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
 				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
 				0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING,
diff -u FreeBSD_HEAD_twa_cvs/tw_cl_io.c FreeBSD_HEAD_twa_3_80_06_003/tw_cl_io.c
--- FreeBSD_HEAD_twa_cvs/tw_cl_io.c	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_cl_io.c	2010-08-24 18:02:12.000000000 -0700
@@ -74,18 +74,12 @@
 	struct tw_cli_req_context		*req;
 	struct tw_cl_command_9k			*cmd;
 	struct tw_cl_scsi_req_packet		*scsi_req;
-	TW_INT32				error;
+	TW_INT32				error = TW_CL_ERR_REQ_SUCCESS;
 
 	tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
 
 	ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
 
-	if (ctlr->reset_in_progress) {
-		tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
-			"I/O during reset: returning busy.");
-		return(TW_OSL_EBUSY);
-	}
-
 	/*
 	 * If working with a firmware version that does not support multiple
 	 * luns, and this request is directed at a non-zero lun, error it
@@ -145,7 +139,12 @@
 			cmd->sg_list, scsi_req->sgl_entries);
 	}
 
-	if ((error = tw_cli_submit_cmd(req))) {
+	if (((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) ||
+		(ctlr->reset_in_progress)) {
+		tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q);
+		TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
+			TWA_CONTROL_UNMASK_COMMAND_INTERRUPT);
+	} else if ((error = tw_cli_submit_cmd(req))) {
 		tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
 			"Could not start request. request = %p, error = %d",
 			req, error);
@@ -171,7 +170,7 @@
 	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
 	struct tw_cl_ctlr_handle	*ctlr_handle = ctlr->ctlr_handle;
 	TW_UINT32			status_reg;
-	TW_INT32			error;
+	TW_INT32			error = 0;
 
 	tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
 
@@ -185,11 +184,7 @@
 				 TWA_COMMAND_QUEUE_OFFSET_LOW,
 				 (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4);
 
-	/* Check to see if we can post a command. */
 	status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
-	if ((error = tw_cli_check_ctlr_state(ctlr, status_reg)))
-		goto out;
-
 	if (status_reg & TWA_STATUS_COMMAND_QUEUE_FULL) {
 		struct tw_cl_req_packet	*req_pkt =
 			(struct tw_cl_req_packet *)(req->orig_req);
@@ -207,14 +202,12 @@
 					"pending internal/ioctl request");
 				req->state = TW_CLI_REQ_STATE_PENDING;
 				tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q);
-				error = 0;
 				/* Unmask command interrupt. */
 				TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
 					TWA_CONTROL_UNMASK_COMMAND_INTERRUPT);
 			} else
 				error = TW_OSL_EBUSY;
 		} else {
-			tw_osl_ctlr_busy(ctlr_handle, req->req_handle);
 			error = TW_OSL_EBUSY;
 		}
 	} else {
@@ -246,7 +239,7 @@
 						 (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4);
 		}
 	}
-out:
+
 	tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
 
 	return(error);
@@ -277,18 +270,12 @@
 	TW_UINT8				opcode;
 	TW_UINT8				sgl_offset;
 	TW_VOID					*sgl = TW_CL_NULL;
-	TW_INT32				error;
+	TW_INT32				error = TW_CL_ERR_REQ_SUCCESS;
 
 	tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered");
 
 	ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
 
-	if (ctlr->reset_in_progress) {
-		tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
-			"Passthru request during reset: returning busy.");
-		return(TW_OSL_EBUSY);
-	}
-
 	if ((req = tw_cli_get_request(ctlr
 		)) == TW_CL_NULL) {
 		tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
@@ -301,7 +288,7 @@
 	req->orig_req = req_pkt;
 	req->tw_cli_callback = tw_cli_complete_io;
 
-	req->flags |= (TW_CLI_REQ_FLAGS_EXTERNAL | TW_CLI_REQ_FLAGS_PASSTHRU);
+	req->flags |= TW_CLI_REQ_FLAGS_PASSTHRU;
 
 	pt_req = &(req_pkt->gen_req_pkt.pt_req);
 
@@ -348,7 +335,12 @@
 		tw_cli_fill_sg_list(ctlr, pt_req->sg_list,
 			sgl, pt_req->sgl_entries);
 
-	if ((error = tw_cli_submit_cmd(req))) {
+	if (((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) ||
+		(ctlr->reset_in_progress)) {
+		tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q);
+		TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
+			TWA_CONTROL_UNMASK_COMMAND_INTERRUPT);
+	} else if ((error = tw_cli_submit_cmd(req))) {
 		tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
 			0x1100, 0x1, TW_CL_SEVERITY_ERROR_STRING,
@@ -760,8 +752,7 @@
 
 	cmd->param.sgl_off__opcode =
 		BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_GET_PARAM);
-	cmd->param.request_id =
-		(TW_UINT8)(TW_CL_SWAP16(req->request_id));
+	cmd->param.request_id = (TW_UINT8)(TW_CL_SWAP16(req->request_id));
 	cmd->param.host_id__unit = BUILD_HOST_ID__UNIT(0, 0);
 	cmd->param.param_count = TW_CL_SWAP16(1);
 
@@ -789,15 +780,14 @@
 		/* There's no call back; wait till the command completes. */
 		error = tw_cli_submit_and_poll_request(req,
 				TW_CLI_REQUEST_TIMEOUT_PERIOD);
-		if (error == TW_OSL_ETIMEDOUT)
-			/* Clean-up done by tw_cli_submit_and_poll_request. */
-			return(error);
 		if (error)
 			goto out;
 		if ((error = cmd->param.status)) {
+#if       0
 			tw_cli_create_ctlr_event(ctlr,
 				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
 				&(req->cmd_pkt->cmd_hdr));
+#endif // 0
 			goto out;
 		}
 		tw_osl_memcpy(param_data, param->data, param_size);
@@ -905,18 +895,17 @@
 
 	/* Submit the command. */
 	if (callback == TW_CL_NULL) {
-		/* There's no call back;  wait till the command completes. */
+		/* There's no call back; wait till the command completes. */
 		error = tw_cli_submit_and_poll_request(req,
-			TW_CLI_REQUEST_TIMEOUT_PERIOD);
-		if (error == TW_OSL_ETIMEDOUT)
-			/* Clean-up done by tw_cli_submit_and_poll_request. */
-			return(error);
+				TW_CLI_REQUEST_TIMEOUT_PERIOD);
 		if (error)
 			goto out;
 		if ((error = cmd->param.status)) {
+#if       0
 			tw_cli_create_ctlr_event(ctlr,
 				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
 				&(req->cmd_pkt->cmd_hdr));
+#endif // 0
 			goto out;
 		}
 		ctlr->internal_req_busy = TW_CL_FALSE;
@@ -1022,9 +1011,7 @@
 	 * tw_cli_submit_pending_queue.  There could be a race in that case.
 	 * Need to revisit.
 	 */
-	if (req->state != TW_CLI_REQ_STATE_PENDING)
-		tw_cl_reset_ctlr(ctlr->ctlr_handle);
-	else {
+	if (req->state == TW_CLI_REQ_STATE_PENDING) {
 		tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(),
 			"Removing request from pending queue");
 		/*
@@ -1053,6 +1040,7 @@
  *			drains any incomplete requests.
  *
  * Input:		ctlr	-- ptr to per ctlr structure
+ * 			req_handle	-- ptr to request handle
  * Output:		None
  * Return value:	0	-- success
  *			non-zero-- failure
@@ -1063,15 +1051,15 @@
 	struct tw_cli_ctlr_context	*ctlr =
 		(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
 	struct twa_softc		*sc = ctlr_handle->osl_ctlr_ctxt;
+	struct tw_cli_req_context	*req;
 	TW_INT32			reset_attempt = 1;
-	TW_INT32			error;
+	TW_INT32			error = 0;
 
 	tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "entered");
 
 	ctlr->reset_in_progress = TW_CL_TRUE;
-	xpt_freeze_simq(sc->sim, 1);
+	twa_teardown_intr(sc);
 
-	tw_cli_disable_interrupts(ctlr);
 
 	/*
 	 * Error back all requests in the complete, busy, and pending queues.
@@ -1080,8 +1068,6 @@
 	 * will continue its course and get submitted to the controller after
 	 * the reset is done (and io_lock is released).
 	 */
-	tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(),
-		"Draining all queues following reset");
 	tw_cli_drain_complete_queue(ctlr);
 	tw_cli_drain_busy_queue(ctlr);
 	tw_cli_drain_pending_queue(ctlr);
@@ -1089,53 +1075,88 @@
 	ctlr->get_more_aens     = TW_CL_FALSE;
 
 	/* Soft reset the controller. */
-try_reset:
-	if ((error = tw_cli_soft_reset(ctlr))) {
-		tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
-			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
-			0x1105, 0x1, TW_CL_SEVERITY_ERROR_STRING,
-			"Controller reset failed",
-			"error = %d; attempt %d", error, reset_attempt++);
-		if (reset_attempt <= TW_CLI_MAX_RESET_ATTEMPTS)
-			goto try_reset;
-		else
-			goto out;
-	}
+	while (reset_attempt <= TW_CLI_MAX_RESET_ATTEMPTS) {
+		if ((error = tw_cli_soft_reset(ctlr))) {
+			tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
+				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
+				0x1105, 0x1, TW_CL_SEVERITY_ERROR_STRING,
+				"Controller reset failed",
+				"error = %d; attempt %d", error, reset_attempt++);
+			reset_attempt++;
+			continue;
+		}
 
-	/* Re-establish logical connection with the controller. */
-	if ((error = tw_cli_init_connection(ctlr,
-			(TW_UINT16)(ctlr->max_simult_reqs),
-			0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL,
-			TW_CL_NULL, TW_CL_NULL))) {
-		tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+		/* Re-establish logical connection with the controller. */
+		if ((error = tw_cli_init_connection(ctlr,
+				(TW_UINT16)(ctlr->max_simult_reqs),
+				0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL,
+				TW_CL_NULL, TW_CL_NULL))) {
+			tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
+				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
+				0x1106, 0x1, TW_CL_SEVERITY_ERROR_STRING,
+				"Can't initialize connection after reset",
+				"error = %d", error);
+			reset_attempt++;
+			continue;
+		}
+
+#ifdef    TW_OSL_DEBUG
+		tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
-			0x1106, 0x1, TW_CL_SEVERITY_ERROR_STRING,
-			"Can't initialize connection after reset",
-			"error = %d", error);
-		goto out;
-	}
+			0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING,
+			"Controller reset done!", " ");
+#endif /* TW_OSL_DEBUG */
+		break;
+	} /* End of while */
 
-	tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
-		TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
-		0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING,
-		"Controller reset done!",
-		" ");
+	/* Move commands from the reset queue to the pending queue. */
+	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_RESET_Q)) != TW_CL_NULL) {
+		tw_osl_timeout(req->req_handle);
+		tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q);
+	}
 
-out:
+	twa_setup_intr(sc);
+	tw_cli_enable_interrupts(ctlr);
+	if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL)
+		TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
+			TWA_CONTROL_UNMASK_COMMAND_INTERRUPT);
 	ctlr->reset_in_progress = TW_CL_FALSE;
-	xpt_release_simq(sc->sim, 1);
+	ctlr->reset_needed = TW_CL_FALSE;
 
-	/*
-	 * Enable interrupts, and also clear attention and response interrupts.
-	 */
-	tw_cli_enable_interrupts(ctlr);
-	
 	/* Request for a bus re-scan. */
-	if (!error)
-		tw_osl_scan_bus(ctlr_handle);
+	tw_osl_scan_bus(ctlr_handle);
+
 	return(error);
 }
 
+TW_VOID
+tw_cl_set_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle)
+{
+	struct tw_cli_ctlr_context	*ctlr =
+		(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
+
+	ctlr->reset_needed = TW_CL_TRUE;
+}
+
+TW_INT32
+tw_cl_is_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle)
+{
+	struct tw_cli_ctlr_context	*ctlr =
+		(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
+
+	return(ctlr->reset_needed);
+}
+
+TW_INT32
+tw_cl_is_active(struct tw_cl_ctlr_handle *ctlr_handle)
+{
+	struct tw_cli_ctlr_context	*ctlr =
+		(struct tw_cli_ctlr_context *)
+		(ctlr_handle->cl_ctlr_ctxt);
+
+		return(ctlr->active);
+}
+
 
 
 /*
@@ -1151,14 +1172,13 @@
 tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr)
 {
 	struct tw_cl_ctlr_handle	*ctlr_handle = ctlr->ctlr_handle;
-	TW_UINT32			status_reg;
 	int				found;
 	int				loop_count;
 	TW_UINT32			error;
 
 	tw_cli_dbg_printf(1, ctlr_handle, tw_osl_cur_func(), "entered");
 
-	tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+	tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 		TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
 		0x1108, 0x3, TW_CL_SEVERITY_INFO_STRING,
 		"Resetting controller...",
@@ -1193,7 +1213,7 @@
 		} while (!found && (loop_count < 6000000)); /* Loop for no more than 60 seconds */
 
 		if (!found) {
-			tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+			tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
 				0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING,
 				"Missed firmware handshake after soft-reset",
@@ -1210,7 +1230,7 @@
 			TWA_STATUS_MICROCONTROLLER_READY |
 			TWA_STATUS_ATTENTION_INTERRUPT,
 			TW_CLI_RESET_TIMEOUT_PERIOD))) {
-		tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+		tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
 			0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING,
 			"Micro-ctlr not ready/No attn intr after reset",
@@ -1244,26 +1264,14 @@
 	}
 	
 	if ((error = tw_cli_find_aen(ctlr, TWA_AEN_SOFT_RESET))) {
-		tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+		tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
 			0x110C, 0x1, TW_CL_SEVERITY_ERROR_STRING,
 			"Reset not reported by controller",
 			"error = %d", error);
 		return(error);
 	}
-	
-	status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
-	
-	if ((error = TW_CLI_STATUS_ERRORS(status_reg)) ||
-			(error = tw_cli_check_ctlr_state(ctlr, status_reg))) {
-		tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
-			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
-			0x110D, 0x1, TW_CL_SEVERITY_ERROR_STRING,
-			"Controller errors detected after reset",
-			"error = %d", error);
-		return(error);
-	}
-	
+
 	return(TW_OSL_ESUCCESS);
 }
 
diff -u FreeBSD_HEAD_twa_cvs/tw_cl_misc.c FreeBSD_HEAD_twa_3_80_06_003/tw_cl_misc.c
--- FreeBSD_HEAD_twa_cvs/tw_cl_misc.c	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_cl_misc.c	2010-08-24 18:02:12.000000000 -0700
@@ -83,7 +83,8 @@
 	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
 
 	/* Walk the busy queue. */
-	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q))) {
+	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) !=
+		TW_CL_NULL) {
 		if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
 			/*
 			 * It's an internal request.  Set the appropriate
@@ -97,20 +98,21 @@
 			req->error_code = TW_CL_ERR_REQ_BUS_RESET;
 			if (req->tw_cli_callback)
 				req->tw_cli_callback(req);
-		} else {
-			if ((req_pkt = req->orig_req)) {
-				/* It's a SCSI request.  Complete it. */
-				tw_cli_dbg_printf(2, ctlr->ctlr_handle,
-					tw_osl_cur_func(),
-					"Completing complete request %p "
-					"on reset",
-					req);
+		} else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
+			/* It's a passthru request.  Complete it. */
+			if ((req_pkt = req->orig_req) != TW_CL_NULL) {
 				req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
-				req_pkt->tw_osl_callback(req->req_handle);
+
+				if (req_pkt->tw_osl_callback)
+					req_pkt->tw_osl_callback(req->req_handle);
 			}
 			tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
+		} else {
+			/* It's an external (SCSI) request.  Add it to the reset queue. */
+			tw_osl_untimeout(req->req_handle);
+			tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q);
 		}
-	}
+	} /* End of while loop */
 }
 
 
@@ -135,7 +137,8 @@
 	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
 
 	/* Walk the busy queue. */
-	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_BUSY_Q))) {
+	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_BUSY_Q)) !=
+		TW_CL_NULL) {
 		if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
 			/*
 			 * It's an internal request.  Set the appropriate
@@ -149,19 +152,21 @@
 			req->error_code = TW_CL_ERR_REQ_BUS_RESET;
 			if (req->tw_cli_callback)
 				req->tw_cli_callback(req);
-		} else {
-			if ((req_pkt = req->orig_req)) {
-				/* It's a SCSI request.  Complete it. */
-				tw_cli_dbg_printf(2, ctlr->ctlr_handle,
-					tw_osl_cur_func(),
-					"Completing busy request %p on reset",
-					req);
+		} else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
+			/* It's a passthru request.  Complete it. */
+			if ((req_pkt = req->orig_req) != TW_CL_NULL) {
 				req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
-				req_pkt->tw_osl_callback(req->req_handle);
+
+				if (req_pkt->tw_osl_callback)
+					req_pkt->tw_osl_callback(req->req_handle);
 			}
 			tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
+		} else {
+			/* It's an external (SCSI) request.  Add it to the reset queue. */
+			tw_osl_untimeout(req->req_handle);
+			tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q);
 		}
-	}
+	} /* End of while loop */
 }
 
 
@@ -188,7 +193,8 @@
 	/*
 	 * Pull requests off the pending queue, and complete them.
 	 */
-	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q))) {
+	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) !=
+		TW_CL_NULL) {
 		if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
 			/*
 			 * It's an internal request.  Set the appropriate
@@ -202,19 +208,21 @@
 			req->error_code = TW_CL_ERR_REQ_BUS_RESET;
 			if (req->tw_cli_callback)
 				req->tw_cli_callback(req);
-		} else {
-			if ((req_pkt = req->orig_req)) {
-				/* It's an external request.  Complete it. */
-				tw_cli_dbg_printf(2, ctlr->ctlr_handle,
-					tw_osl_cur_func(),
-					"Completing pending request %p "
-					"on reset", req);
+		} else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
+			/* It's a passthru request.  Complete it. */
+			if ((req_pkt = req->orig_req) != TW_CL_NULL) {
 				req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
-				req_pkt->tw_osl_callback(req->req_handle);
+
+				if (req_pkt->tw_osl_callback)
+					req_pkt->tw_osl_callback(req->req_handle);
 			}
 			tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
+		} else {
+			/* It's an external (SCSI) request.  Add it to the reset queue. */
+			tw_osl_untimeout(req->req_handle);
+			tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q);
 		}
-	}
+	} /* End of while loop */
 }
 
 
@@ -239,9 +247,6 @@
 	for (;;) {
 		status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
 
-		if (tw_cli_check_ctlr_state(ctlr, status_reg))
-			return(TW_OSL_EGENFAILURE);
-
 		if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
 			return(TW_OSL_ESUCCESS); /* no more response queue entries */
 
@@ -273,9 +278,6 @@
 	for (;;) {
 		status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
 
-		if (tw_cli_check_ctlr_state(ctlr, status_reg))
-			return(TW_OSL_EGENFAILURE);
-
 		if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
 			return(TW_OSL_ENOTTY); /* no more response queue entries */
 
@@ -356,9 +358,11 @@
 
 		if ((error = req->cmd_pkt->command.cmd_pkt_9k.status)) {
 			cmd_hdr = &req->cmd_pkt->cmd_hdr;
+#if       0
 			tw_cli_create_ctlr_event(ctlr,
 				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
 				cmd_hdr);
+#endif // 0
 			break;
 		}
 
@@ -714,7 +718,7 @@
 
 		tw_osl_memzero(desc, 200);
 		if (!(ctlr->reset_phase1_in_progress)) {
-			tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+			tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
 				0x1301, 0x1, TW_CL_SEVERITY_ERROR_STRING,
 				"Missing expected status bit(s)",
@@ -738,7 +742,7 @@
 		     (ctlr->device_id != TW_CL_DEVICE_ID_9K_SA)) ||
 		    (!(ctlr->reset_in_progress)) ||
 		    ((status_reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT) == 0))
-		tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+		tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
 			0x1302, 0x1, TW_CL_SEVERITY_ERROR_STRING,
 			"Unexpected status bit(s)",
@@ -748,7 +752,7 @@
 				TWA_STATUS_UNEXPECTED_BITS, desc));
 
 		if (status_reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT) {
-			tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+			tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
 				0x1303, 0x1, TW_CL_SEVERITY_ERROR_STRING,
 				"PCI parity error: clearing... "
@@ -768,7 +772,7 @@
 		}
 
 		if (status_reg & TWA_STATUS_PCI_ABORT_INTERRUPT) {
-			tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+			tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
 				0x1304, 0x1, TW_CL_SEVERITY_ERROR_STRING,
 				"PCI abort: clearing... ",
@@ -791,7 +795,7 @@
 			if (((ctlr->device_id != TW_CL_DEVICE_ID_9K_E) &&
 			     (ctlr->device_id != TW_CL_DEVICE_ID_9K_SA)) ||
 			    (!(ctlr->reset_in_progress)))
-				tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
+				tw_cl_create_event(ctlr_handle, TW_CL_FALSE,
 						   TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
 						   0x1305, 0x1, TW_CL_SEVERITY_ERROR_STRING,
 						   "Controller queue error: clearing... ",
@@ -801,17 +805,6 @@
 			TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
 				TWA_CONTROL_CLEAR_QUEUE_ERROR);
 		}
-
-		if (status_reg & TWA_STATUS_MICROCONTROLLER_ERROR) {
-			tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
-				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
-				0x1307, 0x1, TW_CL_SEVERITY_ERROR_STRING,
-				"Micro-controller error! ",
-				"status reg = 0x%x %s",
-				status_reg,
-				tw_cli_describe_bits(status_reg, desc));
-			error = TW_OSL_EGENFAILURE;
-		}
 	}
 	return(error);
 }	
@@ -850,8 +843,6 @@
 		tw_osl_strcpy(&str[tw_osl_strlen(str)], "HOST_INTR,");
 	if (reg & TWA_STATUS_PCI_ABORT_INTERRUPT)
 		tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_ABRT,");
-	if (reg & TWA_STATUS_MICROCONTROLLER_ERROR)
-		tw_osl_strcpy(&str[tw_osl_strlen(str)], "MC_ERR,");
 	if (reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT)
 		tw_osl_strcpy(&str[tw_osl_strlen(str)], "Q_ERR,");
 	if (reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT)
diff -u FreeBSD_HEAD_twa_cvs/tw_cl_share.h FreeBSD_HEAD_twa_3_80_06_003/tw_cl_share.h
--- FreeBSD_HEAD_twa_cvs/tw_cl_share.h	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_cl_share.h	2010-08-24 18:02:12.000000000 -0700
@@ -349,10 +349,14 @@
 #endif
 
 
-#ifndef tw_osl_ctlr_busy
-/* Called when CL is too busy to accept new requests. */
-extern TW_VOID	tw_osl_ctlr_busy(struct tw_cl_ctlr_handle *ctlr_handle,
-	struct tw_cl_req_handle *req_handle);
+#ifndef tw_osl_timeout
+/* Start OS timeout() routine after controller reset sequence */
+extern TW_VOID	tw_osl_timeout(struct tw_cl_req_handle *req_handle);
+#endif
+
+#ifndef tw_osl_untimeout
+/* Stop OS timeout() routine during controller reset sequence */
+extern TW_VOID	tw_osl_untimeout(struct tw_cl_req_handle *req_handle);
 #endif
 
 
@@ -552,6 +556,10 @@
 	);
 
 
+extern TW_VOID  tw_cl_set_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle);
+extern TW_INT32 tw_cl_is_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle);
+extern TW_INT32 tw_cl_is_active(struct tw_cl_ctlr_handle *ctlr_handle);
+
 /* CL's interrupt handler. */
 extern TW_INT32	tw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle);
 
diff -u FreeBSD_HEAD_twa_cvs/tw_osl.h FreeBSD_HEAD_twa_3_80_06_003/tw_osl.h
--- FreeBSD_HEAD_twa_cvs/tw_osl.h	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_osl.h	2010-08-24 18:02:12.000000000 -0700
@@ -77,6 +77,7 @@
 						EINPROGRESS */
 #define TW_OSLI_REQ_FLAGS_PASSTHRU	(1<<5)	/* pass through request */
 #define TW_OSLI_REQ_FLAGS_SLEEPING	(1<<6)	/* owner sleeping on this cmd */
+#define TW_OSLI_REQ_FLAGS_FAILED	(1<<7)	/* bus_dmamap_load() failed */
 
 
 #ifdef TW_OSL_DEBUG
@@ -100,6 +101,7 @@
 	struct twa_softc	*ctlr;	/* ptr to OSL's controller context */
 	TW_VOID			*data;	/* ptr to data being passed to CL */
 	TW_UINT32		length;	/* length of buf being passed to CL */
+	TW_UINT64		deadline;/* request timeout (in absolute time) */
 
 	/*
 	 * ptr to, and length of data passed to us from above, in case a buffer
@@ -151,6 +153,9 @@
 	struct mtx		sim_lock_handle;/* sim lock shared with cam */
 	struct mtx		*sim_lock;/* ptr to sim lock */
 
+	struct callout		watchdog_callout[2]; /* For command timout */
+	TW_UINT32		watchdog_index;
+
 #ifdef TW_OSL_DEBUG
 	struct tw_osli_q_stats	q_stats[TW_OSLI_Q_COUNT];/* queue statistics */
 #endif /* TW_OSL_DEBUG */
diff -u FreeBSD_HEAD_twa_cvs/tw_osl_cam.c FreeBSD_HEAD_twa_3_80_06_003/tw_osl_cam.c
--- FreeBSD_HEAD_twa_cvs/tw_osl_cam.c	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_osl_cam.c	2010-08-24 18:02:12.000000000 -0700
@@ -55,7 +55,6 @@
 
 static TW_VOID	twa_action(struct cam_sim *sim, union ccb *ccb);
 static TW_VOID	twa_poll(struct cam_sim *sim);
-static TW_VOID	twa_timeout(TW_VOID *arg);
 
 static TW_INT32	tw_osli_execute_scsi(struct tw_osli_req_context *req,
 	union ccb *ccb);
@@ -81,7 +80,7 @@
 	/*
 	 * Create the device queue for our SIM.
 	 */
-	if ((devq = cam_simq_alloc(TW_OSLI_MAX_NUM_REQUESTS)) == NULL) {
+	if ((devq = cam_simq_alloc(TW_OSLI_MAX_NUM_IOS)) == NULL) {
 		tw_osli_printf(sc, "error = %d",
 			TW_CL_SEVERITY_ERROR_STRING,
 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
@@ -275,6 +274,7 @@
 					"I/O size too big",
 					csio->dxfer_len);
 				ccb_h->status = CAM_REQ_TOO_BIG;
+				ccb_h->status &= ~CAM_SIM_QUEUED;
 				xpt_done(ccb);
 				return(1);
 			}
@@ -290,6 +290,7 @@
 				0x2107,
 				"XPT_SCSI_IO: Got SGList");
 			ccb_h->status = CAM_REQ_INVALID;
+			ccb_h->status &= ~CAM_SIM_QUEUED;
 			xpt_done(ccb);
 			return(1);
 		}
@@ -306,13 +307,20 @@
 		return(1);
 	}
 
-	ccb_h->timeout_ch = timeout(twa_timeout, req,
-		(ccb_h->timeout * hz) / 1000);
+	req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000);
+
+
 	/*
 	 * twa_map_load_data_callback will fill in the SGL,
 	 * and submit the I/O.
 	 */
 	error = tw_osli_map_request(req);
+	if ((error) && (req->flags & TW_OSLI_REQ_FLAGS_FAILED)) {
+		req->deadline = 0;
+		ccb_h->status = CAM_REQ_CMP_ERR;
+		ccb_h->status &= ~CAM_SIM_QUEUED;
+		xpt_done(ccb);
+	}
 	return(error);
 }
 
@@ -345,10 +353,20 @@
 			 * Freeze the simq to maintain ccb ordering.  The next
 			 * ccb that gets completed will unfreeze the simq.
 			 */
+			ccb_h->status &= ~CAM_SIM_QUEUED;
+			ccb_h->status |= CAM_REQUEUE_REQ;
+			xpt_done(ccb);
+			break;
+		}
+
+		if ((tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) {
+			ccb_h->status &= ~CAM_SIM_QUEUED;
 			ccb_h->status |= CAM_REQUEUE_REQ;
 			xpt_done(ccb);
+			tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
 			break;
 		}
+
 		req->req_handle.osl_req_ctxt = req;
 		req->req_handle.is_io = TW_CL_TRUE;
 		req->orig_req = ccb;
@@ -364,25 +382,14 @@
 		break;
 
 	case XPT_RESET_BUS:
-		tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE,
+		tw_cl_create_event(&(sc->ctlr_handle), TW_CL_FALSE,
 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
 			0x2108, 0x3, TW_CL_SEVERITY_INFO_STRING,
 			"Received Reset Bus request from CAM",
 			" ");
 
-		mtx_unlock(sc->sim_lock);
-		if (tw_cl_reset_ctlr(&sc->ctlr_handle)) {
-			tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE,
-				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
-				0x2109, 0x1, TW_CL_SEVERITY_ERROR_STRING,
-				"Failed to reset bus",
-				" ");
-			ccb_h->status = CAM_REQ_CMP_ERR;
-		}
-		else
-			ccb_h->status = CAM_REQ_CMP;
-
-		mtx_lock(sc->sim_lock);
+		tw_cl_set_reset_needed(&(sc->ctlr_handle));
+		ccb_h->status = CAM_REQ_CMP;
 		xpt_done(ccb);
 		break;
 
@@ -450,6 +457,7 @@
                 path_inq->transport_version = 2;
                 path_inq->protocol = PROTO_SCSI;
                 path_inq->protocol_version = SCSI_REV_2;
+                path_inq->maxio = TW_CL_MAX_IO_SIZE;
 		ccb_h->status = CAM_REQ_CMP;
 		xpt_done(ccb);
 		break;
@@ -487,31 +495,6 @@
 
 
 /*
- * Function name:	twa_timeout
- * Description:		Driver entry point for being alerted on a request
- *			timing out.
- *
- * Input:		arg	-- ptr to timed out request
- * Output:		None
- * Return value:	None
- */
-static TW_VOID
-twa_timeout(TW_VOID *arg)
-{
-	struct tw_osli_req_context	*req =
-		(struct tw_osli_req_context *)arg;
-
-	tw_cl_create_event(&(req->ctlr->ctlr_handle), TW_CL_TRUE,
-		TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
-		0x210B, 0x1, TW_CL_SEVERITY_ERROR_STRING,
-		"Request timed out!",
-		"request = %p", req);
-	tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle));
-}
-
-
-
-/*
  * Function name:	tw_osli_request_bus_scan
  * Description:		Requests CAM for a scan of the bus.
  *
@@ -574,20 +557,39 @@
 
 
 /*
- * Function name:	tw_osl_ctlr_busy
- * Description:		CL calls this function on cmd queue full or otherwise,
- *			when it is too busy to accept new requests.
+ * Function name:	tw_osl_timeout
+ * Description:		Call to timeout().
  *
- * Input:		ctlr_handle	-- ptr to controller handle
- *			req_handle	-- ptr to request handle sent by OSL.
+ * Input:		req_handle -- ptr to request handle sent by OSL.
  * Output:		None
  * Return value:	None
  */
 TW_VOID
-tw_osl_ctlr_busy(struct tw_cl_ctlr_handle *ctlr_handle,
-	struct tw_cl_req_handle *req_handle)
+tw_osl_timeout(struct tw_cl_req_handle *req_handle)
+{
+	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
+	union ccb			*ccb = (union ccb *)(req->orig_req);
+	struct ccb_hdr			*ccb_h = &(ccb->ccb_h);
+
+	req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000);
+}
+
+
+
+/*
+ * Function name:	tw_osl_untimeout
+ * Description:		Inverse of call to timeout().
+ *
+ * Input:		req_handle -- ptr to request handle sent by OSL.
+ * Output:		None
+ * Return value:	None
+ */
+TW_VOID
+tw_osl_untimeout(struct tw_cl_req_handle *req_handle)
 {
-	tw_osli_disallow_new_requests(ctlr_handle->osl_ctlr_ctxt, req_handle);
+	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
+
+	req->deadline = 0;
 }
 
 
@@ -655,7 +657,7 @@
 
 	tw_osli_unmap_request(req);
 
-	untimeout(twa_timeout, req, ccb->ccb_h.timeout_ch);
+	req->deadline = 0;
 	if (req->error_code) {
 		/* This request never got submitted to the firmware. */
 		if (req->error_code == EBUSY) {
@@ -682,7 +684,7 @@
 			else if (req_pkt->status & TW_CL_ERR_REQ_SCSI_ERROR)
 				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
 			else if (req_pkt->status & TW_CL_ERR_REQ_BUS_RESET)
-				ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
+				ccb->ccb_h.status |= (CAM_REQUEUE_REQ | CAM_SCSI_BUS_RESET);
 			/*
 			 * If none of the above errors occurred, simply
 			 * mark completion error.
diff -u FreeBSD_HEAD_twa_cvs/tw_osl_freebsd.c FreeBSD_HEAD_twa_3_80_06_003/tw_osl_freebsd.c
--- FreeBSD_HEAD_twa_cvs/tw_osl_freebsd.c	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_osl_freebsd.c	2010-08-24 18:02:12.000000000 -0700
@@ -175,6 +175,9 @@
 static TW_INT32	twa_shutdown(device_t dev);
 static TW_VOID	twa_busdma_lock(TW_VOID *lock_arg, bus_dma_lock_op_t op);
 static TW_VOID	twa_pci_intr(TW_VOID *arg);
+static TW_VOID	twa_watchdog(TW_VOID *arg);
+int twa_setup_intr(struct twa_softc *sc);
+int twa_teardown_intr(struct twa_softc *sc);
 
 static TW_INT32	tw_osli_alloc_mem(struct twa_softc *sc);
 static TW_VOID	tw_osli_free_resources(struct twa_softc *sc);
@@ -238,6 +241,32 @@
 	return(ENXIO);
 }
 
+int twa_setup_intr(struct twa_softc *sc)
+{
+	int error = 0;
+
+	if (!(sc->intr_handle) && (sc->irq_res)) {
+		error = bus_setup_intr(sc->bus_dev, sc->irq_res,
+					INTR_TYPE_CAM | INTR_MPSAFE,
+					NULL, twa_pci_intr,
+					sc, &sc->intr_handle);
+	}
+	return( error );
+}
+
+
+int twa_teardown_intr(struct twa_softc *sc)
+{
+	int error = 0;
+
+	if ((sc->intr_handle) && (sc->irq_res)) {
+		error = bus_teardown_intr(sc->bus_dev,
+						sc->irq_res, sc->intr_handle);
+		sc->intr_handle = NULL;
+	}
+	return( error );
+}
+
 
 
 /*
@@ -354,10 +383,7 @@
 		tw_osli_free_resources(sc);
 		return(ENXIO);
 	}
-	if ((error = bus_setup_intr(sc->bus_dev, sc->irq_res,
-			INTR_TYPE_CAM | INTR_MPSAFE,
-			NULL, twa_pci_intr,	    
-			sc, &sc->intr_handle))) {
+	if ((error = twa_setup_intr(sc))) {
 		tw_osli_printf(sc, "error = %d",
 			TW_CL_SEVERITY_ERROR_STRING,
 			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
@@ -412,10 +438,77 @@
 		return(error);
 	}
 
+	sc->watchdog_index = 0;
+	callout_init(&(sc->watchdog_callout[0]), CALLOUT_MPSAFE);
+	callout_init(&(sc->watchdog_callout[1]), CALLOUT_MPSAFE);
+	callout_reset(&(sc->watchdog_callout[0]), 5*hz, twa_watchdog, &sc->ctlr_handle);
+
 	return(0);
 }
 
 
+static TW_VOID
+twa_watchdog(TW_VOID *arg)
+{
+	struct tw_cl_ctlr_handle *ctlr_handle =
+		(struct tw_cl_ctlr_handle *)arg;
+	struct twa_softc		*sc = ctlr_handle->osl_ctlr_ctxt;
+	int				i;
+	int				i_need_a_reset = 0;
+	int				driver_is_active = 0;
+	int				my_watchdog_was_pending = 1234;
+	TW_UINT64			current_time;
+	struct tw_osli_req_context	*my_req;
+
+
+//==============================================================================
+	current_time = (TW_UINT64) (tw_osl_get_local_time());
+
+	for (i = 0; i < TW_OSLI_MAX_NUM_REQUESTS; i++) {
+		my_req = &(sc->req_ctx_buf[i]);
+
+		if ((my_req->state == TW_OSLI_REQ_STATE_BUSY) &&
+			(my_req->deadline) &&
+			(my_req->deadline < current_time)) {
+			tw_cl_set_reset_needed(ctlr_handle);
+#ifdef    TW_OSL_DEBUG
+			device_printf((sc)->bus_dev, "Request %d timed out! d = %p, c = %p\n", i, (void*)my_req->deadline, (void*)current_time);
+#else  /* TW_OSL_DEBUG */
+			device_printf((sc)->bus_dev, "Request %d timed out!\n", i);
+#endif /* TW_OSL_DEBUG */
+			break;
+		}
+	}
+//==============================================================================
+
+	i_need_a_reset = tw_cl_is_reset_needed(ctlr_handle);
+
+	i = (int) ((sc->watchdog_index++) & 1);
+
+	driver_is_active = tw_cl_is_active(ctlr_handle);
+
+	if (i_need_a_reset) {
+#ifdef    TW_OSL_DEBUG
+		device_printf((sc)->bus_dev, "Watchdog rescheduled in 70 seconds\n");
+#endif /* TW_OSL_DEBUG */
+		my_watchdog_was_pending =
+			callout_reset(&(sc->watchdog_callout[i]), 70*hz, twa_watchdog, &sc->ctlr_handle);
+		tw_cl_reset_ctlr(ctlr_handle);
+#ifdef    TW_OSL_DEBUG
+		device_printf((sc)->bus_dev, "Watchdog reset completed!\n");
+#endif /* TW_OSL_DEBUG */
+	} else if (driver_is_active) {
+		my_watchdog_was_pending =
+			callout_reset(&(sc->watchdog_callout[i]),  5*hz, twa_watchdog, &sc->ctlr_handle);
+	}
+#ifdef    TW_OSL_DEBUG
+	if (i_need_a_reset || my_watchdog_was_pending)
+		device_printf((sc)->bus_dev, "i_need_a_reset = %d, "
+		"driver_is_active = %d, my_watchdog_was_pending = %d\n",
+		i_need_a_reset, driver_is_active, my_watchdog_was_pending);
+#endif /* TW_OSL_DEBUG */
+}
+
 
 /*
  * Function name:	tw_osli_alloc_mem
@@ -715,9 +808,7 @@
 
 
 	/* Disconnect the interrupt handler. */
-	if (sc->intr_handle)
-		if ((error = bus_teardown_intr(sc->bus_dev,
-				sc->irq_res, sc->intr_handle)))
+	if ((error = twa_teardown_intr(sc)))
 			tw_osli_dbg_dprintf(1, sc,
 				"teardown_intr returned %d", error);
 
@@ -809,6 +900,9 @@
 
 	tw_osli_dbg_dprintf(3, sc, "entered");
 
+	/* Disconnect interrupts. */
+	error = twa_teardown_intr(sc);
+
 	/* Disconnect from the controller. */
 	if ((error = tw_cl_shutdown_ctlr(&(sc->ctlr_handle), 0))) {
 		tw_osli_printf(sc, "error = %d",
@@ -997,33 +1091,35 @@
 				error = 0; /* False error */
 				break;
 			}
-			tw_osli_printf(sc, "request = %p",
-				TW_CL_SEVERITY_ERROR_STRING,
-				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
-				0x2018,
-				"Passthru request timed out!",
-				req);
-			/*
-			 * Should I check here if the timeout happened
-			 * because of yet another reset, and not do a
-			 * second reset?
-			 */
-			tw_cl_reset_ctlr(&sc->ctlr_handle);
+			if (!(tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) {
+#ifdef    TW_OSL_DEBUG
+				tw_osli_printf(sc, "request = %p",
+					TW_CL_SEVERITY_ERROR_STRING,
+					TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
+					0x2018,
+					"Passthru request timed out!",
+					req);
+#else  /* TW_OSL_DEBUG */
+			device_printf((sc)->bus_dev, "Passthru request timed out!\n");
+#endif /* TW_OSL_DEBUG */
+				tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle));
+			}
+
+			error = 0;
+			end_time = tw_osl_get_local_time() + timeout;
+			continue;
 			/*
 			 * Don't touch req after a reset.  It (and any
-			 * associated data) will already have been
+			 * associated data) will be
 			 * unmapped by the callback.
 			 */
-			user_buf->driver_pkt.os_status = error;
-			error = ETIMEDOUT;
-			goto fw_passthru_err;
 		}
 		/* 
 		 * Either the request got completed, or we were woken up by a
 		 * signal.  Calculate the new timeout, in case it was the latter.
 		 */
 		timeout = (end_time - tw_osl_get_local_time());
-	}
+	} /* End of while loop */
 
 	/* If there was a payload, copy it back. */
 	if ((!error) && (req->length))
@@ -1037,19 +1133,9 @@
 				error);
 	
 fw_passthru_err:
-	/*
-	 * Print the failure message.  For some reason, on certain OS versions,
-	 * printing this error message during reset hangs the display (although
-	 * the rest of the system is running fine.  So, don't print it if the
-	 * failure was due to a reset.
-	 */
-	if ((error) && (error != TW_CL_ERR_REQ_BUS_RESET))
-		tw_osli_printf(sc, "error = %d",		
-			TW_CL_SEVERITY_ERROR_STRING,
-			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
-			0x201A,
-			"Firmware passthru failed!",
-			error);
+
+	if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET)
+		error = EBUSY;
 
 	user_buf->driver_pkt.os_status = error;
 	/* Free resources. */
@@ -1073,6 +1159,8 @@
 tw_osl_complete_passthru(struct tw_cl_req_handle *req_handle)
 {
 	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
+	struct tw_cl_req_packet		*req_pkt =
+		(struct tw_cl_req_packet *)(&req->req_pkt);
 	struct twa_softc		*sc = req->ctlr;
 
 	tw_osli_dbg_dprintf(5, sc, "entered");
@@ -1120,6 +1208,9 @@
 			if (req->flags & TW_OSLI_REQ_FLAGS_MAPPED)
 				return;
 
+			if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET)
+				return;
+
 			tw_osli_printf(sc, "request = %p",
 				TW_CL_SEVERITY_ERROR_STRING,
 				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
@@ -1166,6 +1257,7 @@
 		req->req_handle.is_io = 0;
 		req->data = NULL;
 		req->length = 0;
+		req->deadline = 0;
 		req->real_data = NULL;
 		req->real_length = 0;
 		req->state = TW_OSLI_REQ_STATE_INIT;/* req being initialized */
@@ -1207,6 +1299,11 @@
 
 	tw_osli_dbg_dprintf(10, sc, "entered");
 
+	if (error == EINVAL) {
+		req->error_code = error;
+		return;
+	}
+
 	/* Mark the request as currently being processed. */
 	req->state = TW_OSLI_REQ_STATE_BUSY;
 	/* Move the request into the busy queue. */
@@ -1400,6 +1497,14 @@
 				mtx_unlock_spin(sc->io_lock);
 				error = 0;
 			} else {
+				tw_osli_printf(sc, "error = %d",
+					TW_CL_SEVERITY_ERROR_STRING,
+					TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
+					0x9999,
+					"Failed to map DMA memory "
+					"for I/O request",
+					error);
+				req->flags |= TW_OSLI_REQ_FLAGS_FAILED;
 				/* Free alignment buffer if it was used. */
 				if (req->flags &
 					TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED) {
diff -u FreeBSD_HEAD_twa_cvs/tw_osl_share.h FreeBSD_HEAD_twa_3_80_06_003/tw_osl_share.h
--- FreeBSD_HEAD_twa_cvs/tw_osl_share.h	2010-08-24 18:06:24.000000000 -0700
+++ FreeBSD_HEAD_twa_3_80_06_003/tw_osl_share.h	2010-08-24 18:02:12.000000000 -0700
@@ -75,7 +75,7 @@
 #define TW_OSL_ENCLOSURE_SUPPORT
 #endif
 
-#define TW_OSL_DRIVER_VERSION_STRING	"3.80.06.002"
+#define TW_OSL_DRIVER_VERSION_STRING	"3.80.06.003"
 
 #define	TW_OSL_CAN_SLEEP
 


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list