1226026Sdelphij/*
2226026Sdelphij * Copyright (c) 2010, LSI Corp.
3226026Sdelphij * All rights reserved.
4226026Sdelphij * Author : Manjunath Ranganathaiah
5226026Sdelphij * Support: freebsdraid@lsi.com
6226026Sdelphij *
7226026Sdelphij * Redistribution and use in source and binary forms, with or without
8226026Sdelphij * modification, are permitted provided that the following conditions
9226026Sdelphij * are met:
10226026Sdelphij *
11226026Sdelphij * 1. Redistributions of source code must retain the above copyright
12226026Sdelphij *    notice, this list of conditions and the following disclaimer.
13226026Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
14226026Sdelphij *    notice, this list of conditions and the following disclaimer in
15226026Sdelphij *    the documentation and/or other materials provided with the
16226026Sdelphij *    distribution.
17226026Sdelphij * 3. Neither the name of the <ORGANIZATION> nor the names of its
18226026Sdelphij *    contributors may be used to endorse or promote products derived
19226026Sdelphij *    from this software without specific prior written permission.
20226026Sdelphij *
21226026Sdelphij * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22226026Sdelphij * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23226026Sdelphij * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24226026Sdelphij * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25226026Sdelphij * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26226026Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27226026Sdelphij * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28226026Sdelphij * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29226026Sdelphij * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30226026Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31226026Sdelphij * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32226026Sdelphij * POSSIBILITY OF SUCH DAMAGE.
33226026Sdelphij *
34226026Sdelphij * $FreeBSD$
35226026Sdelphij */
36226026Sdelphij
37226026Sdelphij#include <dev/tws/tws.h>
38226026Sdelphij#include <dev/tws/tws_hdm.h>
39226026Sdelphij#include <dev/tws/tws_services.h>
40226026Sdelphij#include <sys/time.h>
41226026Sdelphij
42226026Sdelphijvoid tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
43226026Sdelphij                                u_int8_t q_type );
44226026Sdelphijstruct tws_request * tws_q_remove_request(struct tws_softc *sc,
45226026Sdelphij                                struct tws_request *req, u_int8_t q_type );
46226026Sdelphijstruct tws_request *tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type );
47226026Sdelphijvoid tws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
48226026Sdelphij                                u_int8_t q_type );
49226026Sdelphijstruct tws_request * tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type );
50226026Sdelphijvoid tws_print_stats(void *arg);
51226026Sdelphij
52226026Sdelphijstruct tws_sense *tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa);
53226026Sdelphij
54226026Sdelphij
55226026Sdelphij
56226969Sdelphijstatic struct error_desc array[] = {
57226026Sdelphij    { "Cannot add sysctl tree node", 0x2000, ERROR,
58226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
59226026Sdelphij    { "Register window not available", 0x2001, ERROR,
60226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
61226026Sdelphij    { "Can't allocate register window", 0x2002, ERROR,
62226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
63226026Sdelphij    { "Can't allocate interrupt", 0x2003, ERROR,
64226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
65226026Sdelphij    { "Can't set up interrupt", 0x2004, ERROR,
66226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
67226026Sdelphij    { "Couldn't intialize CAM", 0x2007, ERROR,
68226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
69226026Sdelphij    { "Couldn't create SIM device queue", 0x2100, ENOMEM,
70226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
71226026Sdelphij    { "Unable to  create SIM entry", 0x2101, ENOMEM,
72226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
73226026Sdelphij    { "Unable to  register the bus", 0x2102, ENXIO,
74226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
75226026Sdelphij    { "Unable to  create the path", 0x2103, ENXIO,
76226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
77226026Sdelphij    { "Bus scan request to CAM failed", 0x2104, ENXIO,
78226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
79226026Sdelphij    { "Unable to intialize the driver", 0x2008, ENXIO,
80226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
81226026Sdelphij    { "Unable to intialize the controller", 0x2009, ENXIO,
82226026Sdelphij       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
83226026Sdelphij};
84226026Sdelphij
85226026Sdelphijvoid
86226026Sdelphijtws_trace(const char *file, const char *fun, int linenum,
87226026Sdelphij          struct tws_softc *sc, char *desc, u_int64_t val1, u_int64_t val2)
88226026Sdelphij{
89226026Sdelphij
90226026Sdelphij
91226026Sdelphij    struct tws_trace_rec *rec = (struct tws_trace_rec *)sc->trace_q.q;
92226026Sdelphij    volatile u_int16_t head, tail;
93226026Sdelphij    char fmt[256];
94226026Sdelphij
95226026Sdelphij    head = sc->trace_q.head;
96226026Sdelphij    tail = sc->trace_q.tail;
97226026Sdelphij/*
98226026Sdelphij    getnanotime(&rec[tail].ts);
99226026Sdelphij*/
100226026Sdelphij    strncpy(rec[tail].fname, file, TWS_TRACE_FNAME_LEN);
101226026Sdelphij    strncpy(rec[tail].func, fun, TWS_TRACE_FUNC_LEN);
102226026Sdelphij    rec[tail].linenum = linenum;
103226026Sdelphij    strncpy(rec[tail].desc, desc, TWS_TRACE_DESC_LEN);
104226026Sdelphij    rec[tail].val1 = val1;
105226026Sdelphij    rec[tail].val2 = val2;
106226026Sdelphij
107226026Sdelphij    tail = (tail+1) % sc->trace_q.depth;
108226026Sdelphij
109226026Sdelphij    if ( head == tail ) {
110226026Sdelphij        sc->trace_q.overflow = 1;
111226026Sdelphij        sc->trace_q.head = (head+1) % sc->trace_q.depth;
112226026Sdelphij    }
113226026Sdelphij    sc->trace_q.tail = tail;
114226026Sdelphij
115226026Sdelphij/*
116226026Sdelphij    tws_circular_q_insert(sc, &sc->trace_q,
117226026Sdelphij                              &rec, sizeof(struct tws_trace_rec));
118226026Sdelphij*/
119226026Sdelphij    if ( sc->is64bit )
120226026Sdelphij        strcpy(fmt, "%05d:%s::%s :%s: 0x%016lx : 0x%016lx \n");
121226026Sdelphij    else
122226026Sdelphij        strcpy(fmt, "%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n");
123226026Sdelphij
124226026Sdelphij/*
125226026Sdelphij    printf("%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n",
126226026Sdelphij            linenum, file, fun, desc, val1, val2);
127226026Sdelphij*/
128226026Sdelphij    printf(fmt, linenum, file, fun, desc, val1, val2);
129226026Sdelphij}
130226026Sdelphij
131226026Sdelphijvoid
132226026Sdelphijtws_log(struct tws_softc *sc, int index)
133226026Sdelphij{
134226026Sdelphij    device_printf((sc)->tws_dev, array[index].fmt,
135226026Sdelphij                    array[index].error_str,
136226026Sdelphij                    array[index].error_code,
137226026Sdelphij                    array[index].severity_level,
138226026Sdelphij                    array[index].desc );
139226026Sdelphij}
140226026Sdelphij
141226026Sdelphij/* ----------- swap functions ----------- */
142226026Sdelphij
143226026Sdelphij
144226026Sdelphiju_int16_t
145226026Sdelphijtws_swap16(u_int16_t val)
146226026Sdelphij{
147226026Sdelphij    return((val << 8) | (val >> 8));
148226026Sdelphij}
149226026Sdelphij
150226026Sdelphiju_int32_t
151226026Sdelphijtws_swap32(u_int32_t val)
152226026Sdelphij{
153226026Sdelphij    return(((val << 24) | ((val << 8) & (0xFF0000)) |
154226026Sdelphij           ((val >> 8) & (0xFF00)) | (val >> 24)));
155226026Sdelphij}
156226026Sdelphij
157226026Sdelphij
158226026Sdelphiju_int64_t
159226026Sdelphijtws_swap64(u_int64_t val)
160226026Sdelphij{
161226026Sdelphij    return((((u_int64_t)(tws_swap32(((u_int32_t *)(&(val)))[1]))) << 32) |
162226026Sdelphij           ((u_int32_t)(tws_swap32(((u_int32_t *)(&(val)))[0]))));
163226026Sdelphij}
164226026Sdelphij
165226026Sdelphij
166226026Sdelphij/* ----------- reg access ----------- */
167226026Sdelphij
168226026Sdelphij
169226026Sdelphijvoid
170226026Sdelphijtws_write_reg(struct tws_softc *sc, int offset,
171226026Sdelphij                  u_int32_t value, int size)
172226026Sdelphij{
173226026Sdelphij    bus_space_tag_t         bus_tag = sc->bus_tag;
174226026Sdelphij    bus_space_handle_t      bus_handle = sc->bus_handle;
175226026Sdelphij
176226026Sdelphij    if (size == 4)
177226026Sdelphij        bus_space_write_4(bus_tag, bus_handle, offset, value);
178226026Sdelphij    else
179226026Sdelphij        if (size == 2)
180226026Sdelphij            bus_space_write_2(bus_tag, bus_handle, offset,
181226026Sdelphij                                     (u_int16_t)value);
182226026Sdelphij        else
183226026Sdelphij            bus_space_write_1(bus_tag, bus_handle, offset, (u_int8_t)value);
184226026Sdelphij}
185226026Sdelphij
186226026Sdelphiju_int32_t
187226026Sdelphijtws_read_reg(struct tws_softc *sc, int offset, int size)
188226026Sdelphij{
189226026Sdelphij    bus_space_tag_t bus_tag = sc->bus_tag;
190226026Sdelphij    bus_space_handle_t bus_handle = sc->bus_handle;
191226026Sdelphij
192226026Sdelphij    if (size == 4)
193226026Sdelphij        return((u_int32_t)bus_space_read_4(bus_tag, bus_handle, offset));
194226026Sdelphij    else if (size == 2)
195226026Sdelphij            return((u_int32_t)bus_space_read_2(bus_tag, bus_handle, offset));
196226026Sdelphij         else
197226026Sdelphij            return((u_int32_t)bus_space_read_1(bus_tag, bus_handle, offset));
198226026Sdelphij}
199226026Sdelphij
200226026Sdelphij/* --------------------- Q service --------------------- */
201226026Sdelphij
202226026Sdelphij/*
203226026Sdelphij * intialize q  pointers with null.
204226026Sdelphij */
205226026Sdelphijvoid
206226026Sdelphijtws_init_qs(struct tws_softc *sc)
207226026Sdelphij{
208226026Sdelphij
209226026Sdelphij    mtx_lock(&sc->q_lock);
210226026Sdelphij    for(int i=0;i<TWS_MAX_QS;i++) {
211226026Sdelphij        sc->q_head[i] = NULL;
212226026Sdelphij        sc->q_tail[i] = NULL;
213226026Sdelphij    }
214226026Sdelphij    mtx_unlock(&sc->q_lock);
215226026Sdelphij
216226026Sdelphij}
217226026Sdelphij
218226026Sdelphij/* called with lock held */
219226026Sdelphijstatic void
220226026Sdelphijtws_insert2_empty_q(struct tws_softc *sc, struct tws_request *req,
221226026Sdelphij                                u_int8_t q_type )
222226026Sdelphij{
223226026Sdelphij
224226026Sdelphij    mtx_assert(&sc->q_lock, MA_OWNED);
225226026Sdelphij    req->next = req->prev = NULL;
226226026Sdelphij    sc->q_head[q_type] = sc->q_tail[q_type] = req;
227226026Sdelphij
228226026Sdelphij}
229226026Sdelphij
230226026Sdelphij/* called with lock held */
231226026Sdelphijvoid
232226026Sdelphijtws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
233226026Sdelphij                                u_int8_t q_type )
234226026Sdelphij{
235226026Sdelphij
236226026Sdelphij    mtx_assert(&sc->q_lock, MA_OWNED);
237226026Sdelphij    if ( sc->q_head[q_type] == NULL ) {
238226026Sdelphij        tws_insert2_empty_q(sc, req, q_type);
239226026Sdelphij    } else {
240226026Sdelphij        req->next = sc->q_head[q_type];
241226026Sdelphij        req->prev = NULL;
242226026Sdelphij        sc->q_head[q_type]->prev = req;
243226026Sdelphij        sc->q_head[q_type] = req;
244226026Sdelphij    }
245226026Sdelphij
246226026Sdelphij}
247226026Sdelphij
248226026Sdelphij/* called with lock held */
249226026Sdelphijvoid
250226026Sdelphijtws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
251226026Sdelphij                                u_int8_t q_type )
252226026Sdelphij{
253226026Sdelphij
254226026Sdelphij    mtx_assert(&sc->q_lock, MA_OWNED);
255226026Sdelphij    if ( sc->q_tail[q_type] == NULL ) {
256226026Sdelphij        tws_insert2_empty_q(sc, req, q_type);
257226026Sdelphij    } else {
258226026Sdelphij        req->prev = sc->q_tail[q_type];
259226026Sdelphij        req->next = NULL;
260226026Sdelphij        sc->q_tail[q_type]->next = req;
261226026Sdelphij        sc->q_tail[q_type] = req;
262226026Sdelphij    }
263226026Sdelphij
264226026Sdelphij}
265226026Sdelphij
266226026Sdelphij/* called with lock held */
267226026Sdelphijstruct tws_request *
268226026Sdelphijtws_q_remove_head(struct tws_softc *sc, u_int8_t q_type )
269226026Sdelphij{
270226026Sdelphij
271226026Sdelphij    struct tws_request *r;
272226026Sdelphij
273226026Sdelphij    mtx_assert(&sc->q_lock, MA_OWNED);
274226026Sdelphij    r = sc->q_head[q_type];
275226026Sdelphij    if ( !r )
276226026Sdelphij        return(NULL);
277226026Sdelphij    if ( r->next == NULL &&  r->prev == NULL ) {
278226026Sdelphij        /* last element  */
279226026Sdelphij        sc->q_head[q_type] = sc->q_tail[q_type] = NULL;
280226026Sdelphij    } else {
281226026Sdelphij        sc->q_head[q_type] = r->next;
282226026Sdelphij        r->next->prev = NULL;
283226026Sdelphij        r->next = NULL;
284226026Sdelphij        r->prev = NULL;
285226026Sdelphij    }
286226026Sdelphij    return(r);
287226026Sdelphij}
288226026Sdelphij
289226026Sdelphij/* called with lock held */
290226026Sdelphijstruct tws_request *
291226026Sdelphijtws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type )
292226026Sdelphij{
293226026Sdelphij
294226026Sdelphij    struct tws_request *r;
295226026Sdelphij
296226026Sdelphij    mtx_assert(&sc->q_lock, MA_OWNED);
297226026Sdelphij    r = sc->q_tail[q_type];
298226026Sdelphij    if ( !r )
299226026Sdelphij        return(NULL);
300226026Sdelphij    if ( r->next == NULL &&  r->prev == NULL ) {
301226026Sdelphij        /* last element  */
302226026Sdelphij        sc->q_head[q_type] = sc->q_tail[q_type] = NULL;
303226026Sdelphij    } else {
304226026Sdelphij        sc->q_tail[q_type] = r->prev;
305226026Sdelphij        r->prev->next = NULL;
306226026Sdelphij        r->next = NULL;
307226026Sdelphij        r->prev = NULL;
308226026Sdelphij    }
309226026Sdelphij    return(r);
310226026Sdelphij}
311226026Sdelphij
312226026Sdelphij/* returns removed request if successful. return NULL otherwise */
313226026Sdelphij/* called with lock held */
314226026Sdelphijstruct tws_request *
315226026Sdelphijtws_q_remove_request(struct tws_softc *sc, struct tws_request *req,
316226026Sdelphij                                 u_int8_t q_type )
317226026Sdelphij{
318226026Sdelphij
319226026Sdelphij    struct tws_request *r;
320226026Sdelphij
321226026Sdelphij    mtx_assert(&sc->q_lock, MA_OWNED);
322226026Sdelphij    if ( req == NULL ) {
323226026Sdelphij        TWS_TRACE_DEBUG(sc, "null req", 0, q_type);
324226026Sdelphij        return(NULL);
325226026Sdelphij    }
326226026Sdelphij
327226026Sdelphij    if ( req == sc->q_head[q_type] )
328226026Sdelphij        return(tws_q_remove_head(sc, q_type));
329226026Sdelphij    if ( req == sc->q_tail[q_type] )
330226026Sdelphij        return(tws_q_remove_tail(sc, q_type));
331226026Sdelphij
332226026Sdelphij
333226026Sdelphij    /* The given node is not at head or tail.
334226026Sdelphij     * It's in the middle and there are more than
335226026Sdelphij     * 2 elements on the q.
336226026Sdelphij     */
337226026Sdelphij
338226026Sdelphij    if ( req->next == NULL || req->prev == NULL ) {
339226026Sdelphij        TWS_TRACE_DEBUG(sc, "invalid req", 0, q_type);
340226026Sdelphij        return(NULL);
341226026Sdelphij    }
342226026Sdelphij
343226026Sdelphij/* debug only */
344226026Sdelphij    r = sc->q_head[q_type];
345226026Sdelphij    while ( r ) {
346226026Sdelphij        if ( req == r )
347226026Sdelphij            break;
348226026Sdelphij        r = r->next;
349226026Sdelphij    }
350226026Sdelphij
351226026Sdelphij    if ( !r ) {
352226026Sdelphij        TWS_TRACE_DEBUG(sc, "req not in q", 0, req->request_id);
353226026Sdelphij        return(NULL);
354226026Sdelphij    }
355226026Sdelphij/* debug end */
356226026Sdelphij
357226026Sdelphij    req->prev->next = r->next;
358226026Sdelphij    req->next->prev = r->prev;
359226026Sdelphij    req->next = NULL;
360226026Sdelphij    req->prev = NULL;
361226026Sdelphij    return(req);
362226026Sdelphij}
363226026Sdelphij
364226026Sdelphijstruct tws_sense *
365226026Sdelphijtws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa)
366226026Sdelphij{
367226026Sdelphij    struct tws_sense *s;
368226026Sdelphij    int i;
369226026Sdelphij    TWS_TRACE_DEBUG(sc, "entry",sc,mfa);
370226026Sdelphij
371226026Sdelphij    i = (mfa - sc->dma_mem_phys) / sizeof(struct tws_command_packet);
372226026Sdelphij    if ( i>= 0 && i<tws_queue_depth) {
373226026Sdelphij        s = &sc->sense_bufs[i];
374226026Sdelphij        if ( mfa == s->hdr_pkt_phy )
375226026Sdelphij            return(s);
376226026Sdelphij    }
377226026Sdelphij
378226026Sdelphij    TWS_TRACE_DEBUG(sc, "return null",0,mfa);
379226026Sdelphij    return(NULL);
380226026Sdelphij
381226026Sdelphij}
382226026Sdelphij
383226026Sdelphij/* --------------------- Q service end --------------------- */
384226026Sdelphij/* --------------------- misc service start --------------------- */
385226026Sdelphij
386226026Sdelphij
387226026Sdelphijvoid
388226026Sdelphijtws_print_stats(void *arg)
389226026Sdelphij{
390226026Sdelphij
391226026Sdelphij    struct tws_softc *sc = (struct tws_softc *)arg;
392226026Sdelphij
393226026Sdelphij    TWS_TRACE(sc, "reqs(in, out)", sc->stats.reqs_in, sc->stats.reqs_out);
394226026Sdelphij    TWS_TRACE(sc, "reqs(err, intrs)", sc->stats.reqs_errored
395226026Sdelphij                                      , sc->stats.num_intrs);
396226026Sdelphij    TWS_TRACE(sc, "reqs(ioctls, scsi)", sc->stats.ioctls
397226026Sdelphij                                      , sc->stats.scsi_ios);
398226026Sdelphij    timeout(tws_print_stats, sc, 300*hz);
399226026Sdelphij
400226026Sdelphij}
401226026Sdelphij/* --------------------- misc service end --------------------- */
402