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