diff options
author | Warner Losh <imp@FreeBSD.org> | 2021-11-25 07:21:41 +0000 |
---|---|---|
committer | Warner Losh <imp@FreeBSD.org> | 2021-11-25 07:45:13 +0000 |
commit | 8722e05ae1496968114f4be1a68bf5ea62cdbd78 (patch) | |
tree | 30b6f2fadc7915ac155a11e92581affae1b2492d /sys/dev/twa/tw_cl_io.c | |
parent | 0d5935af8f2ea7675760af234723f472240c386f (diff) | |
download | src-8722e05ae1496968114f4be1a68bf5ea62cdbd78.tar.gz src-8722e05ae1496968114f4be1a68bf5ea62cdbd78.zip |
twa: Remove
Belatedly remove twa(4). It was supposed to go before 13.0, but was
overlooked.
Sponsored by: Netflix
Relnotes: yes
Reviewed by: scottl
Differential Revision: https://reviews.freebsd.org/D33114
Diffstat (limited to 'sys/dev/twa/tw_cl_io.c')
-rw-r--r-- | sys/dev/twa/tw_cl_io.c | 1407 |
1 files changed, 0 insertions, 1407 deletions
diff --git a/sys/dev/twa/tw_cl_io.c b/sys/dev/twa/tw_cl_io.c deleted file mode 100644 index a2a84f4daf69..000000000000 --- a/sys/dev/twa/tw_cl_io.c +++ /dev/null @@ -1,1407 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2004-07 Applied Micro Circuits Corporation. - * Copyright (c) 2004-05 Vinod Kashyap - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * AMCC'S 3ware driver for 9000 series storage controllers. - * - * Author: Vinod Kashyap - * Modifications by: Adam Radford - * Modifications by: Manjunath Ranganathaiah - */ - -/* - * Common Layer I/O functions. - */ - -#include "tw_osl_share.h" -#include "tw_cl_share.h" -#include "tw_cl_fwif.h" -#include "tw_cl_ioctl.h" -#include "tw_cl.h" -#include "tw_cl_externs.h" -#include "tw_osl_ioctl.h" - -#include <cam/cam.h> -#include <cam/cam_ccb.h> -#include <cam/cam_xpt_sim.h> - -/* - * Function name: tw_cl_start_io - * Description: Interface to OS Layer for accepting SCSI requests. - * - * Input: ctlr_handle -- controller handle - * req_pkt -- OSL built request packet - * req_handle -- request handle - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -TW_INT32 -tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle, - struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle) -{ - struct tw_cli_ctlr_context *ctlr; - struct tw_cli_req_context *req; - struct tw_cl_command_9k *cmd; - struct tw_cl_scsi_req_packet *scsi_req; - 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 working with a firmware version that does not support multiple - * luns, and this request is directed at a non-zero lun, error it - * back right away. - */ - if ((req_pkt->gen_req_pkt.scsi_req.lun) && - (ctlr->working_srl < TWA_MULTI_LUN_FW_SRL)) { - req_pkt->status |= (TW_CL_ERR_REQ_INVALID_LUN | - TW_CL_ERR_REQ_SCSI_ERROR); - req_pkt->tw_osl_callback(req_handle); - return(TW_CL_ERR_REQ_SUCCESS); - } - - if ((req = tw_cli_get_request(ctlr - )) == TW_CL_NULL) { - tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), - "Out of request context packets: returning busy"); - return(TW_OSL_EBUSY); - } - - req_handle->cl_req_ctxt = req; - req->req_handle = req_handle; - req->orig_req = req_pkt; - req->tw_cli_callback = tw_cli_complete_io; - - req->flags |= TW_CLI_REQ_FLAGS_EXTERNAL; - req->flags |= TW_CLI_REQ_FLAGS_9K; - - scsi_req = &(req_pkt->gen_req_pkt.scsi_req); - - /* Build the cmd pkt. */ - cmd = &(req->cmd_pkt->command.cmd_pkt_9k); - - req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; - - cmd->res__opcode = BUILD_RES__OPCODE(0, TWA_FW_CMD_EXECUTE_SCSI); - cmd->unit = (TW_UINT8)(scsi_req->unit); - cmd->lun_l4__req_id = TW_CL_SWAP16( - BUILD_LUN_L4__REQ_ID(scsi_req->lun, req->request_id)); - cmd->status = 0; - cmd->sgl_offset = 16; /* offset from end of hdr = max cdb len */ - tw_osl_memcpy(cmd->cdb, scsi_req->cdb, scsi_req->cdb_len); - - if (req_pkt->flags & TW_CL_REQ_CALLBACK_FOR_SGLIST) { - TW_UINT32 num_sgl_entries; - - req_pkt->tw_osl_sgl_callback(req_handle, cmd->sg_list, - &num_sgl_entries); - cmd->lun_h4__sgl_entries = - TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun, - num_sgl_entries)); - } else { - cmd->lun_h4__sgl_entries = - TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun, - scsi_req->sgl_entries)); - tw_cli_fill_sg_list(ctlr, scsi_req->sg_list, - cmd->sg_list, scsi_req->sgl_entries); - } - - 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); - tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); - } - return(error); -} - -/* - * 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) { - /* First write the low 4 bytes, then the high 4. */ - tw_osl_write_reg(ctlr_handle, - TWA_COMMAND_QUEUE_OFFSET_LOW, - (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); - 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 - tw_osl_write_reg(ctlr_handle, - TWA_COMMAND_QUEUE_OFFSET, - (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); - } - } - - tw_osl_free_lock(ctlr_handle, ctlr->io_lock); - - return(error); -} - -/* - * Function name: tw_cl_fw_passthru - * Description: Interface to OS Layer for accepting firmware - * passthru requests. - * Input: ctlr_handle -- controller handle - * req_pkt -- OSL built request packet - * req_handle -- request handle - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -TW_INT32 -tw_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle, - struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle) -{ - struct tw_cli_ctlr_context *ctlr; - struct tw_cli_req_context *req; - union tw_cl_command_7k *cmd_7k; - struct tw_cl_command_9k *cmd_9k; - struct tw_cl_passthru_req_packet *pt_req; - TW_UINT8 opcode; - TW_UINT8 sgl_offset; - TW_VOID *sgl = TW_CL_NULL; - 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 ((req = tw_cli_get_request(ctlr - )) == TW_CL_NULL) { - tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), - "Out of request context packets: returning busy"); - return(TW_OSL_EBUSY); - } - - req_handle->cl_req_ctxt = req; - req->req_handle = req_handle; - req->orig_req = req_pkt; - req->tw_cli_callback = tw_cli_complete_io; - - req->flags |= TW_CLI_REQ_FLAGS_PASSTHRU; - - pt_req = &(req_pkt->gen_req_pkt.pt_req); - - tw_osl_memcpy(req->cmd_pkt, pt_req->cmd_pkt, - pt_req->cmd_pkt_length); - /* Build the cmd pkt. */ - if ((opcode = GET_OPCODE(((TW_UINT8 *) - (pt_req->cmd_pkt))[sizeof(struct tw_cl_command_header)])) - == TWA_FW_CMD_EXECUTE_SCSI) { - TW_UINT16 lun_l4, lun_h4; - - tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), - "passthru: 9k cmd pkt"); - req->flags |= TW_CLI_REQ_FLAGS_9K; - cmd_9k = &(req->cmd_pkt->command.cmd_pkt_9k); - lun_l4 = GET_LUN_L4(cmd_9k->lun_l4__req_id); - lun_h4 = GET_LUN_H4(cmd_9k->lun_h4__sgl_entries); - cmd_9k->lun_l4__req_id = TW_CL_SWAP16( - BUILD_LUN_L4__REQ_ID(lun_l4, req->request_id)); - if (pt_req->sgl_entries) { - cmd_9k->lun_h4__sgl_entries = - TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(lun_h4, - pt_req->sgl_entries)); - sgl = (TW_VOID *)(cmd_9k->sg_list); - } - } else { - tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), - "passthru: 7k cmd pkt"); - cmd_7k = &(req->cmd_pkt->command.cmd_pkt_7k); - cmd_7k->generic.request_id = - (TW_UINT8)(TW_CL_SWAP16(req->request_id)); - if ((sgl_offset = - GET_SGL_OFF(cmd_7k->generic.sgl_off__opcode))) { - if (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA) - sgl = (((TW_UINT32 *)cmd_7k) + cmd_7k->generic.size); - else - sgl = (((TW_UINT32 *)cmd_7k) + sgl_offset); - cmd_7k->generic.size += pt_req->sgl_entries * - ((ctlr->flags & TW_CL_64BIT_ADDRESSES) ? 3 : 2); - } - } - - if (sgl) - tw_cli_fill_sg_list(ctlr, pt_req->sg_list, - sgl, pt_req->sgl_entries); - - 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, - "Failed to start passthru command", - "error = %d", error); - tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); - } - return(error); -} - -/* - * Function name: tw_cl_ioctl - * Description: Handler of CL supported ioctl cmds. - * - * Input: ctlr -- ptr to per ctlr structure - * cmd -- ioctl cmd - * buf -- ptr to buffer in kernel memory, which is - * a copy of the input buffer in user-space - * Output: buf -- ptr to buffer in kernel memory, which will - * need to be copied to the output buffer in - * user-space - * Return value: 0 -- success - * non-zero-- failure - */ -TW_INT32 -tw_cl_ioctl(struct tw_cl_ctlr_handle *ctlr_handle, u_long cmd, TW_VOID *buf) -{ - struct tw_cli_ctlr_context *ctlr = - (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); - struct tw_cl_ioctl_packet *user_buf = - (struct tw_cl_ioctl_packet *)buf; - struct tw_cl_event_packet event_buf; - TW_INT32 event_index; - TW_INT32 start_index; - TW_INT32 error = TW_OSL_ESUCCESS; - - tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered"); - - /* Serialize access to the AEN queue and the ioctl lock. */ - tw_osl_get_lock(ctlr_handle, ctlr->gen_lock); - - switch (cmd) { - case TW_CL_IOCTL_GET_FIRST_EVENT: - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Get First Event"); - - if (ctlr->aen_q_wrapped) { - if (ctlr->aen_q_overflow) { - /* - * The aen queue has wrapped, even before some - * events have been retrieved. Let the caller - * know that he missed out on some AEN's. - */ - user_buf->driver_pkt.status = - TW_CL_ERROR_AEN_OVERFLOW; - ctlr->aen_q_overflow = TW_CL_FALSE; - } else - user_buf->driver_pkt.status = 0; - event_index = ctlr->aen_head; - } else { - if (ctlr->aen_head == ctlr->aen_tail) { - user_buf->driver_pkt.status = - TW_CL_ERROR_AEN_NO_EVENTS; - break; - } - user_buf->driver_pkt.status = 0; - event_index = ctlr->aen_tail; /* = 0 */ - } - tw_osl_memcpy(user_buf->data_buf, - &(ctlr->aen_queue[event_index]), - sizeof(struct tw_cl_event_packet)); - - ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; - - break; - - case TW_CL_IOCTL_GET_LAST_EVENT: - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Get Last Event"); - - if (ctlr->aen_q_wrapped) { - if (ctlr->aen_q_overflow) { - /* - * The aen queue has wrapped, even before some - * events have been retrieved. Let the caller - * know that he missed out on some AEN's. - */ - user_buf->driver_pkt.status = - TW_CL_ERROR_AEN_OVERFLOW; - ctlr->aen_q_overflow = TW_CL_FALSE; - } else - user_buf->driver_pkt.status = 0; - } else { - if (ctlr->aen_head == ctlr->aen_tail) { - user_buf->driver_pkt.status = - TW_CL_ERROR_AEN_NO_EVENTS; - break; - } - user_buf->driver_pkt.status = 0; - } - event_index = (ctlr->aen_head - 1 + ctlr->max_aens_supported) % - ctlr->max_aens_supported; - - tw_osl_memcpy(user_buf->data_buf, - &(ctlr->aen_queue[event_index]), - sizeof(struct tw_cl_event_packet)); - - ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; - - break; - - case TW_CL_IOCTL_GET_NEXT_EVENT: - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Get Next Event"); - - user_buf->driver_pkt.status = 0; - if (ctlr->aen_q_wrapped) { - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Get Next Event: wrapped"); - if (ctlr->aen_q_overflow) { - /* - * The aen queue has wrapped, even before some - * events have been retrieved. Let the caller - * know that he missed out on some AEN's. - */ - tw_cli_dbg_printf(2, ctlr_handle, - tw_osl_cur_func(), - "Get Next Event: overflow"); - user_buf->driver_pkt.status = - TW_CL_ERROR_AEN_OVERFLOW; - ctlr->aen_q_overflow = TW_CL_FALSE; - } - start_index = ctlr->aen_head; - } else { - if (ctlr->aen_head == ctlr->aen_tail) { - tw_cli_dbg_printf(3, ctlr_handle, - tw_osl_cur_func(), - "Get Next Event: empty queue"); - user_buf->driver_pkt.status = - TW_CL_ERROR_AEN_NO_EVENTS; - break; - } - start_index = ctlr->aen_tail; /* = 0 */ - } - tw_osl_memcpy(&event_buf, user_buf->data_buf, - sizeof(struct tw_cl_event_packet)); - - event_index = (start_index + event_buf.sequence_id - - ctlr->aen_queue[start_index].sequence_id + 1) % - ctlr->max_aens_supported; - - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Get Next Event: si = %x, ei = %x, ebsi = %x, " - "sisi = %x, eisi = %x", - start_index, event_index, event_buf.sequence_id, - ctlr->aen_queue[start_index].sequence_id, - ctlr->aen_queue[event_index].sequence_id); - - if (! (ctlr->aen_queue[event_index].sequence_id > - event_buf.sequence_id)) { - /* - * We don't have any event matching the criterion. So, - * we have to report TW_CL_ERROR_NO_EVENTS. If we also - * encountered an overflow condition above, we cannot - * report both conditions during this call. We choose - * to report NO_EVENTS this time, and an overflow the - * next time we are called. - */ - if (user_buf->driver_pkt.status == - TW_CL_ERROR_AEN_OVERFLOW) { - /* - * Make a note so we report the overflow - * next time. - */ - ctlr->aen_q_overflow = TW_CL_TRUE; - } - user_buf->driver_pkt.status = TW_CL_ERROR_AEN_NO_EVENTS; - break; - } - /* Copy the event -- even if there has been an overflow. */ - tw_osl_memcpy(user_buf->data_buf, - &(ctlr->aen_queue[event_index]), - sizeof(struct tw_cl_event_packet)); - - ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; - - break; - - case TW_CL_IOCTL_GET_PREVIOUS_EVENT: - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Get Previous Event"); - - user_buf->driver_pkt.status = 0; - if (ctlr->aen_q_wrapped) { - if (ctlr->aen_q_overflow) { - /* - * The aen queue has wrapped, even before some - * events have been retrieved. Let the caller - * know that he missed out on some AEN's. - */ - user_buf->driver_pkt.status = - TW_CL_ERROR_AEN_OVERFLOW; - ctlr->aen_q_overflow = TW_CL_FALSE; - } - start_index = ctlr->aen_head; - } else { - if (ctlr->aen_head == ctlr->aen_tail) { - user_buf->driver_pkt.status = - TW_CL_ERROR_AEN_NO_EVENTS; - break; - } - start_index = ctlr->aen_tail; /* = 0 */ - } - tw_osl_memcpy(&event_buf, user_buf->data_buf, - sizeof(struct tw_cl_event_packet)); - - event_index = (start_index + event_buf.sequence_id - - ctlr->aen_queue[start_index].sequence_id - 1) % - ctlr->max_aens_supported; - - if (! (ctlr->aen_queue[event_index].sequence_id < - event_buf.sequence_id)) { - /* - * We don't have any event matching the criterion. So, - * we have to report TW_CL_ERROR_NO_EVENTS. If we also - * encountered an overflow condition above, we cannot - * report both conditions during this call. We choose - * to report NO_EVENTS this time, and an overflow the - * next time we are called. - */ - if (user_buf->driver_pkt.status == - TW_CL_ERROR_AEN_OVERFLOW) { - /* - * Make a note so we report the overflow - * next time. - */ - ctlr->aen_q_overflow = TW_CL_TRUE; - } - user_buf->driver_pkt.status = TW_CL_ERROR_AEN_NO_EVENTS; - break; - } - /* Copy the event -- even if there has been an overflow. */ - tw_osl_memcpy(user_buf->data_buf, - &(ctlr->aen_queue[event_index]), - sizeof(struct tw_cl_event_packet)); - - ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; - - break; - - case TW_CL_IOCTL_GET_LOCK: - { - struct tw_cl_lock_packet lock_pkt; - TW_TIME cur_time; - - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Get ioctl lock"); - - cur_time = tw_osl_get_local_time(); - tw_osl_memcpy(&lock_pkt, user_buf->data_buf, - sizeof(struct tw_cl_lock_packet)); - - if ((ctlr->ioctl_lock.lock == TW_CLI_LOCK_FREE) || - (lock_pkt.force_flag) || - (cur_time >= ctlr->ioctl_lock.timeout)) { - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "GET_LOCK: Getting lock!"); - ctlr->ioctl_lock.lock = TW_CLI_LOCK_HELD; - ctlr->ioctl_lock.timeout = - cur_time + (lock_pkt.timeout_msec / 1000); - lock_pkt.time_remaining_msec = lock_pkt.timeout_msec; - user_buf->driver_pkt.status = 0; - } else { - tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), - "GET_LOCK: Lock already held!"); - lock_pkt.time_remaining_msec = (TW_UINT32)( - (ctlr->ioctl_lock.timeout - cur_time) * 1000); - user_buf->driver_pkt.status = - TW_CL_ERROR_IOCTL_LOCK_ALREADY_HELD; - } - tw_osl_memcpy(user_buf->data_buf, &lock_pkt, - sizeof(struct tw_cl_lock_packet)); - break; - } - - case TW_CL_IOCTL_RELEASE_LOCK: - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Release ioctl lock"); - - if (ctlr->ioctl_lock.lock == TW_CLI_LOCK_FREE) { - tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), - "twa_ioctl: RELEASE_LOCK: Lock not held!"); - user_buf->driver_pkt.status = - TW_CL_ERROR_IOCTL_LOCK_NOT_HELD; - } else { - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "RELEASE_LOCK: Releasing lock!"); - ctlr->ioctl_lock.lock = TW_CLI_LOCK_FREE; - user_buf->driver_pkt.status = 0; - } - break; - - case TW_CL_IOCTL_GET_COMPATIBILITY_INFO: - { - struct tw_cl_compatibility_packet comp_pkt; - - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Get compatibility info"); - - tw_osl_memcpy(comp_pkt.driver_version, - TW_OSL_DRIVER_VERSION_STRING, - sizeof(TW_OSL_DRIVER_VERSION_STRING)); - comp_pkt.working_srl = ctlr->working_srl; - comp_pkt.working_branch = ctlr->working_branch; - comp_pkt.working_build = ctlr->working_build; - comp_pkt.driver_srl_high = TWA_CURRENT_FW_SRL; - comp_pkt.driver_branch_high = - TWA_CURRENT_FW_BRANCH(ctlr->arch_id); - comp_pkt.driver_build_high = - TWA_CURRENT_FW_BUILD(ctlr->arch_id); - comp_pkt.driver_srl_low = TWA_BASE_FW_SRL; - comp_pkt.driver_branch_low = TWA_BASE_FW_BRANCH; - comp_pkt.driver_build_low = TWA_BASE_FW_BUILD; - comp_pkt.fw_on_ctlr_srl = ctlr->fw_on_ctlr_srl; - comp_pkt.fw_on_ctlr_branch = ctlr->fw_on_ctlr_branch; - comp_pkt.fw_on_ctlr_build = ctlr->fw_on_ctlr_build; - user_buf->driver_pkt.status = 0; - - /* Copy compatibility information to user space. */ - tw_osl_memcpy(user_buf->data_buf, &comp_pkt, - (sizeof(struct tw_cl_compatibility_packet) < - user_buf->driver_pkt.buffer_length) ? - sizeof(struct tw_cl_compatibility_packet) : - user_buf->driver_pkt.buffer_length); - break; - } - - default: - /* Unknown opcode. */ - tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), - "Unknown ioctl cmd 0x%x", cmd); - error = TW_OSL_ENOTTY; - } - - tw_osl_free_lock(ctlr_handle, ctlr->gen_lock); - return(error); -} - -/* - * Function name: tw_cli_get_param - * Description: Get a firmware parameter. - * - * Input: ctlr -- ptr to per ctlr structure - * table_id -- parameter table # - * param_id -- index of the parameter in the table - * param_size -- size of the parameter in bytes - * callback -- ptr to function, if any, to be called - * back on completion; TW_CL_NULL if no callback. - * Output: param_data -- param value - * Return value: 0 -- success - * non-zero-- failure - */ -TW_INT32 -tw_cli_get_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, - TW_INT32 param_id, TW_VOID *param_data, TW_INT32 param_size, - TW_VOID (* callback)(struct tw_cli_req_context *req)) -{ - struct tw_cli_req_context *req; - union tw_cl_command_7k *cmd; - struct tw_cl_param_9k *param = TW_CL_NULL; - TW_INT32 error = TW_OSL_EBUSY; - - tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); - - /* Get a request packet. */ - if ((req = tw_cli_get_request(ctlr - )) == TW_CL_NULL) - goto out; - - /* Make sure this is the only CL internal request at this time. */ - if (ctlr->internal_req_busy) { - error = TW_OSL_EBUSY; - goto out; - } - ctlr->internal_req_busy = TW_CL_TRUE; - req->data = ctlr->internal_req_data; - req->data_phys = ctlr->internal_req_data_phys; - req->length = TW_CLI_SECTOR_SIZE; - req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; - - /* Initialize memory to read data into. */ - param = (struct tw_cl_param_9k *)(req->data); - tw_osl_memzero(param, sizeof(struct tw_cl_param_9k) - 1 + param_size); - - /* Build the cmd pkt. */ - cmd = &(req->cmd_pkt->command.cmd_pkt_7k); - - req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; - - 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.host_id__unit = BUILD_HOST_ID__UNIT(0, 0); - cmd->param.param_count = TW_CL_SWAP16(1); - - if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { - ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].address = - TW_CL_SWAP64(req->data_phys); - ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].length = - TW_CL_SWAP32(req->length); - cmd->param.size = 2 + 3; - } else { - ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].address = - TW_CL_SWAP32(req->data_phys); - ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].length = - TW_CL_SWAP32(req->length); - cmd->param.size = 2 + 2; - } - - /* Specify which parameter we need. */ - param->table_id = TW_CL_SWAP16(table_id | TWA_9K_PARAM_DESCRIPTOR); - param->parameter_id = (TW_UINT8)(param_id); - param->parameter_size_bytes = TW_CL_SWAP16(param_size); - - /* Submit the command. */ - if (callback == TW_CL_NULL) { - /* 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) - 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); - ctlr->internal_req_busy = TW_CL_FALSE; - tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); - } else { - /* There's a call back. Simply submit the command. */ - req->tw_cli_callback = callback; - if ((error = tw_cli_submit_cmd(req))) - goto out; - } - return(0); - -out: - tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, - 0x1101, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "get_param failed", - "error = %d", error); - if (param) - ctlr->internal_req_busy = TW_CL_FALSE; - if (req) - tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); - return(1); -} - -/* - * Function name: tw_cli_set_param - * Description: Set a firmware parameter. - * - * Input: ctlr -- ptr to per ctlr structure - * table_id -- parameter table # - * param_id -- index of the parameter in the table - * param_size -- size of the parameter in bytes - * callback -- ptr to function, if any, to be called - * back on completion; TW_CL_NULL if no callback. - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -TW_INT32 -tw_cli_set_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, - TW_INT32 param_id, TW_INT32 param_size, TW_VOID *data, - TW_VOID (* callback)(struct tw_cli_req_context *req)) -{ - struct tw_cli_req_context *req; - union tw_cl_command_7k *cmd; - struct tw_cl_param_9k *param = TW_CL_NULL; - TW_INT32 error = TW_OSL_EBUSY; - - tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); - - /* Get a request packet. */ - if ((req = tw_cli_get_request(ctlr - )) == TW_CL_NULL) - goto out; - - /* Make sure this is the only CL internal request at this time. */ - if (ctlr->internal_req_busy) { - error = TW_OSL_EBUSY; - goto out; - } - ctlr->internal_req_busy = TW_CL_TRUE; - req->data = ctlr->internal_req_data; - req->data_phys = ctlr->internal_req_data_phys; - req->length = TW_CLI_SECTOR_SIZE; - req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; - - /* Initialize memory to send data using. */ - param = (struct tw_cl_param_9k *)(req->data); - tw_osl_memzero(param, sizeof(struct tw_cl_param_9k) - 1 + param_size); - - /* Build the cmd pkt. */ - cmd = &(req->cmd_pkt->command.cmd_pkt_7k); - - req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; - - cmd->param.sgl_off__opcode = - BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_SET_PARAM); - 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); - - if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { - ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].address = - TW_CL_SWAP64(req->data_phys); - ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].length = - TW_CL_SWAP32(req->length); - cmd->param.size = 2 + 3; - } else { - ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].address = - TW_CL_SWAP32(req->data_phys); - ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].length = - TW_CL_SWAP32(req->length); - cmd->param.size = 2 + 2; - } - - /* Specify which parameter we want to set. */ - param->table_id = TW_CL_SWAP16(table_id | TWA_9K_PARAM_DESCRIPTOR); - param->parameter_id = (TW_UINT8)(param_id); - param->parameter_size_bytes = TW_CL_SWAP16(param_size); - tw_osl_memcpy(param->data, data, param_size); - - /* Submit the command. */ - if (callback == TW_CL_NULL) { - /* 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) - 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; - tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); - } else { - /* There's a call back. Simply submit the command. */ - req->tw_cli_callback = callback; - if ((error = tw_cli_submit_cmd(req))) - goto out; - } - return(error); - -out: - tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, - 0x1102, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "set_param failed", - "error = %d", error); - if (param) - ctlr->internal_req_busy = TW_CL_FALSE; - if (req) - tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); - return(error); -} - -/* - * Function name: tw_cli_submit_and_poll_request - * Description: Sends down a firmware cmd, and waits for the completion - * in a tight loop. - * - * Input: req -- ptr to request pkt - * timeout -- max # of seconds to wait before giving up - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -TW_INT32 -tw_cli_submit_and_poll_request(struct tw_cli_req_context *req, - TW_UINT32 timeout) -{ - struct tw_cli_ctlr_context *ctlr = req->ctlr; - TW_TIME end_time; - TW_INT32 error; - - tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); - - /* - * If the cmd queue is full, tw_cli_submit_cmd will queue this - * request in the pending queue, since this is an internal request. - */ - if ((error = tw_cli_submit_cmd(req))) { - tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, - 0x1103, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Failed to start internal request", - "error = %d", error); - return(error); - } - - /* - * Poll for the response until the command gets completed, or there's - * a timeout. - */ - end_time = tw_osl_get_local_time() + timeout; - do { - if ((error = req->error_code)) - /* - * This will take care of completion due to a reset, - * or a failure in tw_cli_submit_pending_queue. - * The caller should do the clean-up. - */ - return(error); - - /* See if the command completed. */ - tw_cli_process_resp_intr(ctlr); - - if ((req->state != TW_CLI_REQ_STATE_BUSY) && - (req->state != TW_CLI_REQ_STATE_PENDING)) - return(req->state != TW_CLI_REQ_STATE_COMPLETE); - } while (tw_osl_get_local_time() <= end_time); - - /* Time out! */ - tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, - 0x1104, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Internal request timed out", - "request = %p", req); - - /* - * We will reset the controller only if the request has already been - * submitted, so as to not lose the request packet. If a busy request - * timed out, the reset will take care of freeing resources. If a - * pending request timed out, we will free resources for that request, - * right here, thereby avoiding a reset. So, the caller is expected - * to NOT cleanup when TW_OSL_ETIMEDOUT is returned. - */ - - /* - * We have to make sure that this timed out request, if it were in the - * pending queue, doesn't get submitted while we are here, from - * 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_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), - "Removing request from pending queue"); - /* - * Request was never submitted. Clean up. Note that we did - * not do a reset. So, we have to remove the request ourselves - * from the pending queue (as against tw_cli_drain_pendinq_queue - * taking care of it). - */ - tw_cli_req_q_remove_item(req, TW_CLI_PENDING_Q); - if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) == TW_CL_NULL) - TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, - TWA_CONTROL_MASK_COMMAND_INTERRUPT); - if (req->data) - ctlr->internal_req_busy = TW_CL_FALSE; - tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); - } - - return(TW_OSL_ETIMEDOUT); -} - -/* - * Function name: tw_cl_reset_ctlr - * Description: Soft resets and then initializes the controller; - * 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 - */ -TW_INT32 -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 = 0; - - tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "entered"); - - ctlr->reset_in_progress = TW_CL_TRUE; - twa_teardown_intr(sc); - - /* - * Error back all requests in the complete, busy, and pending queues. - * If any request is already on its way to getting submitted, it's in - * none of these queues and so, will not be completed. That request - * will continue its course and get submitted to the controller after - * the reset is done (and io_lock is released). - */ - tw_cli_drain_complete_queue(ctlr); - tw_cli_drain_busy_queue(ctlr); - tw_cli_drain_pending_queue(ctlr); - ctlr->internal_req_busy = TW_CL_FALSE; - ctlr->get_more_aens = TW_CL_FALSE; - - /* Soft reset the controller. */ - 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_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, - 0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING, - "Controller reset done!", " "); -#endif /* TW_OSL_DEBUG */ - break; - } /* End of while */ - - /* 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); - } - - 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. */ - 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); -} - -/* - * Function name: tw_cli_soft_reset - * Description: Does the actual soft reset. - * - * Input: ctlr -- ptr to per ctlr structure - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -TW_INT32 -tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) -{ - struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; - 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_FALSE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, - 0x1108, 0x3, TW_CL_SEVERITY_INFO_STRING, - "Resetting controller...", - " "); - - /* Don't let any new commands get submitted to the controller. */ - tw_osl_get_lock(ctlr_handle, ctlr->io_lock); - - TW_CLI_SOFT_RESET(ctlr_handle); - - if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_X) || - (ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || - (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) { - /* - * There's a hardware bug in the G133 ASIC, which can lead to - * PCI parity errors and hangs, if the host accesses any - * registers when the firmware is resetting the hardware, as - * part of a hard/soft reset. The window of time when the - * problem can occur is about 10 ms. Here, we will handshake - * with the firmware to find out when the firmware is pulling - * down the hardware reset pin, and wait for about 500 ms to - * make sure we don't access any hardware registers (for - * polling) during that window. - */ - ctlr->reset_phase1_in_progress = TW_CL_TRUE; - loop_count = 0; - do { - found = (tw_cli_find_response(ctlr, TWA_RESET_PHASE1_NOTIFICATION_RESPONSE) == TW_OSL_ESUCCESS); - tw_osl_delay(10); - loop_count++; - error = 0x7888; - } while (!found && (loop_count < 6000000)); /* Loop for no more than 60 seconds */ - - if (!found) { - 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", - "error = %d", error); - tw_osl_free_lock(ctlr_handle, ctlr->io_lock); - return(error); - } - - tw_osl_delay(TWA_RESET_PHASE1_WAIT_TIME_MS * 1000); - ctlr->reset_phase1_in_progress = TW_CL_FALSE; - } - - if ((error = tw_cli_poll_status(ctlr, - TWA_STATUS_MICROCONTROLLER_READY | - TWA_STATUS_ATTENTION_INTERRUPT, - TW_CLI_RESET_TIMEOUT_PERIOD))) { - 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", - "error = %d", error); - tw_osl_free_lock(ctlr_handle, ctlr->io_lock); - return(error); - } - - TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, - TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT); - - if ((error = tw_cli_drain_response_queue(ctlr))) { - tw_cl_create_event(ctlr_handle, TW_CL_FALSE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, - 0x110A, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Can't drain response queue after reset", - "error = %d", error); - tw_osl_free_lock(ctlr_handle, ctlr->io_lock); - return(error); - } - - tw_osl_free_lock(ctlr_handle, ctlr->io_lock); - - if ((error = tw_cli_drain_aen_queue(ctlr))) { - tw_cl_create_event(ctlr_handle, TW_CL_FALSE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, - 0x110B, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Can't drain AEN queue after reset", - "error = %d", error); - return(error); - } - - if ((error = tw_cli_find_aen(ctlr, TWA_AEN_SOFT_RESET))) { - 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); - } - - return(TW_OSL_ESUCCESS); -} - -/* - * Function name: tw_cli_send_scsi_cmd - * Description: Sends down a scsi cmd to fw. - * - * Input: req -- ptr to request pkt - * cmd -- opcode of scsi cmd to send - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -TW_INT32 -tw_cli_send_scsi_cmd(struct tw_cli_req_context *req, TW_INT32 cmd) -{ - struct tw_cl_command_packet *cmdpkt; - struct tw_cl_command_9k *cmd9k; - struct tw_cli_ctlr_context *ctlr; - TW_INT32 error; - - ctlr = req->ctlr; - tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); - - /* Make sure this is the only CL internal request at this time. */ - if (ctlr->internal_req_busy) - return(TW_OSL_EBUSY); - ctlr->internal_req_busy = TW_CL_TRUE; - req->data = ctlr->internal_req_data; - req->data_phys = ctlr->internal_req_data_phys; - tw_osl_memzero(req->data, TW_CLI_SECTOR_SIZE); - req->length = TW_CLI_SECTOR_SIZE; - - /* Build the cmd pkt. */ - cmdpkt = req->cmd_pkt; - - cmdpkt->cmd_hdr.header_desc.size_header = 128; - - cmd9k = &(cmdpkt->command.cmd_pkt_9k); - - cmd9k->res__opcode = - BUILD_RES__OPCODE(0, TWA_FW_CMD_EXECUTE_SCSI); - cmd9k->unit = 0; - cmd9k->lun_l4__req_id = TW_CL_SWAP16(req->request_id); - cmd9k->status = 0; - cmd9k->sgl_offset = 16; /* offset from end of hdr = max cdb len */ - cmd9k->lun_h4__sgl_entries = TW_CL_SWAP16(1); - - if (req->ctlr->flags & TW_CL_64BIT_ADDRESSES) { - ((struct tw_cl_sg_desc64 *)(cmd9k->sg_list))[0].address = - TW_CL_SWAP64(req->data_phys); - ((struct tw_cl_sg_desc64 *)(cmd9k->sg_list))[0].length = - TW_CL_SWAP32(req->length); - } else { - ((struct tw_cl_sg_desc32 *)(cmd9k->sg_list))[0].address = - TW_CL_SWAP32(req->data_phys); - ((struct tw_cl_sg_desc32 *)(cmd9k->sg_list))[0].length = - TW_CL_SWAP32(req->length); - } - - cmd9k->cdb[0] = (TW_UINT8)cmd; - cmd9k->cdb[4] = 128; - - if ((error = tw_cli_submit_cmd(req))) - if (error != TW_OSL_EBUSY) { - tw_cli_dbg_printf(1, ctlr->ctlr_handle, - tw_osl_cur_func(), - "Failed to start SCSI command", - "request = %p, error = %d", req, error); - return(TW_OSL_EIO); - } - return(TW_OSL_ESUCCESS); -} - -/* - * Function name: tw_cli_get_aen - * Description: Sends down a Request Sense cmd to fw to fetch an AEN. - * - * Input: ctlr -- ptr to per ctlr structure - * Output: None - * Return value: 0 -- success - * non-zero-- failure - */ -TW_INT32 -tw_cli_get_aen(struct tw_cli_ctlr_context *ctlr) -{ - struct tw_cli_req_context *req; - TW_INT32 error; - - tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); - - if ((req = tw_cli_get_request(ctlr - )) == TW_CL_NULL) - return(TW_OSL_EBUSY); - - req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; - req->flags |= TW_CLI_REQ_FLAGS_9K; - req->tw_cli_callback = tw_cli_aen_callback; - if ((error = tw_cli_send_scsi_cmd(req, 0x03 /* REQUEST_SENSE */))) { - tw_cli_dbg_printf(1, ctlr->ctlr_handle, tw_osl_cur_func(), - "Could not send SCSI command", - "request = %p, error = %d", req, error); - if (req->data) - ctlr->internal_req_busy = TW_CL_FALSE; - tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); - } - return(error); -} - -/* - * Function name: tw_cli_fill_sg_list - * Description: Fills in the scatter/gather list. - * - * Input: ctlr -- ptr to per ctlr structure - * sgl_src -- ptr to fill the sg list from - * sgl_dest-- ptr to sg list - * nsegments--# of segments - * Output: None - * Return value: None - */ -TW_VOID -tw_cli_fill_sg_list(struct tw_cli_ctlr_context *ctlr, TW_VOID *sgl_src, - TW_VOID *sgl_dest, TW_INT32 num_sgl_entries) -{ - TW_INT32 i; - - tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); - - if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { - struct tw_cl_sg_desc64 *sgl_s = - (struct tw_cl_sg_desc64 *)sgl_src; - struct tw_cl_sg_desc64 *sgl_d = - (struct tw_cl_sg_desc64 *)sgl_dest; - - tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), - "64 bit addresses"); - for (i = 0; i < num_sgl_entries; i++) { - sgl_d[i].address = TW_CL_SWAP64(sgl_s->address); - sgl_d[i].length = TW_CL_SWAP32(sgl_s->length); - sgl_s++; - if (ctlr->flags & TW_CL_64BIT_SG_LENGTH) - sgl_s = (struct tw_cl_sg_desc64 *) - (((TW_INT8 *)(sgl_s)) + 4); - } - } else { - struct tw_cl_sg_desc32 *sgl_s = - (struct tw_cl_sg_desc32 *)sgl_src; - struct tw_cl_sg_desc32 *sgl_d = - (struct tw_cl_sg_desc32 *)sgl_dest; - - tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), - "32 bit addresses"); - for (i = 0; i < num_sgl_entries; i++) { - sgl_d[i].address = TW_CL_SWAP32(sgl_s[i].address); - sgl_d[i].length = TW_CL_SWAP32(sgl_s[i].length); - } - } -} |