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: [email protected]
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
tws_trace(const char * file,const char * fun,int linenum,struct tws_softc * sc,char * desc,u_int64_t val1,u_int64_t val2)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
tws_log(struct tws_softc * sc,int index)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
tws_swap16(u_int16_t val)147 tws_swap16(u_int16_t val)
148 {
149 return((val << 8) | (val >> 8));
150 }
151
152 u_int32_t
tws_swap32(u_int32_t val)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
tws_swap64(u_int64_t val)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
tws_write_reg(struct tws_softc * sc,int offset,u_int32_t value,int size)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
tws_read_reg(struct tws_softc * sc,int offset,int size)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
tws_init_qs(struct tws_softc * sc)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
tws_insert2_empty_q(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)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
tws_q_insert_head(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)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
tws_q_insert_tail(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)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 *
tws_q_remove_head(struct tws_softc * sc,u_int8_t q_type)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 *
tws_q_remove_tail(struct tws_softc * sc,u_int8_t q_type)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 *
tws_q_remove_request(struct tws_softc * sc,struct tws_request * req,u_int8_t q_type)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 *
tws_find_sense_from_mfa(struct tws_softc * sc,u_int64_t mfa)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
tws_print_stats(void * arg)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