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_intr.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  * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
    3  * Copyright (c) 2004-05 Vinod Kashyap
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  *      $FreeBSD: releng/7.3/sys/dev/twa/tw_cl_intr.c 172496 2007-10-09 17:43:57Z scottl $
   28  */
   29 
   30 /*
   31  * AMCC'S 3ware driver for 9000 series storage controllers.
   32  *
   33  * Author: Vinod Kashyap
   34  * Modifications by: Adam Radford
   35  * Modifications by: Manjunath Ranganathaiah
   36  */
   37 
   38 
   39 /*
   40  * Common Layer interrupt handling functions.
   41  */
   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 
   53 
   54 /*
   55  * Function name:       twa_interrupt
   56  * Description:         Interrupt handler.  Determines the kind of interrupt,
   57  *                      and returns TW_CL_TRUE if it recognizes the interrupt.
   58  *
   59  * Input:               ctlr_handle     -- controller handle
   60  * Output:              None
   61  * Return value:        TW_CL_TRUE -- interrupt recognized
   62  *                      TW_CL_FALSE-- interrupt not recognized
   63  */
   64 TW_INT32
   65 tw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle)
   66 {
   67         struct tw_cli_ctlr_context      *ctlr =
   68                 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
   69         TW_UINT32                       status_reg;
   70         TW_INT32                        rc = TW_CL_FALSE;
   71 
   72         tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
   73 
   74         /* If we don't have controller context, bail */
   75         if (ctlr == NULL)
   76                 goto out;
   77 
   78         /* If we get an interrupt while resetting, it is a shared
   79            one for another device, so just bail */
   80         if (ctlr->state & TW_CLI_CTLR_STATE_RESET_IN_PROGRESS)
   81                 goto out;
   82 
   83         /*
   84          * Synchronize access between writes to command and control registers
   85          * in 64-bit environments, on G66.
   86          */
   87         if (ctlr->state & TW_CLI_CTLR_STATE_G66_WORKAROUND_NEEDED)
   88                 tw_osl_get_lock(ctlr_handle, ctlr->io_lock);
   89 
   90         /* Read the status register to determine the type of interrupt. */
   91         status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
   92         if (tw_cli_check_ctlr_state(ctlr, status_reg))
   93                 goto out_unlock;
   94 
   95         /* Clear the interrupt. */
   96         if (status_reg & TWA_STATUS_HOST_INTERRUPT) {
   97                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
   98                         "Host interrupt");
   99                 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
  100                         TWA_CONTROL_CLEAR_HOST_INTERRUPT);
  101                 ctlr->host_intr_pending = 0; /* we don't use this */
  102                 rc |= TW_CL_FALSE; /* don't request for a deferred isr call */
  103         }
  104         if (status_reg & TWA_STATUS_ATTENTION_INTERRUPT) {
  105                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
  106                         "Attention interrupt");
  107                 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
  108                         TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT);
  109                 ctlr->attn_intr_pending = 1;
  110                 rc |= TW_CL_TRUE; /* request for a deferred isr call */
  111         }
  112         if (status_reg & TWA_STATUS_COMMAND_INTERRUPT) {
  113                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
  114                         "Command interrupt");
  115                 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
  116                         TWA_CONTROL_MASK_COMMAND_INTERRUPT);
  117                 ctlr->cmd_intr_pending = 1;
  118                 rc |= TW_CL_TRUE; /* request for a deferred isr call */
  119         }
  120         if (status_reg & TWA_STATUS_RESPONSE_INTERRUPT) {
  121                 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
  122                         "Response interrupt");
  123                 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
  124                         TWA_CONTROL_MASK_RESPONSE_INTERRUPT);
  125                 ctlr->resp_intr_pending = 1;
  126                 rc |= TW_CL_TRUE; /* request for a deferred isr call */
  127         }
  128 out_unlock:
  129         if (ctlr->state & TW_CLI_CTLR_STATE_G66_WORKAROUND_NEEDED)
  130                 tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
  131 out:
  132         return(rc);
  133 }
  134 
  135 
  136 
  137 /*
  138  * Function name:       tw_cl_deferred_interrupt
  139  * Description:         Deferred interrupt handler.  Does most of the processing
  140  *                      related to an interrupt.
  141  *
  142  * Input:               ctlr_handle     -- controller handle
  143  * Output:              None
  144  * Return value:        None
  145  */
  146 TW_VOID
  147 tw_cl_deferred_interrupt(struct tw_cl_ctlr_handle *ctlr_handle)
  148 {
  149         struct tw_cli_ctlr_context      *ctlr =
  150                 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
  151 
  152         tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
  153 
  154         /* Dispatch based on the kind of interrupt. */
  155         if (ctlr->host_intr_pending) {
  156                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
  157                         "Processing Host interrupt");
  158                 ctlr->host_intr_pending = 0;
  159                 tw_cli_process_host_intr(ctlr);
  160         }
  161         if (ctlr->attn_intr_pending) {
  162                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
  163                         "Processing Attention interrupt");
  164                 ctlr->attn_intr_pending = 0;
  165                 tw_cli_process_attn_intr(ctlr);
  166         }
  167         if (ctlr->cmd_intr_pending) {
  168                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
  169                         "Processing Command interrupt");
  170                 ctlr->cmd_intr_pending = 0;
  171                 tw_cli_process_cmd_intr(ctlr);
  172         }
  173         if (ctlr->resp_intr_pending) {
  174                 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
  175                         "Processing Response interrupt");
  176                 ctlr->resp_intr_pending = 0;
  177                 tw_cli_process_resp_intr(ctlr);
  178         }
  179 }
  180 
  181 
  182 
  183 /*
  184  * Function name:       tw_cli_process_host_intr
  185  * Description:         This function gets called if we triggered an interrupt.
  186  *                      We don't use it as of now.
  187  *
  188  * Input:               ctlr    -- ptr to CL internal ctlr context
  189  * Output:              None
  190  * Return value:        None
  191  */
  192 TW_VOID
  193 tw_cli_process_host_intr(struct tw_cli_ctlr_context *ctlr)
  194 {
  195         tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  196 }
  197 
  198 
  199 
  200 /*
  201  * Function name:       tw_cli_process_attn_intr
  202  * Description:         This function gets called if the fw posted an AEN
  203  *                      (Asynchronous Event Notification).  It fetches
  204  *                      all the AEN's that the fw might have posted.
  205  *
  206  * Input:               ctlr    -- ptr to CL internal ctlr context
  207  * Output:              None
  208  * Return value:        None
  209  */
  210 TW_VOID
  211 tw_cli_process_attn_intr(struct tw_cli_ctlr_context *ctlr)
  212 {
  213         TW_INT32        error;
  214 
  215         tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  216 
  217         if ((error = tw_cli_get_aen(ctlr))) {
  218                 /*
  219                  * If the driver is already in the process of retrieveing AEN's,
  220                  * we will be returned TW_OSL_EBUSY.  In this case,
  221                  * tw_cli_param_callback or tw_cli_aen_callback will eventually
  222                  * retrieve the AEN this attention interrupt is for.  So, we
  223                  * don't need to print the failure.
  224                  */ 
  225                 if (error != TW_OSL_EBUSY)
  226                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
  227                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
  228                                 0x1200, 0x1, TW_CL_SEVERITY_ERROR_STRING,
  229                                 "Failed to fetch AEN",
  230                                 "error = %d", error);
  231         }
  232 }
  233 
  234 
  235 
  236 /*
  237  * Function name:       tw_cli_process_cmd_intr
  238  * Description:         This function gets called if we hit a queue full
  239  *                      condition earlier, and the fw is now ready for
  240  *                      new cmds.  Submits any pending requests.
  241  *
  242  * Input:               ctlr    -- ptr to CL internal ctlr context
  243  * Output:              None
  244  * Return value:        None
  245  */
  246 TW_VOID
  247 tw_cli_process_cmd_intr(struct tw_cli_ctlr_context *ctlr)
  248 {
  249         tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  250 
  251         /*
  252          * Let the OS Layer submit any requests in its pending queue,
  253          * if it has one.
  254          */
  255         tw_osl_ctlr_ready(ctlr->ctlr_handle);
  256 
  257         /* Start any requests that might be in the pending queue. */
  258         tw_cli_submit_pending_queue(ctlr);
  259 
  260         /*
  261          * If tw_cli_submit_pending_queue was unsuccessful due to a "cmd queue
  262          * full" condition, cmd_intr will already have been unmasked by
  263          * tw_cli_submit_cmd.  We don't need to do it again... simply return.
  264          */
  265 }
  266 
  267 
  268 
  269 /*
  270  * Function name:       tw_cli_process_resp_intr
  271  * Description:         Looks for cmd completions from fw; queues cmds completed
  272  *                      by fw into complete queue.
  273  *
  274  * Input:               ctlr    -- ptr to CL internal ctlr context
  275  * Output:              None
  276  * Return value:        0       -- no ctlr error
  277  *                      non-zero-- ctlr error
  278  */
  279 TW_INT32
  280 tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr)
  281 {
  282         TW_UINT32                       resp;
  283         struct tw_cli_req_context       *req;
  284         TW_INT32                        error;
  285         TW_UINT32                       status_reg;
  286     
  287         tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  288 
  289         /* Serialize access to the controller response queue. */
  290         tw_osl_get_lock(ctlr->ctlr_handle, ctlr->intr_lock);
  291 
  292         for (;;) {
  293                 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
  294                 if ((error = tw_cli_check_ctlr_state(ctlr, status_reg)))
  295                         break;
  296                 if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) {
  297                         tw_cli_dbg_printf(7, ctlr->ctlr_handle,
  298                                 tw_osl_cur_func(), "Response queue empty");
  299                         break;
  300                 }
  301 
  302                 /* Response queue is not empty. */
  303                 resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
  304                 {
  305                         req = &(ctlr->req_ctxt_buf[GET_RESP_ID(resp)]);
  306                 }
  307 
  308                 if (req->state != TW_CLI_REQ_STATE_BUSY) {
  309                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
  310                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
  311                                 0x1201, 0x1, TW_CL_SEVERITY_ERROR_STRING,
  312                                 "Unposted command completed!!",
  313                                 "request = %p, status = %d",
  314                                 req, req->state);
  315 #ifdef TW_OSL_DEBUG
  316                         tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
  317 #endif /* TW_OSL_DEBUG */
  318                         tw_osl_free_lock(ctlr->ctlr_handle, ctlr->intr_lock);
  319                         tw_cl_reset_ctlr(ctlr->ctlr_handle);
  320                         return(TW_OSL_EIO);
  321                 }
  322 
  323                 /*
  324                  * Remove the request from the busy queue, mark it as complete,
  325                  * and enqueue it in the complete queue.
  326                  */
  327                 tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q);
  328                 req->state = TW_CLI_REQ_STATE_COMPLETE;
  329                 tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q);
  330 
  331         }
  332 
  333         /* Unmask the response interrupt. */
  334         TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
  335                 TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT);
  336 
  337         tw_osl_free_lock(ctlr->ctlr_handle, ctlr->intr_lock);
  338 
  339         /* Complete this, and other requests in the complete queue. */
  340         tw_cli_process_complete_queue(ctlr);
  341         
  342         return(error);
  343 }
  344 
  345 
  346 
  347 /*
  348  * Function name:       tw_cli_submit_pending_queue
  349  * Description:         Kick starts any requests in the pending queue.
  350  *
  351  * Input:               ctlr    -- ptr to CL internal ctlr context
  352  * Output:              None
  353  * Return value:        0       -- all pending requests submitted successfully
  354  *                      non-zero-- otherwise
  355  */
  356 TW_INT32
  357 tw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr)
  358 {
  359         struct tw_cli_req_context       *req;
  360         TW_INT32                        error = TW_OSL_ESUCCESS;
  361     
  362         tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  363         
  364         /*
  365          * Pull requests off the pending queue, and submit them.
  366          */
  367         while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) !=
  368                 TW_CL_NULL) {
  369                 if ((error = tw_cli_submit_cmd(req))) {
  370                         if (error == TW_OSL_EBUSY) {
  371                                 tw_cli_dbg_printf(2, ctlr->ctlr_handle,
  372                                         tw_osl_cur_func(),
  373                                         "Requeueing pending request");
  374                                 req->state = TW_CLI_REQ_STATE_PENDING;
  375                                 /*
  376                                  * Queue the request at the head of the pending
  377                                  * queue, and break away, so we don't try to
  378                                  * submit any more requests.
  379                                  */
  380                                 tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q);
  381                                 break;
  382                         } else {
  383                                 tw_cl_create_event(ctlr->ctlr_handle,
  384                                         TW_CL_FALSE,
  385                                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
  386                                         0x1202, 0x1,
  387                                         TW_CL_SEVERITY_ERROR_STRING,
  388                                         "Could not start request "
  389                                         "in pending queue",
  390                                         "request = %p, opcode = 0x%x, "
  391                                         "error = %d", req,
  392                                         GET_OPCODE(req->cmd_pkt->
  393                                                 command.cmd_pkt_9k.res__opcode),
  394                                         error);
  395                                 /*
  396                                  * Set the appropriate error and call the CL
  397                                  * internal callback if there's one.  If the
  398                                  * request originator is polling for completion,
  399                                  * he should be checking req->error to
  400                                  * determine that the request did not go
  401                                  * through.  The request originators are
  402                                  * responsible for the clean-up.
  403                                  */
  404                                 req->error_code = error;
  405                                 req->state = TW_CLI_REQ_STATE_COMPLETE;
  406                                 if (req->tw_cli_callback)
  407                                         req->tw_cli_callback(req);
  408                                 error = TW_OSL_ESUCCESS;
  409                         }
  410                 }
  411         }
  412         return(error);
  413 }
  414 
  415 
  416 
  417 /*
  418  * Function name:       tw_cli_process_complete_queue
  419  * Description:         Calls the CL internal callback routine, if any, for
  420  *                      each request in the complete queue.
  421  *
  422  * Input:               ctlr    -- ptr to CL internal ctlr context
  423  * Output:              None
  424  * Return value:        None
  425  */
  426 TW_VOID
  427 tw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr)
  428 {
  429         struct tw_cli_req_context       *req;
  430     
  431         tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  432 
  433         /*
  434          * Pull commands off the completed list, dispatch them appropriately.
  435          */
  436         while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) !=
  437                 TW_CL_NULL) {
  438                 /* Call the CL internal callback, if there's one. */
  439                 if (req->tw_cli_callback)
  440                         req->tw_cli_callback(req);
  441         }
  442 }
  443 
  444 
  445 
  446 /*
  447  * Function name:       tw_cli_complete_io
  448  * Description:         CL internal callback for SCSI/fw passthru requests.
  449  *
  450  * Input:               req     -- ptr to CL internal request context
  451  * Output:              None
  452  * Return value:        None
  453  */
  454 TW_VOID
  455 tw_cli_complete_io(struct tw_cli_req_context *req)
  456 {
  457         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
  458         struct tw_cl_req_packet         *req_pkt =
  459                 (struct tw_cl_req_packet *)(req->orig_req);
  460 
  461         tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  462 
  463         req_pkt->status = TW_CL_ERR_REQ_SUCCESS;
  464         if (req->error_code) {
  465                 req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND;
  466                 goto out;
  467         }
  468 
  469         if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
  470                 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
  471                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
  472                         0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING,
  473                         "I/O completion on incomplete command!!",
  474                         "request = %p, status = %d",
  475                         req, req->state);
  476 #ifdef TW_OSL_DEBUG
  477                 tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
  478 #endif /* TW_OSL_DEBUG */
  479                 tw_cl_reset_ctlr(ctlr->ctlr_handle);
  480                 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
  481                 goto out;
  482         }
  483 
  484         if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
  485                 /* Copy the command packet back into OSL's space. */
  486                 tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt,
  487                         sizeof(struct tw_cl_command_packet));
  488         } else
  489                 tw_cli_scsi_complete(req);
  490 
  491 out:
  492         req_pkt->tw_osl_callback(req->req_handle);
  493         tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
  494 }
  495 
  496 
  497 
  498 /*
  499  * Function name:       tw_cli_scsi_complete
  500  * Description:         Completion routine for SCSI requests.
  501  *
  502  * Input:               req     -- ptr to CL internal request context
  503  * Output:              None
  504  * Return value:        None
  505  */
  506 TW_VOID
  507 tw_cli_scsi_complete(struct tw_cli_req_context *req)
  508 {
  509         struct tw_cl_req_packet         *req_pkt =
  510                 (struct tw_cl_req_packet *)(req->orig_req);
  511         struct tw_cl_scsi_req_packet    *scsi_req =
  512                 &(req_pkt->gen_req_pkt.scsi_req);
  513         struct tw_cl_command_9k         *cmd =
  514                 &(req->cmd_pkt->command.cmd_pkt_9k);
  515         struct tw_cl_command_header     *cmd_hdr;
  516         TW_UINT16                       error;
  517         TW_UINT8                        *cdb;
  518 
  519         tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(),
  520                 "entered");
  521 
  522         scsi_req->scsi_status = cmd->status;
  523         if (! cmd->status)
  524                 return;
  525 
  526         tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(),
  527                 "req_id = 0x%x, status = 0x%x",
  528                 GET_REQ_ID(cmd->lun_l4__req_id), cmd->status);
  529 
  530         cmd_hdr = &(req->cmd_pkt->cmd_hdr);
  531         error = cmd_hdr->status_block.error;
  532         if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) ||
  533                         (error == TWA_ERROR_UNIT_OFFLINE)) {
  534                 if (GET_LUN_L4(cmd->lun_l4__req_id))
  535                         req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN;
  536                 else
  537                         req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET;
  538         } else {
  539                 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
  540                         tw_osl_cur_func(),
  541                         "cmd = %x %x %x %x %x %x %x",
  542                         GET_OPCODE(cmd->res__opcode),
  543                         GET_SGL_OFF(cmd->res__opcode),
  544                         cmd->unit,
  545                         cmd->lun_l4__req_id,
  546                         cmd->status,
  547                         cmd->sgl_offset,
  548                         cmd->lun_h4__sgl_entries);
  549 
  550                 cdb = (TW_UINT8 *)(cmd->cdb);
  551                 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
  552                         tw_osl_cur_func(),
  553                         "cdb = %x %x %x %x %x %x %x %x "
  554                         "%x %x %x %x %x %x %x %x",
  555                         cdb[0], cdb[1], cdb[2], cdb[3],
  556                         cdb[4], cdb[5], cdb[6], cdb[7],
  557                         cdb[8], cdb[9], cdb[10], cdb[11],
  558                         cdb[12], cdb[13], cdb[14], cdb[15]);
  559 
  560                 /* 
  561                  * Print the error. Firmware doesn't yet support
  562                  * the 'Mode Sense' cmd.  Don't print if the cmd
  563                  * is 'Mode Sense', and the error is 'Invalid field
  564                  * in CDB'.
  565                  */
  566                 if (! ((cdb[0] == 0x1A) && (error == 0x10D)))
  567                         tw_cli_create_ctlr_event(req->ctlr,
  568                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
  569                                 cmd_hdr);
  570         }
  571 
  572         if (scsi_req->sense_data) {
  573                 tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data,
  574                         TWA_SENSE_DATA_LENGTH);
  575                 scsi_req->sense_len = TWA_SENSE_DATA_LENGTH;
  576                 req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID;
  577         }
  578         req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR;
  579 }
  580 
  581 
  582 
  583 /*
  584  * Function name:       tw_cli_param_callback
  585  * Description:         Callback for get/set_param requests.
  586  *
  587  * Input:               req     -- ptr to completed request pkt
  588  * Output:              None
  589  * Return value:        None
  590  */
  591 TW_VOID
  592 tw_cli_param_callback(struct tw_cli_req_context *req)
  593 {
  594         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
  595         union tw_cl_command_7k          *cmd =
  596                 &(req->cmd_pkt->command.cmd_pkt_7k);
  597         TW_INT32                        error;
  598 
  599         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  600 
  601         /*
  602          * If the request was never submitted to the controller, the function
  603          * that sets req->error is responsible for calling tw_cl_create_event.
  604          */
  605         if (! req->error_code)
  606                 if (cmd->param.status) {
  607                         tw_cli_create_ctlr_event(ctlr,
  608                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
  609                                 &(req->cmd_pkt->cmd_hdr));
  610                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
  611                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
  612                                 0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING,
  613                                 "get/set_param failed",
  614                                 "status = %d", cmd->param.status);
  615                 }
  616 
  617         ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
  618         tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
  619 
  620         if ((ctlr->state & TW_CLI_CTLR_STATE_GET_MORE_AENS) &&
  621                 (!(ctlr->state & TW_CLI_CTLR_STATE_RESET_IN_PROGRESS))) {
  622                 ctlr->state &= ~TW_CLI_CTLR_STATE_GET_MORE_AENS;
  623                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
  624                         "Fetching more AEN's");
  625                 if ((error = tw_cli_get_aen(ctlr)))
  626                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
  627                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
  628                                 0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING,
  629                                 "Failed to fetch all AEN's from param_callback",
  630                                 "error = %d", error);
  631         }
  632 }
  633 
  634 
  635 
  636 /*
  637  * Function name:       tw_cli_aen_callback
  638  * Description:         Callback for requests to fetch AEN's.
  639  *
  640  * Input:               req     -- ptr to completed request pkt
  641  * Output:              None
  642  * Return value:        None
  643  */
  644 TW_VOID
  645 tw_cli_aen_callback(struct tw_cli_req_context *req)
  646 {
  647         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
  648         struct tw_cl_command_header     *cmd_hdr;
  649         struct tw_cl_command_9k         *cmd =
  650                 &(req->cmd_pkt->command.cmd_pkt_9k);
  651         TW_UINT16                       aen_code = TWA_AEN_QUEUE_EMPTY;
  652         TW_INT32                        error;
  653 
  654         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  655 
  656         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
  657                 "req_id = 0x%x, req error = %d, status = 0x%x",
  658                 GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status);
  659 
  660         /*
  661          * If the request was never submitted to the controller, the function
  662          * that sets error is responsible for calling tw_cl_create_event.
  663          */
  664         if (!(error = req->error_code))
  665                 if ((error = cmd->status)) {
  666                         cmd_hdr = (struct tw_cl_command_header *)
  667                                 (&(req->cmd_pkt->cmd_hdr));
  668                         tw_cli_create_ctlr_event(ctlr,
  669                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
  670                                 cmd_hdr);
  671                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
  672                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
  673                                 0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING,
  674                                 "Request Sense failed",
  675                                 "opcode = 0x%x, status = %d",
  676                                 GET_OPCODE(cmd->res__opcode), cmd->status);
  677                 }
  678 
  679         if (error) {
  680                 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
  681                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
  682                 return;
  683         }
  684 
  685         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
  686                 "Request Sense command succeeded");
  687 
  688         aen_code = tw_cli_manage_aen(ctlr, req);
  689 
  690         if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) {
  691                 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
  692                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
  693                 if (aen_code != TWA_AEN_QUEUE_EMPTY)
  694                         if ((error = tw_cli_get_aen(ctlr)))
  695                                 tw_cl_create_event(ctlr->ctlr_handle,
  696                                         TW_CL_FALSE,
  697                                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
  698                                         0x1207, 0x1,
  699                                         TW_CL_SEVERITY_ERROR_STRING,
  700                                         "Failed to fetch all AEN's",
  701                                         "error = %d", error);
  702         }
  703 }
  704 
  705 
  706 
  707 /*
  708  * Function name:       tw_cli_manage_aen
  709  * Description:         Handles AEN's.
  710  *
  711  * Input:               ctlr    -- ptr to CL internal ctlr context
  712  *                      req     -- ptr to CL internal request context
  713  * Output:              None
  714  * Return value:        None
  715  */
  716 TW_UINT16
  717 tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr,
  718         struct tw_cli_req_context *req)
  719 {
  720         struct tw_cl_command_header     *cmd_hdr;
  721         TW_UINT16                       aen_code;
  722         TW_TIME                         local_time;
  723         TW_TIME                         sync_time;
  724         TW_UINT32                       error;
  725 
  726         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  727 
  728         cmd_hdr = (struct tw_cl_command_header *)(req->data);
  729         aen_code = cmd_hdr->status_block.error;
  730 
  731         switch (aen_code) {
  732         case TWA_AEN_SYNC_TIME_WITH_HOST:
  733                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
  734                         "Received AEN_SYNC_TIME");
  735                 /*
  736                  * Free the internal req pkt right here, since
  737                  * tw_cli_set_param will need it.
  738                  */
  739                 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
  740                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
  741 
  742                 /*
  743                  * We will use a callback in tw_cli_set_param only when
  744                  * interrupts are enabled and we can expect our callback
  745                  * to get called.  Setting the TW_CLI_CTLR_STATE_GET_MORE_AENS
  746                  * flag will make the callback continue to try to retrieve
  747                  * more AEN's.
  748                  */
  749                 if (ctlr->state & TW_CLI_CTLR_STATE_INTR_ENABLED)
  750                         ctlr->state |= TW_CLI_CTLR_STATE_GET_MORE_AENS;
  751                 /* Calculate time (in seconds) since last Sunday 12.00 AM. */
  752                 local_time = tw_osl_get_local_time();
  753                 sync_time = (local_time - (3 * 86400)) % 604800;
  754                 if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE,
  755                                 TWA_PARAM_TIME_SCHED_TIME, 4,
  756                                 &sync_time,
  757                                 (ctlr->state & TW_CLI_CTLR_STATE_INTR_ENABLED)
  758                                 ? tw_cli_param_callback : TW_CL_NULL)))
  759                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
  760                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
  761                                 0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING,
  762                                 "Unable to sync time with ctlr",
  763                                 "error = %d", error);
  764 
  765                 break;
  766 
  767 
  768         case TWA_AEN_QUEUE_EMPTY:
  769                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
  770                         "AEN queue empty");
  771                 break;
  772 
  773 
  774         default:
  775                 /* Queue the event. */
  776 
  777                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
  778                         "Queueing AEN");
  779                 tw_cli_create_ctlr_event(ctlr,
  780                         TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT,
  781                         cmd_hdr);
  782                 break;
  783         } /* switch */
  784         return(aen_code);
  785 }
  786 
  787 
  788 
  789 /*
  790  * Function name:       tw_cli_enable_interrupts
  791  * Description:         Enables interrupts on the controller
  792  *
  793  * Input:               ctlr    -- ptr to CL internal ctlr context
  794  * Output:              None
  795  * Return value:        None
  796  */
  797 TW_VOID
  798 tw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr)
  799 {
  800         tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  801 
  802         ctlr->state |= TW_CLI_CTLR_STATE_INTR_ENABLED;
  803         TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
  804                 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT |
  805                 TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT |
  806                 TWA_CONTROL_ENABLE_INTERRUPTS);
  807 }
  808 
  809 
  810 
  811 /*
  812  * Function name:       twa_setup
  813  * Description:         Disables interrupts on the controller
  814  *
  815  * Input:               ctlr    -- ptr to CL internal ctlr context
  816  * Output:              None
  817  * Return value:        None
  818  */
  819 TW_VOID
  820 tw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr)
  821 {
  822         tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
  823 
  824         TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
  825                 TWA_CONTROL_DISABLE_INTERRUPTS);
  826         ctlr->state &= ~TW_CLI_CTLR_STATE_INTR_ENABLED;
  827 }
  828 

Cache object: 75997fed8e8a4f12a67bb94a749c9722


[ 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.