xref: /dragonfly/sys/dev/raid/tws/tws_services.c (revision 86d7f5d3)
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: src/sys/dev/tws/tws_cam.c,v 1.3 2007/05/09 04:16:32 mrangana Exp $
35  */
36 
37 #include <dev/raid/tws/tws.h>
38 #include <dev/raid/tws/tws_hdm.h>
39 #include <dev/raid/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 
55 
56 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
tws_trace(const char * file,const char * fun,int linenum,struct tws_softc * sc,char * desc,u_int64_t val1,u_int64_t val2)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 
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     kprintf("%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n",
126             linenum, file, fun, desc, val1, val2);
127 */
128     kprintf(fmt, linenum, file, fun, desc, val1, val2);
129 }
130 
131 void
tws_log(struct tws_softc * sc,int index)132 tws_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 
144 u_int16_t
tws_swap16(u_int16_t val)145 tws_swap16(u_int16_t val)
146 {
147     return((val << 8) | (val >> 8));
148 }
149 
150 u_int32_t
tws_swap32(u_int32_t val)151 tws_swap32(u_int32_t val)
152 {
153     return(((val << 24) | ((val << 8) & (0xFF0000)) |
154            ((val >> 8) & (0xFF00)) | (val >> 24)));
155 }
156 
157 
158 u_int64_t
tws_swap64(u_int64_t val)159 tws_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 
169 void
tws_write_reg(struct tws_softc * sc,int offset,u_int32_t value,int size)170 tws_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 
186 u_int32_t
tws_read_reg(struct tws_softc * sc,int offset,int size)187 tws_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  */
205 void
tws_init_qs(struct tws_softc * sc)206 tws_init_qs(struct tws_softc *sc)
207 {
208 
209     lockmgr(&sc->q_lock, LK_EXCLUSIVE);
210     for(int i=0;i<TWS_MAX_QS;i++) {
211         sc->q_head[i] = NULL;
212         sc->q_tail[i] = NULL;
213     }
214     lockmgr(&sc->q_lock, LK_RELEASE);
215 
216 }
217 
218 /* called with lock held */
219 static void
tws_insert2_empty_q(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)220 tws_insert2_empty_q(struct tws_softc *sc, struct tws_request *req,
221                                 u_int8_t q_type )
222 {
223 
224     KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
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 */
231 void
tws_q_insert_head(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)232 tws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
233                                 u_int8_t q_type )
234 {
235 
236     KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
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 */
249 void
tws_q_insert_tail(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)250 tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
251                                 u_int8_t q_type )
252 {
253 
254     KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
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 */
267 struct tws_request *
tws_q_remove_head(struct tws_softc * sc,u_int8_t q_type)268 tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type )
269 {
270 
271     struct tws_request *r;
272 
273     KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
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 */
290 struct tws_request *
tws_q_remove_tail(struct tws_softc * sc,u_int8_t q_type)291 tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type )
292 {
293 
294     struct tws_request *r;
295 
296     KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
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 */
314 struct tws_request *
tws_q_remove_request(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)315 tws_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     KKASSERT(lockstatus(&sc->q_lock, curthread) != 0);
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 
364 struct tws_sense *
tws_find_sense_from_mfa(struct tws_softc * sc,u_int64_t mfa)365 tws_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 
387 void
tws_print_stats(void * arg)388 tws_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     callout_reset(&sc->print_stats_handle, 300*hz, tws_print_stats, sc);
399 
400 }
401 /* --------------------- misc service end --------------------- */
402