xref: /freebsd/sys/dev/tws/tws_services.c (revision 5e53a4f90f82c4345f277dd87cc9292f26e04a29)
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 
57 
58 static 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 
87 void
88 tws_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 
133 void
134 tws_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 
146 u_int16_t
147 tws_swap16(u_int16_t val)
148 {
149     return((val << 8) | (val >> 8));
150 }
151 
152 u_int32_t
153 tws_swap32(u_int32_t val)
154 {
155     return(((val << 24) | ((val << 8) & (0xFF0000)) |
156            ((val >> 8) & (0xFF00)) | (val >> 24)));
157 }
158 
159 
160 u_int64_t
161 tws_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 
171 void
172 tws_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 
188 u_int32_t
189 tws_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  */
207 void
208 tws_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 */
221 static void
222 tws_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 */
233 void
234 tws_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 */
251 void
252 tws_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 */
269 struct tws_request *
270 tws_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 */
292 struct tws_request *
293 tws_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 */
316 struct tws_request *
317 tws_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 
366 struct tws_sense *
367 tws_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 
389 void
390 tws_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