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