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/tws/tws_user.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) 2010, LSI Corp.
    3  * All rights reserved.
    4  * Author : Manjunath Ranganathaiah
    5  * Support: freebsdraid@lsi.com
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  *
   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
   15  *    the documentation and/or other materials provided with the
   16  *    distribution.
   17  * 3. Neither the name of the <ORGANIZATION> nor the names of its
   18  *    contributors may be used to endorse or promote products derived
   19  *    from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32  * POSSIBILITY OF SUCH DAMAGE.
   33  *
   34  * $FreeBSD: releng/11.2/sys/dev/tws/tws_user.c 331722 2018-03-29 02:50:57Z eadler $
   35  */
   36 
   37 #include <dev/tws/tws.h>
   38 #include <dev/tws/tws_services.h>
   39 #include <dev/tws/tws_hdm.h>
   40 #include <dev/tws/tws_user.h>
   41 
   42 
   43 int tws_ioctl(struct cdev *dev, long unsigned int cmd, caddr_t buf, int flags, 
   44                                                     struct thread *td);
   45 void tws_passthru_complete(struct tws_request *req);
   46 extern void tws_circular_aenq_insert(struct tws_softc *sc,
   47                     struct tws_circular_q *cq, struct tws_event_packet *aen);
   48 
   49 
   50 static int tws_passthru(struct tws_softc *sc, void *buf);
   51 static int tws_ioctl_aen(struct tws_softc *sc, u_long cmd, void *buf);
   52 
   53 extern int tws_bus_scan(struct tws_softc *sc);
   54 extern struct tws_request *tws_get_request(struct tws_softc *sc, 
   55                                            u_int16_t type);
   56 extern int32_t tws_map_request(struct tws_softc *sc, struct tws_request *req);
   57 extern void tws_unmap_request(struct tws_softc *sc, struct tws_request *req);
   58 extern uint8_t tws_get_state(struct tws_softc *sc);
   59 extern void tws_timeout(void *arg);
   60 
   61 int
   62 tws_ioctl(struct cdev *dev, u_long cmd, caddr_t buf, int flags, 
   63                                                     struct thread *td)
   64 {
   65     struct tws_softc *sc = (struct tws_softc *)(dev->si_drv1);
   66     int error;
   67 
   68     TWS_TRACE_DEBUG(sc, "entry", sc, cmd);
   69     sc->stats.ioctls++;
   70     switch(cmd) {
   71         case TWS_IOCTL_FIRMWARE_PASS_THROUGH :
   72             error = tws_passthru(sc, (void *)buf);
   73             break;
   74         case TWS_IOCTL_SCAN_BUS :
   75             TWS_TRACE_DEBUG(sc, "scan-bus", 0, 0);
   76             error = tws_bus_scan(sc);
   77             break;
   78         default :
   79             TWS_TRACE_DEBUG(sc, "ioctl-aen", cmd, buf);
   80             error = tws_ioctl_aen(sc, cmd, (void *)buf);
   81             break;
   82 
   83     }
   84     return(error);
   85 }
   86 
   87 static int 
   88 tws_passthru(struct tws_softc *sc, void *buf)
   89 {
   90     struct tws_request *req;
   91     struct tws_ioctl_no_data_buf *ubuf = (struct tws_ioctl_no_data_buf *)buf;
   92     int error;
   93     u_int16_t lun4;
   94 
   95 
   96     if ( tws_get_state(sc) != TWS_ONLINE) {
   97         return(EBUSY);
   98     }
   99 
  100     //==============================================================================================
  101     // Get a command
  102     //
  103     do {
  104         req = tws_get_request(sc, TWS_REQ_TYPE_PASSTHRU);
  105         if ( !req ) {
  106             error = tsleep(sc,  0, "tws_sleep", TWS_IOCTL_TIMEOUT*hz);
  107             if ( error == EWOULDBLOCK ) {
  108                 return(ETIMEDOUT);
  109             }
  110         } else {
  111             // Make sure we are still ready for new commands...
  112             if ( tws_get_state(sc) != TWS_ONLINE) {
  113                 return(EBUSY);
  114             }
  115             break;
  116         }
  117     } while(1);
  118 
  119     req->length = (ubuf->driver_pkt.buffer_length + 511) & ~511;
  120     TWS_TRACE_DEBUG(sc, "datal,rid", req->length, req->request_id);
  121     if ( req->length ) {
  122         req->data = sc->ioctl_data_mem;
  123         req->dma_map = sc->ioctl_data_map;
  124 
  125         //==========================================================================================
  126         // Copy data in from user space
  127         //
  128         error = copyin(ubuf->pdata, req->data, req->length);
  129     }
  130 
  131     //==============================================================================================
  132     // Set command fields
  133     //
  134     req->flags = TWS_DIR_IN | TWS_DIR_OUT;
  135     req->cb = tws_passthru_complete;
  136 
  137     memcpy(&req->cmd_pkt->cmd, &ubuf->cmd_pkt.cmd, 
  138                               sizeof(struct tws_command_apache));
  139 
  140     if ( GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) == 
  141                                                TWS_FW_CMD_EXECUTE_SCSI ) { 
  142         lun4 = req->cmd_pkt->cmd.pkt_a.lun_l4__req_id & 0xF000;
  143         req->cmd_pkt->cmd.pkt_a.lun_l4__req_id = lun4 | req->request_id;
  144     } else {
  145         req->cmd_pkt->cmd.pkt_g.generic.request_id = (u_int8_t) req->request_id;
  146     }
  147 
  148     //==============================================================================================
  149     // Send command to controller
  150     //
  151     error = tws_map_request(sc, req);
  152     if (error) {
  153         ubuf->driver_pkt.os_status = error;
  154         goto out_data;
  155     }
  156 
  157     if ( req->state == TWS_REQ_STATE_COMPLETE ) {
  158         ubuf->driver_pkt.os_status = req->error_code;
  159         goto out_unmap;
  160     }
  161 
  162     mtx_lock(&sc->gen_lock);
  163     error = mtx_sleep(req, &sc->gen_lock, 0, "tws_passthru", TWS_IOCTL_TIMEOUT*hz);
  164     mtx_unlock(&sc->gen_lock);
  165     if (( req->state != TWS_REQ_STATE_COMPLETE ) && ( error == EWOULDBLOCK )) {
  166             TWS_TRACE_DEBUG(sc, "msleep timeout", error, req->request_id);
  167             tws_timeout((void*) req);
  168     }
  169 
  170 out_unmap:
  171     if ( req->error_code == TWS_REQ_RET_RESET ) {
  172         error = EBUSY;
  173         req->error_code = EBUSY;
  174         TWS_TRACE_DEBUG(sc, "ioctl reset", error, req->request_id);
  175     }
  176 
  177     tws_unmap_request(sc, req);
  178 
  179     //==============================================================================================
  180     // Return command status to user space
  181     //
  182     memcpy(&ubuf->cmd_pkt.hdr, &req->cmd_pkt->hdr, sizeof(struct tws_command_apache));
  183     memcpy(&ubuf->cmd_pkt.cmd, &req->cmd_pkt->cmd, sizeof(struct tws_command_apache));
  184 
  185 out_data:
  186     if ( req->length ) {
  187         //==========================================================================================
  188         // Copy data out to user space
  189         //
  190         if ( !error )
  191             error = copyout(req->data, ubuf->pdata, ubuf->driver_pkt.buffer_length);
  192     }
  193 
  194     if ( error ) 
  195         TWS_TRACE_DEBUG(sc, "errored", error, 0);
  196 
  197     if ( req->error_code != TWS_REQ_RET_SUBMIT_SUCCESS )
  198         ubuf->driver_pkt.os_status = error;
  199 
  200     //==============================================================================================
  201     // Free command
  202     //
  203     req->state = TWS_REQ_STATE_FREE;
  204 
  205     wakeup_one(sc);
  206 
  207     return(error);
  208 }
  209 
  210 void 
  211 tws_passthru_complete(struct tws_request *req)
  212 {
  213     req->state = TWS_REQ_STATE_COMPLETE;
  214     wakeup_one(req);
  215 
  216 }
  217 
  218 static void 
  219 tws_retrive_aen(struct tws_softc *sc, u_long cmd, 
  220                             struct tws_ioctl_packet *ubuf)
  221 {
  222     u_int16_t index=0;
  223     struct tws_event_packet eventp, *qp;
  224 
  225     if ( sc->aen_q.head == sc->aen_q.tail ) {
  226         ubuf->driver_pkt.status = TWS_AEN_NO_EVENTS;
  227         return;
  228     }
  229     
  230     ubuf->driver_pkt.status = 0;
  231 
  232     /* 
  233      * once this flag is set cli will not display alarms 
  234      * needs a revisit from tools?
  235      */
  236     if ( sc->aen_q.overflow ) {
  237         ubuf->driver_pkt.status = TWS_AEN_OVERFLOW;
  238         sc->aen_q.overflow = 0; /* reset */
  239     }
  240 
  241     qp = (struct tws_event_packet *)sc->aen_q.q;
  242 
  243     switch (cmd) {
  244         case TWS_IOCTL_GET_FIRST_EVENT :
  245             index = sc->aen_q.head;
  246             break;
  247         case TWS_IOCTL_GET_LAST_EVENT :
  248             /* index = tail-1 */ 
  249             index = (sc->aen_q.depth + sc->aen_q.tail - 1) % sc->aen_q.depth;
  250             break;
  251         case TWS_IOCTL_GET_NEXT_EVENT :
  252             memcpy(&eventp, ubuf->data_buf, sizeof(struct tws_event_packet));
  253             index = sc->aen_q.head;
  254             do {
  255                 if ( qp[index].sequence_id == 
  256                            (eventp.sequence_id + 1) )
  257                     break;
  258                 index  = (index+1) % sc->aen_q.depth;
  259             }while ( index != sc->aen_q.tail );
  260             if ( index == sc->aen_q.tail ) {
  261                 ubuf->driver_pkt.status = TWS_AEN_NO_EVENTS;
  262                 return;
  263             }
  264             break;
  265         case TWS_IOCTL_GET_PREVIOUS_EVENT :
  266             memcpy(&eventp, ubuf->data_buf, sizeof(struct tws_event_packet));
  267             index = sc->aen_q.head;
  268             do {
  269                 if ( qp[index].sequence_id == 
  270                            (eventp.sequence_id - 1) )
  271                     break;
  272                 index  = (index+1) % sc->aen_q.depth;
  273             }while ( index != sc->aen_q.tail );
  274             if ( index == sc->aen_q.tail ) {
  275                 ubuf->driver_pkt.status = TWS_AEN_NO_EVENTS;
  276                 return;
  277             }
  278             break;
  279         default :
  280             TWS_TRACE_DEBUG(sc, "not a valid event", sc, cmd);
  281             ubuf->driver_pkt.status = TWS_AEN_NO_EVENTS;
  282             return;
  283     }
  284 
  285     memcpy(ubuf->data_buf, &qp[index], 
  286                            sizeof(struct tws_event_packet));
  287     qp[index].retrieved = TWS_AEN_RETRIEVED;
  288 
  289     return;
  290 
  291 }
  292 
  293 static int 
  294 tws_ioctl_aen(struct tws_softc *sc, u_long cmd, void *buf)
  295 {
  296 
  297     struct tws_ioctl_packet *ubuf = (struct tws_ioctl_packet *)buf;
  298     struct tws_compatibility_packet cpkt;
  299     struct tws_lock_packet lpkt;
  300     time_t ctime;
  301 
  302     mtx_lock(&sc->gen_lock);
  303     ubuf->driver_pkt.status = 0;
  304     switch(cmd) {
  305         case TWS_IOCTL_GET_FIRST_EVENT :
  306         case TWS_IOCTL_GET_LAST_EVENT :
  307         case TWS_IOCTL_GET_NEXT_EVENT :
  308         case TWS_IOCTL_GET_PREVIOUS_EVENT :
  309             tws_retrive_aen(sc,cmd,ubuf);
  310             break;
  311         case TWS_IOCTL_GET_LOCK :
  312             ctime = TWS_LOCAL_TIME;
  313             memcpy(&lpkt, ubuf->data_buf, sizeof(struct tws_lock_packet));
  314             if ( (sc->ioctl_lock.lock == TWS_IOCTL_LOCK_FREE) ||
  315                  (lpkt.force_flag) ||
  316                  (ctime >= sc->ioctl_lock.timeout) ) {
  317                 sc->ioctl_lock.lock = TWS_IOCTL_LOCK_HELD;
  318                 sc->ioctl_lock.timeout = ctime + (lpkt.timeout_msec / 1000);
  319                 lpkt.time_remaining_msec = lpkt.timeout_msec;
  320             }  else {
  321                 lpkt.time_remaining_msec = (u_int32_t)
  322                           ((sc->ioctl_lock.timeout - ctime) * 1000);
  323                 ubuf->driver_pkt.status = TWS_IOCTL_LOCK_ALREADY_HELD;
  324 
  325             }
  326             break;
  327         case TWS_IOCTL_RELEASE_LOCK :
  328             if (sc->ioctl_lock.lock == TWS_IOCTL_LOCK_FREE) {
  329                 ubuf->driver_pkt.status = TWS_IOCTL_LOCK_NOT_HELD;
  330             } else {
  331                 sc->ioctl_lock.lock = TWS_IOCTL_LOCK_FREE;
  332                 ubuf->driver_pkt.status = 0;
  333             }
  334             break;
  335         case TWS_IOCTL_GET_COMPATIBILITY_INFO :
  336             TWS_TRACE_DEBUG(sc, "get comp info", sc, cmd);
  337 
  338             memcpy( cpkt.driver_version, TWS_DRIVER_VERSION_STRING,
  339                                          sizeof(TWS_DRIVER_VERSION_STRING));
  340             cpkt.working_srl = sc->cinfo.working_srl;
  341             cpkt.working_branch = sc->cinfo.working_branch;
  342             cpkt.working_build = sc->cinfo.working_build;
  343             cpkt.driver_srl_high = TWS_CURRENT_FW_SRL;
  344             cpkt.driver_branch_high = TWS_CURRENT_FW_BRANCH;
  345             cpkt.driver_build_high = TWS_CURRENT_FW_BUILD;
  346             cpkt.driver_srl_low = TWS_BASE_FW_SRL;
  347             cpkt.driver_branch_low = TWS_BASE_FW_BRANCH;
  348             cpkt.driver_build_low = TWS_BASE_FW_BUILD;
  349             cpkt.fw_on_ctlr_srl = sc->cinfo.fw_on_ctlr_srl;
  350             cpkt.fw_on_ctlr_branch = sc->cinfo.fw_on_ctlr_branch;
  351             cpkt.fw_on_ctlr_build = sc->cinfo.fw_on_ctlr_build;
  352             ubuf->driver_pkt.status = 0;
  353             int len = sizeof(struct tws_compatibility_packet);
  354             if ( ubuf->driver_pkt.buffer_length < len )
  355                 len = ubuf->driver_pkt.buffer_length;
  356             memcpy(ubuf->data_buf, &cpkt, len);
  357 
  358             break;
  359         default :
  360             TWS_TRACE_DEBUG(sc, "not valid cmd", cmd, 
  361                            TWS_IOCTL_GET_COMPATIBILITY_INFO);
  362             break;
  363 
  364     }
  365     mtx_unlock(&sc->gen_lock);
  366     return(SUCCESS);
  367 
  368 }
  369 
  370 void
  371 tws_circular_aenq_insert(struct tws_softc *sc, struct tws_circular_q *cq,
  372 struct tws_event_packet *aen)
  373 {
  374 
  375     struct tws_event_packet *q = (struct tws_event_packet *)cq->q;
  376     volatile u_int16_t head, tail;
  377     u_int8_t retr;
  378     mtx_assert(&sc->gen_lock, MA_OWNED);
  379 
  380     head = cq->head;
  381     tail = cq->tail;
  382     retr = q[tail].retrieved;
  383 
  384     memcpy(&q[tail], aen, sizeof(struct tws_event_packet));
  385     tail = (tail+1) % cq->depth;
  386 
  387     if ( head == tail ) { /* q is full */
  388         if ( retr != TWS_AEN_RETRIEVED )
  389             cq->overflow = 1;
  390         cq->head = (head+1) % cq->depth;
  391     }
  392     cq->tail = tail;
  393 
  394 }

Cache object: 5f2305249be024d5e08ec2e8a5ffd763


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