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: src/sys/dev/twe/twevar.h,v 1.1.2.4 2002/03/07 09:57:02 msmith Exp $ 28 */ 29 30 #ifdef TWE_DEBUG 31 #define debug(level, fmt, args...) \ 32 do { \ 33 if (level <= TWE_DEBUG) printf("%s: " fmt "\n", __func__ , ##args); \ 34 } while(0) 35 #define debug_called(level) \ 36 do { \ 37 if (level <= TWE_DEBUG) printf("%s: called\n", __func__); \ 38 } while(0) 39 #else 40 #define debug(level, fmt, args...) 41 #define debug_called(level) 42 #endif 43 44 /* 45 * Structure describing a logical unit as attached to the controller 46 */ 47 struct twe_drive 48 { 49 /* unit properties */ 50 u_int32_t td_size; 51 int td_cylinders; 52 int td_heads; 53 int td_sectors; 54 int td_unit; 55 56 /* unit state and type */ 57 u_int8_t td_state; 58 u_int8_t td_type; 59 60 /* handle for attached driver */ 61 device_t td_disk; 62 }; 63 64 /* 65 * Per-command control structure. 66 * 67 * Note that due to alignment constraints on the tc_command field, this *must* be 64-byte aligned. 68 * We achieve this by placing the command at the beginning of the structure, and using malloc() 69 * to allocate each structure. 70 */ 71 struct twe_request 72 { 73 /* controller command */ 74 TWE_Command tr_command; /* command as submitted to controller */ 75 76 /* command payload */ 77 void *tr_data; /* data buffer */ 78 void *tr_realdata; /* copy of real data buffer pointer for alignment fixup */ 79 size_t tr_length; 80 81 TAILQ_ENTRY(twe_request) tr_link; /* list linkage */ 82 struct twe_softc *tr_sc; /* controller that owns us */ 83 int tr_status; /* command status */ 84 #define TWE_CMD_SETUP 0 /* being assembled */ 85 #define TWE_CMD_BUSY 1 /* submitted to controller */ 86 #define TWE_CMD_COMPLETE 2 /* completed by controller (maybe with error) */ 87 int tr_flags; 88 #define TWE_CMD_DATAIN (1<<0) 89 #define TWE_CMD_DATAOUT (1<<1) 90 #define TWE_CMD_ALIGNBUF (1<<2) /* data in bio is misaligned, have to copy to/from private buffer */ 91 #define TWE_CMD_SLEEPER (1<<3) /* owner is sleeping on this command */ 92 void (* tr_complete)(struct twe_request *tr); /* completion handler */ 93 void *tr_private; /* submitter-private data or wait channel */ 94 95 TWE_PLATFORM_REQUEST /* platform-specific request elements */ 96 }; 97 98 /* 99 * Per-controller state. 100 */ 101 struct twe_softc 102 { 103 /* controller queues and arrays */ 104 TAILQ_HEAD(, twe_request) twe_free; /* command structures available for reuse */ 105 twe_bioq twe_bioq; /* outstanding I/O operations */ 106 TAILQ_HEAD(, twe_request) twe_ready; /* requests ready for the controller */ 107 TAILQ_HEAD(, twe_request) twe_busy; /* requests busy in the controller */ 108 TAILQ_HEAD(, twe_request) twe_complete; /* active commands (busy or waiting for completion) */ 109 struct twe_request *twe_lookup[TWE_Q_LENGTH]; /* commands indexed by request ID */ 110 struct twe_drive twe_drive[TWE_MAX_UNITS]; /* attached drives */ 111 112 /* asynchronous event handling */ 113 u_int16_t twe_aen_queue[TWE_Q_LENGTH]; /* AENs queued for userland tool(s) */ 114 int twe_aen_head, twe_aen_tail; /* ringbuffer pointers for AEN queue */ 115 int twe_wait_aen; /* wait-for-aen notification */ 116 117 /* controller status */ 118 int twe_state; 119 #define TWE_STATE_INTEN (1<<0) /* interrupts have been enabled */ 120 #define TWE_STATE_SHUTDOWN (1<<1) /* controller is shut down */ 121 #define TWE_STATE_OPEN (1<<2) /* control device is open */ 122 #define TWE_STATE_SUSPEND (1<<3) /* controller is suspended */ 123 int twe_host_id; 124 struct twe_qstat twe_qstat[TWEQ_COUNT]; /* queue statistics */ 125 126 TWE_PLATFORM_SOFTC /* platform-specific softc elements */ 127 }; 128 129 /* 130 * Interface betwen driver core and platform-dependant code. 131 */ 132 extern int twe_setup(struct twe_softc *sc); /* do early driver/controller setup */ 133 extern void twe_init(struct twe_softc *sc); /* init controller */ 134 extern void twe_deinit(struct twe_softc *sc); /* stop controller */ 135 extern void twe_intr(struct twe_softc *sc); /* hardware interrupt signalled */ 136 extern void twe_startio(struct twe_softc *sc); 137 extern int twe_dump_blocks(struct twe_softc *sc, int unit, /* crashdump block write */ 138 u_int32_t lba, void *data, int nblks); 139 extern int twe_ioctl(struct twe_softc *sc, int cmd, 140 void *addr); /* handle user request */ 141 extern void twe_describe_controller(struct twe_softc *sc); /* print controller info */ 142 extern void twe_print_controller(struct twe_softc *sc); 143 extern void twe_enable_interrupts(struct twe_softc *sc); /* enable controller interrupts */ 144 extern void twe_disable_interrupts(struct twe_softc *sc); /* disable controller interrupts */ 145 146 extern void twe_attach_drive(struct twe_softc *sc, 147 struct twe_drive *dr); /* attach drive when found in twe_init */ 148 extern void twe_clear_pci_parity_error(struct twe_softc *sc); 149 extern void twe_clear_pci_abort(struct twe_softc *sc); 150 extern void twed_intr(twe_bio *bp); /* return bio from core */ 151 extern struct twe_request *twe_allocate_request(struct twe_softc *sc); /* allocate request structure */ 152 extern void twe_free_request(struct twe_request *tr); /* free request structure */ 153 extern void twe_map_request(struct twe_request *tr); /* make request visible to controller, do s/g */ 154 extern void twe_unmap_request(struct twe_request *tr); /* cleanup after transfer, unmap */ 155 156 /******************************************************************************** 157 * Queue primitives 158 */ 159 #define TWEQ_ADD(sc, qname) \ 160 do { \ 161 struct twe_qstat *qs = &(sc)->twe_qstat[qname]; \ 162 \ 163 qs->q_length++; \ 164 if (qs->q_length > qs->q_max) \ 165 qs->q_max = qs->q_length; \ 166 } while(0) 167 168 #define TWEQ_REMOVE(sc, qname) (sc)->twe_qstat[qname].q_length-- 169 #define TWEQ_INIT(sc, qname) \ 170 do { \ 171 sc->twe_qstat[qname].q_length = 0; \ 172 sc->twe_qstat[qname].q_max = 0; \ 173 } while(0) 174 175 176 #define TWEQ_REQUEST_QUEUE(name, index) \ 177 static __inline void \ 178 twe_initq_ ## name (struct twe_softc *sc) \ 179 { \ 180 TAILQ_INIT(&sc->twe_ ## name); \ 181 TWEQ_INIT(sc, index); \ 182 } \ 183 static __inline void \ 184 twe_enqueue_ ## name (struct twe_request *tr) \ 185 { \ 186 int s; \ 187 \ 188 s = splbio(); \ 189 TAILQ_INSERT_TAIL(&tr->tr_sc->twe_ ## name, tr, tr_link); \ 190 TWEQ_ADD(tr->tr_sc, index); \ 191 splx(s); \ 192 } \ 193 static __inline void \ 194 twe_requeue_ ## name (struct twe_request *tr) \ 195 { \ 196 int s; \ 197 \ 198 s = splbio(); \ 199 TAILQ_INSERT_HEAD(&tr->tr_sc->twe_ ## name, tr, tr_link); \ 200 TWEQ_ADD(tr->tr_sc, index); \ 201 splx(s); \ 202 } \ 203 static __inline struct twe_request * \ 204 twe_dequeue_ ## name (struct twe_softc *sc) \ 205 { \ 206 struct twe_request *tr; \ 207 int s; \ 208 \ 209 s = splbio(); \ 210 if ((tr = TAILQ_FIRST(&sc->twe_ ## name)) != NULL) { \ 211 TAILQ_REMOVE(&sc->twe_ ## name, tr, tr_link); \ 212 TWEQ_REMOVE(sc, index); \ 213 } \ 214 splx(s); \ 215 return(tr); \ 216 } \ 217 static __inline void \ 218 twe_remove_ ## name (struct twe_request *tr) \ 219 { \ 220 int s; \ 221 \ 222 s = splbio(); \ 223 TAILQ_REMOVE(&tr->tr_sc->twe_ ## name, tr, tr_link); \ 224 TWEQ_REMOVE(tr->tr_sc, index); \ 225 splx(s); \ 226 } 227 228 TWEQ_REQUEST_QUEUE(free, TWEQ_FREE) 229 TWEQ_REQUEST_QUEUE(ready, TWEQ_READY) 230 TWEQ_REQUEST_QUEUE(busy, TWEQ_BUSY) 231 TWEQ_REQUEST_QUEUE(complete, TWEQ_COMPLETE) 232 233 234 /* 235 * outstanding bio queue 236 */ 237 static __inline void 238 twe_initq_bio(struct twe_softc *sc) 239 { 240 TWE_BIO_QINIT(sc->twe_bioq); 241 TWEQ_INIT(sc, TWEQ_BIO); 242 } 243 244 static __inline void 245 twe_enqueue_bio(struct twe_softc *sc, twe_bio *bp) 246 { 247 int s; 248 249 s = splbio(); 250 TWE_BIO_QINSERT(sc->twe_bioq, bp); 251 TWEQ_ADD(sc, TWEQ_BIO); 252 splx(s); 253 } 254 255 static __inline twe_bio * 256 twe_dequeue_bio(struct twe_softc *sc) 257 { 258 int s; 259 twe_bio *bp; 260 261 s = splbio(); 262 if ((bp = TWE_BIO_QFIRST(sc->twe_bioq)) != NULL) { 263 TWE_BIO_QREMOVE(sc->twe_bioq, bp); 264 TWEQ_REMOVE(sc, TWEQ_BIO); 265 } 266 splx(s); 267 return(bp); 268 } 269