tws_services.c revision 226887
1226026Sdelphij/* 2226026Sdelphij * Copyright (c) 2010, LSI Corp. 3226026Sdelphij * All rights reserved. 4226026Sdelphij * Author : Manjunath Ranganathaiah 5226026Sdelphij * Support: freebsdraid@lsi.com 6226026Sdelphij * 7226026Sdelphij * Redistribution and use in source and binary forms, with or without 8226026Sdelphij * modification, are permitted provided that the following conditions 9226026Sdelphij * are met: 10226026Sdelphij * 11226026Sdelphij * 1. Redistributions of source code must retain the above copyright 12226026Sdelphij * notice, this list of conditions and the following disclaimer. 13226026Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 14226026Sdelphij * notice, this list of conditions and the following disclaimer in 15226026Sdelphij * the documentation and/or other materials provided with the 16226026Sdelphij * distribution. 17226026Sdelphij * 3. Neither the name of the <ORGANIZATION> nor the names of its 18226026Sdelphij * contributors may be used to endorse or promote products derived 19226026Sdelphij * from this software without specific prior written permission. 20226026Sdelphij * 21226026Sdelphij * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22226026Sdelphij * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23226026Sdelphij * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24226026Sdelphij * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25226026Sdelphij * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26226026Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27226026Sdelphij * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28226026Sdelphij * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29226026Sdelphij * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30226026Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31226026Sdelphij * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32226026Sdelphij * POSSIBILITY OF SUCH DAMAGE. 33226026Sdelphij * 34226026Sdelphij * $FreeBSD: head/sys/dev/tws/tws_services.c 226887 2011-10-28 17:53:34Z delphij $ 35226026Sdelphij */ 36226026Sdelphij 37226026Sdelphij#include <dev/tws/tws.h> 38226026Sdelphij#include <dev/tws/tws_hdm.h> 39226026Sdelphij#include <dev/tws/tws_services.h> 40226026Sdelphij#include <sys/time.h> 41226026Sdelphij 42226026Sdelphijvoid tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req, 43226026Sdelphij u_int8_t q_type ); 44226026Sdelphijstruct tws_request * tws_q_remove_request(struct tws_softc *sc, 45226026Sdelphij struct tws_request *req, u_int8_t q_type ); 46226026Sdelphijstruct tws_request *tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type ); 47226026Sdelphijvoid tws_q_insert_head(struct tws_softc *sc, struct tws_request *req, 48226026Sdelphij u_int8_t q_type ); 49226026Sdelphijstruct tws_request * tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type ); 50226026Sdelphijvoid tws_print_stats(void *arg); 51226026Sdelphij 52226026Sdelphijstruct tws_sense *tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa); 53226026Sdelphij 54226026Sdelphij 55226026Sdelphij 56226887Sdelphijstatic struct error_desc array[] = { 57226026Sdelphij { "Cannot add sysctl tree node", 0x2000, ERROR, 58226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 59226026Sdelphij { "Register window not available", 0x2001, ERROR, 60226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 61226026Sdelphij { "Can't allocate register window", 0x2002, ERROR, 62226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 63226026Sdelphij { "Can't allocate interrupt", 0x2003, ERROR, 64226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 65226026Sdelphij { "Can't set up interrupt", 0x2004, ERROR, 66226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 67226026Sdelphij { "Couldn't intialize CAM", 0x2007, ERROR, 68226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 69226026Sdelphij { "Couldn't create SIM device queue", 0x2100, ENOMEM, 70226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 71226026Sdelphij { "Unable to create SIM entry", 0x2101, ENOMEM, 72226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 73226026Sdelphij { "Unable to register the bus", 0x2102, ENXIO, 74226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 75226026Sdelphij { "Unable to create the path", 0x2103, ENXIO, 76226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 77226026Sdelphij { "Bus scan request to CAM failed", 0x2104, ENXIO, 78226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 79226026Sdelphij { "Unable to intialize the driver", 0x2008, ENXIO, 80226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 81226026Sdelphij { "Unable to intialize the controller", 0x2009, ENXIO, 82226026Sdelphij "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, 83226026Sdelphij}; 84226026Sdelphij 85226026Sdelphijvoid 86226026Sdelphijtws_trace(const char *file, const char *fun, int linenum, 87226026Sdelphij struct tws_softc *sc, char *desc, u_int64_t val1, u_int64_t val2) 88226026Sdelphij{ 89226026Sdelphij 90226026Sdelphij 91226026Sdelphij struct tws_trace_rec *rec = (struct tws_trace_rec *)sc->trace_q.q; 92226026Sdelphij volatile u_int16_t head, tail; 93226026Sdelphij char fmt[256]; 94226026Sdelphij 95226026Sdelphij head = sc->trace_q.head; 96226026Sdelphij tail = sc->trace_q.tail; 97226026Sdelphij/* 98226026Sdelphij getnanotime(&rec[tail].ts); 99226026Sdelphij*/ 100226026Sdelphij strncpy(rec[tail].fname, file, TWS_TRACE_FNAME_LEN); 101226026Sdelphij strncpy(rec[tail].func, fun, TWS_TRACE_FUNC_LEN); 102226026Sdelphij rec[tail].linenum = linenum; 103226026Sdelphij strncpy(rec[tail].desc, desc, TWS_TRACE_DESC_LEN); 104226026Sdelphij rec[tail].val1 = val1; 105226026Sdelphij rec[tail].val2 = val2; 106226026Sdelphij 107226026Sdelphij tail = (tail+1) % sc->trace_q.depth; 108226026Sdelphij 109226026Sdelphij if ( head == tail ) { 110226026Sdelphij sc->trace_q.overflow = 1; 111226026Sdelphij sc->trace_q.head = (head+1) % sc->trace_q.depth; 112226026Sdelphij } 113226026Sdelphij sc->trace_q.tail = tail; 114226026Sdelphij 115226026Sdelphij/* 116226026Sdelphij tws_circular_q_insert(sc, &sc->trace_q, 117226026Sdelphij &rec, sizeof(struct tws_trace_rec)); 118226026Sdelphij*/ 119226026Sdelphij if ( sc->is64bit ) 120226026Sdelphij strcpy(fmt, "%05d:%s::%s :%s: 0x%016lx : 0x%016lx \n"); 121226026Sdelphij else 122226026Sdelphij strcpy(fmt, "%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n"); 123226026Sdelphij 124226026Sdelphij/* 125226026Sdelphij printf("%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n", 126226026Sdelphij linenum, file, fun, desc, val1, val2); 127226026Sdelphij*/ 128226026Sdelphij printf(fmt, linenum, file, fun, desc, val1, val2); 129226026Sdelphij} 130226026Sdelphij 131226026Sdelphijvoid 132226026Sdelphijtws_log(struct tws_softc *sc, int index) 133226026Sdelphij{ 134226026Sdelphij device_printf((sc)->tws_dev, array[index].fmt, 135226026Sdelphij array[index].error_str, 136226026Sdelphij array[index].error_code, 137226026Sdelphij array[index].severity_level, 138226026Sdelphij array[index].desc ); 139226026Sdelphij} 140226026Sdelphij 141226026Sdelphij/* ----------- swap functions ----------- */ 142226026Sdelphij 143226026Sdelphij 144226026Sdelphiju_int16_t 145226026Sdelphijtws_swap16(u_int16_t val) 146226026Sdelphij{ 147226026Sdelphij return((val << 8) | (val >> 8)); 148226026Sdelphij} 149226026Sdelphij 150226026Sdelphiju_int32_t 151226026Sdelphijtws_swap32(u_int32_t val) 152226026Sdelphij{ 153226026Sdelphij return(((val << 24) | ((val << 8) & (0xFF0000)) | 154226026Sdelphij ((val >> 8) & (0xFF00)) | (val >> 24))); 155226026Sdelphij} 156226026Sdelphij 157226026Sdelphij 158226026Sdelphiju_int64_t 159226026Sdelphijtws_swap64(u_int64_t val) 160226026Sdelphij{ 161226026Sdelphij return((((u_int64_t)(tws_swap32(((u_int32_t *)(&(val)))[1]))) << 32) | 162226026Sdelphij ((u_int32_t)(tws_swap32(((u_int32_t *)(&(val)))[0])))); 163226026Sdelphij} 164226026Sdelphij 165226026Sdelphij 166226026Sdelphij/* ----------- reg access ----------- */ 167226026Sdelphij 168226026Sdelphij 169226026Sdelphijvoid 170226026Sdelphijtws_write_reg(struct tws_softc *sc, int offset, 171226026Sdelphij u_int32_t value, int size) 172226026Sdelphij{ 173226026Sdelphij bus_space_tag_t bus_tag = sc->bus_tag; 174226026Sdelphij bus_space_handle_t bus_handle = sc->bus_handle; 175226026Sdelphij 176226026Sdelphij if (size == 4) 177226026Sdelphij bus_space_write_4(bus_tag, bus_handle, offset, value); 178226026Sdelphij else 179226026Sdelphij if (size == 2) 180226026Sdelphij bus_space_write_2(bus_tag, bus_handle, offset, 181226026Sdelphij (u_int16_t)value); 182226026Sdelphij else 183226026Sdelphij bus_space_write_1(bus_tag, bus_handle, offset, (u_int8_t)value); 184226026Sdelphij} 185226026Sdelphij 186226026Sdelphiju_int32_t 187226026Sdelphijtws_read_reg(struct tws_softc *sc, int offset, int size) 188226026Sdelphij{ 189226026Sdelphij bus_space_tag_t bus_tag = sc->bus_tag; 190226026Sdelphij bus_space_handle_t bus_handle = sc->bus_handle; 191226026Sdelphij 192226026Sdelphij if (size == 4) 193226026Sdelphij return((u_int32_t)bus_space_read_4(bus_tag, bus_handle, offset)); 194226026Sdelphij else if (size == 2) 195226026Sdelphij return((u_int32_t)bus_space_read_2(bus_tag, bus_handle, offset)); 196226026Sdelphij else 197226026Sdelphij return((u_int32_t)bus_space_read_1(bus_tag, bus_handle, offset)); 198226026Sdelphij} 199226026Sdelphij 200226026Sdelphij/* --------------------- Q service --------------------- */ 201226026Sdelphij 202226026Sdelphij/* 203226026Sdelphij * intialize q pointers with null. 204226026Sdelphij */ 205226026Sdelphijvoid 206226026Sdelphijtws_init_qs(struct tws_softc *sc) 207226026Sdelphij{ 208226026Sdelphij 209226026Sdelphij mtx_lock(&sc->q_lock); 210226026Sdelphij for(int i=0;i<TWS_MAX_QS;i++) { 211226026Sdelphij sc->q_head[i] = NULL; 212226026Sdelphij sc->q_tail[i] = NULL; 213226026Sdelphij } 214226026Sdelphij mtx_unlock(&sc->q_lock); 215226026Sdelphij 216226026Sdelphij} 217226026Sdelphij 218226026Sdelphij/* called with lock held */ 219226026Sdelphijstatic void 220226026Sdelphijtws_insert2_empty_q(struct tws_softc *sc, struct tws_request *req, 221226026Sdelphij u_int8_t q_type ) 222226026Sdelphij{ 223226026Sdelphij 224226026Sdelphij mtx_assert(&sc->q_lock, MA_OWNED); 225226026Sdelphij req->next = req->prev = NULL; 226226026Sdelphij sc->q_head[q_type] = sc->q_tail[q_type] = req; 227226026Sdelphij 228226026Sdelphij} 229226026Sdelphij 230226026Sdelphij/* called with lock held */ 231226026Sdelphijvoid 232226026Sdelphijtws_q_insert_head(struct tws_softc *sc, struct tws_request *req, 233226026Sdelphij u_int8_t q_type ) 234226026Sdelphij{ 235226026Sdelphij 236226026Sdelphij mtx_assert(&sc->q_lock, MA_OWNED); 237226026Sdelphij if ( sc->q_head[q_type] == NULL ) { 238226026Sdelphij tws_insert2_empty_q(sc, req, q_type); 239226026Sdelphij } else { 240226026Sdelphij req->next = sc->q_head[q_type]; 241226026Sdelphij req->prev = NULL; 242226026Sdelphij sc->q_head[q_type]->prev = req; 243226026Sdelphij sc->q_head[q_type] = req; 244226026Sdelphij } 245226026Sdelphij 246226026Sdelphij} 247226026Sdelphij 248226026Sdelphij/* called with lock held */ 249226026Sdelphijvoid 250226026Sdelphijtws_q_insert_tail(struct tws_softc *sc, struct tws_request *req, 251226026Sdelphij u_int8_t q_type ) 252226026Sdelphij{ 253226026Sdelphij 254226026Sdelphij mtx_assert(&sc->q_lock, MA_OWNED); 255226026Sdelphij if ( sc->q_tail[q_type] == NULL ) { 256226026Sdelphij tws_insert2_empty_q(sc, req, q_type); 257226026Sdelphij } else { 258226026Sdelphij req->prev = sc->q_tail[q_type]; 259226026Sdelphij req->next = NULL; 260226026Sdelphij sc->q_tail[q_type]->next = req; 261226026Sdelphij sc->q_tail[q_type] = req; 262226026Sdelphij } 263226026Sdelphij 264226026Sdelphij} 265226026Sdelphij 266226026Sdelphij/* called with lock held */ 267226026Sdelphijstruct tws_request * 268226026Sdelphijtws_q_remove_head(struct tws_softc *sc, u_int8_t q_type ) 269226026Sdelphij{ 270226026Sdelphij 271226026Sdelphij struct tws_request *r; 272226026Sdelphij 273226026Sdelphij mtx_assert(&sc->q_lock, MA_OWNED); 274226026Sdelphij r = sc->q_head[q_type]; 275226026Sdelphij if ( !r ) 276226026Sdelphij return(NULL); 277226026Sdelphij if ( r->next == NULL && r->prev == NULL ) { 278226026Sdelphij /* last element */ 279226026Sdelphij sc->q_head[q_type] = sc->q_tail[q_type] = NULL; 280226026Sdelphij } else { 281226026Sdelphij sc->q_head[q_type] = r->next; 282226026Sdelphij r->next->prev = NULL; 283226026Sdelphij r->next = NULL; 284226026Sdelphij r->prev = NULL; 285226026Sdelphij } 286226026Sdelphij return(r); 287226026Sdelphij} 288226026Sdelphij 289226026Sdelphij/* called with lock held */ 290226026Sdelphijstruct tws_request * 291226026Sdelphijtws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type ) 292226026Sdelphij{ 293226026Sdelphij 294226026Sdelphij struct tws_request *r; 295226026Sdelphij 296226026Sdelphij mtx_assert(&sc->q_lock, MA_OWNED); 297226026Sdelphij r = sc->q_tail[q_type]; 298226026Sdelphij if ( !r ) 299226026Sdelphij return(NULL); 300226026Sdelphij if ( r->next == NULL && r->prev == NULL ) { 301226026Sdelphij /* last element */ 302226026Sdelphij sc->q_head[q_type] = sc->q_tail[q_type] = NULL; 303226026Sdelphij } else { 304226026Sdelphij sc->q_tail[q_type] = r->prev; 305226026Sdelphij r->prev->next = NULL; 306226026Sdelphij r->next = NULL; 307226026Sdelphij r->prev = NULL; 308226026Sdelphij } 309226026Sdelphij return(r); 310226026Sdelphij} 311226026Sdelphij 312226026Sdelphij/* returns removed request if successful. return NULL otherwise */ 313226026Sdelphij/* called with lock held */ 314226026Sdelphijstruct tws_request * 315226026Sdelphijtws_q_remove_request(struct tws_softc *sc, struct tws_request *req, 316226026Sdelphij u_int8_t q_type ) 317226026Sdelphij{ 318226026Sdelphij 319226026Sdelphij struct tws_request *r; 320226026Sdelphij 321226026Sdelphij mtx_assert(&sc->q_lock, MA_OWNED); 322226026Sdelphij if ( req == NULL ) { 323226026Sdelphij TWS_TRACE_DEBUG(sc, "null req", 0, q_type); 324226026Sdelphij return(NULL); 325226026Sdelphij } 326226026Sdelphij 327226026Sdelphij if ( req == sc->q_head[q_type] ) 328226026Sdelphij return(tws_q_remove_head(sc, q_type)); 329226026Sdelphij if ( req == sc->q_tail[q_type] ) 330226026Sdelphij return(tws_q_remove_tail(sc, q_type)); 331226026Sdelphij 332226026Sdelphij 333226026Sdelphij /* The given node is not at head or tail. 334226026Sdelphij * It's in the middle and there are more than 335226026Sdelphij * 2 elements on the q. 336226026Sdelphij */ 337226026Sdelphij 338226026Sdelphij if ( req->next == NULL || req->prev == NULL ) { 339226026Sdelphij TWS_TRACE_DEBUG(sc, "invalid req", 0, q_type); 340226026Sdelphij return(NULL); 341226026Sdelphij } 342226026Sdelphij 343226026Sdelphij/* debug only */ 344226026Sdelphij r = sc->q_head[q_type]; 345226026Sdelphij while ( r ) { 346226026Sdelphij if ( req == r ) 347226026Sdelphij break; 348226026Sdelphij r = r->next; 349226026Sdelphij } 350226026Sdelphij 351226026Sdelphij if ( !r ) { 352226026Sdelphij TWS_TRACE_DEBUG(sc, "req not in q", 0, req->request_id); 353226026Sdelphij return(NULL); 354226026Sdelphij } 355226026Sdelphij/* debug end */ 356226026Sdelphij 357226026Sdelphij req->prev->next = r->next; 358226026Sdelphij req->next->prev = r->prev; 359226026Sdelphij req->next = NULL; 360226026Sdelphij req->prev = NULL; 361226026Sdelphij return(req); 362226026Sdelphij} 363226026Sdelphij 364226026Sdelphijstruct tws_sense * 365226026Sdelphijtws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa) 366226026Sdelphij{ 367226026Sdelphij struct tws_sense *s; 368226026Sdelphij int i; 369226026Sdelphij TWS_TRACE_DEBUG(sc, "entry",sc,mfa); 370226026Sdelphij 371226026Sdelphij i = (mfa - sc->dma_mem_phys) / sizeof(struct tws_command_packet); 372226026Sdelphij if ( i>= 0 && i<tws_queue_depth) { 373226026Sdelphij s = &sc->sense_bufs[i]; 374226026Sdelphij if ( mfa == s->hdr_pkt_phy ) 375226026Sdelphij return(s); 376226026Sdelphij } 377226026Sdelphij 378226026Sdelphij TWS_TRACE_DEBUG(sc, "return null",0,mfa); 379226026Sdelphij return(NULL); 380226026Sdelphij 381226026Sdelphij} 382226026Sdelphij 383226026Sdelphij/* --------------------- Q service end --------------------- */ 384226026Sdelphij/* --------------------- misc service start --------------------- */ 385226026Sdelphij 386226026Sdelphij 387226026Sdelphijvoid 388226026Sdelphijtws_print_stats(void *arg) 389226026Sdelphij{ 390226026Sdelphij 391226026Sdelphij struct tws_softc *sc = (struct tws_softc *)arg; 392226026Sdelphij 393226026Sdelphij TWS_TRACE(sc, "reqs(in, out)", sc->stats.reqs_in, sc->stats.reqs_out); 394226026Sdelphij TWS_TRACE(sc, "reqs(err, intrs)", sc->stats.reqs_errored 395226026Sdelphij , sc->stats.num_intrs); 396226026Sdelphij TWS_TRACE(sc, "reqs(ioctls, scsi)", sc->stats.ioctls 397226026Sdelphij , sc->stats.scsi_ios); 398226026Sdelphij timeout(tws_print_stats, sc, 300*hz); 399226026Sdelphij 400226026Sdelphij} 401226026Sdelphij/* --------------------- misc service end --------------------- */ 402