xref: /dflybsd-src/sys/dev/raid/tws/tws_user.c (revision aaea8fd38687ebe012024c20a7d5b8e15c61d3b3)
133190b70SSascha Wildner /*
233190b70SSascha Wildner  * Copyright (c) 2010, LSI Corp.
333190b70SSascha Wildner  * All rights reserved.
433190b70SSascha Wildner  * Author : Manjunath Ranganathaiah
533190b70SSascha Wildner  * Support: freebsdraid@lsi.com
633190b70SSascha Wildner  *
733190b70SSascha Wildner  * Redistribution and use in source and binary forms, with or without
833190b70SSascha Wildner  * modification, are permitted provided that the following conditions
933190b70SSascha Wildner  * are met:
1033190b70SSascha Wildner  *
1133190b70SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
1233190b70SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
1333190b70SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
1433190b70SSascha Wildner  *    notice, this list of conditions and the following disclaimer in
1533190b70SSascha Wildner  *    the documentation and/or other materials provided with the
1633190b70SSascha Wildner  *    distribution.
1733190b70SSascha Wildner  * 3. Neither the name of the <ORGANIZATION> nor the names of its
1833190b70SSascha Wildner  *    contributors may be used to endorse or promote products derived
1933190b70SSascha Wildner  *    from this software without specific prior written permission.
2033190b70SSascha Wildner  *
2133190b70SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2233190b70SSascha Wildner  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2333190b70SSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2433190b70SSascha Wildner  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2533190b70SSascha Wildner  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2633190b70SSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2733190b70SSascha Wildner  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2833190b70SSascha Wildner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2933190b70SSascha Wildner  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3033190b70SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3133190b70SSascha Wildner  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3233190b70SSascha Wildner  * POSSIBILITY OF SUCH DAMAGE.
3333190b70SSascha Wildner  *
3433190b70SSascha Wildner  * $FreeBSD: src/sys/dev/tws/tws_user.c,v 1.3 2007/05/09 04:16:32 mrangana Exp $
3533190b70SSascha Wildner  */
3633190b70SSascha Wildner 
3733190b70SSascha Wildner #include <dev/raid/tws/tws.h>
3833190b70SSascha Wildner #include <dev/raid/tws/tws_services.h>
3933190b70SSascha Wildner #include <dev/raid/tws/tws_hdm.h>
4033190b70SSascha Wildner #include <dev/raid/tws/tws_user.h>
4133190b70SSascha Wildner 
4233190b70SSascha Wildner 
4333190b70SSascha Wildner d_ioctl_t    tws_ioctl;
4433190b70SSascha Wildner 
4533190b70SSascha Wildner void tws_passthru_complete(struct tws_request *req);
4633190b70SSascha Wildner extern void tws_circular_aenq_insert(struct tws_softc *sc,
4733190b70SSascha Wildner                     struct tws_circular_q *cq, struct tws_event_packet *aen);
4833190b70SSascha Wildner 
4933190b70SSascha Wildner 
5033190b70SSascha Wildner static int tws_passthru(struct tws_softc *sc, void *buf);
5133190b70SSascha Wildner static int tws_ioctl_aen(struct tws_softc *sc, u_long cmd, void *buf);
5233190b70SSascha Wildner 
5333190b70SSascha Wildner extern int tws_bus_scan(struct tws_softc *sc);
5433190b70SSascha Wildner extern struct tws_request *tws_get_request(struct tws_softc *sc,
5533190b70SSascha Wildner                                            u_int16_t type);
5633190b70SSascha Wildner extern int32_t tws_map_request(struct tws_softc *sc, struct tws_request *req);
5733190b70SSascha Wildner extern void tws_unmap_request(struct tws_softc *sc, struct tws_request *req);
5833190b70SSascha Wildner extern uint8_t tws_get_state(struct tws_softc *sc);
5933190b70SSascha Wildner extern void tws_reset(void *arg);
6033190b70SSascha Wildner 
6133190b70SSascha Wildner int
tws_ioctl(struct dev_ioctl_args * ap)6233190b70SSascha Wildner tws_ioctl(struct dev_ioctl_args *ap)
6333190b70SSascha Wildner {
6433190b70SSascha Wildner     cdev_t dev = ap->a_head.a_dev;
6533190b70SSascha Wildner     u_long cmd = ap->a_cmd;
6633190b70SSascha Wildner     caddr_t buf = ap->a_data;
6733190b70SSascha Wildner     struct tws_softc *sc = (struct tws_softc *)(dev->si_drv1);
6833190b70SSascha Wildner     int error;
6933190b70SSascha Wildner 
7033190b70SSascha Wildner     TWS_TRACE_DEBUG(sc, "entry", sc, cmd);
7133190b70SSascha Wildner     sc->stats.ioctls++;
7233190b70SSascha Wildner     switch(cmd) {
7333190b70SSascha Wildner         case TWS_IOCTL_FIRMWARE_PASS_THROUGH :
7433190b70SSascha Wildner             error = tws_passthru(sc, (void *)buf);
7533190b70SSascha Wildner             break;
7633190b70SSascha Wildner         case TWS_IOCTL_SCAN_BUS :
7733190b70SSascha Wildner             TWS_TRACE_DEBUG(sc, "scan-bus", 0, 0);
7833190b70SSascha Wildner             lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
7933190b70SSascha Wildner             error = tws_bus_scan(sc);
8033190b70SSascha Wildner             lockmgr(&sc->sim_lock, LK_RELEASE);
8133190b70SSascha Wildner             break;
8233190b70SSascha Wildner         default :
8333190b70SSascha Wildner             TWS_TRACE_DEBUG(sc, "ioctl-aen", cmd, buf);
8433190b70SSascha Wildner             error = tws_ioctl_aen(sc, cmd, (void *)buf);
8533190b70SSascha Wildner             break;
8633190b70SSascha Wildner 
8733190b70SSascha Wildner     }
8833190b70SSascha Wildner     return(error);
8933190b70SSascha Wildner }
9033190b70SSascha Wildner 
9133190b70SSascha Wildner static int
tws_passthru(struct tws_softc * sc,void * buf)9233190b70SSascha Wildner tws_passthru(struct tws_softc *sc, void *buf)
9333190b70SSascha Wildner {
9433190b70SSascha Wildner     struct tws_request *req;
9533190b70SSascha Wildner     struct tws_ioctl_no_data_buf *ubuf = (struct tws_ioctl_no_data_buf *)buf;
9633190b70SSascha Wildner     int error;
9733190b70SSascha Wildner     u_int16_t lun4;
9833190b70SSascha Wildner 
9933190b70SSascha Wildner     if ( tws_get_state(sc) == TWS_RESET ) {
10033190b70SSascha Wildner         return(EBUSY);
10133190b70SSascha Wildner     }
10233190b70SSascha Wildner 
10333190b70SSascha Wildner     do {
10433190b70SSascha Wildner         req = tws_get_request(sc, TWS_PASSTHRU_REQ);
10533190b70SSascha Wildner         if ( !req ) {
10633190b70SSascha Wildner             sc->chan = 1;
10733190b70SSascha Wildner             error = tsleep((void *)&sc->chan,  0,
10833190b70SSascha Wildner                                    "tws_sleep", TWS_IO_TIMEOUT*hz);
10933190b70SSascha Wildner             if ( error == EWOULDBLOCK ) {
11033190b70SSascha Wildner                 return(ETIMEDOUT);
11133190b70SSascha Wildner             }
11233190b70SSascha Wildner         } else {
11333190b70SSascha Wildner             break;
11433190b70SSascha Wildner         }
11533190b70SSascha Wildner     }while(1);
11633190b70SSascha Wildner 
11733190b70SSascha Wildner     req->length = ubuf->driver_pkt.buffer_length;
11833190b70SSascha Wildner     TWS_TRACE_DEBUG(sc, "datal,rid", req->length, req->request_id);
11933190b70SSascha Wildner     if ( req->length ) {
12033190b70SSascha Wildner         req->data = kmalloc(req->length, M_TWS, M_WAITOK | M_ZERO);
12133190b70SSascha Wildner         error = copyin(ubuf->pdata, req->data, req->length);
12233190b70SSascha Wildner     }
12333190b70SSascha Wildner     req->flags = TWS_DIR_IN | TWS_DIR_OUT;
12433190b70SSascha Wildner     req->cb = tws_passthru_complete;
12533190b70SSascha Wildner 
12633190b70SSascha Wildner     memcpy(&req->cmd_pkt->cmd, &ubuf->cmd_pkt.cmd,
12733190b70SSascha Wildner                               sizeof(struct tws_command_apache));
12833190b70SSascha Wildner 
12933190b70SSascha Wildner     if ( GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) ==
13033190b70SSascha Wildner                                                TWS_FW_CMD_EXECUTE_SCSI ) {
13133190b70SSascha Wildner         lun4 = req->cmd_pkt->cmd.pkt_a.lun_l4__req_id & 0xF000;
13233190b70SSascha Wildner         req->cmd_pkt->cmd.pkt_a.lun_l4__req_id = lun4 | req->request_id;
13333190b70SSascha Wildner     } else {
13433190b70SSascha Wildner         req->cmd_pkt->cmd.pkt_g.generic.request_id = (u_int8_t) req->request_id;
13533190b70SSascha Wildner 
13633190b70SSascha Wildner     }
13733190b70SSascha Wildner 
13833190b70SSascha Wildner 
13933190b70SSascha Wildner     lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
14033190b70SSascha Wildner     req->error_code = tws_map_request(sc, req);
14133190b70SSascha Wildner 
14233190b70SSascha Wildner     error = lksleep(req, &sc->gen_lock, 0, "tws_passthru", TWS_IO_TIMEOUT*hz);
14333190b70SSascha Wildner     if ( error == EWOULDBLOCK ) {
14433190b70SSascha Wildner         error = ETIMEDOUT;
14533190b70SSascha Wildner         TWS_TRACE_DEBUG(sc, "lksleep timeout", error, req->request_id);
146*4e1af74fSSascha Wildner         tws_reset(sc);
14733190b70SSascha Wildner     }
14833190b70SSascha Wildner 
14933190b70SSascha Wildner     if ( req->error_code == TWS_REQ_REQUEUE ) {
15033190b70SSascha Wildner         error = EBUSY;
15133190b70SSascha Wildner     }
15233190b70SSascha Wildner 
15333190b70SSascha Wildner     tws_unmap_request(sc, req);
15433190b70SSascha Wildner 
15533190b70SSascha Wildner     memcpy(&ubuf->cmd_pkt.hdr, &req->cmd_pkt->hdr, sizeof(struct tws_command_apache));
15633190b70SSascha Wildner     memcpy(&ubuf->cmd_pkt.cmd, &req->cmd_pkt->cmd, sizeof(struct tws_command_apache));
15733190b70SSascha Wildner     if ( !error && req->length ) {
15833190b70SSascha Wildner         error = copyout(req->data, ubuf->pdata, req->length);
15933190b70SSascha Wildner     }
16033190b70SSascha Wildner 
16133190b70SSascha Wildner     kfree(req->data, M_TWS);
16233190b70SSascha Wildner     req->state = TWS_REQ_STATE_FREE;
16333190b70SSascha Wildner     lockmgr(&sc->gen_lock, LK_RELEASE);
16433190b70SSascha Wildner 
16533190b70SSascha Wildner     if ( error )
16633190b70SSascha Wildner         TWS_TRACE_DEBUG(sc, "errored", error, 0);
16733190b70SSascha Wildner     if ( req->error_code  != TWS_REQ_SUBMIT_SUCCESS )
16833190b70SSascha Wildner         ubuf->driver_pkt.os_status = error;
16933190b70SSascha Wildner     if ( sc->chan && tws_get_state(sc) != TWS_RESET ) {
17033190b70SSascha Wildner         sc->chan = 0;
17133190b70SSascha Wildner         wakeup((void *)&sc->chan);
17233190b70SSascha Wildner     }
17333190b70SSascha Wildner     return(error);
17433190b70SSascha Wildner }
17533190b70SSascha Wildner 
17633190b70SSascha Wildner void
tws_passthru_complete(struct tws_request * req)17733190b70SSascha Wildner tws_passthru_complete(struct tws_request *req)
17833190b70SSascha Wildner {
17933190b70SSascha Wildner     struct tws_softc *sc = req->sc;
18033190b70SSascha Wildner 
18133190b70SSascha Wildner     lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
18233190b70SSascha Wildner     wakeup_one(req);
18333190b70SSascha Wildner     lockmgr(&sc->gen_lock, LK_RELEASE);
18433190b70SSascha Wildner 
18533190b70SSascha Wildner }
18633190b70SSascha Wildner 
18733190b70SSascha Wildner static void
tws_retrive_aen(struct tws_softc * sc,u_long cmd,struct tws_ioctl_packet * ubuf)18833190b70SSascha Wildner tws_retrive_aen(struct tws_softc *sc, u_long cmd,
18933190b70SSascha Wildner                             struct tws_ioctl_packet *ubuf)
19033190b70SSascha Wildner {
19133190b70SSascha Wildner     u_int16_t index=0;
19233190b70SSascha Wildner     struct tws_event_packet eventp, *qp;
19333190b70SSascha Wildner 
19433190b70SSascha Wildner     if ( sc->aen_q.head == sc->aen_q.tail ) {
19533190b70SSascha Wildner         ubuf->driver_pkt.status = TWS_AEN_NO_EVENTS;
19633190b70SSascha Wildner         return;
19733190b70SSascha Wildner     }
19833190b70SSascha Wildner 
19933190b70SSascha Wildner     ubuf->driver_pkt.status = 0;
20033190b70SSascha Wildner 
20133190b70SSascha Wildner     /*
20233190b70SSascha Wildner      * once this flag is set cli will not display alarms
20333190b70SSascha Wildner      * needs a revisit from tools?
20433190b70SSascha Wildner      */
20533190b70SSascha Wildner     if ( sc->aen_q.overflow ) {
20633190b70SSascha Wildner         ubuf->driver_pkt.status = TWS_AEN_OVERFLOW;
20733190b70SSascha Wildner         sc->aen_q.overflow = 0; /* reset */
20833190b70SSascha Wildner     }
20933190b70SSascha Wildner 
21033190b70SSascha Wildner     qp = (struct tws_event_packet *)sc->aen_q.q;
21133190b70SSascha Wildner 
21233190b70SSascha Wildner     switch (cmd) {
21333190b70SSascha Wildner         case TWS_IOCTL_GET_FIRST_EVENT :
21433190b70SSascha Wildner             index = sc->aen_q.head;
21533190b70SSascha Wildner             break;
21633190b70SSascha Wildner         case TWS_IOCTL_GET_LAST_EVENT :
21733190b70SSascha Wildner             /* index = tail-1 */
21833190b70SSascha Wildner             index = (sc->aen_q.depth + sc->aen_q.tail - 1) % sc->aen_q.depth;
21933190b70SSascha Wildner             break;
22033190b70SSascha Wildner         case TWS_IOCTL_GET_NEXT_EVENT :
22133190b70SSascha Wildner             memcpy(&eventp, ubuf->data_buf, sizeof(struct tws_event_packet));
22233190b70SSascha Wildner             index = sc->aen_q.head;
22333190b70SSascha Wildner             do {
22433190b70SSascha Wildner                 if ( qp[index].sequence_id ==
22533190b70SSascha Wildner                            (eventp.sequence_id + 1) )
22633190b70SSascha Wildner                     break;
22733190b70SSascha Wildner                 index  = (index+1) % sc->aen_q.depth;
22833190b70SSascha Wildner             }while ( index != sc->aen_q.tail );
22933190b70SSascha Wildner             if ( index == sc->aen_q.tail ) {
23033190b70SSascha Wildner                 ubuf->driver_pkt.status = TWS_AEN_NO_EVENTS;
23133190b70SSascha Wildner                 return;
23233190b70SSascha Wildner             }
23333190b70SSascha Wildner             break;
23433190b70SSascha Wildner         case TWS_IOCTL_GET_PREVIOUS_EVENT :
23533190b70SSascha Wildner             memcpy(&eventp, ubuf->data_buf, sizeof(struct tws_event_packet));
23633190b70SSascha Wildner             index = sc->aen_q.head;
23733190b70SSascha Wildner             do {
23833190b70SSascha Wildner                 if ( qp[index].sequence_id ==
23933190b70SSascha Wildner                            (eventp.sequence_id - 1) )
24033190b70SSascha Wildner                     break;
24133190b70SSascha Wildner                 index  = (index+1) % sc->aen_q.depth;
24233190b70SSascha Wildner             }while ( index != sc->aen_q.tail );
24333190b70SSascha Wildner             if ( index == sc->aen_q.tail ) {
24433190b70SSascha Wildner                 ubuf->driver_pkt.status = TWS_AEN_NO_EVENTS;
24533190b70SSascha Wildner                 return;
24633190b70SSascha Wildner             }
24733190b70SSascha Wildner             break;
24833190b70SSascha Wildner         default :
24933190b70SSascha Wildner             TWS_TRACE_DEBUG(sc, "not a valid event", sc, cmd);
25033190b70SSascha Wildner             ubuf->driver_pkt.status = TWS_AEN_NO_EVENTS;
25133190b70SSascha Wildner             return;
25233190b70SSascha Wildner     }
25333190b70SSascha Wildner 
25433190b70SSascha Wildner     memcpy(ubuf->data_buf, &qp[index],
25533190b70SSascha Wildner                            sizeof(struct tws_event_packet));
25633190b70SSascha Wildner     qp[index].retrieved = TWS_AEN_RETRIEVED;
25733190b70SSascha Wildner 
25833190b70SSascha Wildner     return;
25933190b70SSascha Wildner 
26033190b70SSascha Wildner }
26133190b70SSascha Wildner 
26233190b70SSascha Wildner static int
tws_ioctl_aen(struct tws_softc * sc,u_long cmd,void * buf)26333190b70SSascha Wildner tws_ioctl_aen(struct tws_softc *sc, u_long cmd, void *buf)
26433190b70SSascha Wildner {
26533190b70SSascha Wildner 
26633190b70SSascha Wildner     struct tws_ioctl_packet *ubuf = (struct tws_ioctl_packet *)buf;
26733190b70SSascha Wildner     struct tws_compatibility_packet cpkt;
26833190b70SSascha Wildner     struct tws_lock_packet lpkt;
26933190b70SSascha Wildner     time_t ctime;
27033190b70SSascha Wildner 
27133190b70SSascha Wildner     lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
27233190b70SSascha Wildner     ubuf->driver_pkt.status = 0;
27333190b70SSascha Wildner     switch(cmd) {
27433190b70SSascha Wildner         case TWS_IOCTL_GET_FIRST_EVENT :
27533190b70SSascha Wildner         case TWS_IOCTL_GET_LAST_EVENT :
27633190b70SSascha Wildner         case TWS_IOCTL_GET_NEXT_EVENT :
27733190b70SSascha Wildner         case TWS_IOCTL_GET_PREVIOUS_EVENT :
27833190b70SSascha Wildner             tws_retrive_aen(sc,cmd,ubuf);
27933190b70SSascha Wildner             break;
28033190b70SSascha Wildner         case TWS_IOCTL_GET_LOCK :
28133190b70SSascha Wildner             ctime = TWS_LOCAL_TIME;
28233190b70SSascha Wildner             memcpy(&lpkt, ubuf->data_buf, sizeof(struct tws_lock_packet));
28333190b70SSascha Wildner             if ( (sc->ioctl_lock.lock == TWS_IOCTL_LOCK_FREE) ||
28433190b70SSascha Wildner                  (lpkt.force_flag) ||
28533190b70SSascha Wildner                  (ctime >= sc->ioctl_lock.timeout) ) {
28633190b70SSascha Wildner                 sc->ioctl_lock.lock = TWS_IOCTL_LOCK_HELD;
28733190b70SSascha Wildner                 sc->ioctl_lock.timeout = ctime + (lpkt.timeout_msec / 1000);
28833190b70SSascha Wildner                 lpkt.time_remaining_msec = lpkt.timeout_msec;
28933190b70SSascha Wildner             }  else {
29033190b70SSascha Wildner                 lpkt.time_remaining_msec = (u_int32_t)
29133190b70SSascha Wildner                           ((sc->ioctl_lock.timeout - ctime) * 1000);
29233190b70SSascha Wildner                 ubuf->driver_pkt.status = TWS_IOCTL_LOCK_ALREADY_HELD;
29333190b70SSascha Wildner 
29433190b70SSascha Wildner             }
29533190b70SSascha Wildner             break;
29633190b70SSascha Wildner         case TWS_IOCTL_RELEASE_LOCK :
29733190b70SSascha Wildner             if (sc->ioctl_lock.lock == TWS_IOCTL_LOCK_FREE) {
29833190b70SSascha Wildner                 ubuf->driver_pkt.status = TWS_IOCTL_LOCK_NOT_HELD;
29933190b70SSascha Wildner             } else {
30033190b70SSascha Wildner                 sc->ioctl_lock.lock = TWS_IOCTL_LOCK_FREE;
30133190b70SSascha Wildner                 ubuf->driver_pkt.status = 0;
30233190b70SSascha Wildner             }
30333190b70SSascha Wildner             break;
30433190b70SSascha Wildner         case TWS_IOCTL_GET_COMPATIBILITY_INFO :
30533190b70SSascha Wildner             TWS_TRACE_DEBUG(sc, "get comp info", sc, cmd);
30633190b70SSascha Wildner 
30733190b70SSascha Wildner             memcpy( cpkt.driver_version, TWS_DRIVER_VERSION_STRING,
30833190b70SSascha Wildner                                          sizeof(TWS_DRIVER_VERSION_STRING));
30933190b70SSascha Wildner             cpkt.working_srl = sc->cinfo.working_srl;
31033190b70SSascha Wildner             cpkt.working_branch = sc->cinfo.working_branch;
31133190b70SSascha Wildner             cpkt.working_build = sc->cinfo.working_build;
31233190b70SSascha Wildner             cpkt.driver_srl_high = TWS_CURRENT_FW_SRL;
31333190b70SSascha Wildner             cpkt.driver_branch_high = TWS_CURRENT_FW_BRANCH;
31433190b70SSascha Wildner             cpkt.driver_build_high = TWS_CURRENT_FW_BUILD;
31533190b70SSascha Wildner             cpkt.driver_srl_low = TWS_BASE_FW_SRL;
31633190b70SSascha Wildner             cpkt.driver_branch_low = TWS_BASE_FW_BRANCH;
31733190b70SSascha Wildner             cpkt.driver_build_low = TWS_BASE_FW_BUILD;
31833190b70SSascha Wildner             cpkt.fw_on_ctlr_srl = sc->cinfo.fw_on_ctlr_srl;
31933190b70SSascha Wildner             cpkt.fw_on_ctlr_branch = sc->cinfo.fw_on_ctlr_branch;
32033190b70SSascha Wildner             cpkt.fw_on_ctlr_build = sc->cinfo.fw_on_ctlr_build;
32133190b70SSascha Wildner             ubuf->driver_pkt.status = 0;
32233190b70SSascha Wildner             int len = sizeof(struct tws_compatibility_packet);
32333190b70SSascha Wildner             if ( ubuf->driver_pkt.buffer_length < len )
32433190b70SSascha Wildner                 len = ubuf->driver_pkt.buffer_length;
32533190b70SSascha Wildner             memcpy(ubuf->data_buf, &cpkt, len);
32633190b70SSascha Wildner 
32733190b70SSascha Wildner             break;
32833190b70SSascha Wildner         default :
32933190b70SSascha Wildner             TWS_TRACE_DEBUG(sc, "not valid cmd", cmd,
33033190b70SSascha Wildner                            TWS_IOCTL_GET_COMPATIBILITY_INFO);
33133190b70SSascha Wildner             break;
33233190b70SSascha Wildner 
33333190b70SSascha Wildner     }
33433190b70SSascha Wildner     lockmgr(&sc->gen_lock, LK_RELEASE);
33533190b70SSascha Wildner     return(SUCCESS);
33633190b70SSascha Wildner 
33733190b70SSascha Wildner }
33833190b70SSascha Wildner 
33933190b70SSascha Wildner void
tws_circular_aenq_insert(struct tws_softc * sc,struct tws_circular_q * cq,struct tws_event_packet * aen)34033190b70SSascha Wildner tws_circular_aenq_insert(struct tws_softc *sc, struct tws_circular_q *cq,
34133190b70SSascha Wildner struct tws_event_packet *aen)
34233190b70SSascha Wildner {
34333190b70SSascha Wildner 
34433190b70SSascha Wildner     struct tws_event_packet *q = (struct tws_event_packet *)cq->q;
34533190b70SSascha Wildner     volatile u_int16_t head, tail;
34633190b70SSascha Wildner     u_int8_t retr;
34733190b70SSascha Wildner     KKASSERT(lockstatus(&sc->gen_lock, curthread) != 0);
34833190b70SSascha Wildner 
34933190b70SSascha Wildner     head = cq->head;
35033190b70SSascha Wildner     tail = cq->tail;
35133190b70SSascha Wildner     retr = q[tail].retrieved;
35233190b70SSascha Wildner 
35333190b70SSascha Wildner     memcpy(&q[tail], aen, sizeof(struct tws_event_packet));
35433190b70SSascha Wildner     tail = (tail+1) % cq->depth;
35533190b70SSascha Wildner 
35633190b70SSascha Wildner     if ( head == tail ) { /* q is full */
35733190b70SSascha Wildner         if ( retr != TWS_AEN_RETRIEVED )
35833190b70SSascha Wildner             cq->overflow = 1;
35933190b70SSascha Wildner         cq->head = (head+1) % cq->depth;
36033190b70SSascha Wildner     }
36133190b70SSascha Wildner     cq->tail = tail;
36233190b70SSascha Wildner 
36333190b70SSascha Wildner }
364