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