1/*- 2 * Copyright (c) 2000 Michael Smith 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30#define TWE_DRIVER_VERSION_STRING "1.50.01.002" 31 32#ifdef TWE_DEBUG 33#define debug(level, fmt, args...) \ 34 do { \ 35 if (level <= TWE_DEBUG) printf("%s: " fmt "\n", __func__ , ##args); \ 36 } while(0) 37#define debug_called(level) \ 38 do { \ 39 if (level <= TWE_DEBUG) printf("%s: called\n", __func__); \ 40 } while(0) 41#else 42#define debug(level, fmt, args...) 43#define debug_called(level) 44#endif 45 46/* 47 * Structure describing a logical unit as attached to the controller 48 */ 49struct twe_drive 50{ 51 /* unit properties */ 52 u_int32_t td_size; 53 int td_cylinders; 54 int td_heads; 55 int td_sectors; 56 int td_sys_unit; /* device unit number */ 57 int td_twe_unit; /* index into sc->twe_drive[] */ 58 59 /* unit state and type */ 60 u_int8_t td_state; 61 u_int8_t td_type; 62 u_int8_t td_stripe; 63 64 /* handle for attached driver */ 65 device_t td_disk; 66}; 67 68/* 69 * Per-command control structure. 70 * 71 * Note that due to alignment constraints on the tc_command field, this *must* be 64-byte aligned. 72 * We achieve this by placing the command at the beginning of the structure, and using malloc() 73 * to allocate each structure. 74 */ 75struct twe_request 76{ 77 int tr_tag; 78 /* command payload */ 79 void *tr_data; /* data buffer */ 80 void *tr_realdata; /* copy of real data buffer pointer for alignment fixup */ 81 size_t tr_length; 82 83 TAILQ_ENTRY(twe_request) tr_link; /* list linkage */ 84 struct twe_softc *tr_sc; /* controller that owns us */ 85 int tr_status; /* command status */ 86#define TWE_CMD_SETUP 0 /* being assembled */ 87#define TWE_CMD_BUSY 1 /* submitted to controller */ 88#define TWE_CMD_COMPLETE 2 /* completed by controller (maybe with error) */ 89#define TWE_CMD_ERROR 3 /* encountered error, even before submission to controller */ 90 int tr_flags; 91#define TWE_CMD_DATAIN (1<<0) 92#define TWE_CMD_DATAOUT (1<<1) 93#define TWE_CMD_ALIGNBUF (1<<2) /* data in bio is misaligned, have to copy to/from private buffer */ 94#define TWE_CMD_SLEEPER (1<<3) /* owner is sleeping on this command */ 95#define TWE_CMD_IMMEDIATE (1<<4) /* immediate request */ 96#define TWE_CMD_MAPPED (1<<5) 97#define TWE_CMD_IN_PROGRESS (1<<6) /* bus_dmamap_load returned EINPROGRESS */ 98 void (* tr_complete)(struct twe_request *tr); /* completion handler */ 99 void *tr_private; /* submitter-private data or wait channel */ 100 101 TWE_PLATFORM_REQUEST /* platform-specific request elements */ 102}; 103 104#define TWE_FIND_COMMAND(tr) \ 105 (TWE_Command *)((u_int8_t *)(tr)->tr_sc->twe_cmd + \ 106 ((tr)->tr_tag * sizeof(TWE_Command))) 107#define TWE_FIND_COMMANDPHYS(tr) ((tr)->tr_sc->twe_cmdphys + \ 108 ((tr)->tr_tag * sizeof(TWE_Command))) 109 110/* 111 * Per-controller state. 112 */ 113struct twe_softc 114{ 115 /* controller queues and arrays */ 116 TAILQ_HEAD(, twe_request) twe_free; /* command structures available for reuse */ 117 struct bio_queue_head twe_bioq; /* outstanding I/O operations */ 118 TAILQ_HEAD(, twe_request) twe_ready; /* requests ready for the controller */ 119 TAILQ_HEAD(, twe_request) twe_busy; /* requests busy in the controller */ 120 TAILQ_HEAD(, twe_request) twe_complete; /* active commands (busy or waiting for completion) */ 121 struct twe_request *twe_lookup[TWE_Q_LENGTH]; /* commands indexed by request ID */ 122 struct twe_drive twe_drive[TWE_MAX_UNITS]; /* attached drives */ 123 124 /* asynchronous event handling */ 125 u_int16_t twe_aen_queue[TWE_Q_LENGTH]; /* AENs queued for userland tool(s) */ 126 int twe_aen_head, twe_aen_tail; /* ringbuffer pointers for AEN queue */ 127 int twe_wait_aen; /* wait-for-aen notification */ 128 char twe_aen_buf[80]; /* AEN format buffer */ 129 130 /* controller status */ 131 int twe_state; 132#define TWE_STATE_INTEN (1<<0) /* interrupts have been enabled */ 133#define TWE_STATE_SHUTDOWN (1<<1) /* controller is shut down */ 134#define TWE_STATE_OPEN (1<<2) /* control device is open */ 135#define TWE_STATE_SUSPEND (1<<3) /* controller is suspended */ 136#define TWE_STATE_FRZN (1<<4) /* got EINPROGRESS */ 137#define TWE_STATE_CTLR_BUSY (1<<5) /* controller cmd queue full */ 138#define TWE_STATE_DETACHING (1<<6) /* controller is being shut down */ 139 int twe_host_id; 140 struct twe_qstat twe_qstat[TWEQ_COUNT]; /* queue statistics */ 141 142 TWE_PLATFORM_SOFTC /* platform-specific softc elements */ 143}; 144 145/* 146 * Interface betwen driver core and platform-dependant code. 147 */ 148extern int twe_setup(struct twe_softc *sc); /* do early driver/controller setup */ 149extern void twe_init(struct twe_softc *sc); /* init controller */ 150extern void twe_deinit(struct twe_softc *sc); /* stop controller */ 151extern void twe_intr(struct twe_softc *sc); /* hardware interrupt signalled */ 152extern void twe_startio(struct twe_softc *sc); 153extern int twe_start(struct twe_request *tr); 154extern int twe_dump_blocks(struct twe_softc *sc, int unit, /* crashdump block write */ 155 u_int32_t lba, void *data, int nblks); 156extern int twe_ioctl(struct twe_softc *sc, u_long cmd, 157 void *addr); /* handle user request */ 158extern void twe_describe_controller(struct twe_softc *sc); /* print controller info */ 159extern void twe_print_controller(struct twe_softc *sc); 160extern void twe_enable_interrupts(struct twe_softc *sc); /* enable controller interrupts */ 161extern void twe_disable_interrupts(struct twe_softc *sc); /* disable controller interrupts */ 162 163extern int twe_attach_drive(struct twe_softc *sc, 164 struct twe_drive *dr); /* attach drive when found in twe_init */ 165extern int twe_detach_drive(struct twe_softc *sc, 166 int unit); /* detach drive */ 167extern void twe_clear_pci_parity_error(struct twe_softc *sc); 168extern void twe_clear_pci_abort(struct twe_softc *sc); 169extern void twed_intr(struct bio *bp); /* return bio from core */ 170extern struct twe_request *twe_allocate_request(struct twe_softc *sc, int tag); /* allocate request structure */ 171extern void twe_free_request(struct twe_request *tr); /* free request structure */ 172extern int twe_map_request(struct twe_request *tr); /* make request visible to controller, do s/g */ 173extern void twe_unmap_request(struct twe_request *tr); /* cleanup after transfer, unmap */ 174 175/******************************************************************************** 176 * Queue primitives 177 */ 178#define TWEQ_ADD(sc, qname) \ 179 do { \ 180 struct twe_qstat *qs = &(sc)->twe_qstat[qname]; \ 181 \ 182 qs->q_length++; \ 183 if (qs->q_length > qs->q_max) \ 184 qs->q_max = qs->q_length; \ 185 } while(0) 186 187#define TWEQ_REMOVE(sc, qname) \ 188 do { \ 189 struct twe_qstat *qs = &(sc)->twe_qstat[qname]; \ 190 \ 191 qs->q_length--; \ 192 if (qs->q_length < qs->q_min) \ 193 qs->q_min = qs->q_length; \ 194 } while(0); 195 196#define TWEQ_INIT(sc, qname) \ 197 do { \ 198 sc->twe_qstat[qname].q_length = 0; \ 199 sc->twe_qstat[qname].q_max = 0; \ 200 sc->twe_qstat[qname].q_min = 0xFFFFFFFF; \ 201 } while(0) 202 203 204#define TWEQ_REQUEST_QUEUE(name, index) \ 205static __inline void \ 206twe_initq_ ## name (struct twe_softc *sc) \ 207{ \ 208 TAILQ_INIT(&sc->twe_ ## name); \ 209 TWEQ_INIT(sc, index); \ 210} \ 211static __inline void \ 212twe_enqueue_ ## name (struct twe_request *tr) \ 213{ \ 214 TAILQ_INSERT_TAIL(&tr->tr_sc->twe_ ## name, tr, tr_link); \ 215 TWEQ_ADD(tr->tr_sc, index); \ 216} \ 217static __inline void \ 218twe_requeue_ ## name (struct twe_request *tr) \ 219{ \ 220 TAILQ_INSERT_HEAD(&tr->tr_sc->twe_ ## name, tr, tr_link); \ 221 TWEQ_ADD(tr->tr_sc, index); \ 222} \ 223static __inline struct twe_request * \ 224twe_dequeue_ ## name (struct twe_softc *sc) \ 225{ \ 226 struct twe_request *tr; \ 227 \ 228 if ((tr = TAILQ_FIRST(&sc->twe_ ## name)) != NULL) { \ 229 TAILQ_REMOVE(&sc->twe_ ## name, tr, tr_link); \ 230 TWEQ_REMOVE(sc, index); \ 231 } \ 232 return(tr); \ 233} \ 234static __inline void \ 235twe_remove_ ## name (struct twe_request *tr) \ 236{ \ 237 TAILQ_REMOVE(&tr->tr_sc->twe_ ## name, tr, tr_link); \ 238 TWEQ_REMOVE(tr->tr_sc, index); \ 239} 240 241TWEQ_REQUEST_QUEUE(free, TWEQ_FREE) 242TWEQ_REQUEST_QUEUE(ready, TWEQ_READY) 243TWEQ_REQUEST_QUEUE(busy, TWEQ_BUSY) 244TWEQ_REQUEST_QUEUE(complete, TWEQ_COMPLETE) 245 246/* 247 * outstanding bio queue 248 */ 249static __inline void 250twe_initq_bio(struct twe_softc *sc) 251{ 252 bioq_init(&sc->twe_bioq); 253 TWEQ_INIT(sc, TWEQ_BIO); 254} 255 256static __inline void 257twe_enqueue_bio(struct twe_softc *sc, struct bio *bp) 258{ 259 bioq_insert_tail(&sc->twe_bioq, bp); 260 TWEQ_ADD(sc, TWEQ_BIO); 261} 262 263static __inline struct bio * 264twe_dequeue_bio(struct twe_softc *sc) 265{ 266 struct bio *bp; 267 268 if ((bp = bioq_first(&sc->twe_bioq)) != NULL) { 269 bioq_remove(&sc->twe_bioq, bp); 270 TWEQ_REMOVE(sc, TWEQ_BIO); 271 } 272 return(bp); 273} 274