186d7f5d3SJohn Marino /*
286d7f5d3SJohn Marino * Copyright (c) 2010, LSI Corp.
386d7f5d3SJohn Marino * All rights reserved.
486d7f5d3SJohn Marino * Author : Manjunath Ranganathaiah
586d7f5d3SJohn Marino * Support: freebsdraid@lsi.com
686d7f5d3SJohn Marino *
786d7f5d3SJohn Marino * Redistribution and use in source and binary forms, with or without
886d7f5d3SJohn Marino * modification, are permitted provided that the following conditions
986d7f5d3SJohn Marino * are met:
1086d7f5d3SJohn Marino *
1186d7f5d3SJohn Marino * 1. Redistributions of source code must retain the above copyright
1286d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer.
1386d7f5d3SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
1486d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer in
1586d7f5d3SJohn Marino * the documentation and/or other materials provided with the
1686d7f5d3SJohn Marino * distribution.
1786d7f5d3SJohn Marino * 3. Neither the name of the <ORGANIZATION> nor the names of its
1886d7f5d3SJohn Marino * contributors may be used to endorse or promote products derived
1986d7f5d3SJohn Marino * from this software without specific prior written permission.
2086d7f5d3SJohn Marino *
2186d7f5d3SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2286d7f5d3SJohn Marino * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2386d7f5d3SJohn Marino * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2486d7f5d3SJohn Marino * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2586d7f5d3SJohn Marino * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2686d7f5d3SJohn Marino * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2786d7f5d3SJohn Marino * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2886d7f5d3SJohn Marino * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2986d7f5d3SJohn Marino * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3086d7f5d3SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3186d7f5d3SJohn Marino * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3286d7f5d3SJohn Marino * POSSIBILITY OF SUCH DAMAGE.
3386d7f5d3SJohn Marino *
3486d7f5d3SJohn Marino * $FreeBSD: src/sys/dev/tws/tws_cam.c,v 1.3 2007/05/09 04:16:32 mrangana Exp $
3586d7f5d3SJohn Marino */
3686d7f5d3SJohn Marino
3786d7f5d3SJohn Marino #include <dev/raid/tws/tws.h>
3886d7f5d3SJohn Marino #include <dev/raid/tws/tws_hdm.h>
3986d7f5d3SJohn Marino #include <dev/raid/tws/tws_services.h>
4086d7f5d3SJohn Marino #include <sys/time.h>
4186d7f5d3SJohn Marino
4286d7f5d3SJohn Marino void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
4386d7f5d3SJohn Marino u_int8_t q_type );
4486d7f5d3SJohn Marino struct tws_request * tws_q_remove_request(struct tws_softc *sc,
4586d7f5d3SJohn Marino struct tws_request *req, u_int8_t q_type );
4686d7f5d3SJohn Marino struct tws_request *tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type );
4786d7f5d3SJohn Marino void tws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
4886d7f5d3SJohn Marino u_int8_t q_type );
4986d7f5d3SJohn Marino struct tws_request * tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type );
5086d7f5d3SJohn Marino void tws_print_stats(void *arg);
5186d7f5d3SJohn Marino
5286d7f5d3SJohn Marino struct tws_sense *tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa);
5386d7f5d3SJohn Marino
5486d7f5d3SJohn Marino
5586d7f5d3SJohn Marino
5686d7f5d3SJohn Marino struct error_desc array[] = {
5786d7f5d3SJohn Marino { "Cannot add sysctl tree node", 0x2000, ERROR,
5886d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
5986d7f5d3SJohn Marino { "Register window not available", 0x2001, ERROR,
6086d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
6186d7f5d3SJohn Marino { "Can't allocate register window", 0x2002, ERROR,
6286d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
6386d7f5d3SJohn Marino { "Can't allocate interrupt", 0x2003, ERROR,
6486d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
6586d7f5d3SJohn Marino { "Can't set up interrupt", 0x2004, ERROR,
6686d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
6786d7f5d3SJohn Marino { "Couldn't intialize CAM", 0x2007, ERROR,
6886d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
6986d7f5d3SJohn Marino { "Couldn't create SIM device queue", 0x2100, ENOMEM,
7086d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
7186d7f5d3SJohn Marino { "Unable to create SIM entry", 0x2101, ENOMEM,
7286d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
7386d7f5d3SJohn Marino { "Unable to register the bus", 0x2102, ENXIO,
7486d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
7586d7f5d3SJohn Marino { "Unable to create the path", 0x2103, ENXIO,
7686d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
7786d7f5d3SJohn Marino { "Bus scan request to CAM failed", 0x2104, ENXIO,
7886d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
7986d7f5d3SJohn Marino { "Unable to intialize the driver", 0x2008, ENXIO,
8086d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
8186d7f5d3SJohn Marino { "Unable to intialize the controller", 0x2009, ENXIO,
8286d7f5d3SJohn Marino "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
8386d7f5d3SJohn Marino };
8486d7f5d3SJohn Marino
8586d7f5d3SJohn Marino void
tws_trace(const char * file,const char * fun,int linenum,struct tws_softc * sc,char * desc,u_int64_t val1,u_int64_t val2)8686d7f5d3SJohn Marino tws_trace(const char *file, const char *fun, int linenum,
8786d7f5d3SJohn Marino struct tws_softc *sc, char *desc, u_int64_t val1, u_int64_t val2)
8886d7f5d3SJohn Marino {
8986d7f5d3SJohn Marino
9086d7f5d3SJohn Marino
9186d7f5d3SJohn Marino struct tws_trace_rec *rec = (struct tws_trace_rec *)sc->trace_q.q;
9286d7f5d3SJohn Marino volatile u_int16_t head, tail;
9386d7f5d3SJohn Marino char fmt[256];
9486d7f5d3SJohn Marino
9586d7f5d3SJohn Marino head = sc->trace_q.head;
9686d7f5d3SJohn Marino tail = sc->trace_q.tail;
9786d7f5d3SJohn Marino /*
9886d7f5d3SJohn Marino getnanotime(&rec[tail].ts);
9986d7f5d3SJohn Marino */
10086d7f5d3SJohn Marino strncpy(rec[tail].fname, file, TWS_TRACE_FNAME_LEN);
10186d7f5d3SJohn Marino strncpy(rec[tail].func, fun, TWS_TRACE_FUNC_LEN);
10286d7f5d3SJohn Marino rec[tail].linenum = linenum;
10386d7f5d3SJohn Marino strncpy(rec[tail].desc, desc, TWS_TRACE_DESC_LEN);
10486d7f5d3SJohn Marino rec[tail].val1 = val1;
10586d7f5d3SJohn Marino rec[tail].val2 = val2;
10686d7f5d3SJohn Marino
10786d7f5d3SJohn Marino tail = (tail+1) % sc->trace_q.depth;
10886d7f5d3SJohn Marino
10986d7f5d3SJohn Marino if ( head == tail ) {
11086d7f5d3SJohn Marino sc->trace_q.overflow = 1;
11186d7f5d3SJohn Marino sc->trace_q.head = (head+1) % sc->trace_q.depth;
11286d7f5d3SJohn Marino }
11386d7f5d3SJohn Marino sc->trace_q.tail = tail;
11486d7f5d3SJohn Marino
11586d7f5d3SJohn Marino /*
11686d7f5d3SJohn Marino tws_circular_q_insert(sc, &sc->trace_q,
11786d7f5d3SJohn Marino &rec, sizeof(struct tws_trace_rec));
11886d7f5d3SJohn Marino */
11986d7f5d3SJohn Marino if ( sc->is64bit )
12086d7f5d3SJohn Marino strcpy(fmt, "%05d:%s::%s :%s: 0x%016lx : 0x%016lx \n");
12186d7f5d3SJohn Marino else
12286d7f5d3SJohn Marino strcpy(fmt, "%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n");
12386d7f5d3SJohn Marino
12486d7f5d3SJohn Marino /*
12586d7f5d3SJohn Marino kprintf("%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n",
12686d7f5d3SJohn Marino linenum, file, fun, desc, val1, val2);
12786d7f5d3SJohn Marino */
12886d7f5d3SJohn Marino kprintf(fmt, linenum, file, fun, desc, val1, val2);
12986d7f5d3SJohn Marino }
13086d7f5d3SJohn Marino
13186d7f5d3SJohn Marino void
tws_log(struct tws_softc * sc,int index)13286d7f5d3SJohn Marino tws_log(struct tws_softc *sc, int index)
13386d7f5d3SJohn Marino {
13486d7f5d3SJohn Marino device_printf((sc)->tws_dev, array[index].fmt,
13586d7f5d3SJohn Marino array[index].error_str,
13686d7f5d3SJohn Marino array[index].error_code,
13786d7f5d3SJohn Marino array[index].severity_level,
13886d7f5d3SJohn Marino array[index].desc );
13986d7f5d3SJohn Marino }
14086d7f5d3SJohn Marino
14186d7f5d3SJohn Marino /* ----------- swap functions ----------- */
14286d7f5d3SJohn Marino
14386d7f5d3SJohn Marino
14486d7f5d3SJohn Marino u_int16_t
tws_swap16(u_int16_t val)14586d7f5d3SJohn Marino tws_swap16(u_int16_t val)
14686d7f5d3SJohn Marino {
14786d7f5d3SJohn Marino return((val << 8) | (val >> 8));
14886d7f5d3SJohn Marino }
14986d7f5d3SJohn Marino
15086d7f5d3SJohn Marino u_int32_t
tws_swap32(u_int32_t val)15186d7f5d3SJohn Marino tws_swap32(u_int32_t val)
15286d7f5d3SJohn Marino {
15386d7f5d3SJohn Marino return(((val << 24) | ((val << 8) & (0xFF0000)) |
15486d7f5d3SJohn Marino ((val >> 8) & (0xFF00)) | (val >> 24)));
15586d7f5d3SJohn Marino }
15686d7f5d3SJohn Marino
15786d7f5d3SJohn Marino
15886d7f5d3SJohn Marino u_int64_t
tws_swap64(u_int64_t val)15986d7f5d3SJohn Marino tws_swap64(u_int64_t val)
16086d7f5d3SJohn Marino {
16186d7f5d3SJohn Marino return((((u_int64_t)(tws_swap32(((u_int32_t *)(&(val)))[1]))) << 32) |
16286d7f5d3SJohn Marino ((u_int32_t)(tws_swap32(((u_int32_t *)(&(val)))[0]))));
16386d7f5d3SJohn Marino }
16486d7f5d3SJohn Marino
16586d7f5d3SJohn Marino
16686d7f5d3SJohn Marino /* ----------- reg access ----------- */
16786d7f5d3SJohn Marino
16886d7f5d3SJohn Marino
16986d7f5d3SJohn Marino void
tws_write_reg(struct tws_softc * sc,int offset,u_int32_t value,int size)17086d7f5d3SJohn Marino tws_write_reg(struct tws_softc *sc, int offset,
17186d7f5d3SJohn Marino u_int32_t value, int size)
17286d7f5d3SJohn Marino {
17386d7f5d3SJohn Marino bus_space_tag_t bus_tag = sc->bus_tag;
17486d7f5d3SJohn Marino bus_space_handle_t bus_handle = sc->bus_handle;
17586d7f5d3SJohn Marino
17686d7f5d3SJohn Marino if (size == 4)
17786d7f5d3SJohn Marino bus_space_write_4(bus_tag, bus_handle, offset, value);
17886d7f5d3SJohn Marino else
17986d7f5d3SJohn Marino if (size == 2)
18086d7f5d3SJohn Marino bus_space_write_2(bus_tag, bus_handle, offset,
18186d7f5d3SJohn Marino (u_int16_t)value);
18286d7f5d3SJohn Marino else
18386d7f5d3SJohn Marino bus_space_write_1(bus_tag, bus_handle, offset, (u_int8_t)value);
18486d7f5d3SJohn Marino }
18586d7f5d3SJohn Marino
18686d7f5d3SJohn Marino u_int32_t
tws_read_reg(struct tws_softc * sc,int offset,int size)18786d7f5d3SJohn Marino tws_read_reg(struct tws_softc *sc, int offset, int size)
18886d7f5d3SJohn Marino {
18986d7f5d3SJohn Marino bus_space_tag_t bus_tag = sc->bus_tag;
19086d7f5d3SJohn Marino bus_space_handle_t bus_handle = sc->bus_handle;
19186d7f5d3SJohn Marino
19286d7f5d3SJohn Marino if (size == 4)
19386d7f5d3SJohn Marino return((u_int32_t)bus_space_read_4(bus_tag, bus_handle, offset));
19486d7f5d3SJohn Marino else if (size == 2)
19586d7f5d3SJohn Marino return((u_int32_t)bus_space_read_2(bus_tag, bus_handle, offset));
19686d7f5d3SJohn Marino else
19786d7f5d3SJohn Marino return((u_int32_t)bus_space_read_1(bus_tag, bus_handle, offset));
19886d7f5d3SJohn Marino }
19986d7f5d3SJohn Marino
20086d7f5d3SJohn Marino /* --------------------- Q service --------------------- */
20186d7f5d3SJohn Marino
20286d7f5d3SJohn Marino /*
20386d7f5d3SJohn Marino * intialize q pointers with null.
20486d7f5d3SJohn Marino */
20586d7f5d3SJohn Marino void
tws_init_qs(struct tws_softc * sc)20686d7f5d3SJohn Marino tws_init_qs(struct tws_softc *sc)
20786d7f5d3SJohn Marino {
20886d7f5d3SJohn Marino
20986d7f5d3SJohn Marino lockmgr(&sc->q_lock, LK_EXCLUSIVE);
21086d7f5d3SJohn Marino for(int i=0;i<TWS_MAX_QS;i++) {
21186d7f5d3SJohn Marino sc->q_head[i] = NULL;
21286d7f5d3SJohn Marino sc->q_tail[i] = NULL;
21386d7f5d3SJohn Marino }
21486d7f5d3SJohn Marino lockmgr(&sc->q_lock, LK_RELEASE);
21586d7f5d3SJohn Marino
21686d7f5d3SJohn Marino }
21786d7f5d3SJohn Marino
21886d7f5d3SJohn Marino /* called with lock held */
21986d7f5d3SJohn Marino static void
tws_insert2_empty_q(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)22086d7f5d3SJohn Marino tws_insert2_empty_q(struct tws_softc *sc, struct tws_request *req,
22186d7f5d3SJohn Marino u_int8_t q_type )
22286d7f5d3SJohn Marino {
22386d7f5d3SJohn Marino
22486d7f5d3SJohn Marino KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
22586d7f5d3SJohn Marino req->next = req->prev = NULL;
22686d7f5d3SJohn Marino sc->q_head[q_type] = sc->q_tail[q_type] = req;
22786d7f5d3SJohn Marino
22886d7f5d3SJohn Marino }
22986d7f5d3SJohn Marino
23086d7f5d3SJohn Marino /* called with lock held */
23186d7f5d3SJohn Marino void
tws_q_insert_head(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)23286d7f5d3SJohn Marino tws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
23386d7f5d3SJohn Marino u_int8_t q_type )
23486d7f5d3SJohn Marino {
23586d7f5d3SJohn Marino
23686d7f5d3SJohn Marino KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
23786d7f5d3SJohn Marino if ( sc->q_head[q_type] == NULL ) {
23886d7f5d3SJohn Marino tws_insert2_empty_q(sc, req, q_type);
23986d7f5d3SJohn Marino } else {
24086d7f5d3SJohn Marino req->next = sc->q_head[q_type];
24186d7f5d3SJohn Marino req->prev = NULL;
24286d7f5d3SJohn Marino sc->q_head[q_type]->prev = req;
24386d7f5d3SJohn Marino sc->q_head[q_type] = req;
24486d7f5d3SJohn Marino }
24586d7f5d3SJohn Marino
24686d7f5d3SJohn Marino }
24786d7f5d3SJohn Marino
24886d7f5d3SJohn Marino /* called with lock held */
24986d7f5d3SJohn Marino void
tws_q_insert_tail(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)25086d7f5d3SJohn Marino tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
25186d7f5d3SJohn Marino u_int8_t q_type )
25286d7f5d3SJohn Marino {
25386d7f5d3SJohn Marino
25486d7f5d3SJohn Marino KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
25586d7f5d3SJohn Marino if ( sc->q_tail[q_type] == NULL ) {
25686d7f5d3SJohn Marino tws_insert2_empty_q(sc, req, q_type);
25786d7f5d3SJohn Marino } else {
25886d7f5d3SJohn Marino req->prev = sc->q_tail[q_type];
25986d7f5d3SJohn Marino req->next = NULL;
26086d7f5d3SJohn Marino sc->q_tail[q_type]->next = req;
26186d7f5d3SJohn Marino sc->q_tail[q_type] = req;
26286d7f5d3SJohn Marino }
26386d7f5d3SJohn Marino
26486d7f5d3SJohn Marino }
26586d7f5d3SJohn Marino
26686d7f5d3SJohn Marino /* called with lock held */
26786d7f5d3SJohn Marino struct tws_request *
tws_q_remove_head(struct tws_softc * sc,u_int8_t q_type)26886d7f5d3SJohn Marino tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type )
26986d7f5d3SJohn Marino {
27086d7f5d3SJohn Marino
27186d7f5d3SJohn Marino struct tws_request *r;
27286d7f5d3SJohn Marino
27386d7f5d3SJohn Marino KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
27486d7f5d3SJohn Marino r = sc->q_head[q_type];
27586d7f5d3SJohn Marino if ( !r )
27686d7f5d3SJohn Marino return(NULL);
27786d7f5d3SJohn Marino if ( r->next == NULL && r->prev == NULL ) {
27886d7f5d3SJohn Marino /* last element */
27986d7f5d3SJohn Marino sc->q_head[q_type] = sc->q_tail[q_type] = NULL;
28086d7f5d3SJohn Marino } else {
28186d7f5d3SJohn Marino sc->q_head[q_type] = r->next;
28286d7f5d3SJohn Marino r->next->prev = NULL;
28386d7f5d3SJohn Marino r->next = NULL;
28486d7f5d3SJohn Marino r->prev = NULL;
28586d7f5d3SJohn Marino }
28686d7f5d3SJohn Marino return(r);
28786d7f5d3SJohn Marino }
28886d7f5d3SJohn Marino
28986d7f5d3SJohn Marino /* called with lock held */
29086d7f5d3SJohn Marino struct tws_request *
tws_q_remove_tail(struct tws_softc * sc,u_int8_t q_type)29186d7f5d3SJohn Marino tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type )
29286d7f5d3SJohn Marino {
29386d7f5d3SJohn Marino
29486d7f5d3SJohn Marino struct tws_request *r;
29586d7f5d3SJohn Marino
29686d7f5d3SJohn Marino KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
29786d7f5d3SJohn Marino r = sc->q_tail[q_type];
29886d7f5d3SJohn Marino if ( !r )
29986d7f5d3SJohn Marino return(NULL);
30086d7f5d3SJohn Marino if ( r->next == NULL && r->prev == NULL ) {
30186d7f5d3SJohn Marino /* last element */
30286d7f5d3SJohn Marino sc->q_head[q_type] = sc->q_tail[q_type] = NULL;
30386d7f5d3SJohn Marino } else {
30486d7f5d3SJohn Marino sc->q_tail[q_type] = r->prev;
30586d7f5d3SJohn Marino r->prev->next = NULL;
30686d7f5d3SJohn Marino r->next = NULL;
30786d7f5d3SJohn Marino r->prev = NULL;
30886d7f5d3SJohn Marino }
30986d7f5d3SJohn Marino return(r);
31086d7f5d3SJohn Marino }
31186d7f5d3SJohn Marino
31286d7f5d3SJohn Marino /* returns removed request if successful. return NULL otherwise */
31386d7f5d3SJohn Marino /* called with lock held */
31486d7f5d3SJohn Marino struct tws_request *
tws_q_remove_request(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)31586d7f5d3SJohn Marino tws_q_remove_request(struct tws_softc *sc, struct tws_request *req,
31686d7f5d3SJohn Marino u_int8_t q_type )
31786d7f5d3SJohn Marino {
31886d7f5d3SJohn Marino
31986d7f5d3SJohn Marino struct tws_request *r;
32086d7f5d3SJohn Marino
32186d7f5d3SJohn Marino KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
32286d7f5d3SJohn Marino if ( req == NULL ) {
32386d7f5d3SJohn Marino TWS_TRACE_DEBUG(sc, "null req", 0, q_type);
32486d7f5d3SJohn Marino return(NULL);
32586d7f5d3SJohn Marino }
32686d7f5d3SJohn Marino
32786d7f5d3SJohn Marino if ( req == sc->q_head[q_type] )
32886d7f5d3SJohn Marino return(tws_q_remove_head(sc, q_type));
32986d7f5d3SJohn Marino if ( req == sc->q_tail[q_type] )
33086d7f5d3SJohn Marino return(tws_q_remove_tail(sc, q_type));
33186d7f5d3SJohn Marino
33286d7f5d3SJohn Marino
33386d7f5d3SJohn Marino /* The given node is not at head or tail.
33486d7f5d3SJohn Marino * It's in the middle and there are more than
33586d7f5d3SJohn Marino * 2 elements on the q.
33686d7f5d3SJohn Marino */
33786d7f5d3SJohn Marino
33886d7f5d3SJohn Marino if ( req->next == NULL || req->prev == NULL ) {
33986d7f5d3SJohn Marino TWS_TRACE_DEBUG(sc, "invalid req", 0, q_type);
34086d7f5d3SJohn Marino return(NULL);
34186d7f5d3SJohn Marino }
34286d7f5d3SJohn Marino
34386d7f5d3SJohn Marino /* debug only */
34486d7f5d3SJohn Marino r = sc->q_head[q_type];
34586d7f5d3SJohn Marino while ( r ) {
34686d7f5d3SJohn Marino if ( req == r )
34786d7f5d3SJohn Marino break;
34886d7f5d3SJohn Marino r = r->next;
34986d7f5d3SJohn Marino }
35086d7f5d3SJohn Marino
35186d7f5d3SJohn Marino if ( !r ) {
35286d7f5d3SJohn Marino TWS_TRACE_DEBUG(sc, "req not in q", 0, req->request_id);
35386d7f5d3SJohn Marino return(NULL);
35486d7f5d3SJohn Marino }
35586d7f5d3SJohn Marino /* debug end */
35686d7f5d3SJohn Marino
35786d7f5d3SJohn Marino req->prev->next = r->next;
35886d7f5d3SJohn Marino req->next->prev = r->prev;
35986d7f5d3SJohn Marino req->next = NULL;
36086d7f5d3SJohn Marino req->prev = NULL;
36186d7f5d3SJohn Marino return(req);
36286d7f5d3SJohn Marino }
36386d7f5d3SJohn Marino
36486d7f5d3SJohn Marino struct tws_sense *
tws_find_sense_from_mfa(struct tws_softc * sc,u_int64_t mfa)36586d7f5d3SJohn Marino tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa)
36686d7f5d3SJohn Marino {
36786d7f5d3SJohn Marino struct tws_sense *s;
36886d7f5d3SJohn Marino int i;
36986d7f5d3SJohn Marino TWS_TRACE_DEBUG(sc, "entry",sc,mfa);
37086d7f5d3SJohn Marino
37186d7f5d3SJohn Marino i = (mfa - sc->dma_mem_phys) / sizeof(struct tws_command_packet);
37286d7f5d3SJohn Marino if ( i>= 0 && i<tws_queue_depth) {
37386d7f5d3SJohn Marino s = &sc->sense_bufs[i];
37486d7f5d3SJohn Marino if ( mfa == s->hdr_pkt_phy )
37586d7f5d3SJohn Marino return(s);
37686d7f5d3SJohn Marino }
37786d7f5d3SJohn Marino
37886d7f5d3SJohn Marino TWS_TRACE_DEBUG(sc, "return null",0,mfa);
37986d7f5d3SJohn Marino return(NULL);
38086d7f5d3SJohn Marino
38186d7f5d3SJohn Marino }
38286d7f5d3SJohn Marino
38386d7f5d3SJohn Marino /* --------------------- Q service end --------------------- */
38486d7f5d3SJohn Marino /* --------------------- misc service start --------------------- */
38586d7f5d3SJohn Marino
38686d7f5d3SJohn Marino
38786d7f5d3SJohn Marino void
tws_print_stats(void * arg)38886d7f5d3SJohn Marino tws_print_stats(void *arg)
38986d7f5d3SJohn Marino {
39086d7f5d3SJohn Marino
39186d7f5d3SJohn Marino struct tws_softc *sc = (struct tws_softc *)arg;
39286d7f5d3SJohn Marino
39386d7f5d3SJohn Marino TWS_TRACE(sc, "reqs(in, out)", sc->stats.reqs_in, sc->stats.reqs_out);
39486d7f5d3SJohn Marino TWS_TRACE(sc, "reqs(err, intrs)", sc->stats.reqs_errored
39586d7f5d3SJohn Marino , sc->stats.num_intrs);
39686d7f5d3SJohn Marino TWS_TRACE(sc, "reqs(ioctls, scsi)", sc->stats.ioctls
39786d7f5d3SJohn Marino , sc->stats.scsi_ios);
39886d7f5d3SJohn Marino callout_reset(&sc->print_stats_handle, 300*hz, tws_print_stats, sc);
39986d7f5d3SJohn Marino
40086d7f5d3SJohn Marino }
40186d7f5d3SJohn Marino /* --------------------- misc service end --------------------- */
402