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 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 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 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 147 tws_swap16(u_int16_t val) 148 { 149 return((val << 8) | (val >> 8)); 150 } 151 152 u_int32_t 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 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 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