1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2010, LSI Corp.
5 * All rights reserved.
6 * Author : Manjunath Ranganathaiah
7 * Support: freebsdraid@lsi.com
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in
17 *    the documentation and/or other materials provided with the
18 *    distribution.
19 * 3. Neither the name of the <ORGANIZATION> nor the names of its
20 *    contributors may be used to endorse or promote products derived
21 *    from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 * $FreeBSD$
37 */
38
39#include <dev/tws/tws.h>
40#include <dev/tws/tws_hdm.h>
41#include <dev/tws/tws_services.h>
42#include <sys/time.h>
43
44void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
45                                u_int8_t q_type );
46struct tws_request * tws_q_remove_request(struct tws_softc *sc,
47                                struct tws_request *req, u_int8_t q_type );
48struct tws_request *tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type );
49void tws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
50                                u_int8_t q_type );
51struct tws_request * tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type );
52void tws_print_stats(void *arg);
53
54struct tws_sense *tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa);
55
56
57
58static struct error_desc array[] = {
59    { "Cannot add sysctl tree node", 0x2000, ERROR,
60       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
61    { "Register window not available", 0x2001, ERROR,
62       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
63    { "Can't allocate register window", 0x2002, ERROR,
64       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
65    { "Can't allocate interrupt", 0x2003, ERROR,
66       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
67    { "Can't set up interrupt", 0x2004, ERROR,
68       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
69    { "Couldn't intialize CAM", 0x2007, ERROR,
70       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
71    { "Couldn't create SIM device queue", 0x2100, ENOMEM,
72       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
73    { "Unable to  create SIM entry", 0x2101, ENOMEM,
74       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
75    { "Unable to  register the bus", 0x2102, ENXIO,
76       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
77    { "Unable to  create the path", 0x2103, ENXIO,
78       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
79    { "Bus scan request to CAM failed", 0x2104, ENXIO,
80       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
81    { "Unable to intialize the driver", 0x2008, ENXIO,
82       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
83    { "Unable to intialize the controller", 0x2009, ENXIO,
84       "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" },
85};
86
87void
88tws_trace(const char *file, const char *fun, int linenum,
89          struct tws_softc *sc, char *desc, u_int64_t val1, u_int64_t val2)
90{
91
92
93    struct tws_trace_rec *rec = (struct tws_trace_rec *)sc->trace_q.q;
94    volatile u_int16_t head, tail;
95    char fmt[256];
96
97    head = sc->trace_q.head;
98    tail = sc->trace_q.tail;
99/*
100    getnanotime(&rec[tail].ts);
101*/
102    strncpy(rec[tail].fname, file, TWS_TRACE_FNAME_LEN);
103    strncpy(rec[tail].func, fun, TWS_TRACE_FUNC_LEN);
104    rec[tail].linenum = linenum;
105    strncpy(rec[tail].desc, desc, TWS_TRACE_DESC_LEN);
106    rec[tail].val1 = val1;
107    rec[tail].val2 = val2;
108
109    tail = (tail+1) % sc->trace_q.depth;
110
111    if ( head == tail ) {
112        sc->trace_q.overflow = 1;
113        sc->trace_q.head = (head+1) % sc->trace_q.depth;
114    }
115    sc->trace_q.tail = tail;
116
117/*
118    tws_circular_q_insert(sc, &sc->trace_q,
119                              &rec, sizeof(struct tws_trace_rec));
120*/
121    if ( sc->is64bit )
122        strcpy(fmt, "%05d:%s::%s :%s: 0x%016lx : 0x%016lx \n");
123    else
124        strcpy(fmt, "%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n");
125
126/*
127    printf("%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n",
128            linenum, file, fun, desc, val1, val2);
129*/
130    printf(fmt, linenum, file, fun, desc, val1, val2);
131}
132
133void
134tws_log(struct tws_softc *sc, int index)
135{
136    device_printf((sc)->tws_dev, array[index].fmt,
137                    array[index].error_str,
138                    array[index].error_code,
139                    array[index].severity_level,
140                    array[index].desc );
141}
142
143/* ----------- swap functions ----------- */
144
145
146u_int16_t
147tws_swap16(u_int16_t val)
148{
149    return((val << 8) | (val >> 8));
150}
151
152u_int32_t
153tws_swap32(u_int32_t val)
154{
155    return(((val << 24) | ((val << 8) & (0xFF0000)) |
156           ((val >> 8) & (0xFF00)) | (val >> 24)));
157}
158
159
160u_int64_t
161tws_swap64(u_int64_t val)
162{
163    return((((u_int64_t)(tws_swap32(((u_int32_t *)(&(val)))[1]))) << 32) |
164           ((u_int32_t)(tws_swap32(((u_int32_t *)(&(val)))[0]))));
165}
166
167
168/* ----------- reg access ----------- */
169
170
171void
172tws_write_reg(struct tws_softc *sc, int offset,
173                  u_int32_t value, int size)
174{
175    bus_space_tag_t         bus_tag = sc->bus_tag;
176    bus_space_handle_t      bus_handle = sc->bus_handle;
177
178    if (size == 4)
179        bus_space_write_4(bus_tag, bus_handle, offset, value);
180    else
181        if (size == 2)
182            bus_space_write_2(bus_tag, bus_handle, offset,
183                                     (u_int16_t)value);
184        else
185            bus_space_write_1(bus_tag, bus_handle, offset, (u_int8_t)value);
186}
187
188u_int32_t
189tws_read_reg(struct tws_softc *sc, int offset, int size)
190{
191    bus_space_tag_t bus_tag = sc->bus_tag;
192    bus_space_handle_t bus_handle = sc->bus_handle;
193
194    if (size == 4)
195        return((u_int32_t)bus_space_read_4(bus_tag, bus_handle, offset));
196    else if (size == 2)
197            return((u_int32_t)bus_space_read_2(bus_tag, bus_handle, offset));
198         else
199            return((u_int32_t)bus_space_read_1(bus_tag, bus_handle, offset));
200}
201
202/* --------------------- Q service --------------------- */
203
204/*
205 * intialize q  pointers with null.
206 */
207void
208tws_init_qs(struct tws_softc *sc)
209{
210
211    mtx_lock(&sc->q_lock);
212    for(int i=0;i<TWS_MAX_QS;i++) {
213        sc->q_head[i] = NULL;
214        sc->q_tail[i] = NULL;
215    }
216    mtx_unlock(&sc->q_lock);
217
218}
219
220/* called with lock held */
221static void
222tws_insert2_empty_q(struct tws_softc *sc, struct tws_request *req,
223                                u_int8_t q_type )
224{
225
226    mtx_assert(&sc->q_lock, MA_OWNED);
227    req->next = req->prev = NULL;
228    sc->q_head[q_type] = sc->q_tail[q_type] = req;
229
230}
231
232/* called with lock held */
233void
234tws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
235                                u_int8_t q_type )
236{
237
238    mtx_assert(&sc->q_lock, MA_OWNED);
239    if ( sc->q_head[q_type] == NULL ) {
240        tws_insert2_empty_q(sc, req, q_type);
241    } else {
242        req->next = sc->q_head[q_type];
243        req->prev = NULL;
244        sc->q_head[q_type]->prev = req;
245        sc->q_head[q_type] = req;
246    }
247
248}
249
250/* called with lock held */
251void
252tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
253                                u_int8_t q_type )
254{
255
256    mtx_assert(&sc->q_lock, MA_OWNED);
257    if ( sc->q_tail[q_type] == NULL ) {
258        tws_insert2_empty_q(sc, req, q_type);
259    } else {
260        req->prev = sc->q_tail[q_type];
261        req->next = NULL;
262        sc->q_tail[q_type]->next = req;
263        sc->q_tail[q_type] = req;
264    }
265
266}
267
268/* called with lock held */
269struct tws_request *
270tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type )
271{
272
273    struct tws_request *r;
274
275    mtx_assert(&sc->q_lock, MA_OWNED);
276    r = sc->q_head[q_type];
277    if ( !r )
278        return(NULL);
279    if ( r->next == NULL &&  r->prev == NULL ) {
280        /* last element  */
281        sc->q_head[q_type] = sc->q_tail[q_type] = NULL;
282    } else {
283        sc->q_head[q_type] = r->next;
284        r->next->prev = NULL;
285        r->next = NULL;
286        r->prev = NULL;
287    }
288    return(r);
289}
290
291/* called with lock held */
292struct tws_request *
293tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type )
294{
295
296    struct tws_request *r;
297
298    mtx_assert(&sc->q_lock, MA_OWNED);
299    r = sc->q_tail[q_type];
300    if ( !r )
301        return(NULL);
302    if ( r->next == NULL &&  r->prev == NULL ) {
303        /* last element  */
304        sc->q_head[q_type] = sc->q_tail[q_type] = NULL;
305    } else {
306        sc->q_tail[q_type] = r->prev;
307        r->prev->next = NULL;
308        r->next = NULL;
309        r->prev = NULL;
310    }
311    return(r);
312}
313
314/* returns removed request if successful. return NULL otherwise */
315/* called with lock held */
316struct tws_request *
317tws_q_remove_request(struct tws_softc *sc, struct tws_request *req,
318                                 u_int8_t q_type )
319{
320
321    struct tws_request *r;
322
323    mtx_assert(&sc->q_lock, MA_OWNED);
324    if ( req == NULL ) {
325        TWS_TRACE_DEBUG(sc, "null req", 0, q_type);
326        return(NULL);
327    }
328
329    if ( req == sc->q_head[q_type] )
330        return(tws_q_remove_head(sc, q_type));
331    if ( req == sc->q_tail[q_type] )
332        return(tws_q_remove_tail(sc, q_type));
333
334
335    /* The given node is not at head or tail.
336     * It's in the middle and there are more than
337     * 2 elements on the q.
338     */
339
340    if ( req->next == NULL || req->prev == NULL ) {
341        TWS_TRACE_DEBUG(sc, "invalid req", 0, q_type);
342        return(NULL);
343    }
344
345/* debug only */
346    r = sc->q_head[q_type];
347    while ( r ) {
348        if ( req == r )
349            break;
350        r = r->next;
351    }
352
353    if ( !r ) {
354        TWS_TRACE_DEBUG(sc, "req not in q", 0, req->request_id);
355        return(NULL);
356    }
357/* debug end */
358
359    req->prev->next = r->next;
360    req->next->prev = r->prev;
361    req->next = NULL;
362    req->prev = NULL;
363    return(req);
364}
365
366struct tws_sense *
367tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa)
368{
369    struct tws_sense *s;
370    int i;
371    TWS_TRACE_DEBUG(sc, "entry",sc,mfa);
372
373    i = (mfa - sc->dma_mem_phys) / sizeof(struct tws_command_packet);
374    if ( i>= 0 && i<tws_queue_depth) {
375        s = &sc->sense_bufs[i];
376        if ( mfa == s->hdr_pkt_phy )
377            return(s);
378    }
379
380    TWS_TRACE_DEBUG(sc, "return null",0,mfa);
381    return(NULL);
382
383}
384
385/* --------------------- Q service end --------------------- */
386/* --------------------- misc service start --------------------- */
387
388
389void
390tws_print_stats(void *arg)
391{
392
393    struct tws_softc *sc = (struct tws_softc *)arg;
394
395    TWS_TRACE(sc, "reqs(in, out)", sc->stats.reqs_in, sc->stats.reqs_out);
396    TWS_TRACE(sc, "reqs(err, intrs)", sc->stats.reqs_errored
397                                      , sc->stats.num_intrs);
398    TWS_TRACE(sc, "reqs(ioctls, scsi)", sc->stats.ioctls
399                                      , sc->stats.scsi_ios);
400    callout_reset(&sc->stats_timer, 300 * hz, tws_print_stats, sc);
401}
402/* --------------------- misc service end --------------------- */
403