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