From: Sascha Wildner Date: Tue, 14 Sep 2010 19:48:10 +0000 (+0200) Subject: twa(4): Sync with FreeBSD (twa(4) version 3.80.06.003). X-Git-Tag: v2.9.0~200 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/4fbf05f972ecaeee1d81e85f6a69c42d4b3c1f69 twa(4): Sync with FreeBSD (twa(4) version 3.80.06.003). Thanks to Xin Li for notifying me of this update. Tested-by: Damian Lubosch --- diff --git a/sys/dev/raid/twa/tw_cl.h b/sys/dev/raid/twa/tw_cl.h index 8963c9efc5..9827b05aac 100644 --- a/sys/dev/raid/twa/tw_cl.h +++ b/sys/dev/raid/twa/tw_cl.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_cl.h,v 1.5 2010/07/09 17:38:15 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_cl.h,v 1.6 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -88,7 +88,8 @@ struct tw_cli_q_stats { #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 @@ struct tw_cli_ctlr_context { 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 --git a/sys/dev/raid/twa/tw_cl_externs.h b/sys/dev/raid/twa/tw_cl_externs.h index 441a841a86..171e92a4db 100644 --- a/sys/dev/raid/twa/tw_cl_externs.h +++ b/sys/dev/raid/twa/tw_cl_externs.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_cl_externs.h,v 1.3 2007/05/09 04:16:32 scottl Exp $ + * $FreeBSD: src/sys/dev/twa/tw_cl_externs.h,v 1.4 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -86,6 +86,8 @@ extern TW_INT32 tw_cli_submit_and_poll_request(struct tw_cli_req_context *req, /* 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 --git a/sys/dev/raid/twa/tw_cl_fwif.h b/sys/dev/raid/twa/tw_cl_fwif.h index 3c8e8a42e0..f4564e34e5 100644 --- a/sys/dev/raid/twa/tw_cl_fwif.h +++ b/sys/dev/raid/twa/tw_cl_fwif.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_cl_fwif.h,v 1.4 2010/06/09 21:40:38 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_cl_fwif.h,v 1.5 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -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 --git a/sys/dev/raid/twa/tw_cl_init.c b/sys/dev/raid/twa/tw_cl_init.c index 3a8c2a166c..067efe94c7 100644 --- a/sys/dev/raid/twa/tw_cl_init.c +++ b/sys/dev/raid/twa/tw_cl_init.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_cl_init.c,v 1.6 2010/06/09 21:40:38 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_cl_init.c,v 1.7 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -315,6 +315,7 @@ tw_cl_init_ctlr(struct tw_cl_ctlr_handle *ctlr_handle, TW_UINT32 flags, 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 @@ tw_cli_init_connection(struct tw_cli_ctlr_context *ctlr, /* 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 --git a/sys/dev/raid/twa/tw_cl_intr.c b/sys/dev/raid/twa/tw_cl_intr.c index 8f0cee9dbb..462579af4d 100644 --- a/sys/dev/raid/twa/tw_cl_intr.c +++ b/sys/dev/raid/twa/tw_cl_intr.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_cl_intr.c,v 1.5 2010/06/09 21:40:38 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_cl_intr.c,v 1.6 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -248,8 +248,7 @@ tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr) #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 @@ tw_cli_complete_io(struct tw_cli_req_context *req) #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 @@ tw_cli_scsi_complete(struct tw_cli_req_context *req) 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_scsi_complete(struct tw_cli_req_context *req) 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 @@ tw_cli_param_callback(struct tw_cli_req_context *req) */ 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 @@ tw_cli_aen_callback(struct tw_cli_req_context *req) 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 --git a/sys/dev/raid/twa/tw_cl_io.c b/sys/dev/raid/twa/tw_cl_io.c index bd2244a5ed..e3da8e927f 100644 --- a/sys/dev/raid/twa/tw_cl_io.c +++ b/sys/dev/raid/twa/tw_cl_io.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_cl_io.c,v 1.6 2010/06/09 21:40:38 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_cl_io.c,v 1.7 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -74,18 +74,12 @@ tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle, 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 @@ tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle, 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 @@ tw_cli_submit_cmd(struct tw_cli_req_context *req) 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 @@ tw_cli_submit_cmd(struct tw_cli_req_context *req) 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 @@ tw_cli_submit_cmd(struct tw_cli_req_context *req) "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_cli_submit_cmd(struct tw_cli_req_context *req) (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_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle, 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 @@ tw_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle, 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_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle, 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 @@ tw_cli_get_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, 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 @@ tw_cli_get_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, /* 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 @@ tw_cli_set_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, /* 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_and_poll_request(struct tw_cli_req_context *req, * 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 @@ tw_cli_submit_and_poll_request(struct tw_cli_req_context *req, * 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 @@ tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle) 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 @@ tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle) * 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 @@ tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle) 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, - 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; - } + /* 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; + } - 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!", - " "); +#ifdef TW_OSL_DEBUG + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, + TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, + 0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING, + "Controller reset done!", " "); +#endif /* TW_OSL_DEBUG */ + break; + } /* End of while */ -out: - ctlr->reset_in_progress = TW_CL_FALSE; - xpt_release_simq(sc->sim, 1); + /* 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); + } - /* - * Enable interrupts, and also clear attention and response interrupts. - */ + 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; + ctlr->reset_needed = TW_CL_FALSE; /* 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_INT32 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 @@ tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) } 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 @@ tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) 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,7 +1264,7 @@ tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) } 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", @@ -1252,18 +1272,6 @@ tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) 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 --git a/sys/dev/raid/twa/tw_cl_misc.c b/sys/dev/raid/twa/tw_cl_misc.c index 7993430a53..9b4e7f86f9 100644 --- a/sys/dev/raid/twa/tw_cl_misc.c +++ b/sys/dev/raid/twa/tw_cl_misc.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_cl_misc.c,v 1.6 2010/06/17 19:48:03 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_cl_misc.c,v 1.7 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -83,7 +83,8 @@ tw_cli_drain_complete_queue(struct tw_cli_ctlr_context *ctlr) 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 @@ tw_cli_drain_complete_queue(struct tw_cli_ctlr_context *ctlr) 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_drain_busy_queue(struct tw_cli_ctlr_context *ctlr) 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 @@ tw_cli_drain_busy_queue(struct tw_cli_ctlr_context *ctlr) 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 @@ tw_cli_drain_pending_queue(struct tw_cli_ctlr_context *ctlr) /* * 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 @@ tw_cli_drain_pending_queue(struct tw_cli_ctlr_context *ctlr) 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 @@ tw_cli_drain_response_queue(struct tw_cli_ctlr_context *ctlr) 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 @@ tw_cli_find_response(struct tw_cli_ctlr_context *ctlr, TW_INT32 req_id) 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 @@ tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr) 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_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) 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 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) (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 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) 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 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) } 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 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) 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_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) 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_cli_describe_bits(TW_UINT32 reg, TW_INT8 *str) 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 --git a/sys/dev/raid/twa/tw_cl_share.h b/sys/dev/raid/twa/tw_cl_share.h index ec8326dd2b..80dd4539d8 100644 --- a/sys/dev/raid/twa/tw_cl_share.h +++ b/sys/dev/raid/twa/tw_cl_share.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_cl_share.h,v 1.7 2010/07/09 17:38:15 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_cl_share.h,v 1.8 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -349,10 +349,14 @@ extern TW_VOID tw_osl_breakpoint(TW_VOID); #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_INT32 tw_cl_init_ctlr(struct tw_cl_ctlr_handle *ctlr_handle, ); +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 --git a/sys/dev/raid/twa/tw_osl.h b/sys/dev/raid/twa/tw_osl.h index 144953a3a8..5989065139 100644 --- a/sys/dev/raid/twa/tw_osl.h +++ b/sys/dev/raid/twa/tw_osl.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_osl.h,v 1.8 2010/06/09 21:40:38 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_osl.h,v 1.9 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -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 tw_osli_req_context { 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 twa_softc { struct lock sim_lock_handle;/* sim lock shared with cam */ struct lock *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 --git a/sys/dev/raid/twa/tw_osl_cam.c b/sys/dev/raid/twa/tw_osl_cam.c index a5bffa6db5..6b31fc1a21 100644 --- a/sys/dev/raid/twa/tw_osl_cam.c +++ b/sys/dev/raid/twa/tw_osl_cam.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_osl_cam.c,v 1.14 2010/06/09 21:40:38 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_osl_cam.c,v 1.15 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -56,7 +56,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_VOID twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb); static TW_INT32 tw_osli_execute_scsi(struct tw_osli_req_context *req, @@ -83,7 +82,7 @@ tw_osli_cam_attach(struct twa_softc *sc) /* * 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, @@ -276,6 +275,7 @@ tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb) "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); } @@ -291,6 +291,7 @@ tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb) 0x2107, "XPT_SCSI_IO: Got SGList"); ccb_h->status = CAM_REQ_INVALID; + ccb_h->status &= ~CAM_SIM_QUEUED; xpt_done(ccb); return(1); } @@ -307,13 +308,20 @@ tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb) return(1); } - callout_reset(&ccb->ccb_h.timeout_ch, - (ccb_h->timeout * hz) / 1000, twa_timeout, req); + 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); } @@ -346,10 +354,20 @@ twa_action(struct cam_sim *sim, union ccb *ccb) * 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; @@ -365,25 +383,14 @@ twa_action(struct cam_sim *sim, union ccb *ccb) 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", " "); - lockmgr(sc->sim_lock, LK_RELEASE); - 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; - - lockmgr(sc->sim_lock, LK_EXCLUSIVE); + tw_cl_set_reset_needed(&(sc->ctlr_handle)); + ccb_h->status = CAM_REQ_CMP; xpt_done(ccb); break; @@ -451,6 +458,9 @@ twa_action(struct cam_sim *sim, union ccb *ccb) path_inq->transport_version = 2; path_inq->protocol = PROTO_SCSI; path_inq->protocol_version = SCSI_REV_2; +#if 0 /* XXX swildner */ + path_inq->maxio = TW_CL_MAX_IO_SIZE; +#endif ccb_h->status = CAM_REQ_CMP; xpt_done(ccb); break; @@ -487,31 +497,6 @@ twa_poll(struct cam_sim *sim) -/* - * 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. @@ -606,20 +591,39 @@ tw_osli_disallow_new_requests(struct twa_softc *sc, /* - * 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; } @@ -687,7 +691,7 @@ tw_osl_complete_io(struct tw_cl_req_handle *req_handle) tw_osli_unmap_request(req); - callout_stop(&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) { @@ -714,7 +718,7 @@ tw_osl_complete_io(struct tw_cl_req_handle *req_handle) 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 --git a/sys/dev/raid/twa/tw_osl_freebsd.c b/sys/dev/raid/twa/tw_osl_freebsd.c index 045531f441..1579f03907 100644 --- a/sys/dev/raid/twa/tw_osl_freebsd.c +++ b/sys/dev/raid/twa/tw_osl_freebsd.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_osl_freebsd.c,v 1.15 2010/06/09 21:40:38 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_osl_freebsd.c,v 1.18 2010/09/04 16:27:14 bz Exp $ */ /* @@ -181,6 +181,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); #endif 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); @@ -244,6 +247,32 @@ twa_probe(device_t dev) 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, + 0, + twa_pci_intr, + sc, &sc->intr_handle, NULL); + } + 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 ); +} + /* @@ -360,10 +389,7 @@ twa_attach(device_t dev) tw_osli_free_resources(sc); return(ENXIO); } - if ((error = bus_setup_intr(sc->bus_dev, sc->irq_res, - 0, - twa_pci_intr, - sc, &sc->intr_handle, NULL))) { + if ((error = twa_setup_intr(sc))) { tw_osli_printf(sc, "error = %d", TW_CL_SEVERITY_ERROR_STRING, TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, @@ -418,10 +444,74 @@ twa_attach(device_t dev) return(error); } + sc->watchdog_index = 0; + callout_init(&(sc->watchdog_callout[0])); + callout_init(&(sc->watchdog_callout[1])); + 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; + 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 = %llu, c = %llu\n", i, my_req->deadline, 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 */ + 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) { + callout_reset(&(sc->watchdog_callout[i]), 5*hz, twa_watchdog, &sc->ctlr_handle); + } +#ifdef TW_OSL_DEBUG + if (i_need_a_reset) + device_printf((sc)->bus_dev, "i_need_a_reset = %d, " + "driver_is_active = %d\n", + i_need_a_reset, driver_is_active); +#endif /* TW_OSL_DEBUG */ +} + /* * Function name: tw_osli_alloc_mem @@ -721,9 +811,7 @@ tw_osli_free_resources(struct twa_softc *sc) /* 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); @@ -816,6 +904,15 @@ twa_shutdown(device_t dev) tw_osli_dbg_dprintf(3, sc, "entered"); + /* Disconnect interrupts. */ + error = twa_teardown_intr(sc); + +#if 0 /* XXX swildner */ + /* Stop watchdog task. */ + callout_drain(&(sc->watchdog_callout[0])); + callout_drain(&(sc->watchdog_callout[1])); +#endif + /* Disconnect from the controller. */ if ((error = tw_cl_shutdown_ctlr(&(sc->ctlr_handle), 0))) { tw_osli_printf(sc, "error = %d", @@ -1006,33 +1103,35 @@ tw_osli_fw_passthru(struct twa_softc *sc, TW_INT8 *buf) 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)) @@ -1046,19 +1145,9 @@ tw_osli_fw_passthru(struct twa_softc *sc, TW_INT8 *buf) 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. */ @@ -1082,6 +1171,8 @@ TW_VOID 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"); @@ -1129,6 +1220,9 @@ tw_osl_complete_passthru(struct tw_cl_req_handle *req_handle) 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, @@ -1175,6 +1269,7 @@ tw_osli_get_request(struct twa_softc *sc) 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 */ @@ -1216,6 +1311,11 @@ twa_map_load_data_callback(TW_VOID *arg, bus_dma_segment_t *segs, 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. */ @@ -1409,6 +1509,14 @@ tw_osli_map_request(struct tw_osli_req_context *req) spin_unlock(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 --git a/sys/dev/raid/twa/tw_osl_share.h b/sys/dev/raid/twa/tw_osl_share.h index 53e14ab3ce..096c911ab3 100644 --- a/sys/dev/raid/twa/tw_osl_share.h +++ b/sys/dev/raid/twa/tw_osl_share.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/twa/tw_osl_share.h,v 1.10 2010/06/09 21:40:38 delphij Exp $ + * $FreeBSD: src/sys/dev/twa/tw_osl_share.h,v 1.11 2010/08/30 19:15:04 delphij Exp $ */ /* @@ -76,7 +76,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