diff options
| author | Xin LI <delphij@FreeBSD.org> | 2011-10-04 21:40:25 +0000 |
|---|---|---|
| committer | Xin LI <delphij@FreeBSD.org> | 2011-10-04 21:40:25 +0000 |
| commit | db1fda10b421d404dcb38912df8453ca21645810 (patch) | |
| tree | 8bf58a4bedd5b6037fb04497b9166be360ce5c7b /sys/dev/tws/tws_services.c | |
| parent | eed142e1e9b5e757ba7d4f6e0d994763de200fce (diff) | |
Notes
Diffstat (limited to 'sys/dev/tws/tws_services.c')
| -rw-r--r-- | sys/dev/tws/tws_services.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/sys/dev/tws/tws_services.c b/sys/dev/tws/tws_services.c new file mode 100644 index 000000000000..07200b595d15 --- /dev/null +++ b/sys/dev/tws/tws_services.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2010, LSI Corp. + * All rights reserved. + * Author : Manjunath Ranganathaiah + * Support: freebsdraid@lsi.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of the <ORGANIZATION> nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <dev/tws/tws.h> +#include <dev/tws/tws_hdm.h> +#include <dev/tws/tws_services.h> +#include <sys/time.h> + +void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req, + u_int8_t q_type ); +struct tws_request * tws_q_remove_request(struct tws_softc *sc, + struct tws_request *req, u_int8_t q_type ); +struct tws_request *tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type ); +void tws_q_insert_head(struct tws_softc *sc, struct tws_request *req, + u_int8_t q_type ); +struct tws_request * tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type ); +void tws_print_stats(void *arg); + +struct tws_sense *tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa); + + + +struct error_desc array[] = { + { "Cannot add sysctl tree node", 0x2000, ERROR, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Register window not available", 0x2001, ERROR, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Can't allocate register window", 0x2002, ERROR, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Can't allocate interrupt", 0x2003, ERROR, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Can't set up interrupt", 0x2004, ERROR, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Couldn't intialize CAM", 0x2007, ERROR, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Couldn't create SIM device queue", 0x2100, ENOMEM, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Unable to create SIM entry", 0x2101, ENOMEM, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Unable to register the bus", 0x2102, ENXIO, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Unable to create the path", 0x2103, ENXIO, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Bus scan request to CAM failed", 0x2104, ENXIO, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Unable to intialize the driver", 0x2008, ENXIO, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, + { "Unable to intialize the controller", 0x2009, ENXIO, + "%s: (0x%02X: 0x%04X): %s:\n", "ERROR" }, +}; + +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) +{ + + + struct tws_trace_rec *rec = (struct tws_trace_rec *)sc->trace_q.q; + volatile u_int16_t head, tail; + char fmt[256]; + + head = sc->trace_q.head; + tail = sc->trace_q.tail; +/* + getnanotime(&rec[tail].ts); +*/ + strncpy(rec[tail].fname, file, TWS_TRACE_FNAME_LEN); + strncpy(rec[tail].func, fun, TWS_TRACE_FUNC_LEN); + rec[tail].linenum = linenum; + strncpy(rec[tail].desc, desc, TWS_TRACE_DESC_LEN); + rec[tail].val1 = val1; + rec[tail].val2 = val2; + + tail = (tail+1) % sc->trace_q.depth; + + if ( head == tail ) { + sc->trace_q.overflow = 1; + sc->trace_q.head = (head+1) % sc->trace_q.depth; + } + sc->trace_q.tail = tail; + +/* + tws_circular_q_insert(sc, &sc->trace_q, + &rec, sizeof(struct tws_trace_rec)); +*/ + if ( sc->is64bit ) + strcpy(fmt, "%05d:%s::%s :%s: 0x%016lx : 0x%016lx \n"); + else + strcpy(fmt, "%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n"); + +/* + printf("%05d:%s::%s :%s: 0x%016llx : 0x%016llx \n", + linenum, file, fun, desc, val1, val2); +*/ + printf(fmt, linenum, file, fun, desc, val1, val2); +} + +void +tws_log(struct tws_softc *sc, int index) +{ + device_printf((sc)->tws_dev, array[index].fmt, + array[index].error_str, + array[index].error_code, + array[index].severity_level, + array[index].desc ); +} + +/* ----------- swap functions ----------- */ + + +u_int16_t +tws_swap16(u_int16_t val) +{ + return((val << 8) | (val >> 8)); +} + +u_int32_t +tws_swap32(u_int32_t val) +{ + return(((val << 24) | ((val << 8) & (0xFF0000)) | + ((val >> 8) & (0xFF00)) | (val >> 24))); +} + + +u_int64_t +tws_swap64(u_int64_t val) +{ + return((((u_int64_t)(tws_swap32(((u_int32_t *)(&(val)))[1]))) << 32) | + ((u_int32_t)(tws_swap32(((u_int32_t *)(&(val)))[0])))); +} + + +/* ----------- reg access ----------- */ + + +void +tws_write_reg(struct tws_softc *sc, int offset, + u_int32_t value, int size) +{ + bus_space_tag_t bus_tag = sc->bus_tag; + bus_space_handle_t bus_handle = sc->bus_handle; + + if (size == 4) + bus_space_write_4(bus_tag, bus_handle, offset, value); + else + if (size == 2) + bus_space_write_2(bus_tag, bus_handle, offset, + (u_int16_t)value); + else + bus_space_write_1(bus_tag, bus_handle, offset, (u_int8_t)value); +} + +u_int32_t +tws_read_reg(struct tws_softc *sc, int offset, int size) +{ + bus_space_tag_t bus_tag = sc->bus_tag; + bus_space_handle_t bus_handle = sc->bus_handle; + + if (size == 4) + return((u_int32_t)bus_space_read_4(bus_tag, bus_handle, offset)); + else if (size == 2) + return((u_int32_t)bus_space_read_2(bus_tag, bus_handle, offset)); + else + return((u_int32_t)bus_space_read_1(bus_tag, bus_handle, offset)); +} + +/* --------------------- Q service --------------------- */ + +/* + * intialize q pointers with null. + */ +void +tws_init_qs(struct tws_softc *sc) +{ + + mtx_lock(&sc->q_lock); + for(int i=0;i<TWS_MAX_QS;i++) { + sc->q_head[i] = NULL; + sc->q_tail[i] = NULL; + } + mtx_unlock(&sc->q_lock); + +} + +/* called with lock held */ +static void +tws_insert2_empty_q(struct tws_softc *sc, struct tws_request *req, + u_int8_t q_type ) +{ + + mtx_assert(&sc->q_lock, MA_OWNED); + req->next = req->prev = NULL; + sc->q_head[q_type] = sc->q_tail[q_type] = req; + +} + +/* called with lock held */ +void +tws_q_insert_head(struct tws_softc *sc, struct tws_request *req, + u_int8_t q_type ) +{ + + mtx_assert(&sc->q_lock, MA_OWNED); + if ( sc->q_head[q_type] == NULL ) { + tws_insert2_empty_q(sc, req, q_type); + } else { + req->next = sc->q_head[q_type]; + req->prev = NULL; + sc->q_head[q_type]->prev = req; + sc->q_head[q_type] = req; + } + +} + +/* called with lock held */ +void +tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req, + u_int8_t q_type ) +{ + + mtx_assert(&sc->q_lock, MA_OWNED); + if ( sc->q_tail[q_type] == NULL ) { + tws_insert2_empty_q(sc, req, q_type); + } else { + req->prev = sc->q_tail[q_type]; + req->next = NULL; + sc->q_tail[q_type]->next = req; + sc->q_tail[q_type] = req; + } + +} + +/* called with lock held */ +struct tws_request * +tws_q_remove_head(struct tws_softc *sc, u_int8_t q_type ) +{ + + struct tws_request *r; + + mtx_assert(&sc->q_lock, MA_OWNED); + r = sc->q_head[q_type]; + if ( !r ) + return(NULL); + if ( r->next == NULL && r->prev == NULL ) { + /* last element */ + sc->q_head[q_type] = sc->q_tail[q_type] = NULL; + } else { + sc->q_head[q_type] = r->next; + r->next->prev = NULL; + r->next = NULL; + r->prev = NULL; + } + return(r); +} + +/* called with lock held */ +struct tws_request * +tws_q_remove_tail(struct tws_softc *sc, u_int8_t q_type ) +{ + + struct tws_request *r; + + mtx_assert(&sc->q_lock, MA_OWNED); + r = sc->q_tail[q_type]; + if ( !r ) + return(NULL); + if ( r->next == NULL && r->prev == NULL ) { + /* last element */ + sc->q_head[q_type] = sc->q_tail[q_type] = NULL; + } else { + sc->q_tail[q_type] = r->prev; + r->prev->next = NULL; + r->next = NULL; + r->prev = NULL; + } + return(r); +} + +/* returns removed request if successful. return NULL otherwise */ +/* called with lock held */ +struct tws_request * +tws_q_remove_request(struct tws_softc *sc, struct tws_request *req, + u_int8_t q_type ) +{ + + struct tws_request *r; + + mtx_assert(&sc->q_lock, MA_OWNED); + if ( req == NULL ) { + TWS_TRACE_DEBUG(sc, "null req", 0, q_type); + return(NULL); + } + + if ( req == sc->q_head[q_type] ) + return(tws_q_remove_head(sc, q_type)); + if ( req == sc->q_tail[q_type] ) + return(tws_q_remove_tail(sc, q_type)); + + + /* The given node is not at head or tail. + * It's in the middle and there are more than + * 2 elements on the q. + */ + + if ( req->next == NULL || req->prev == NULL ) { + TWS_TRACE_DEBUG(sc, "invalid req", 0, q_type); + return(NULL); + } + +/* debug only */ + r = sc->q_head[q_type]; + while ( r ) { + if ( req == r ) + break; + r = r->next; + } + + if ( !r ) { + TWS_TRACE_DEBUG(sc, "req not in q", 0, req->request_id); + return(NULL); + } +/* debug end */ + + req->prev->next = r->next; + req->next->prev = r->prev; + req->next = NULL; + req->prev = NULL; + return(req); +} + +struct tws_sense * +tws_find_sense_from_mfa(struct tws_softc *sc, u_int64_t mfa) +{ + struct tws_sense *s; + int i; + TWS_TRACE_DEBUG(sc, "entry",sc,mfa); + + i = (mfa - sc->dma_mem_phys) / sizeof(struct tws_command_packet); + if ( i>= 0 && i<tws_queue_depth) { + s = &sc->sense_bufs[i]; + if ( mfa == s->hdr_pkt_phy ) + return(s); + } + + TWS_TRACE_DEBUG(sc, "return null",0,mfa); + return(NULL); + +} + +/* --------------------- Q service end --------------------- */ +/* --------------------- misc service start --------------------- */ + + +void +tws_print_stats(void *arg) +{ + + struct tws_softc *sc = (struct tws_softc *)arg; + + TWS_TRACE(sc, "reqs(in, out)", sc->stats.reqs_in, sc->stats.reqs_out); + TWS_TRACE(sc, "reqs(err, intrs)", sc->stats.reqs_errored + , sc->stats.num_intrs); + TWS_TRACE(sc, "reqs(ioctls, scsi)", sc->stats.ioctls + , sc->stats.scsi_ios); + timeout(tws_print_stats, sc, 300*hz); + +} +/* --------------------- misc service end --------------------- */ |
