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$
35 */
36
37#include <dev/tws/tws.h>
38#include <dev/tws/tws_hdm.h>
39#include <dev/tws/tws_services.h>
40#include <sys/time.h>
41
42void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
43                                u_int8_t q_type );
44struct tws_request * tws_q_remove_request(struct tws_softc *sc,
45                                struct tws_request *req, u_int8_t q_type );
46struct tws_request *tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type );
47void tws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
48                                u_int8_t q_type );
49struct tws_request * tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type );
50void tws_print_stats(void *arg);
51
52struct tws_sense *tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa);
53
54
55
56static struct error_desc array[] = {
57    { "Cannot add sysctl tree node", 0x2000, ERROR,
58       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
59    { "Register window not available", 0x2001, ERROR,
60       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
61    { "Can't allocate register window", 0x2002, ERROR,
62       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
63    { "Can't allocate interrupt", 0x2003, ERROR,
64       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
65    { "Can't set up interrupt", 0x2004, ERROR,
66       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
67    { "Couldn't intialize CAM", 0x2007, ERROR,
68       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
69    { "Couldn't create SIM device queue", 0x2100, ENOMEM,
70       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
71    { "Unable to  create SIM entry", 0x2101, ENOMEM,
72       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
73    { "Unable to  register the bus", 0x2102, ENXIO,
74       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
75    { "Unable to  create the path", 0x2103, ENXIO,
76       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
77    { "Bus scan request to CAM failed", 0x2104, ENXIO,
78       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
79    { "Unable to intialize the driver", 0x2008, ENXIO,
80       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
81    { "Unable to intialize the controller", 0x2009, ENXIO,
82       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
83};
84
85void
86tws_trace(const char *file, const char *fun, int linenum,
87          struct tws_softc *sc, char *desc, u_int64_t val1, u_int64_t val2)
88{
89
90
91    struct tws_trace_rec *rec = (struct tws_trace_rec *)sc->trace_q.q;
92    volatile u_int16_t head, tail;
93    char fmt[256];
94
95    head = sc->trace_q.head;
96    tail = sc->trace_q.tail;
97/*
98    getnanotime(&rec[tail].ts);
99*/
100    strncpy(rec[tail].fname, file, TWS_TRACE_FNAME_LEN);
101    strncpy(rec[tail].func, fun, TWS_TRACE_FUNC_LEN);
102    rec[tail].linenum = linenum;
103    strncpy(rec[tail].desc, desc, TWS_TRACE_DESC_LEN);
104    rec[tail].val1 = val1;
105    rec[tail].val2 = val2;
106
107    tail = (tail+1) % sc->trace_q.depth;
108
109    if ( head == tail ) {
110        sc->trace_q.overflow = 1;
111        sc->trace_q.head = (head+1) % sc->trace_q.depth;
112    }
113    sc->trace_q.tail = tail;
114
115/*
116    tws_circular_q_insert(sc, &sc->trace_q,
117                              &rec, sizeof(struct tws_trace_rec));
118*/
119    if ( sc->is64bit )
120        strcpy(fmt, "%05d:%s::%s :%s: 0x%016lx : 0x%016lx \n");
121    else
122        strcpy(fmt, "%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n");
123
124/*
125    printf("%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n",
126            linenum, file, fun, desc, val1, val2);
127*/
128    printf(fmt, linenum, file, fun, desc, val1, val2);
129}
130
131void
132tws_log(struct tws_softc *sc, int index)
133{
134    device_printf((sc)->tws_dev, array[index].fmt,
135                    array[index].error_str,
136                    array[index].error_code,
137                    array[index].severity_level,
138                    array[index].desc );
139}
140
141/* ----------- swap functions ----------- */
142
143
144u_int16_t
145tws_swap16(u_int16_t val)
146{
147    return((val << 8) | (val >> 8));
148}
149
150u_int32_t
151tws_swap32(u_int32_t val)
152{
153    return(((val << 24) | ((val << 8) & (0xFF0000)) |
154           ((val >> 8) & (0xFF00)) | (val >> 24)));
155}
156
157
158u_int64_t
159tws_swap64(u_int64_t val)
160{
161    return((((u_int64_t)(tws_swap32(((u_int32_t *)(&(val)))[1]))) << 32) |
162           ((u_int32_t)(tws_swap32(((u_int32_t *)(&(val)))[0]))));
163}
164
165
166/* ----------- reg access ----------- */
167
168
169void
170tws_write_reg(struct tws_softc *sc, int offset,
171                  u_int32_t value, int size)
172{
173    bus_space_tag_t         bus_tag = sc->bus_tag;
174    bus_space_handle_t      bus_handle = sc->bus_handle;
175
176    if (size == 4)
177        bus_space_write_4(bus_tag, bus_handle, offset, value);
178    else
179        if (size == 2)
180            bus_space_write_2(bus_tag, bus_handle, offset,
181                                     (u_int16_t)value);
182        else
183            bus_space_write_1(bus_tag, bus_handle, offset, (u_int8_t)value);
184}
185
186u_int32_t
187tws_read_reg(struct tws_softc *sc, int offset, int size)
188{
189    bus_space_tag_t bus_tag = sc->bus_tag;
190    bus_space_handle_t bus_handle = sc->bus_handle;
191
192    if (size == 4)
193        return((u_int32_t)bus_space_read_4(bus_tag, bus_handle, offset));
194    else if (size == 2)
195            return((u_int32_t)bus_space_read_2(bus_tag, bus_handle, offset));
196         else
197            return((u_int32_t)bus_space_read_1(bus_tag, bus_handle, offset));
198}
199
200/* --------------------- Q service --------------------- */
201
202/*
203 * intialize q  pointers with null.
204 */
205void
206tws_init_qs(struct tws_softc *sc)
207{
208
209    mtx_lock(&sc->q_lock);
210    for(int i=0;i<TWS_MAX_QS;i++) {
211        sc->q_head[i] = NULL;
212        sc->q_tail[i] = NULL;
213    }
214    mtx_unlock(&sc->q_lock);
215
216}
217
218/* called with lock held */
219static void
220tws_insert2_empty_q(struct tws_softc *sc, struct tws_request *req,
221                                u_int8_t q_type )
222{
223
224    mtx_assert(&sc->q_lock, MA_OWNED);
225    req->next = req->prev = NULL;
226    sc->q_head[q_type] = sc->q_tail[q_type] = req;
227
228}
229
230/* called with lock held */
231void
232tws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
233                                u_int8_t q_type )
234{
235
236    mtx_assert(&sc->q_lock, MA_OWNED);
237    if ( sc->q_head[q_type] == NULL ) {
238        tws_insert2_empty_q(sc, req, q_type);
239    } else {
240        req->next = sc->q_head[q_type];
241        req->prev = NULL;
242        sc->q_head[q_type]->prev = req;
243        sc->q_head[q_type] = req;
244    }
245
246}
247
248/* called with lock held */
249void
250tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
251                                u_int8_t q_type )
252{
253
254    mtx_assert(&sc->q_lock, MA_OWNED);
255    if ( sc->q_tail[q_type] == NULL ) {
256        tws_insert2_empty_q(sc, req, q_type);
257    } else {
258        req->prev = sc->q_tail[q_type];
259        req->next = NULL;
260        sc->q_tail[q_type]->next = req;
261        sc->q_tail[q_type] = req;
262    }
263
264}
265
266/* called with lock held */
267struct tws_request *
268tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type )
269{
270
271    struct tws_request *r;
272
273    mtx_assert(&sc->q_lock, MA_OWNED);
274    r = sc->q_head[q_type];
275    if ( !r )
276        return(NULL);
277    if ( r->next == NULL &&  r->prev == NULL ) {
278        /* last element  */
279        sc->q_head[q_type] = sc->q_tail[q_type] = NULL;
280    } else {
281        sc->q_head[q_type] = r->next;
282        r->next->prev = NULL;
283        r->next = NULL;
284        r->prev = NULL;
285    }
286    return(r);
287}
288
289/* called with lock held */
290struct tws_request *
291tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type )
292{
293
294    struct tws_request *r;
295
296    mtx_assert(&sc->q_lock, MA_OWNED);
297    r = sc->q_tail[q_type];
298    if ( !r )
299        return(NULL);
300    if ( r->next == NULL &&  r->prev == NULL ) {
301        /* last element  */
302        sc->q_head[q_type] = sc->q_tail[q_type] = NULL;
303    } else {
304        sc->q_tail[q_type] = r->prev;
305        r->prev->next = NULL;
306        r->next = NULL;
307        r->prev = NULL;
308    }
309    return(r);
310}
311
312/* returns removed request if successful. return NULL otherwise */
313/* called with lock held */
314struct tws_request *
315tws_q_remove_request(struct tws_softc *sc, struct tws_request *req,
316                                 u_int8_t q_type )
317{
318
319    struct tws_request *r;
320
321    mtx_assert(&sc->q_lock, MA_OWNED);
322    if ( req == NULL ) {
323        TWS_TRACE_DEBUG(sc, "null req", 0, q_type);
324        return(NULL);
325    }
326
327    if ( req == sc->q_head[q_type] )
328        return(tws_q_remove_head(sc, q_type));
329    if ( req == sc->q_tail[q_type] )
330        return(tws_q_remove_tail(sc, q_type));
331
332
333    /* The given node is not at head or tail.
334     * It's in the middle and there are more than
335     * 2 elements on the q.
336     */
337
338    if ( req->next == NULL || req->prev == NULL ) {
339        TWS_TRACE_DEBUG(sc, "invalid req", 0, q_type);
340        return(NULL);
341    }
342
343/* debug only */
344    r = sc->q_head[q_type];
345    while ( r ) {
346        if ( req == r )
347            break;
348        r = r->next;
349    }
350
351    if ( !r ) {
352        TWS_TRACE_DEBUG(sc, "req not in q", 0, req->request_id);
353        return(NULL);
354    }
355/* debug end */
356
357    req->prev->next = r->next;
358    req->next->prev = r->prev;
359    req->next = NULL;
360    req->prev = NULL;
361    return(req);
362}
363
364struct tws_sense *
365tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa)
366{
367    struct tws_sense *s;
368    int i;
369    TWS_TRACE_DEBUG(sc, "entry",sc,mfa);
370
371    i = (mfa - sc->dma_mem_phys) / sizeof(struct tws_command_packet);
372    if ( i>= 0 && i<tws_queue_depth) {
373        s = &sc->sense_bufs[i];
374        if ( mfa == s->hdr_pkt_phy )
375            return(s);
376    }
377
378    TWS_TRACE_DEBUG(sc, "return null",0,mfa);
379    return(NULL);
380
381}
382
383/* --------------------- Q service end --------------------- */
384/* --------------------- misc service start --------------------- */
385
386
387void
388tws_print_stats(void *arg)
389{
390
391    struct tws_softc *sc = (struct tws_softc *)arg;
392
393    TWS_TRACE(sc, "reqs(in, out)", sc->stats.reqs_in, sc->stats.reqs_out);
394    TWS_TRACE(sc, "reqs(err, intrs)", sc->stats.reqs_errored
395                                      , sc->stats.num_intrs);
396    TWS_TRACE(sc, "reqs(ioctls, scsi)", sc->stats.ioctls
397                                      , sc->stats.scsi_ios);
398    timeout(tws_print_stats, sc, 300*hz);
399
400}
401/* --------------------- misc service end --------------------- */
402