1*df54c2f9SSascha Wildner /* 2*df54c2f9SSascha Wildner * Copyright (c) 2004-07 Applied Micro Circuits Corporation. 3*df54c2f9SSascha Wildner * Copyright (c) 2004-05 Vinod Kashyap 4*df54c2f9SSascha Wildner * All rights reserved. 5*df54c2f9SSascha Wildner * 6*df54c2f9SSascha Wildner * Redistribution and use in source and binary forms, with or without 7*df54c2f9SSascha Wildner * modification, are permitted provided that the following conditions 8*df54c2f9SSascha Wildner * are met: 9*df54c2f9SSascha Wildner * 1. Redistributions of source code must retain the above copyright 10*df54c2f9SSascha Wildner * notice, this list of conditions and the following disclaimer. 11*df54c2f9SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 12*df54c2f9SSascha Wildner * notice, this list of conditions and the following disclaimer in the 13*df54c2f9SSascha Wildner * documentation and/or other materials provided with the distribution. 14*df54c2f9SSascha Wildner * 15*df54c2f9SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*df54c2f9SSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*df54c2f9SSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*df54c2f9SSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*df54c2f9SSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*df54c2f9SSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*df54c2f9SSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*df54c2f9SSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*df54c2f9SSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*df54c2f9SSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*df54c2f9SSascha Wildner * SUCH DAMAGE. 26*df54c2f9SSascha Wildner * 27*df54c2f9SSascha Wildner * $FreeBSD: src/sys/dev/twa/tw_cl_io.c,v 1.6 2010/06/09 21:40:38 delphij Exp $ 28*df54c2f9SSascha Wildner */ 29*df54c2f9SSascha Wildner 30*df54c2f9SSascha Wildner /* 31*df54c2f9SSascha Wildner * AMCC'S 3ware driver for 9000 series storage controllers. 32*df54c2f9SSascha Wildner * 33*df54c2f9SSascha Wildner * Author: Vinod Kashyap 34*df54c2f9SSascha Wildner * Modifications by: Adam Radford 35*df54c2f9SSascha Wildner * Modifications by: Manjunath Ranganathaiah 36*df54c2f9SSascha Wildner */ 37*df54c2f9SSascha Wildner 38*df54c2f9SSascha Wildner 39*df54c2f9SSascha Wildner /* 40*df54c2f9SSascha Wildner * Common Layer I/O functions. 41*df54c2f9SSascha Wildner */ 42*df54c2f9SSascha Wildner 43*df54c2f9SSascha Wildner 44*df54c2f9SSascha Wildner #include "tw_osl_share.h" 45*df54c2f9SSascha Wildner #include "tw_cl_share.h" 46*df54c2f9SSascha Wildner #include "tw_cl_fwif.h" 47*df54c2f9SSascha Wildner #include "tw_cl_ioctl.h" 48*df54c2f9SSascha Wildner #include "tw_cl.h" 49*df54c2f9SSascha Wildner #include "tw_cl_externs.h" 50*df54c2f9SSascha Wildner #include "tw_osl_ioctl.h" 51*df54c2f9SSascha Wildner 52*df54c2f9SSascha Wildner #include <bus/cam/cam.h> 53*df54c2f9SSascha Wildner #include <bus/cam/cam_ccb.h> 54*df54c2f9SSascha Wildner #include <bus/cam/cam_xpt_sim.h> 55*df54c2f9SSascha Wildner 56*df54c2f9SSascha Wildner 57*df54c2f9SSascha Wildner 58*df54c2f9SSascha Wildner /* 59*df54c2f9SSascha Wildner * Function name: tw_cl_start_io 60*df54c2f9SSascha Wildner * Description: Interface to OS Layer for accepting SCSI requests. 61*df54c2f9SSascha Wildner * 62*df54c2f9SSascha Wildner * Input: ctlr_handle -- controller handle 63*df54c2f9SSascha Wildner * req_pkt -- OSL built request packet 64*df54c2f9SSascha Wildner * req_handle -- request handle 65*df54c2f9SSascha Wildner * Output: None 66*df54c2f9SSascha Wildner * Return value: 0 -- success 67*df54c2f9SSascha Wildner * non-zero-- failure 68*df54c2f9SSascha Wildner */ 69*df54c2f9SSascha Wildner TW_INT32 70*df54c2f9SSascha Wildner tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle, 71*df54c2f9SSascha Wildner struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle) 72*df54c2f9SSascha Wildner { 73*df54c2f9SSascha Wildner struct tw_cli_ctlr_context *ctlr; 74*df54c2f9SSascha Wildner struct tw_cli_req_context *req; 75*df54c2f9SSascha Wildner struct tw_cl_command_9k *cmd; 76*df54c2f9SSascha Wildner struct tw_cl_scsi_req_packet *scsi_req; 77*df54c2f9SSascha Wildner TW_INT32 error; 78*df54c2f9SSascha Wildner 79*df54c2f9SSascha Wildner tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); 80*df54c2f9SSascha Wildner 81*df54c2f9SSascha Wildner ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 82*df54c2f9SSascha Wildner 83*df54c2f9SSascha Wildner if (ctlr->reset_in_progress) { 84*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 85*df54c2f9SSascha Wildner "I/O during reset: returning busy."); 86*df54c2f9SSascha Wildner return(TW_OSL_EBUSY); 87*df54c2f9SSascha Wildner } 88*df54c2f9SSascha Wildner 89*df54c2f9SSascha Wildner /* 90*df54c2f9SSascha Wildner * If working with a firmware version that does not support multiple 91*df54c2f9SSascha Wildner * luns, and this request is directed at a non-zero lun, error it 92*df54c2f9SSascha Wildner * back right away. 93*df54c2f9SSascha Wildner */ 94*df54c2f9SSascha Wildner if ((req_pkt->gen_req_pkt.scsi_req.lun) && 95*df54c2f9SSascha Wildner (ctlr->working_srl < TWA_MULTI_LUN_FW_SRL)) { 96*df54c2f9SSascha Wildner req_pkt->status |= (TW_CL_ERR_REQ_INVALID_LUN | 97*df54c2f9SSascha Wildner TW_CL_ERR_REQ_SCSI_ERROR); 98*df54c2f9SSascha Wildner req_pkt->tw_osl_callback(req_handle); 99*df54c2f9SSascha Wildner return(TW_CL_ERR_REQ_SUCCESS); 100*df54c2f9SSascha Wildner } 101*df54c2f9SSascha Wildner 102*df54c2f9SSascha Wildner if ((req = tw_cli_get_request(ctlr 103*df54c2f9SSascha Wildner )) == TW_CL_NULL) { 104*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 105*df54c2f9SSascha Wildner "Out of request context packets: returning busy"); 106*df54c2f9SSascha Wildner return(TW_OSL_EBUSY); 107*df54c2f9SSascha Wildner } 108*df54c2f9SSascha Wildner 109*df54c2f9SSascha Wildner req_handle->cl_req_ctxt = req; 110*df54c2f9SSascha Wildner req->req_handle = req_handle; 111*df54c2f9SSascha Wildner req->orig_req = req_pkt; 112*df54c2f9SSascha Wildner req->tw_cli_callback = tw_cli_complete_io; 113*df54c2f9SSascha Wildner 114*df54c2f9SSascha Wildner req->flags |= TW_CLI_REQ_FLAGS_EXTERNAL; 115*df54c2f9SSascha Wildner req->flags |= TW_CLI_REQ_FLAGS_9K; 116*df54c2f9SSascha Wildner 117*df54c2f9SSascha Wildner scsi_req = &(req_pkt->gen_req_pkt.scsi_req); 118*df54c2f9SSascha Wildner 119*df54c2f9SSascha Wildner /* Build the cmd pkt. */ 120*df54c2f9SSascha Wildner cmd = &(req->cmd_pkt->command.cmd_pkt_9k); 121*df54c2f9SSascha Wildner 122*df54c2f9SSascha Wildner req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; 123*df54c2f9SSascha Wildner 124*df54c2f9SSascha Wildner cmd->res__opcode = BUILD_RES__OPCODE(0, TWA_FW_CMD_EXECUTE_SCSI); 125*df54c2f9SSascha Wildner cmd->unit = (TW_UINT8)(scsi_req->unit); 126*df54c2f9SSascha Wildner cmd->lun_l4__req_id = TW_CL_SWAP16( 127*df54c2f9SSascha Wildner BUILD_LUN_L4__REQ_ID(scsi_req->lun, req->request_id)); 128*df54c2f9SSascha Wildner cmd->status = 0; 129*df54c2f9SSascha Wildner cmd->sgl_offset = 16; /* offset from end of hdr = max cdb len */ 130*df54c2f9SSascha Wildner tw_osl_memcpy(cmd->cdb, scsi_req->cdb, scsi_req->cdb_len); 131*df54c2f9SSascha Wildner 132*df54c2f9SSascha Wildner if (req_pkt->flags & TW_CL_REQ_CALLBACK_FOR_SGLIST) { 133*df54c2f9SSascha Wildner TW_UINT32 num_sgl_entries; 134*df54c2f9SSascha Wildner 135*df54c2f9SSascha Wildner req_pkt->tw_osl_sgl_callback(req_handle, cmd->sg_list, 136*df54c2f9SSascha Wildner &num_sgl_entries); 137*df54c2f9SSascha Wildner cmd->lun_h4__sgl_entries = 138*df54c2f9SSascha Wildner TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun, 139*df54c2f9SSascha Wildner num_sgl_entries)); 140*df54c2f9SSascha Wildner } else { 141*df54c2f9SSascha Wildner cmd->lun_h4__sgl_entries = 142*df54c2f9SSascha Wildner TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun, 143*df54c2f9SSascha Wildner scsi_req->sgl_entries)); 144*df54c2f9SSascha Wildner tw_cli_fill_sg_list(ctlr, scsi_req->sg_list, 145*df54c2f9SSascha Wildner cmd->sg_list, scsi_req->sgl_entries); 146*df54c2f9SSascha Wildner } 147*df54c2f9SSascha Wildner 148*df54c2f9SSascha Wildner if ((error = tw_cli_submit_cmd(req))) { 149*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 150*df54c2f9SSascha Wildner "Could not start request. request = %p, error = %d", 151*df54c2f9SSascha Wildner req, error); 152*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 153*df54c2f9SSascha Wildner } 154*df54c2f9SSascha Wildner return(error); 155*df54c2f9SSascha Wildner } 156*df54c2f9SSascha Wildner 157*df54c2f9SSascha Wildner 158*df54c2f9SSascha Wildner 159*df54c2f9SSascha Wildner /* 160*df54c2f9SSascha Wildner * Function name: tw_cli_submit_cmd 161*df54c2f9SSascha Wildner * Description: Submits a cmd to firmware. 162*df54c2f9SSascha Wildner * 163*df54c2f9SSascha Wildner * Input: req -- ptr to CL internal request context 164*df54c2f9SSascha Wildner * Output: None 165*df54c2f9SSascha Wildner * Return value: 0 -- success 166*df54c2f9SSascha Wildner * non-zero-- failure 167*df54c2f9SSascha Wildner */ 168*df54c2f9SSascha Wildner TW_INT32 169*df54c2f9SSascha Wildner tw_cli_submit_cmd(struct tw_cli_req_context *req) 170*df54c2f9SSascha Wildner { 171*df54c2f9SSascha Wildner struct tw_cli_ctlr_context *ctlr = req->ctlr; 172*df54c2f9SSascha Wildner struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; 173*df54c2f9SSascha Wildner TW_UINT32 status_reg; 174*df54c2f9SSascha Wildner TW_INT32 error; 175*df54c2f9SSascha Wildner 176*df54c2f9SSascha Wildner tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); 177*df54c2f9SSascha Wildner 178*df54c2f9SSascha Wildner /* Serialize access to the controller cmd queue. */ 179*df54c2f9SSascha Wildner tw_osl_get_lock(ctlr_handle, ctlr->io_lock); 180*df54c2f9SSascha Wildner 181*df54c2f9SSascha Wildner /* For 9650SE first write low 4 bytes */ 182*df54c2f9SSascha Wildner if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || 183*df54c2f9SSascha Wildner (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) 184*df54c2f9SSascha Wildner tw_osl_write_reg(ctlr_handle, 185*df54c2f9SSascha Wildner TWA_COMMAND_QUEUE_OFFSET_LOW, 186*df54c2f9SSascha Wildner (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); 187*df54c2f9SSascha Wildner 188*df54c2f9SSascha Wildner /* Check to see if we can post a command. */ 189*df54c2f9SSascha Wildner status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); 190*df54c2f9SSascha Wildner if ((error = tw_cli_check_ctlr_state(ctlr, status_reg))) 191*df54c2f9SSascha Wildner goto out; 192*df54c2f9SSascha Wildner 193*df54c2f9SSascha Wildner if (status_reg & TWA_STATUS_COMMAND_QUEUE_FULL) { 194*df54c2f9SSascha Wildner struct tw_cl_req_packet *req_pkt = 195*df54c2f9SSascha Wildner (struct tw_cl_req_packet *)(req->orig_req); 196*df54c2f9SSascha Wildner 197*df54c2f9SSascha Wildner tw_cli_dbg_printf(7, ctlr_handle, tw_osl_cur_func(), 198*df54c2f9SSascha Wildner "Cmd queue full"); 199*df54c2f9SSascha Wildner 200*df54c2f9SSascha Wildner if ((req->flags & TW_CLI_REQ_FLAGS_INTERNAL) 201*df54c2f9SSascha Wildner || ((req_pkt) && 202*df54c2f9SSascha Wildner (req_pkt->flags & TW_CL_REQ_RETRY_ON_BUSY)) 203*df54c2f9SSascha Wildner ) { 204*df54c2f9SSascha Wildner if (req->state != TW_CLI_REQ_STATE_PENDING) { 205*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, 206*df54c2f9SSascha Wildner tw_osl_cur_func(), 207*df54c2f9SSascha Wildner "pending internal/ioctl request"); 208*df54c2f9SSascha Wildner req->state = TW_CLI_REQ_STATE_PENDING; 209*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); 210*df54c2f9SSascha Wildner error = 0; 211*df54c2f9SSascha Wildner /* Unmask command interrupt. */ 212*df54c2f9SSascha Wildner TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 213*df54c2f9SSascha Wildner TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); 214*df54c2f9SSascha Wildner } else 215*df54c2f9SSascha Wildner error = TW_OSL_EBUSY; 216*df54c2f9SSascha Wildner } else { 217*df54c2f9SSascha Wildner tw_osl_ctlr_busy(ctlr_handle, req->req_handle); 218*df54c2f9SSascha Wildner error = TW_OSL_EBUSY; 219*df54c2f9SSascha Wildner } 220*df54c2f9SSascha Wildner } else { 221*df54c2f9SSascha Wildner tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), 222*df54c2f9SSascha Wildner "Submitting command"); 223*df54c2f9SSascha Wildner 224*df54c2f9SSascha Wildner /* Insert command into busy queue */ 225*df54c2f9SSascha Wildner req->state = TW_CLI_REQ_STATE_BUSY; 226*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_BUSY_Q); 227*df54c2f9SSascha Wildner 228*df54c2f9SSascha Wildner if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || 229*df54c2f9SSascha Wildner (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) { 230*df54c2f9SSascha Wildner /* Now write the high 4 bytes */ 231*df54c2f9SSascha Wildner tw_osl_write_reg(ctlr_handle, 232*df54c2f9SSascha Wildner TWA_COMMAND_QUEUE_OFFSET_HIGH, 233*df54c2f9SSascha Wildner (TW_UINT32)(((TW_UINT64)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)))>>32), 4); 234*df54c2f9SSascha Wildner } else { 235*df54c2f9SSascha Wildner if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 236*df54c2f9SSascha Wildner /* First write the low 4 bytes, then the high 4. */ 237*df54c2f9SSascha Wildner tw_osl_write_reg(ctlr_handle, 238*df54c2f9SSascha Wildner TWA_COMMAND_QUEUE_OFFSET_LOW, 239*df54c2f9SSascha Wildner (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); 240*df54c2f9SSascha Wildner tw_osl_write_reg(ctlr_handle, 241*df54c2f9SSascha Wildner TWA_COMMAND_QUEUE_OFFSET_HIGH, 242*df54c2f9SSascha Wildner (TW_UINT32)(((TW_UINT64)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)))>>32), 4); 243*df54c2f9SSascha Wildner } else 244*df54c2f9SSascha Wildner tw_osl_write_reg(ctlr_handle, 245*df54c2f9SSascha Wildner TWA_COMMAND_QUEUE_OFFSET, 246*df54c2f9SSascha Wildner (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); 247*df54c2f9SSascha Wildner } 248*df54c2f9SSascha Wildner } 249*df54c2f9SSascha Wildner out: 250*df54c2f9SSascha Wildner tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 251*df54c2f9SSascha Wildner 252*df54c2f9SSascha Wildner return(error); 253*df54c2f9SSascha Wildner } 254*df54c2f9SSascha Wildner 255*df54c2f9SSascha Wildner 256*df54c2f9SSascha Wildner 257*df54c2f9SSascha Wildner /* 258*df54c2f9SSascha Wildner * Function name: tw_cl_fw_passthru 259*df54c2f9SSascha Wildner * Description: Interface to OS Layer for accepting firmware 260*df54c2f9SSascha Wildner * passthru requests. 261*df54c2f9SSascha Wildner * Input: ctlr_handle -- controller handle 262*df54c2f9SSascha Wildner * req_pkt -- OSL built request packet 263*df54c2f9SSascha Wildner * req_handle -- request handle 264*df54c2f9SSascha Wildner * Output: None 265*df54c2f9SSascha Wildner * Return value: 0 -- success 266*df54c2f9SSascha Wildner * non-zero-- failure 267*df54c2f9SSascha Wildner */ 268*df54c2f9SSascha Wildner TW_INT32 269*df54c2f9SSascha Wildner tw_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle, 270*df54c2f9SSascha Wildner struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle) 271*df54c2f9SSascha Wildner { 272*df54c2f9SSascha Wildner struct tw_cli_ctlr_context *ctlr; 273*df54c2f9SSascha Wildner struct tw_cli_req_context *req; 274*df54c2f9SSascha Wildner union tw_cl_command_7k *cmd_7k; 275*df54c2f9SSascha Wildner struct tw_cl_command_9k *cmd_9k; 276*df54c2f9SSascha Wildner struct tw_cl_passthru_req_packet *pt_req; 277*df54c2f9SSascha Wildner TW_UINT8 opcode; 278*df54c2f9SSascha Wildner TW_UINT8 sgl_offset; 279*df54c2f9SSascha Wildner TW_VOID *sgl = TW_CL_NULL; 280*df54c2f9SSascha Wildner TW_INT32 error; 281*df54c2f9SSascha Wildner 282*df54c2f9SSascha Wildner tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered"); 283*df54c2f9SSascha Wildner 284*df54c2f9SSascha Wildner ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 285*df54c2f9SSascha Wildner 286*df54c2f9SSascha Wildner if (ctlr->reset_in_progress) { 287*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 288*df54c2f9SSascha Wildner "Passthru request during reset: returning busy."); 289*df54c2f9SSascha Wildner return(TW_OSL_EBUSY); 290*df54c2f9SSascha Wildner } 291*df54c2f9SSascha Wildner 292*df54c2f9SSascha Wildner if ((req = tw_cli_get_request(ctlr 293*df54c2f9SSascha Wildner )) == TW_CL_NULL) { 294*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 295*df54c2f9SSascha Wildner "Out of request context packets: returning busy"); 296*df54c2f9SSascha Wildner return(TW_OSL_EBUSY); 297*df54c2f9SSascha Wildner } 298*df54c2f9SSascha Wildner 299*df54c2f9SSascha Wildner req_handle->cl_req_ctxt = req; 300*df54c2f9SSascha Wildner req->req_handle = req_handle; 301*df54c2f9SSascha Wildner req->orig_req = req_pkt; 302*df54c2f9SSascha Wildner req->tw_cli_callback = tw_cli_complete_io; 303*df54c2f9SSascha Wildner 304*df54c2f9SSascha Wildner req->flags |= (TW_CLI_REQ_FLAGS_EXTERNAL | TW_CLI_REQ_FLAGS_PASSTHRU); 305*df54c2f9SSascha Wildner 306*df54c2f9SSascha Wildner pt_req = &(req_pkt->gen_req_pkt.pt_req); 307*df54c2f9SSascha Wildner 308*df54c2f9SSascha Wildner tw_osl_memcpy(req->cmd_pkt, pt_req->cmd_pkt, 309*df54c2f9SSascha Wildner pt_req->cmd_pkt_length); 310*df54c2f9SSascha Wildner /* Build the cmd pkt. */ 311*df54c2f9SSascha Wildner if ((opcode = GET_OPCODE(((TW_UINT8 *) 312*df54c2f9SSascha Wildner (pt_req->cmd_pkt))[sizeof(struct tw_cl_command_header)])) 313*df54c2f9SSascha Wildner == TWA_FW_CMD_EXECUTE_SCSI) { 314*df54c2f9SSascha Wildner TW_UINT16 lun_l4, lun_h4; 315*df54c2f9SSascha Wildner 316*df54c2f9SSascha Wildner tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), 317*df54c2f9SSascha Wildner "passthru: 9k cmd pkt"); 318*df54c2f9SSascha Wildner req->flags |= TW_CLI_REQ_FLAGS_9K; 319*df54c2f9SSascha Wildner cmd_9k = &(req->cmd_pkt->command.cmd_pkt_9k); 320*df54c2f9SSascha Wildner lun_l4 = GET_LUN_L4(cmd_9k->lun_l4__req_id); 321*df54c2f9SSascha Wildner lun_h4 = GET_LUN_H4(cmd_9k->lun_h4__sgl_entries); 322*df54c2f9SSascha Wildner cmd_9k->lun_l4__req_id = TW_CL_SWAP16( 323*df54c2f9SSascha Wildner BUILD_LUN_L4__REQ_ID(lun_l4, req->request_id)); 324*df54c2f9SSascha Wildner if (pt_req->sgl_entries) { 325*df54c2f9SSascha Wildner cmd_9k->lun_h4__sgl_entries = 326*df54c2f9SSascha Wildner TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(lun_h4, 327*df54c2f9SSascha Wildner pt_req->sgl_entries)); 328*df54c2f9SSascha Wildner sgl = (TW_VOID *)(cmd_9k->sg_list); 329*df54c2f9SSascha Wildner } 330*df54c2f9SSascha Wildner } else { 331*df54c2f9SSascha Wildner tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), 332*df54c2f9SSascha Wildner "passthru: 7k cmd pkt"); 333*df54c2f9SSascha Wildner cmd_7k = &(req->cmd_pkt->command.cmd_pkt_7k); 334*df54c2f9SSascha Wildner cmd_7k->generic.request_id = 335*df54c2f9SSascha Wildner (TW_UINT8)(TW_CL_SWAP16(req->request_id)); 336*df54c2f9SSascha Wildner if ((sgl_offset = 337*df54c2f9SSascha Wildner GET_SGL_OFF(cmd_7k->generic.sgl_off__opcode))) { 338*df54c2f9SSascha Wildner if (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA) 339*df54c2f9SSascha Wildner sgl = (((TW_UINT32 *)cmd_7k) + cmd_7k->generic.size); 340*df54c2f9SSascha Wildner else 341*df54c2f9SSascha Wildner sgl = (((TW_UINT32 *)cmd_7k) + sgl_offset); 342*df54c2f9SSascha Wildner cmd_7k->generic.size += pt_req->sgl_entries * 343*df54c2f9SSascha Wildner ((ctlr->flags & TW_CL_64BIT_ADDRESSES) ? 3 : 2); 344*df54c2f9SSascha Wildner } 345*df54c2f9SSascha Wildner } 346*df54c2f9SSascha Wildner 347*df54c2f9SSascha Wildner if (sgl) 348*df54c2f9SSascha Wildner tw_cli_fill_sg_list(ctlr, pt_req->sg_list, 349*df54c2f9SSascha Wildner sgl, pt_req->sgl_entries); 350*df54c2f9SSascha Wildner 351*df54c2f9SSascha Wildner if ((error = tw_cli_submit_cmd(req))) { 352*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 353*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 354*df54c2f9SSascha Wildner 0x1100, 0x1, TW_CL_SEVERITY_ERROR_STRING, 355*df54c2f9SSascha Wildner "Failed to start passthru command", 356*df54c2f9SSascha Wildner "error = %d", error); 357*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 358*df54c2f9SSascha Wildner } 359*df54c2f9SSascha Wildner return(error); 360*df54c2f9SSascha Wildner } 361*df54c2f9SSascha Wildner 362*df54c2f9SSascha Wildner 363*df54c2f9SSascha Wildner 364*df54c2f9SSascha Wildner /* 365*df54c2f9SSascha Wildner * Function name: tw_cl_ioctl 366*df54c2f9SSascha Wildner * Description: Handler of CL supported ioctl cmds. 367*df54c2f9SSascha Wildner * 368*df54c2f9SSascha Wildner * Input: ctlr -- ptr to per ctlr structure 369*df54c2f9SSascha Wildner * cmd -- ioctl cmd 370*df54c2f9SSascha Wildner * buf -- ptr to buffer in kernel memory, which is 371*df54c2f9SSascha Wildner * a copy of the input buffer in user-space 372*df54c2f9SSascha Wildner * Output: buf -- ptr to buffer in kernel memory, which will 373*df54c2f9SSascha Wildner * need to be copied to the output buffer in 374*df54c2f9SSascha Wildner * user-space 375*df54c2f9SSascha Wildner * Return value: 0 -- success 376*df54c2f9SSascha Wildner * non-zero-- failure 377*df54c2f9SSascha Wildner */ 378*df54c2f9SSascha Wildner TW_INT32 379*df54c2f9SSascha Wildner tw_cl_ioctl(struct tw_cl_ctlr_handle *ctlr_handle, u_long cmd, TW_VOID *buf) 380*df54c2f9SSascha Wildner { 381*df54c2f9SSascha Wildner struct tw_cli_ctlr_context *ctlr = 382*df54c2f9SSascha Wildner (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 383*df54c2f9SSascha Wildner struct tw_cl_ioctl_packet *user_buf = 384*df54c2f9SSascha Wildner (struct tw_cl_ioctl_packet *)buf; 385*df54c2f9SSascha Wildner struct tw_cl_event_packet event_buf; 386*df54c2f9SSascha Wildner TW_INT32 event_index; 387*df54c2f9SSascha Wildner TW_INT32 start_index; 388*df54c2f9SSascha Wildner TW_INT32 error = TW_OSL_ESUCCESS; 389*df54c2f9SSascha Wildner 390*df54c2f9SSascha Wildner tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered"); 391*df54c2f9SSascha Wildner 392*df54c2f9SSascha Wildner /* Serialize access to the AEN queue and the ioctl lock. */ 393*df54c2f9SSascha Wildner tw_osl_get_lock(ctlr_handle, ctlr->gen_lock); 394*df54c2f9SSascha Wildner 395*df54c2f9SSascha Wildner switch (cmd) { 396*df54c2f9SSascha Wildner case TW_CL_IOCTL_GET_FIRST_EVENT: 397*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 398*df54c2f9SSascha Wildner "Get First Event"); 399*df54c2f9SSascha Wildner 400*df54c2f9SSascha Wildner if (ctlr->aen_q_wrapped) { 401*df54c2f9SSascha Wildner if (ctlr->aen_q_overflow) { 402*df54c2f9SSascha Wildner /* 403*df54c2f9SSascha Wildner * The aen queue has wrapped, even before some 404*df54c2f9SSascha Wildner * events have been retrieved. Let the caller 405*df54c2f9SSascha Wildner * know that he missed out on some AEN's. 406*df54c2f9SSascha Wildner */ 407*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 408*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_OVERFLOW; 409*df54c2f9SSascha Wildner ctlr->aen_q_overflow = TW_CL_FALSE; 410*df54c2f9SSascha Wildner } else 411*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 0; 412*df54c2f9SSascha Wildner event_index = ctlr->aen_head; 413*df54c2f9SSascha Wildner } else { 414*df54c2f9SSascha Wildner if (ctlr->aen_head == ctlr->aen_tail) { 415*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 416*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_NO_EVENTS; 417*df54c2f9SSascha Wildner break; 418*df54c2f9SSascha Wildner } 419*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 0; 420*df54c2f9SSascha Wildner event_index = ctlr->aen_tail; /* = 0 */ 421*df54c2f9SSascha Wildner } 422*df54c2f9SSascha Wildner tw_osl_memcpy(user_buf->data_buf, 423*df54c2f9SSascha Wildner &(ctlr->aen_queue[event_index]), 424*df54c2f9SSascha Wildner sizeof(struct tw_cl_event_packet)); 425*df54c2f9SSascha Wildner 426*df54c2f9SSascha Wildner ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; 427*df54c2f9SSascha Wildner 428*df54c2f9SSascha Wildner break; 429*df54c2f9SSascha Wildner 430*df54c2f9SSascha Wildner 431*df54c2f9SSascha Wildner case TW_CL_IOCTL_GET_LAST_EVENT: 432*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 433*df54c2f9SSascha Wildner "Get Last Event"); 434*df54c2f9SSascha Wildner 435*df54c2f9SSascha Wildner if (ctlr->aen_q_wrapped) { 436*df54c2f9SSascha Wildner if (ctlr->aen_q_overflow) { 437*df54c2f9SSascha Wildner /* 438*df54c2f9SSascha Wildner * The aen queue has wrapped, even before some 439*df54c2f9SSascha Wildner * events have been retrieved. Let the caller 440*df54c2f9SSascha Wildner * know that he missed out on some AEN's. 441*df54c2f9SSascha Wildner */ 442*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 443*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_OVERFLOW; 444*df54c2f9SSascha Wildner ctlr->aen_q_overflow = TW_CL_FALSE; 445*df54c2f9SSascha Wildner } else 446*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 0; 447*df54c2f9SSascha Wildner } else { 448*df54c2f9SSascha Wildner if (ctlr->aen_head == ctlr->aen_tail) { 449*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 450*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_NO_EVENTS; 451*df54c2f9SSascha Wildner break; 452*df54c2f9SSascha Wildner } 453*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 0; 454*df54c2f9SSascha Wildner } 455*df54c2f9SSascha Wildner event_index = (ctlr->aen_head - 1 + ctlr->max_aens_supported) % 456*df54c2f9SSascha Wildner ctlr->max_aens_supported; 457*df54c2f9SSascha Wildner 458*df54c2f9SSascha Wildner tw_osl_memcpy(user_buf->data_buf, 459*df54c2f9SSascha Wildner &(ctlr->aen_queue[event_index]), 460*df54c2f9SSascha Wildner sizeof(struct tw_cl_event_packet)); 461*df54c2f9SSascha Wildner 462*df54c2f9SSascha Wildner ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; 463*df54c2f9SSascha Wildner 464*df54c2f9SSascha Wildner break; 465*df54c2f9SSascha Wildner 466*df54c2f9SSascha Wildner 467*df54c2f9SSascha Wildner case TW_CL_IOCTL_GET_NEXT_EVENT: 468*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 469*df54c2f9SSascha Wildner "Get Next Event"); 470*df54c2f9SSascha Wildner 471*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 0; 472*df54c2f9SSascha Wildner if (ctlr->aen_q_wrapped) { 473*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 474*df54c2f9SSascha Wildner "Get Next Event: wrapped"); 475*df54c2f9SSascha Wildner if (ctlr->aen_q_overflow) { 476*df54c2f9SSascha Wildner /* 477*df54c2f9SSascha Wildner * The aen queue has wrapped, even before some 478*df54c2f9SSascha Wildner * events have been retrieved. Let the caller 479*df54c2f9SSascha Wildner * know that he missed out on some AEN's. 480*df54c2f9SSascha Wildner */ 481*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, 482*df54c2f9SSascha Wildner tw_osl_cur_func(), 483*df54c2f9SSascha Wildner "Get Next Event: overflow"); 484*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 485*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_OVERFLOW; 486*df54c2f9SSascha Wildner ctlr->aen_q_overflow = TW_CL_FALSE; 487*df54c2f9SSascha Wildner } 488*df54c2f9SSascha Wildner start_index = ctlr->aen_head; 489*df54c2f9SSascha Wildner } else { 490*df54c2f9SSascha Wildner if (ctlr->aen_head == ctlr->aen_tail) { 491*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, 492*df54c2f9SSascha Wildner tw_osl_cur_func(), 493*df54c2f9SSascha Wildner "Get Next Event: empty queue"); 494*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 495*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_NO_EVENTS; 496*df54c2f9SSascha Wildner break; 497*df54c2f9SSascha Wildner } 498*df54c2f9SSascha Wildner start_index = ctlr->aen_tail; /* = 0 */ 499*df54c2f9SSascha Wildner } 500*df54c2f9SSascha Wildner tw_osl_memcpy(&event_buf, user_buf->data_buf, 501*df54c2f9SSascha Wildner sizeof(struct tw_cl_event_packet)); 502*df54c2f9SSascha Wildner 503*df54c2f9SSascha Wildner event_index = (start_index + event_buf.sequence_id - 504*df54c2f9SSascha Wildner ctlr->aen_queue[start_index].sequence_id + 1) % 505*df54c2f9SSascha Wildner ctlr->max_aens_supported; 506*df54c2f9SSascha Wildner 507*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 508*df54c2f9SSascha Wildner "Get Next Event: si = %x, ei = %x, ebsi = %x, " 509*df54c2f9SSascha Wildner "sisi = %x, eisi = %x", 510*df54c2f9SSascha Wildner start_index, event_index, event_buf.sequence_id, 511*df54c2f9SSascha Wildner ctlr->aen_queue[start_index].sequence_id, 512*df54c2f9SSascha Wildner ctlr->aen_queue[event_index].sequence_id); 513*df54c2f9SSascha Wildner 514*df54c2f9SSascha Wildner if (! (ctlr->aen_queue[event_index].sequence_id > 515*df54c2f9SSascha Wildner event_buf.sequence_id)) { 516*df54c2f9SSascha Wildner /* 517*df54c2f9SSascha Wildner * We don't have any event matching the criterion. So, 518*df54c2f9SSascha Wildner * we have to report TW_CL_ERROR_NO_EVENTS. If we also 519*df54c2f9SSascha Wildner * encountered an overflow condition above, we cannot 520*df54c2f9SSascha Wildner * report both conditions during this call. We choose 521*df54c2f9SSascha Wildner * to report NO_EVENTS this time, and an overflow the 522*df54c2f9SSascha Wildner * next time we are called. 523*df54c2f9SSascha Wildner */ 524*df54c2f9SSascha Wildner if (user_buf->driver_pkt.status == 525*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_OVERFLOW) { 526*df54c2f9SSascha Wildner /* 527*df54c2f9SSascha Wildner * Make a note so we report the overflow 528*df54c2f9SSascha Wildner * next time. 529*df54c2f9SSascha Wildner */ 530*df54c2f9SSascha Wildner ctlr->aen_q_overflow = TW_CL_TRUE; 531*df54c2f9SSascha Wildner } 532*df54c2f9SSascha Wildner user_buf->driver_pkt.status = TW_CL_ERROR_AEN_NO_EVENTS; 533*df54c2f9SSascha Wildner break; 534*df54c2f9SSascha Wildner } 535*df54c2f9SSascha Wildner /* Copy the event -- even if there has been an overflow. */ 536*df54c2f9SSascha Wildner tw_osl_memcpy(user_buf->data_buf, 537*df54c2f9SSascha Wildner &(ctlr->aen_queue[event_index]), 538*df54c2f9SSascha Wildner sizeof(struct tw_cl_event_packet)); 539*df54c2f9SSascha Wildner 540*df54c2f9SSascha Wildner ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; 541*df54c2f9SSascha Wildner 542*df54c2f9SSascha Wildner break; 543*df54c2f9SSascha Wildner 544*df54c2f9SSascha Wildner 545*df54c2f9SSascha Wildner case TW_CL_IOCTL_GET_PREVIOUS_EVENT: 546*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 547*df54c2f9SSascha Wildner "Get Previous Event"); 548*df54c2f9SSascha Wildner 549*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 0; 550*df54c2f9SSascha Wildner if (ctlr->aen_q_wrapped) { 551*df54c2f9SSascha Wildner if (ctlr->aen_q_overflow) { 552*df54c2f9SSascha Wildner /* 553*df54c2f9SSascha Wildner * The aen queue has wrapped, even before some 554*df54c2f9SSascha Wildner * events have been retrieved. Let the caller 555*df54c2f9SSascha Wildner * know that he missed out on some AEN's. 556*df54c2f9SSascha Wildner */ 557*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 558*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_OVERFLOW; 559*df54c2f9SSascha Wildner ctlr->aen_q_overflow = TW_CL_FALSE; 560*df54c2f9SSascha Wildner } 561*df54c2f9SSascha Wildner start_index = ctlr->aen_head; 562*df54c2f9SSascha Wildner } else { 563*df54c2f9SSascha Wildner if (ctlr->aen_head == ctlr->aen_tail) { 564*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 565*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_NO_EVENTS; 566*df54c2f9SSascha Wildner break; 567*df54c2f9SSascha Wildner } 568*df54c2f9SSascha Wildner start_index = ctlr->aen_tail; /* = 0 */ 569*df54c2f9SSascha Wildner } 570*df54c2f9SSascha Wildner tw_osl_memcpy(&event_buf, user_buf->data_buf, 571*df54c2f9SSascha Wildner sizeof(struct tw_cl_event_packet)); 572*df54c2f9SSascha Wildner 573*df54c2f9SSascha Wildner event_index = (start_index + event_buf.sequence_id - 574*df54c2f9SSascha Wildner ctlr->aen_queue[start_index].sequence_id - 1) % 575*df54c2f9SSascha Wildner ctlr->max_aens_supported; 576*df54c2f9SSascha Wildner 577*df54c2f9SSascha Wildner if (! (ctlr->aen_queue[event_index].sequence_id < 578*df54c2f9SSascha Wildner event_buf.sequence_id)) { 579*df54c2f9SSascha Wildner /* 580*df54c2f9SSascha Wildner * We don't have any event matching the criterion. So, 581*df54c2f9SSascha Wildner * we have to report TW_CL_ERROR_NO_EVENTS. If we also 582*df54c2f9SSascha Wildner * encountered an overflow condition above, we cannot 583*df54c2f9SSascha Wildner * report both conditions during this call. We choose 584*df54c2f9SSascha Wildner * to report NO_EVENTS this time, and an overflow the 585*df54c2f9SSascha Wildner * next time we are called. 586*df54c2f9SSascha Wildner */ 587*df54c2f9SSascha Wildner if (user_buf->driver_pkt.status == 588*df54c2f9SSascha Wildner TW_CL_ERROR_AEN_OVERFLOW) { 589*df54c2f9SSascha Wildner /* 590*df54c2f9SSascha Wildner * Make a note so we report the overflow 591*df54c2f9SSascha Wildner * next time. 592*df54c2f9SSascha Wildner */ 593*df54c2f9SSascha Wildner ctlr->aen_q_overflow = TW_CL_TRUE; 594*df54c2f9SSascha Wildner } 595*df54c2f9SSascha Wildner user_buf->driver_pkt.status = TW_CL_ERROR_AEN_NO_EVENTS; 596*df54c2f9SSascha Wildner break; 597*df54c2f9SSascha Wildner } 598*df54c2f9SSascha Wildner /* Copy the event -- even if there has been an overflow. */ 599*df54c2f9SSascha Wildner tw_osl_memcpy(user_buf->data_buf, 600*df54c2f9SSascha Wildner &(ctlr->aen_queue[event_index]), 601*df54c2f9SSascha Wildner sizeof(struct tw_cl_event_packet)); 602*df54c2f9SSascha Wildner 603*df54c2f9SSascha Wildner ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; 604*df54c2f9SSascha Wildner 605*df54c2f9SSascha Wildner break; 606*df54c2f9SSascha Wildner 607*df54c2f9SSascha Wildner 608*df54c2f9SSascha Wildner case TW_CL_IOCTL_GET_LOCK: 609*df54c2f9SSascha Wildner { 610*df54c2f9SSascha Wildner struct tw_cl_lock_packet lock_pkt; 611*df54c2f9SSascha Wildner TW_TIME cur_time; 612*df54c2f9SSascha Wildner 613*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 614*df54c2f9SSascha Wildner "Get ioctl lock"); 615*df54c2f9SSascha Wildner 616*df54c2f9SSascha Wildner cur_time = tw_osl_get_local_time(); 617*df54c2f9SSascha Wildner tw_osl_memcpy(&lock_pkt, user_buf->data_buf, 618*df54c2f9SSascha Wildner sizeof(struct tw_cl_lock_packet)); 619*df54c2f9SSascha Wildner 620*df54c2f9SSascha Wildner if ((ctlr->ioctl_lock.lock == TW_CLI_LOCK_FREE) || 621*df54c2f9SSascha Wildner (lock_pkt.force_flag) || 622*df54c2f9SSascha Wildner (cur_time >= ctlr->ioctl_lock.timeout)) { 623*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 624*df54c2f9SSascha Wildner "GET_LOCK: Getting lock!"); 625*df54c2f9SSascha Wildner ctlr->ioctl_lock.lock = TW_CLI_LOCK_HELD; 626*df54c2f9SSascha Wildner ctlr->ioctl_lock.timeout = 627*df54c2f9SSascha Wildner cur_time + (lock_pkt.timeout_msec / 1000); 628*df54c2f9SSascha Wildner lock_pkt.time_remaining_msec = lock_pkt.timeout_msec; 629*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 0; 630*df54c2f9SSascha Wildner } else { 631*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 632*df54c2f9SSascha Wildner "GET_LOCK: Lock already held!"); 633*df54c2f9SSascha Wildner lock_pkt.time_remaining_msec = (TW_UINT32)( 634*df54c2f9SSascha Wildner (ctlr->ioctl_lock.timeout - cur_time) * 1000); 635*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 636*df54c2f9SSascha Wildner TW_CL_ERROR_IOCTL_LOCK_ALREADY_HELD; 637*df54c2f9SSascha Wildner } 638*df54c2f9SSascha Wildner tw_osl_memcpy(user_buf->data_buf, &lock_pkt, 639*df54c2f9SSascha Wildner sizeof(struct tw_cl_lock_packet)); 640*df54c2f9SSascha Wildner break; 641*df54c2f9SSascha Wildner } 642*df54c2f9SSascha Wildner 643*df54c2f9SSascha Wildner 644*df54c2f9SSascha Wildner case TW_CL_IOCTL_RELEASE_LOCK: 645*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 646*df54c2f9SSascha Wildner "Release ioctl lock"); 647*df54c2f9SSascha Wildner 648*df54c2f9SSascha Wildner if (ctlr->ioctl_lock.lock == TW_CLI_LOCK_FREE) { 649*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 650*df54c2f9SSascha Wildner "twa_ioctl: RELEASE_LOCK: Lock not held!"); 651*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 652*df54c2f9SSascha Wildner TW_CL_ERROR_IOCTL_LOCK_NOT_HELD; 653*df54c2f9SSascha Wildner } else { 654*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 655*df54c2f9SSascha Wildner "RELEASE_LOCK: Releasing lock!"); 656*df54c2f9SSascha Wildner ctlr->ioctl_lock.lock = TW_CLI_LOCK_FREE; 657*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 0; 658*df54c2f9SSascha Wildner } 659*df54c2f9SSascha Wildner break; 660*df54c2f9SSascha Wildner 661*df54c2f9SSascha Wildner 662*df54c2f9SSascha Wildner case TW_CL_IOCTL_GET_COMPATIBILITY_INFO: 663*df54c2f9SSascha Wildner { 664*df54c2f9SSascha Wildner struct tw_cl_compatibility_packet comp_pkt; 665*df54c2f9SSascha Wildner 666*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 667*df54c2f9SSascha Wildner "Get compatibility info"); 668*df54c2f9SSascha Wildner 669*df54c2f9SSascha Wildner tw_osl_memcpy(comp_pkt.driver_version, 670*df54c2f9SSascha Wildner TW_OSL_DRIVER_VERSION_STRING, 671*df54c2f9SSascha Wildner sizeof(TW_OSL_DRIVER_VERSION_STRING)); 672*df54c2f9SSascha Wildner comp_pkt.working_srl = ctlr->working_srl; 673*df54c2f9SSascha Wildner comp_pkt.working_branch = ctlr->working_branch; 674*df54c2f9SSascha Wildner comp_pkt.working_build = ctlr->working_build; 675*df54c2f9SSascha Wildner comp_pkt.driver_srl_high = TWA_CURRENT_FW_SRL; 676*df54c2f9SSascha Wildner comp_pkt.driver_branch_high = 677*df54c2f9SSascha Wildner TWA_CURRENT_FW_BRANCH(ctlr->arch_id); 678*df54c2f9SSascha Wildner comp_pkt.driver_build_high = 679*df54c2f9SSascha Wildner TWA_CURRENT_FW_BUILD(ctlr->arch_id); 680*df54c2f9SSascha Wildner comp_pkt.driver_srl_low = TWA_BASE_FW_SRL; 681*df54c2f9SSascha Wildner comp_pkt.driver_branch_low = TWA_BASE_FW_BRANCH; 682*df54c2f9SSascha Wildner comp_pkt.driver_build_low = TWA_BASE_FW_BUILD; 683*df54c2f9SSascha Wildner comp_pkt.fw_on_ctlr_srl = ctlr->fw_on_ctlr_srl; 684*df54c2f9SSascha Wildner comp_pkt.fw_on_ctlr_branch = ctlr->fw_on_ctlr_branch; 685*df54c2f9SSascha Wildner comp_pkt.fw_on_ctlr_build = ctlr->fw_on_ctlr_build; 686*df54c2f9SSascha Wildner user_buf->driver_pkt.status = 0; 687*df54c2f9SSascha Wildner 688*df54c2f9SSascha Wildner /* Copy compatibility information to user space. */ 689*df54c2f9SSascha Wildner tw_osl_memcpy(user_buf->data_buf, &comp_pkt, 690*df54c2f9SSascha Wildner (sizeof(struct tw_cl_compatibility_packet) < 691*df54c2f9SSascha Wildner user_buf->driver_pkt.buffer_length) ? 692*df54c2f9SSascha Wildner sizeof(struct tw_cl_compatibility_packet) : 693*df54c2f9SSascha Wildner user_buf->driver_pkt.buffer_length); 694*df54c2f9SSascha Wildner break; 695*df54c2f9SSascha Wildner } 696*df54c2f9SSascha Wildner 697*df54c2f9SSascha Wildner default: 698*df54c2f9SSascha Wildner /* Unknown opcode. */ 699*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 700*df54c2f9SSascha Wildner "Unknown ioctl cmd 0x%x", cmd); 701*df54c2f9SSascha Wildner error = TW_OSL_ENOTTY; 702*df54c2f9SSascha Wildner } 703*df54c2f9SSascha Wildner 704*df54c2f9SSascha Wildner tw_osl_free_lock(ctlr_handle, ctlr->gen_lock); 705*df54c2f9SSascha Wildner return(error); 706*df54c2f9SSascha Wildner } 707*df54c2f9SSascha Wildner 708*df54c2f9SSascha Wildner 709*df54c2f9SSascha Wildner 710*df54c2f9SSascha Wildner /* 711*df54c2f9SSascha Wildner * Function name: tw_cli_get_param 712*df54c2f9SSascha Wildner * Description: Get a firmware parameter. 713*df54c2f9SSascha Wildner * 714*df54c2f9SSascha Wildner * Input: ctlr -- ptr to per ctlr structure 715*df54c2f9SSascha Wildner * table_id -- parameter table # 716*df54c2f9SSascha Wildner * param_id -- index of the parameter in the table 717*df54c2f9SSascha Wildner * param_size -- size of the parameter in bytes 718*df54c2f9SSascha Wildner * callback -- ptr to function, if any, to be called 719*df54c2f9SSascha Wildner * back on completion; TW_CL_NULL if no callback. 720*df54c2f9SSascha Wildner * Output: param_data -- param value 721*df54c2f9SSascha Wildner * Return value: 0 -- success 722*df54c2f9SSascha Wildner * non-zero-- failure 723*df54c2f9SSascha Wildner */ 724*df54c2f9SSascha Wildner TW_INT32 725*df54c2f9SSascha Wildner tw_cli_get_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, 726*df54c2f9SSascha Wildner TW_INT32 param_id, TW_VOID *param_data, TW_INT32 param_size, 727*df54c2f9SSascha Wildner TW_VOID (* callback)(struct tw_cli_req_context *req)) 728*df54c2f9SSascha Wildner { 729*df54c2f9SSascha Wildner struct tw_cli_req_context *req; 730*df54c2f9SSascha Wildner union tw_cl_command_7k *cmd; 731*df54c2f9SSascha Wildner struct tw_cl_param_9k *param = TW_CL_NULL; 732*df54c2f9SSascha Wildner TW_INT32 error = TW_OSL_EBUSY; 733*df54c2f9SSascha Wildner 734*df54c2f9SSascha Wildner tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 735*df54c2f9SSascha Wildner 736*df54c2f9SSascha Wildner /* Get a request packet. */ 737*df54c2f9SSascha Wildner if ((req = tw_cli_get_request(ctlr 738*df54c2f9SSascha Wildner )) == TW_CL_NULL) 739*df54c2f9SSascha Wildner goto out; 740*df54c2f9SSascha Wildner 741*df54c2f9SSascha Wildner /* Make sure this is the only CL internal request at this time. */ 742*df54c2f9SSascha Wildner if (ctlr->internal_req_busy) { 743*df54c2f9SSascha Wildner error = TW_OSL_EBUSY; 744*df54c2f9SSascha Wildner goto out; 745*df54c2f9SSascha Wildner } 746*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_TRUE; 747*df54c2f9SSascha Wildner req->data = ctlr->internal_req_data; 748*df54c2f9SSascha Wildner req->data_phys = ctlr->internal_req_data_phys; 749*df54c2f9SSascha Wildner req->length = TW_CLI_SECTOR_SIZE; 750*df54c2f9SSascha Wildner req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; 751*df54c2f9SSascha Wildner 752*df54c2f9SSascha Wildner /* Initialize memory to read data into. */ 753*df54c2f9SSascha Wildner param = (struct tw_cl_param_9k *)(req->data); 754*df54c2f9SSascha Wildner tw_osl_memzero(param, sizeof(struct tw_cl_param_9k) - 1 + param_size); 755*df54c2f9SSascha Wildner 756*df54c2f9SSascha Wildner /* Build the cmd pkt. */ 757*df54c2f9SSascha Wildner cmd = &(req->cmd_pkt->command.cmd_pkt_7k); 758*df54c2f9SSascha Wildner 759*df54c2f9SSascha Wildner req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; 760*df54c2f9SSascha Wildner 761*df54c2f9SSascha Wildner cmd->param.sgl_off__opcode = 762*df54c2f9SSascha Wildner BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_GET_PARAM); 763*df54c2f9SSascha Wildner cmd->param.request_id = 764*df54c2f9SSascha Wildner (TW_UINT8)(TW_CL_SWAP16(req->request_id)); 765*df54c2f9SSascha Wildner cmd->param.host_id__unit = BUILD_HOST_ID__UNIT(0, 0); 766*df54c2f9SSascha Wildner cmd->param.param_count = TW_CL_SWAP16(1); 767*df54c2f9SSascha Wildner 768*df54c2f9SSascha Wildner if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 769*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].address = 770*df54c2f9SSascha Wildner TW_CL_SWAP64(req->data_phys); 771*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].length = 772*df54c2f9SSascha Wildner TW_CL_SWAP32(req->length); 773*df54c2f9SSascha Wildner cmd->param.size = 2 + 3; 774*df54c2f9SSascha Wildner } else { 775*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].address = 776*df54c2f9SSascha Wildner TW_CL_SWAP32(req->data_phys); 777*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].length = 778*df54c2f9SSascha Wildner TW_CL_SWAP32(req->length); 779*df54c2f9SSascha Wildner cmd->param.size = 2 + 2; 780*df54c2f9SSascha Wildner } 781*df54c2f9SSascha Wildner 782*df54c2f9SSascha Wildner /* Specify which parameter we need. */ 783*df54c2f9SSascha Wildner param->table_id = TW_CL_SWAP16(table_id | TWA_9K_PARAM_DESCRIPTOR); 784*df54c2f9SSascha Wildner param->parameter_id = (TW_UINT8)(param_id); 785*df54c2f9SSascha Wildner param->parameter_size_bytes = TW_CL_SWAP16(param_size); 786*df54c2f9SSascha Wildner 787*df54c2f9SSascha Wildner /* Submit the command. */ 788*df54c2f9SSascha Wildner if (callback == TW_CL_NULL) { 789*df54c2f9SSascha Wildner /* There's no call back; wait till the command completes. */ 790*df54c2f9SSascha Wildner error = tw_cli_submit_and_poll_request(req, 791*df54c2f9SSascha Wildner TW_CLI_REQUEST_TIMEOUT_PERIOD); 792*df54c2f9SSascha Wildner if (error == TW_OSL_ETIMEDOUT) 793*df54c2f9SSascha Wildner /* Clean-up done by tw_cli_submit_and_poll_request. */ 794*df54c2f9SSascha Wildner return(error); 795*df54c2f9SSascha Wildner if (error) 796*df54c2f9SSascha Wildner goto out; 797*df54c2f9SSascha Wildner if ((error = cmd->param.status)) { 798*df54c2f9SSascha Wildner tw_cli_create_ctlr_event(ctlr, 799*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 800*df54c2f9SSascha Wildner &(req->cmd_pkt->cmd_hdr)); 801*df54c2f9SSascha Wildner goto out; 802*df54c2f9SSascha Wildner } 803*df54c2f9SSascha Wildner tw_osl_memcpy(param_data, param->data, param_size); 804*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_FALSE; 805*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 806*df54c2f9SSascha Wildner } else { 807*df54c2f9SSascha Wildner /* There's a call back. Simply submit the command. */ 808*df54c2f9SSascha Wildner req->tw_cli_callback = callback; 809*df54c2f9SSascha Wildner if ((error = tw_cli_submit_cmd(req))) 810*df54c2f9SSascha Wildner goto out; 811*df54c2f9SSascha Wildner } 812*df54c2f9SSascha Wildner return(0); 813*df54c2f9SSascha Wildner 814*df54c2f9SSascha Wildner out: 815*df54c2f9SSascha Wildner tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 816*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 817*df54c2f9SSascha Wildner 0x1101, 0x1, TW_CL_SEVERITY_ERROR_STRING, 818*df54c2f9SSascha Wildner "get_param failed", 819*df54c2f9SSascha Wildner "error = %d", error); 820*df54c2f9SSascha Wildner if (param) 821*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_FALSE; 822*df54c2f9SSascha Wildner if (req) 823*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 824*df54c2f9SSascha Wildner return(1); 825*df54c2f9SSascha Wildner } 826*df54c2f9SSascha Wildner 827*df54c2f9SSascha Wildner 828*df54c2f9SSascha Wildner 829*df54c2f9SSascha Wildner /* 830*df54c2f9SSascha Wildner * Function name: tw_cli_set_param 831*df54c2f9SSascha Wildner * Description: Set a firmware parameter. 832*df54c2f9SSascha Wildner * 833*df54c2f9SSascha Wildner * Input: ctlr -- ptr to per ctlr structure 834*df54c2f9SSascha Wildner * table_id -- parameter table # 835*df54c2f9SSascha Wildner * param_id -- index of the parameter in the table 836*df54c2f9SSascha Wildner * param_size -- size of the parameter in bytes 837*df54c2f9SSascha Wildner * callback -- ptr to function, if any, to be called 838*df54c2f9SSascha Wildner * back on completion; TW_CL_NULL if no callback. 839*df54c2f9SSascha Wildner * Output: None 840*df54c2f9SSascha Wildner * Return value: 0 -- success 841*df54c2f9SSascha Wildner * non-zero-- failure 842*df54c2f9SSascha Wildner */ 843*df54c2f9SSascha Wildner TW_INT32 844*df54c2f9SSascha Wildner tw_cli_set_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, 845*df54c2f9SSascha Wildner TW_INT32 param_id, TW_INT32 param_size, TW_VOID *data, 846*df54c2f9SSascha Wildner TW_VOID (* callback)(struct tw_cli_req_context *req)) 847*df54c2f9SSascha Wildner { 848*df54c2f9SSascha Wildner struct tw_cli_req_context *req; 849*df54c2f9SSascha Wildner union tw_cl_command_7k *cmd; 850*df54c2f9SSascha Wildner struct tw_cl_param_9k *param = TW_CL_NULL; 851*df54c2f9SSascha Wildner TW_INT32 error = TW_OSL_EBUSY; 852*df54c2f9SSascha Wildner 853*df54c2f9SSascha Wildner tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 854*df54c2f9SSascha Wildner 855*df54c2f9SSascha Wildner /* Get a request packet. */ 856*df54c2f9SSascha Wildner if ((req = tw_cli_get_request(ctlr 857*df54c2f9SSascha Wildner )) == TW_CL_NULL) 858*df54c2f9SSascha Wildner goto out; 859*df54c2f9SSascha Wildner 860*df54c2f9SSascha Wildner /* Make sure this is the only CL internal request at this time. */ 861*df54c2f9SSascha Wildner if (ctlr->internal_req_busy) { 862*df54c2f9SSascha Wildner error = TW_OSL_EBUSY; 863*df54c2f9SSascha Wildner goto out; 864*df54c2f9SSascha Wildner } 865*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_TRUE; 866*df54c2f9SSascha Wildner req->data = ctlr->internal_req_data; 867*df54c2f9SSascha Wildner req->data_phys = ctlr->internal_req_data_phys; 868*df54c2f9SSascha Wildner req->length = TW_CLI_SECTOR_SIZE; 869*df54c2f9SSascha Wildner req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; 870*df54c2f9SSascha Wildner 871*df54c2f9SSascha Wildner /* Initialize memory to send data using. */ 872*df54c2f9SSascha Wildner param = (struct tw_cl_param_9k *)(req->data); 873*df54c2f9SSascha Wildner tw_osl_memzero(param, sizeof(struct tw_cl_param_9k) - 1 + param_size); 874*df54c2f9SSascha Wildner 875*df54c2f9SSascha Wildner /* Build the cmd pkt. */ 876*df54c2f9SSascha Wildner cmd = &(req->cmd_pkt->command.cmd_pkt_7k); 877*df54c2f9SSascha Wildner 878*df54c2f9SSascha Wildner req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; 879*df54c2f9SSascha Wildner 880*df54c2f9SSascha Wildner cmd->param.sgl_off__opcode = 881*df54c2f9SSascha Wildner BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_SET_PARAM); 882*df54c2f9SSascha Wildner cmd->param.request_id = (TW_UINT8)(TW_CL_SWAP16(req->request_id)); 883*df54c2f9SSascha Wildner cmd->param.host_id__unit = BUILD_HOST_ID__UNIT(0, 0); 884*df54c2f9SSascha Wildner cmd->param.param_count = TW_CL_SWAP16(1); 885*df54c2f9SSascha Wildner 886*df54c2f9SSascha Wildner if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 887*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].address = 888*df54c2f9SSascha Wildner TW_CL_SWAP64(req->data_phys); 889*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].length = 890*df54c2f9SSascha Wildner TW_CL_SWAP32(req->length); 891*df54c2f9SSascha Wildner cmd->param.size = 2 + 3; 892*df54c2f9SSascha Wildner } else { 893*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].address = 894*df54c2f9SSascha Wildner TW_CL_SWAP32(req->data_phys); 895*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].length = 896*df54c2f9SSascha Wildner TW_CL_SWAP32(req->length); 897*df54c2f9SSascha Wildner cmd->param.size = 2 + 2; 898*df54c2f9SSascha Wildner } 899*df54c2f9SSascha Wildner 900*df54c2f9SSascha Wildner /* Specify which parameter we want to set. */ 901*df54c2f9SSascha Wildner param->table_id = TW_CL_SWAP16(table_id | TWA_9K_PARAM_DESCRIPTOR); 902*df54c2f9SSascha Wildner param->parameter_id = (TW_UINT8)(param_id); 903*df54c2f9SSascha Wildner param->parameter_size_bytes = TW_CL_SWAP16(param_size); 904*df54c2f9SSascha Wildner tw_osl_memcpy(param->data, data, param_size); 905*df54c2f9SSascha Wildner 906*df54c2f9SSascha Wildner /* Submit the command. */ 907*df54c2f9SSascha Wildner if (callback == TW_CL_NULL) { 908*df54c2f9SSascha Wildner /* There's no call back; wait till the command completes. */ 909*df54c2f9SSascha Wildner error = tw_cli_submit_and_poll_request(req, 910*df54c2f9SSascha Wildner TW_CLI_REQUEST_TIMEOUT_PERIOD); 911*df54c2f9SSascha Wildner if (error == TW_OSL_ETIMEDOUT) 912*df54c2f9SSascha Wildner /* Clean-up done by tw_cli_submit_and_poll_request. */ 913*df54c2f9SSascha Wildner return(error); 914*df54c2f9SSascha Wildner if (error) 915*df54c2f9SSascha Wildner goto out; 916*df54c2f9SSascha Wildner if ((error = cmd->param.status)) { 917*df54c2f9SSascha Wildner tw_cli_create_ctlr_event(ctlr, 918*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 919*df54c2f9SSascha Wildner &(req->cmd_pkt->cmd_hdr)); 920*df54c2f9SSascha Wildner goto out; 921*df54c2f9SSascha Wildner } 922*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_FALSE; 923*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 924*df54c2f9SSascha Wildner } else { 925*df54c2f9SSascha Wildner /* There's a call back. Simply submit the command. */ 926*df54c2f9SSascha Wildner req->tw_cli_callback = callback; 927*df54c2f9SSascha Wildner if ((error = tw_cli_submit_cmd(req))) 928*df54c2f9SSascha Wildner goto out; 929*df54c2f9SSascha Wildner } 930*df54c2f9SSascha Wildner return(error); 931*df54c2f9SSascha Wildner 932*df54c2f9SSascha Wildner out: 933*df54c2f9SSascha Wildner tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 934*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 935*df54c2f9SSascha Wildner 0x1102, 0x1, TW_CL_SEVERITY_ERROR_STRING, 936*df54c2f9SSascha Wildner "set_param failed", 937*df54c2f9SSascha Wildner "error = %d", error); 938*df54c2f9SSascha Wildner if (param) 939*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_FALSE; 940*df54c2f9SSascha Wildner if (req) 941*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 942*df54c2f9SSascha Wildner return(error); 943*df54c2f9SSascha Wildner } 944*df54c2f9SSascha Wildner 945*df54c2f9SSascha Wildner 946*df54c2f9SSascha Wildner 947*df54c2f9SSascha Wildner /* 948*df54c2f9SSascha Wildner * Function name: tw_cli_submit_and_poll_request 949*df54c2f9SSascha Wildner * Description: Sends down a firmware cmd, and waits for the completion 950*df54c2f9SSascha Wildner * in a tight loop. 951*df54c2f9SSascha Wildner * 952*df54c2f9SSascha Wildner * Input: req -- ptr to request pkt 953*df54c2f9SSascha Wildner * timeout -- max # of seconds to wait before giving up 954*df54c2f9SSascha Wildner * Output: None 955*df54c2f9SSascha Wildner * Return value: 0 -- success 956*df54c2f9SSascha Wildner * non-zero-- failure 957*df54c2f9SSascha Wildner */ 958*df54c2f9SSascha Wildner TW_INT32 959*df54c2f9SSascha Wildner tw_cli_submit_and_poll_request(struct tw_cli_req_context *req, 960*df54c2f9SSascha Wildner TW_UINT32 timeout) 961*df54c2f9SSascha Wildner { 962*df54c2f9SSascha Wildner struct tw_cli_ctlr_context *ctlr = req->ctlr; 963*df54c2f9SSascha Wildner TW_TIME end_time; 964*df54c2f9SSascha Wildner TW_INT32 error; 965*df54c2f9SSascha Wildner 966*df54c2f9SSascha Wildner tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 967*df54c2f9SSascha Wildner 968*df54c2f9SSascha Wildner /* 969*df54c2f9SSascha Wildner * If the cmd queue is full, tw_cli_submit_cmd will queue this 970*df54c2f9SSascha Wildner * request in the pending queue, since this is an internal request. 971*df54c2f9SSascha Wildner */ 972*df54c2f9SSascha Wildner if ((error = tw_cli_submit_cmd(req))) { 973*df54c2f9SSascha Wildner tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 974*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 975*df54c2f9SSascha Wildner 0x1103, 0x1, TW_CL_SEVERITY_ERROR_STRING, 976*df54c2f9SSascha Wildner "Failed to start internal request", 977*df54c2f9SSascha Wildner "error = %d", error); 978*df54c2f9SSascha Wildner return(error); 979*df54c2f9SSascha Wildner } 980*df54c2f9SSascha Wildner 981*df54c2f9SSascha Wildner /* 982*df54c2f9SSascha Wildner * Poll for the response until the command gets completed, or there's 983*df54c2f9SSascha Wildner * a timeout. 984*df54c2f9SSascha Wildner */ 985*df54c2f9SSascha Wildner end_time = tw_osl_get_local_time() + timeout; 986*df54c2f9SSascha Wildner do { 987*df54c2f9SSascha Wildner if ((error = req->error_code)) 988*df54c2f9SSascha Wildner /* 989*df54c2f9SSascha Wildner * This will take care of completion due to a reset, 990*df54c2f9SSascha Wildner * or a failure in tw_cli_submit_pending_queue. 991*df54c2f9SSascha Wildner * The caller should do the clean-up. 992*df54c2f9SSascha Wildner */ 993*df54c2f9SSascha Wildner return(error); 994*df54c2f9SSascha Wildner 995*df54c2f9SSascha Wildner /* See if the command completed. */ 996*df54c2f9SSascha Wildner tw_cli_process_resp_intr(ctlr); 997*df54c2f9SSascha Wildner 998*df54c2f9SSascha Wildner if ((req->state != TW_CLI_REQ_STATE_BUSY) && 999*df54c2f9SSascha Wildner (req->state != TW_CLI_REQ_STATE_PENDING)) 1000*df54c2f9SSascha Wildner return(req->state != TW_CLI_REQ_STATE_COMPLETE); 1001*df54c2f9SSascha Wildner } while (tw_osl_get_local_time() <= end_time); 1002*df54c2f9SSascha Wildner 1003*df54c2f9SSascha Wildner /* Time out! */ 1004*df54c2f9SSascha Wildner tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 1005*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 1006*df54c2f9SSascha Wildner 0x1104, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1007*df54c2f9SSascha Wildner "Internal request timed out", 1008*df54c2f9SSascha Wildner "request = %p", req); 1009*df54c2f9SSascha Wildner 1010*df54c2f9SSascha Wildner /* 1011*df54c2f9SSascha Wildner * We will reset the controller only if the request has already been 1012*df54c2f9SSascha Wildner * submitted, so as to not lose the request packet. If a busy request 1013*df54c2f9SSascha Wildner * timed out, the reset will take care of freeing resources. If a 1014*df54c2f9SSascha Wildner * pending request timed out, we will free resources for that request, 1015*df54c2f9SSascha Wildner * right here, thereby avoiding a reset. So, the caller is expected 1016*df54c2f9SSascha Wildner * to NOT cleanup when TW_OSL_ETIMEDOUT is returned. 1017*df54c2f9SSascha Wildner */ 1018*df54c2f9SSascha Wildner 1019*df54c2f9SSascha Wildner /* 1020*df54c2f9SSascha Wildner * We have to make sure that this timed out request, if it were in the 1021*df54c2f9SSascha Wildner * pending queue, doesn't get submitted while we are here, from 1022*df54c2f9SSascha Wildner * tw_cli_submit_pending_queue. There could be a race in that case. 1023*df54c2f9SSascha Wildner * Need to revisit. 1024*df54c2f9SSascha Wildner */ 1025*df54c2f9SSascha Wildner if (req->state != TW_CLI_REQ_STATE_PENDING) 1026*df54c2f9SSascha Wildner tw_cl_reset_ctlr(ctlr->ctlr_handle); 1027*df54c2f9SSascha Wildner else { 1028*df54c2f9SSascha Wildner tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), 1029*df54c2f9SSascha Wildner "Removing request from pending queue"); 1030*df54c2f9SSascha Wildner /* 1031*df54c2f9SSascha Wildner * Request was never submitted. Clean up. Note that we did 1032*df54c2f9SSascha Wildner * not do a reset. So, we have to remove the request ourselves 1033*df54c2f9SSascha Wildner * from the pending queue (as against tw_cli_drain_pendinq_queue 1034*df54c2f9SSascha Wildner * taking care of it). 1035*df54c2f9SSascha Wildner */ 1036*df54c2f9SSascha Wildner tw_cli_req_q_remove_item(req, TW_CLI_PENDING_Q); 1037*df54c2f9SSascha Wildner if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) == TW_CL_NULL) 1038*df54c2f9SSascha Wildner TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 1039*df54c2f9SSascha Wildner TWA_CONTROL_MASK_COMMAND_INTERRUPT); 1040*df54c2f9SSascha Wildner if (req->data) 1041*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_FALSE; 1042*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 1043*df54c2f9SSascha Wildner } 1044*df54c2f9SSascha Wildner 1045*df54c2f9SSascha Wildner return(TW_OSL_ETIMEDOUT); 1046*df54c2f9SSascha Wildner } 1047*df54c2f9SSascha Wildner 1048*df54c2f9SSascha Wildner 1049*df54c2f9SSascha Wildner 1050*df54c2f9SSascha Wildner /* 1051*df54c2f9SSascha Wildner * Function name: tw_cl_reset_ctlr 1052*df54c2f9SSascha Wildner * Description: Soft resets and then initializes the controller; 1053*df54c2f9SSascha Wildner * drains any incomplete requests. 1054*df54c2f9SSascha Wildner * 1055*df54c2f9SSascha Wildner * Input: ctlr -- ptr to per ctlr structure 1056*df54c2f9SSascha Wildner * Output: None 1057*df54c2f9SSascha Wildner * Return value: 0 -- success 1058*df54c2f9SSascha Wildner * non-zero-- failure 1059*df54c2f9SSascha Wildner */ 1060*df54c2f9SSascha Wildner TW_INT32 1061*df54c2f9SSascha Wildner tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle) 1062*df54c2f9SSascha Wildner { 1063*df54c2f9SSascha Wildner struct tw_cli_ctlr_context *ctlr = 1064*df54c2f9SSascha Wildner (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 1065*df54c2f9SSascha Wildner struct twa_softc *sc = ctlr_handle->osl_ctlr_ctxt; 1066*df54c2f9SSascha Wildner TW_INT32 reset_attempt = 1; 1067*df54c2f9SSascha Wildner TW_INT32 error; 1068*df54c2f9SSascha Wildner 1069*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "entered"); 1070*df54c2f9SSascha Wildner 1071*df54c2f9SSascha Wildner ctlr->reset_in_progress = TW_CL_TRUE; 1072*df54c2f9SSascha Wildner xpt_freeze_simq(sc->sim, 1); 1073*df54c2f9SSascha Wildner 1074*df54c2f9SSascha Wildner tw_cli_disable_interrupts(ctlr); 1075*df54c2f9SSascha Wildner 1076*df54c2f9SSascha Wildner /* 1077*df54c2f9SSascha Wildner * Error back all requests in the complete, busy, and pending queues. 1078*df54c2f9SSascha Wildner * If any request is already on its way to getting submitted, it's in 1079*df54c2f9SSascha Wildner * none of these queues and so, will not be completed. That request 1080*df54c2f9SSascha Wildner * will continue its course and get submitted to the controller after 1081*df54c2f9SSascha Wildner * the reset is done (and io_lock is released). 1082*df54c2f9SSascha Wildner */ 1083*df54c2f9SSascha Wildner tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 1084*df54c2f9SSascha Wildner "Draining all queues following reset"); 1085*df54c2f9SSascha Wildner tw_cli_drain_complete_queue(ctlr); 1086*df54c2f9SSascha Wildner tw_cli_drain_busy_queue(ctlr); 1087*df54c2f9SSascha Wildner tw_cli_drain_pending_queue(ctlr); 1088*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_FALSE; 1089*df54c2f9SSascha Wildner ctlr->get_more_aens = TW_CL_FALSE; 1090*df54c2f9SSascha Wildner 1091*df54c2f9SSascha Wildner /* Soft reset the controller. */ 1092*df54c2f9SSascha Wildner try_reset: 1093*df54c2f9SSascha Wildner if ((error = tw_cli_soft_reset(ctlr))) { 1094*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 1095*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1096*df54c2f9SSascha Wildner 0x1105, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1097*df54c2f9SSascha Wildner "Controller reset failed", 1098*df54c2f9SSascha Wildner "error = %d; attempt %d", error, reset_attempt++); 1099*df54c2f9SSascha Wildner if (reset_attempt <= TW_CLI_MAX_RESET_ATTEMPTS) 1100*df54c2f9SSascha Wildner goto try_reset; 1101*df54c2f9SSascha Wildner else 1102*df54c2f9SSascha Wildner goto out; 1103*df54c2f9SSascha Wildner } 1104*df54c2f9SSascha Wildner 1105*df54c2f9SSascha Wildner /* Re-establish logical connection with the controller. */ 1106*df54c2f9SSascha Wildner if ((error = tw_cli_init_connection(ctlr, 1107*df54c2f9SSascha Wildner (TW_UINT16)(ctlr->max_simult_reqs), 1108*df54c2f9SSascha Wildner 0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL, 1109*df54c2f9SSascha Wildner TW_CL_NULL, TW_CL_NULL))) { 1110*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 1111*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1112*df54c2f9SSascha Wildner 0x1106, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1113*df54c2f9SSascha Wildner "Can't initialize connection after reset", 1114*df54c2f9SSascha Wildner "error = %d", error); 1115*df54c2f9SSascha Wildner goto out; 1116*df54c2f9SSascha Wildner } 1117*df54c2f9SSascha Wildner 1118*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 1119*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1120*df54c2f9SSascha Wildner 0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING, 1121*df54c2f9SSascha Wildner "Controller reset done!", 1122*df54c2f9SSascha Wildner " "); 1123*df54c2f9SSascha Wildner 1124*df54c2f9SSascha Wildner out: 1125*df54c2f9SSascha Wildner ctlr->reset_in_progress = TW_CL_FALSE; 1126*df54c2f9SSascha Wildner xpt_release_simq(sc->sim, 1); 1127*df54c2f9SSascha Wildner 1128*df54c2f9SSascha Wildner /* 1129*df54c2f9SSascha Wildner * Enable interrupts, and also clear attention and response interrupts. 1130*df54c2f9SSascha Wildner */ 1131*df54c2f9SSascha Wildner tw_cli_enable_interrupts(ctlr); 1132*df54c2f9SSascha Wildner 1133*df54c2f9SSascha Wildner /* Request for a bus re-scan. */ 1134*df54c2f9SSascha Wildner if (!error) 1135*df54c2f9SSascha Wildner tw_osl_scan_bus(ctlr_handle); 1136*df54c2f9SSascha Wildner return(error); 1137*df54c2f9SSascha Wildner } 1138*df54c2f9SSascha Wildner 1139*df54c2f9SSascha Wildner 1140*df54c2f9SSascha Wildner 1141*df54c2f9SSascha Wildner /* 1142*df54c2f9SSascha Wildner * Function name: tw_cli_soft_reset 1143*df54c2f9SSascha Wildner * Description: Does the actual soft reset. 1144*df54c2f9SSascha Wildner * 1145*df54c2f9SSascha Wildner * Input: ctlr -- ptr to per ctlr structure 1146*df54c2f9SSascha Wildner * Output: None 1147*df54c2f9SSascha Wildner * Return value: 0 -- success 1148*df54c2f9SSascha Wildner * non-zero-- failure 1149*df54c2f9SSascha Wildner */ 1150*df54c2f9SSascha Wildner TW_INT32 1151*df54c2f9SSascha Wildner tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) 1152*df54c2f9SSascha Wildner { 1153*df54c2f9SSascha Wildner struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; 1154*df54c2f9SSascha Wildner TW_UINT32 status_reg; 1155*df54c2f9SSascha Wildner int found; 1156*df54c2f9SSascha Wildner int loop_count; 1157*df54c2f9SSascha Wildner TW_UINT32 error; 1158*df54c2f9SSascha Wildner 1159*df54c2f9SSascha Wildner tw_cli_dbg_printf(1, ctlr_handle, tw_osl_cur_func(), "entered"); 1160*df54c2f9SSascha Wildner 1161*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 1162*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1163*df54c2f9SSascha Wildner 0x1108, 0x3, TW_CL_SEVERITY_INFO_STRING, 1164*df54c2f9SSascha Wildner "Resetting controller...", 1165*df54c2f9SSascha Wildner " "); 1166*df54c2f9SSascha Wildner 1167*df54c2f9SSascha Wildner /* Don't let any new commands get submitted to the controller. */ 1168*df54c2f9SSascha Wildner tw_osl_get_lock(ctlr_handle, ctlr->io_lock); 1169*df54c2f9SSascha Wildner 1170*df54c2f9SSascha Wildner TW_CLI_SOFT_RESET(ctlr_handle); 1171*df54c2f9SSascha Wildner 1172*df54c2f9SSascha Wildner if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_X) || 1173*df54c2f9SSascha Wildner (ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || 1174*df54c2f9SSascha Wildner (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) { 1175*df54c2f9SSascha Wildner /* 1176*df54c2f9SSascha Wildner * There's a hardware bug in the G133 ASIC, which can lead to 1177*df54c2f9SSascha Wildner * PCI parity errors and hangs, if the host accesses any 1178*df54c2f9SSascha Wildner * registers when the firmware is resetting the hardware, as 1179*df54c2f9SSascha Wildner * part of a hard/soft reset. The window of time when the 1180*df54c2f9SSascha Wildner * problem can occur is about 10 ms. Here, we will handshake 1181*df54c2f9SSascha Wildner * with the firmware to find out when the firmware is pulling 1182*df54c2f9SSascha Wildner * down the hardware reset pin, and wait for about 500 ms to 1183*df54c2f9SSascha Wildner * make sure we don't access any hardware registers (for 1184*df54c2f9SSascha Wildner * polling) during that window. 1185*df54c2f9SSascha Wildner */ 1186*df54c2f9SSascha Wildner ctlr->reset_phase1_in_progress = TW_CL_TRUE; 1187*df54c2f9SSascha Wildner loop_count = 0; 1188*df54c2f9SSascha Wildner do { 1189*df54c2f9SSascha Wildner found = (tw_cli_find_response(ctlr, TWA_RESET_PHASE1_NOTIFICATION_RESPONSE) == TW_OSL_ESUCCESS); 1190*df54c2f9SSascha Wildner tw_osl_delay(10); 1191*df54c2f9SSascha Wildner loop_count++; 1192*df54c2f9SSascha Wildner error = 0x7888; 1193*df54c2f9SSascha Wildner } while (!found && (loop_count < 6000000)); /* Loop for no more than 60 seconds */ 1194*df54c2f9SSascha Wildner 1195*df54c2f9SSascha Wildner if (!found) { 1196*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 1197*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1198*df54c2f9SSascha Wildner 0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1199*df54c2f9SSascha Wildner "Missed firmware handshake after soft-reset", 1200*df54c2f9SSascha Wildner "error = %d", error); 1201*df54c2f9SSascha Wildner tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1202*df54c2f9SSascha Wildner return(error); 1203*df54c2f9SSascha Wildner } 1204*df54c2f9SSascha Wildner 1205*df54c2f9SSascha Wildner tw_osl_delay(TWA_RESET_PHASE1_WAIT_TIME_MS * 1000); 1206*df54c2f9SSascha Wildner ctlr->reset_phase1_in_progress = TW_CL_FALSE; 1207*df54c2f9SSascha Wildner } 1208*df54c2f9SSascha Wildner 1209*df54c2f9SSascha Wildner if ((error = tw_cli_poll_status(ctlr, 1210*df54c2f9SSascha Wildner TWA_STATUS_MICROCONTROLLER_READY | 1211*df54c2f9SSascha Wildner TWA_STATUS_ATTENTION_INTERRUPT, 1212*df54c2f9SSascha Wildner TW_CLI_RESET_TIMEOUT_PERIOD))) { 1213*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 1214*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1215*df54c2f9SSascha Wildner 0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1216*df54c2f9SSascha Wildner "Micro-ctlr not ready/No attn intr after reset", 1217*df54c2f9SSascha Wildner "error = %d", error); 1218*df54c2f9SSascha Wildner tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1219*df54c2f9SSascha Wildner return(error); 1220*df54c2f9SSascha Wildner } 1221*df54c2f9SSascha Wildner 1222*df54c2f9SSascha Wildner TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 1223*df54c2f9SSascha Wildner TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT); 1224*df54c2f9SSascha Wildner 1225*df54c2f9SSascha Wildner if ((error = tw_cli_drain_response_queue(ctlr))) { 1226*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1227*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 1228*df54c2f9SSascha Wildner 0x110A, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1229*df54c2f9SSascha Wildner "Can't drain response queue after reset", 1230*df54c2f9SSascha Wildner "error = %d", error); 1231*df54c2f9SSascha Wildner tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1232*df54c2f9SSascha Wildner return(error); 1233*df54c2f9SSascha Wildner } 1234*df54c2f9SSascha Wildner 1235*df54c2f9SSascha Wildner tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1236*df54c2f9SSascha Wildner 1237*df54c2f9SSascha Wildner if ((error = tw_cli_drain_aen_queue(ctlr))) { 1238*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1239*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 1240*df54c2f9SSascha Wildner 0x110B, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1241*df54c2f9SSascha Wildner "Can't drain AEN queue after reset", 1242*df54c2f9SSascha Wildner "error = %d", error); 1243*df54c2f9SSascha Wildner return(error); 1244*df54c2f9SSascha Wildner } 1245*df54c2f9SSascha Wildner 1246*df54c2f9SSascha Wildner if ((error = tw_cli_find_aen(ctlr, TWA_AEN_SOFT_RESET))) { 1247*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 1248*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1249*df54c2f9SSascha Wildner 0x110C, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1250*df54c2f9SSascha Wildner "Reset not reported by controller", 1251*df54c2f9SSascha Wildner "error = %d", error); 1252*df54c2f9SSascha Wildner return(error); 1253*df54c2f9SSascha Wildner } 1254*df54c2f9SSascha Wildner 1255*df54c2f9SSascha Wildner status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); 1256*df54c2f9SSascha Wildner 1257*df54c2f9SSascha Wildner if ((error = TW_CLI_STATUS_ERRORS(status_reg)) || 1258*df54c2f9SSascha Wildner (error = tw_cli_check_ctlr_state(ctlr, status_reg))) { 1259*df54c2f9SSascha Wildner tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 1260*df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1261*df54c2f9SSascha Wildner 0x110D, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1262*df54c2f9SSascha Wildner "Controller errors detected after reset", 1263*df54c2f9SSascha Wildner "error = %d", error); 1264*df54c2f9SSascha Wildner return(error); 1265*df54c2f9SSascha Wildner } 1266*df54c2f9SSascha Wildner 1267*df54c2f9SSascha Wildner return(TW_OSL_ESUCCESS); 1268*df54c2f9SSascha Wildner } 1269*df54c2f9SSascha Wildner 1270*df54c2f9SSascha Wildner 1271*df54c2f9SSascha Wildner 1272*df54c2f9SSascha Wildner /* 1273*df54c2f9SSascha Wildner * Function name: tw_cli_send_scsi_cmd 1274*df54c2f9SSascha Wildner * Description: Sends down a scsi cmd to fw. 1275*df54c2f9SSascha Wildner * 1276*df54c2f9SSascha Wildner * Input: req -- ptr to request pkt 1277*df54c2f9SSascha Wildner * cmd -- opcode of scsi cmd to send 1278*df54c2f9SSascha Wildner * Output: None 1279*df54c2f9SSascha Wildner * Return value: 0 -- success 1280*df54c2f9SSascha Wildner * non-zero-- failure 1281*df54c2f9SSascha Wildner */ 1282*df54c2f9SSascha Wildner TW_INT32 1283*df54c2f9SSascha Wildner tw_cli_send_scsi_cmd(struct tw_cli_req_context *req, TW_INT32 cmd) 1284*df54c2f9SSascha Wildner { 1285*df54c2f9SSascha Wildner struct tw_cl_command_packet *cmdpkt; 1286*df54c2f9SSascha Wildner struct tw_cl_command_9k *cmd9k; 1287*df54c2f9SSascha Wildner struct tw_cli_ctlr_context *ctlr; 1288*df54c2f9SSascha Wildner TW_INT32 error; 1289*df54c2f9SSascha Wildner 1290*df54c2f9SSascha Wildner ctlr = req->ctlr; 1291*df54c2f9SSascha Wildner tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 1292*df54c2f9SSascha Wildner 1293*df54c2f9SSascha Wildner /* Make sure this is the only CL internal request at this time. */ 1294*df54c2f9SSascha Wildner if (ctlr->internal_req_busy) 1295*df54c2f9SSascha Wildner return(TW_OSL_EBUSY); 1296*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_TRUE; 1297*df54c2f9SSascha Wildner req->data = ctlr->internal_req_data; 1298*df54c2f9SSascha Wildner req->data_phys = ctlr->internal_req_data_phys; 1299*df54c2f9SSascha Wildner tw_osl_memzero(req->data, TW_CLI_SECTOR_SIZE); 1300*df54c2f9SSascha Wildner req->length = TW_CLI_SECTOR_SIZE; 1301*df54c2f9SSascha Wildner 1302*df54c2f9SSascha Wildner /* Build the cmd pkt. */ 1303*df54c2f9SSascha Wildner cmdpkt = req->cmd_pkt; 1304*df54c2f9SSascha Wildner 1305*df54c2f9SSascha Wildner cmdpkt->cmd_hdr.header_desc.size_header = 128; 1306*df54c2f9SSascha Wildner 1307*df54c2f9SSascha Wildner cmd9k = &(cmdpkt->command.cmd_pkt_9k); 1308*df54c2f9SSascha Wildner 1309*df54c2f9SSascha Wildner cmd9k->res__opcode = 1310*df54c2f9SSascha Wildner BUILD_RES__OPCODE(0, TWA_FW_CMD_EXECUTE_SCSI); 1311*df54c2f9SSascha Wildner cmd9k->unit = 0; 1312*df54c2f9SSascha Wildner cmd9k->lun_l4__req_id = TW_CL_SWAP16(req->request_id); 1313*df54c2f9SSascha Wildner cmd9k->status = 0; 1314*df54c2f9SSascha Wildner cmd9k->sgl_offset = 16; /* offset from end of hdr = max cdb len */ 1315*df54c2f9SSascha Wildner cmd9k->lun_h4__sgl_entries = TW_CL_SWAP16(1); 1316*df54c2f9SSascha Wildner 1317*df54c2f9SSascha Wildner if (req->ctlr->flags & TW_CL_64BIT_ADDRESSES) { 1318*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc64 *)(cmd9k->sg_list))[0].address = 1319*df54c2f9SSascha Wildner TW_CL_SWAP64(req->data_phys); 1320*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc64 *)(cmd9k->sg_list))[0].length = 1321*df54c2f9SSascha Wildner TW_CL_SWAP32(req->length); 1322*df54c2f9SSascha Wildner } else { 1323*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc32 *)(cmd9k->sg_list))[0].address = 1324*df54c2f9SSascha Wildner TW_CL_SWAP32(req->data_phys); 1325*df54c2f9SSascha Wildner ((struct tw_cl_sg_desc32 *)(cmd9k->sg_list))[0].length = 1326*df54c2f9SSascha Wildner TW_CL_SWAP32(req->length); 1327*df54c2f9SSascha Wildner } 1328*df54c2f9SSascha Wildner 1329*df54c2f9SSascha Wildner cmd9k->cdb[0] = (TW_UINT8)cmd; 1330*df54c2f9SSascha Wildner cmd9k->cdb[4] = 128; 1331*df54c2f9SSascha Wildner 1332*df54c2f9SSascha Wildner if ((error = tw_cli_submit_cmd(req))) 1333*df54c2f9SSascha Wildner if (error != TW_OSL_EBUSY) { 1334*df54c2f9SSascha Wildner tw_cli_dbg_printf(1, ctlr->ctlr_handle, 1335*df54c2f9SSascha Wildner tw_osl_cur_func(), 1336*df54c2f9SSascha Wildner "Failed to start SCSI command", 1337*df54c2f9SSascha Wildner "request = %p, error = %d", req, error); 1338*df54c2f9SSascha Wildner return(TW_OSL_EIO); 1339*df54c2f9SSascha Wildner } 1340*df54c2f9SSascha Wildner return(TW_OSL_ESUCCESS); 1341*df54c2f9SSascha Wildner } 1342*df54c2f9SSascha Wildner 1343*df54c2f9SSascha Wildner 1344*df54c2f9SSascha Wildner 1345*df54c2f9SSascha Wildner /* 1346*df54c2f9SSascha Wildner * Function name: tw_cli_get_aen 1347*df54c2f9SSascha Wildner * Description: Sends down a Request Sense cmd to fw to fetch an AEN. 1348*df54c2f9SSascha Wildner * 1349*df54c2f9SSascha Wildner * Input: ctlr -- ptr to per ctlr structure 1350*df54c2f9SSascha Wildner * Output: None 1351*df54c2f9SSascha Wildner * Return value: 0 -- success 1352*df54c2f9SSascha Wildner * non-zero-- failure 1353*df54c2f9SSascha Wildner */ 1354*df54c2f9SSascha Wildner TW_INT32 1355*df54c2f9SSascha Wildner tw_cli_get_aen(struct tw_cli_ctlr_context *ctlr) 1356*df54c2f9SSascha Wildner { 1357*df54c2f9SSascha Wildner struct tw_cli_req_context *req; 1358*df54c2f9SSascha Wildner TW_INT32 error; 1359*df54c2f9SSascha Wildner 1360*df54c2f9SSascha Wildner tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 1361*df54c2f9SSascha Wildner 1362*df54c2f9SSascha Wildner if ((req = tw_cli_get_request(ctlr 1363*df54c2f9SSascha Wildner )) == TW_CL_NULL) 1364*df54c2f9SSascha Wildner return(TW_OSL_EBUSY); 1365*df54c2f9SSascha Wildner 1366*df54c2f9SSascha Wildner req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; 1367*df54c2f9SSascha Wildner req->flags |= TW_CLI_REQ_FLAGS_9K; 1368*df54c2f9SSascha Wildner req->tw_cli_callback = tw_cli_aen_callback; 1369*df54c2f9SSascha Wildner if ((error = tw_cli_send_scsi_cmd(req, 0x03 /* REQUEST_SENSE */))) { 1370*df54c2f9SSascha Wildner tw_cli_dbg_printf(1, ctlr->ctlr_handle, tw_osl_cur_func(), 1371*df54c2f9SSascha Wildner "Could not send SCSI command", 1372*df54c2f9SSascha Wildner "request = %p, error = %d", req, error); 1373*df54c2f9SSascha Wildner if (req->data) 1374*df54c2f9SSascha Wildner ctlr->internal_req_busy = TW_CL_FALSE; 1375*df54c2f9SSascha Wildner tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 1376*df54c2f9SSascha Wildner } 1377*df54c2f9SSascha Wildner return(error); 1378*df54c2f9SSascha Wildner } 1379*df54c2f9SSascha Wildner 1380*df54c2f9SSascha Wildner 1381*df54c2f9SSascha Wildner 1382*df54c2f9SSascha Wildner /* 1383*df54c2f9SSascha Wildner * Function name: tw_cli_fill_sg_list 1384*df54c2f9SSascha Wildner * Description: Fills in the scatter/gather list. 1385*df54c2f9SSascha Wildner * 1386*df54c2f9SSascha Wildner * Input: ctlr -- ptr to per ctlr structure 1387*df54c2f9SSascha Wildner * sgl_src -- ptr to fill the sg list from 1388*df54c2f9SSascha Wildner * sgl_dest-- ptr to sg list 1389*df54c2f9SSascha Wildner * nsegments--# of segments 1390*df54c2f9SSascha Wildner * Output: None 1391*df54c2f9SSascha Wildner * Return value: None 1392*df54c2f9SSascha Wildner */ 1393*df54c2f9SSascha Wildner TW_VOID 1394*df54c2f9SSascha Wildner tw_cli_fill_sg_list(struct tw_cli_ctlr_context *ctlr, TW_VOID *sgl_src, 1395*df54c2f9SSascha Wildner TW_VOID *sgl_dest, TW_INT32 num_sgl_entries) 1396*df54c2f9SSascha Wildner { 1397*df54c2f9SSascha Wildner TW_INT32 i; 1398*df54c2f9SSascha Wildner 1399*df54c2f9SSascha Wildner tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 1400*df54c2f9SSascha Wildner 1401*df54c2f9SSascha Wildner if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 1402*df54c2f9SSascha Wildner struct tw_cl_sg_desc64 *sgl_s = 1403*df54c2f9SSascha Wildner (struct tw_cl_sg_desc64 *)sgl_src; 1404*df54c2f9SSascha Wildner struct tw_cl_sg_desc64 *sgl_d = 1405*df54c2f9SSascha Wildner (struct tw_cl_sg_desc64 *)sgl_dest; 1406*df54c2f9SSascha Wildner 1407*df54c2f9SSascha Wildner tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), 1408*df54c2f9SSascha Wildner "64 bit addresses"); 1409*df54c2f9SSascha Wildner for (i = 0; i < num_sgl_entries; i++) { 1410*df54c2f9SSascha Wildner sgl_d[i].address = TW_CL_SWAP64(sgl_s->address); 1411*df54c2f9SSascha Wildner sgl_d[i].length = TW_CL_SWAP32(sgl_s->length); 1412*df54c2f9SSascha Wildner sgl_s++; 1413*df54c2f9SSascha Wildner if (ctlr->flags & TW_CL_64BIT_SG_LENGTH) 1414*df54c2f9SSascha Wildner sgl_s = (struct tw_cl_sg_desc64 *) 1415*df54c2f9SSascha Wildner (((TW_INT8 *)(sgl_s)) + 4); 1416*df54c2f9SSascha Wildner } 1417*df54c2f9SSascha Wildner } else { 1418*df54c2f9SSascha Wildner struct tw_cl_sg_desc32 *sgl_s = 1419*df54c2f9SSascha Wildner (struct tw_cl_sg_desc32 *)sgl_src; 1420*df54c2f9SSascha Wildner struct tw_cl_sg_desc32 *sgl_d = 1421*df54c2f9SSascha Wildner (struct tw_cl_sg_desc32 *)sgl_dest; 1422*df54c2f9SSascha Wildner 1423*df54c2f9SSascha Wildner tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), 1424*df54c2f9SSascha Wildner "32 bit addresses"); 1425*df54c2f9SSascha Wildner for (i = 0; i < num_sgl_entries; i++) { 1426*df54c2f9SSascha Wildner sgl_d[i].address = TW_CL_SWAP32(sgl_s[i].address); 1427*df54c2f9SSascha Wildner sgl_d[i].length = TW_CL_SWAP32(sgl_s[i].length); 1428*df54c2f9SSascha Wildner } 1429*df54c2f9SSascha Wildner } 1430*df54c2f9SSascha Wildner } 1431