/* * Function name: tw_cl_print_ctlr_stats * Description: Prints the current status of the controller. * * Input: ctlr_handle-- controller handle * Output: None * Return value: None */ TW_VOID tw_cl_print_ctlr_stats(struct tw_cl_ctlr_handle *ctlr_handle) { struct tw_cli_ctlr_context *ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); TW_UINT32 status_reg; TW_INT8 desc[200]; tw_cli_dbg_printf(7, ctlr->ctlr_handle, "", "entered"); /* Print current controller details. */ tw_cli_dbg_printf(0, ctlr_handle, "", "cl_ctlr_ctxt = %p", ctlr); tw_osl_memzero(desc, 200); status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); tw_cli_dbg_printf(0, ctlr_handle, "", "status reg = 0x%x %s", status_reg, tw_cli_describe_bits(status_reg, desc)); tw_cli_dbg_printf(0, ctlr_handle, "", "CLq type current max"); tw_cli_dbg_printf(0, ctlr_handle, "", "free %04d %04d", ctlr->q_stats[TW_CLI_FREE_Q].cur_len, ctlr->q_stats[TW_CLI_FREE_Q].max_len); tw_cli_dbg_printf(0, ctlr_handle, "", "busy %04d %04d", ctlr->q_stats[TW_CLI_BUSY_Q].cur_len, ctlr->q_stats[TW_CLI_BUSY_Q].max_len); tw_cli_dbg_printf(0, ctlr_handle, "", "pending %04d %04d", ctlr->q_stats[TW_CLI_PENDING_Q].cur_len, ctlr->q_stats[TW_CLI_PENDING_Q].max_len); tw_cli_dbg_printf(0, ctlr_handle, "", "complete %04d %04d", ctlr->q_stats[TW_CLI_COMPLETE_Q].cur_len, ctlr->q_stats[TW_CLI_COMPLETE_Q].max_len); tw_cli_dbg_printf(0, ctlr_handle, "", "AEN queue head %d tail %d", ctlr->aen_head, ctlr->aen_tail); }
/* * Function name: tw_cli_find_response * Description: Find a particular response in the ctlr response queue. * * Input: ctlr -- ptr to per ctlr structure * req_id -- request id of the response to look for * Output: None * Return value: 0 -- success * non-zero-- failure */ TW_INT32 tw_cli_find_response(struct tw_cli_ctlr_context *ctlr, TW_INT32 req_id) { TW_UINT32 resp; TW_INT32 resp_id; TW_UINT32 status_reg; tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); for (;;) { status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) return(TW_OSL_ENOTTY); /* no more response queue entries */ if (ctlr->device_id == TW_CL_DEVICE_ID_9K) { resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle); resp_id = GET_RESP_ID(resp); } else { resp = TW_CLI_READ_LARGE_RESPONSE_QUEUE( ctlr->ctlr_handle); resp_id = GET_LARGE_RESP_ID(resp); } if (resp_id == req_id) return(TW_OSL_ESUCCESS); /* found the req_id */ } }
/* * Function name: twa_interrupt * Description: Interrupt handler. Determines the kind of interrupt, * and returns TW_CL_TRUE if it recognizes the interrupt. * * Input: ctlr_handle -- controller handle * Output: None * Return value: TW_CL_TRUE -- interrupt recognized * TW_CL_FALSE-- interrupt not recognized */ TW_INT32 tw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle) { struct tw_cli_ctlr_context *ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); TW_UINT32 status_reg; TW_INT32 rc = TW_CL_FALSE; tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); /* If we don't have controller context, bail */ if (ctlr == NULL) goto out; /* * Bail If we get an interrupt while resetting, or shutting down. */ if (ctlr->reset_in_progress || !(ctlr->active)) goto out; /* Read the status register to determine the type of interrupt. */ status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); if (tw_cli_check_ctlr_state(ctlr, status_reg)) goto out; /* Clear the interrupt. */ if (status_reg & TWA_STATUS_HOST_INTERRUPT) { tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(), "Host interrupt"); TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, TWA_CONTROL_CLEAR_HOST_INTERRUPT); } if (status_reg & TWA_STATUS_ATTENTION_INTERRUPT) { tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(), "Attention interrupt"); rc |= TW_CL_TRUE; /* request for a deferred isr call */ tw_cli_process_attn_intr(ctlr); TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT); } if (status_reg & TWA_STATUS_COMMAND_INTERRUPT) { tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(), "Command interrupt"); rc |= TW_CL_TRUE; /* request for a deferred isr call */ tw_cli_process_cmd_intr(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_MASK_COMMAND_INTERRUPT); } if (status_reg & TWA_STATUS_RESPONSE_INTERRUPT) { tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "Response interrupt"); rc |= TW_CL_TRUE; /* request for a deferred isr call */ tw_cli_process_resp_intr(ctlr); } out: return(rc); }
/* * Function name: tw_cli_process_resp_intr * Description: Looks for cmd completions from fw; queues cmds completed * by fw into complete queue. * * Input: ctlr -- ptr to CL internal ctlr context * Output: None * Return value: 0 -- no ctlr error * non-zero-- ctlr error */ TW_INT32 tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr) { TW_UINT32 resp; struct tw_cli_req_context *req; TW_INT32 error; TW_UINT32 status_reg; tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); for (;;) { status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); if ((error = tw_cli_check_ctlr_state(ctlr, status_reg))) break; if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) { tw_cli_dbg_printf(7, ctlr->ctlr_handle, tw_osl_cur_func(), "Response queue empty"); break; } /* Response queue is not empty. */ resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle); { req = &(ctlr->req_ctxt_buf[GET_RESP_ID(resp)]); } if (req->state != TW_CLI_REQ_STATE_BUSY) { tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 0x1201, 0x1, TW_CL_SEVERITY_ERROR_STRING, "Unposted command completed!!", "request = %p, status = %d", req, req->state); #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); } /* * Remove the request from the busy queue, mark it as complete, * and enqueue it in the complete queue. */ tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q); req->state = TW_CLI_REQ_STATE_COMPLETE; tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q); } /* Complete this, and other requests in the complete queue. */ tw_cli_process_complete_queue(ctlr); return(error); }
/* * Function name: tw_cli_drain_response_queue * Description: Drain the controller response queue. * * Input: ctlr -- ptr to per ctlr structure * Output: None * Return value: 0 -- success * non-zero-- failure */ TW_INT32 tw_cli_drain_response_queue(struct tw_cli_ctlr_context *ctlr) { TW_UINT32 resp; TW_UINT32 status_reg; tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); for (;;) { status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) return(TW_OSL_ESUCCESS); /* no more response queue entries */ resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle); } }
/* * Function name: tw_cli_poll_status * Description: Poll for a given status to show up in the firmware * status register. * * Input: ctlr -- ptr to CL internal ctlr context * status -- status to look for * timeout -- max # of seconds to wait before giving up * Output: None * Return value: 0 -- success * non-zero-- failure */ TW_INT32 tw_cli_poll_status(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status, TW_UINT32 timeout) { TW_TIME end_time; TW_UINT32 status_reg; tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); end_time = tw_osl_get_local_time() + timeout; do { status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); if ((status_reg & status) == status) /* got the required bit(s) */ return(TW_OSL_ESUCCESS); tw_osl_delay(1000); } while (tw_osl_get_local_time() <= end_time); return(TW_OSL_ETIMEDOUT); }
/* * Function name: tw_cli_submit_cmd * Description: Submits a cmd to firmware. * * Input: req -- ptr to CL internal request context * Output: None * Return value: 0 -- success * non-zero-- failure */ TW_INT32 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 = 0; tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); /* Serialize access to the controller cmd queue. */ tw_osl_get_lock(ctlr_handle, ctlr->io_lock); /* For 9650SE first write low 4 bytes */ if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) tw_osl_write_reg(ctlr_handle, TWA_COMMAND_QUEUE_OFFSET_LOW, (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); if (status_reg & TWA_STATUS_COMMAND_QUEUE_FULL) { struct tw_cl_req_packet *req_pkt = (struct tw_cl_req_packet *)(req->orig_req); tw_cli_dbg_printf(7, ctlr_handle, tw_osl_cur_func(), "Cmd queue full"); if ((req->flags & TW_CLI_REQ_FLAGS_INTERNAL) || ((req_pkt) && (req_pkt->flags & TW_CL_REQ_RETRY_ON_BUSY)) ) { if (req->state != TW_CLI_REQ_STATE_PENDING) { tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "pending internal/ioctl request"); req->state = TW_CLI_REQ_STATE_PENDING; tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); /* Unmask command interrupt. */ TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); } else error = TW_OSL_EBUSY; } else { error = TW_OSL_EBUSY; } } else { tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "Submitting command"); /* Insert command into busy queue */ req->state = TW_CLI_REQ_STATE_BUSY; tw_cli_req_q_insert_tail(req, TW_CLI_BUSY_Q); if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) { /* Now write the high 4 bytes */ tw_osl_write_reg(ctlr_handle, TWA_COMMAND_QUEUE_OFFSET_HIGH, (TW_UINT32)(((TW_UINT64)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)))>>32), 4); } else { if (ctlr->flags & TW_CL_64BIT_ADDRESSES) {