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$ 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 callout_reset(&sc->stats_timer, 300 * hz, tws_print_stats, sc); 399 } 400 /* --------------------- misc service end --------------------- */ 401