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: releng/8.4/sys/dev/tws/tws_services.c 226970 2011-10-31 20:03:09Z delphij $
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
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
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 printf("%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n",
126 linenum, file, fun, desc, val1, val2);
127 */
128 printf(fmt, linenum, file, fun, desc, val1, val2);
129 }
130
131 void
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
145 tws_swap16(u_int16_t val)
146 {
147 return((val << 8) | (val >> 8));
148 }
149
150 u_int32_t
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
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
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
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
206 tws_init_qs(struct tws_softc *sc)
207 {
208
209 mtx_lock(&sc->q_lock);
210 for(int i=0;i<TWS_MAX_QS;i++) {
211 sc->q_head[i] = NULL;
212 sc->q_tail[i] = NULL;
213 }
214 mtx_unlock(&sc->q_lock);
215
216 }
217
218 /* called with lock held */
219 static void
220 tws_insert2_empty_q(struct tws_softc *sc, struct tws_request *req,
221 u_int8_t q_type )
222 {
223
224 mtx_assert(&sc->q_lock, MA_OWNED);
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
232 tws_q_insert_head(struct tws_softc *sc, struct tws_request *req,
233 u_int8_t q_type )
234 {
235
236 mtx_assert(&sc->q_lock, MA_OWNED);
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
250 tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
251 u_int8_t q_type )
252 {
253
254 mtx_assert(&sc->q_lock, MA_OWNED);
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 *
268 tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type )
269 {
270
271 struct tws_request *r;
272
273 mtx_assert(&sc->q_lock, MA_OWNED);
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 *
291 tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type )
292 {
293
294 struct tws_request *r;
295
296 mtx_assert(&sc->q_lock, MA_OWNED);
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 *
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 mtx_assert(&sc->q_lock, MA_OWNED);
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 *
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
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 timeout(tws_print_stats, sc, 300*hz);
399
400 }
401 /* --------------------- misc service end --------------------- */
Cache object: 8d89eadb1d26152da253ee9d755908ea
|