The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/twa/tw_cl_io.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 5931d6434211715092ae62bc1fa1293d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.