Commit | Line | Data |
---|---|---|
984263bc MD |
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 | * | |
f21d89e9 | 27 | * $FreeBSD: src/sys/dev/twe/twevar.h,v 1.19 2012/11/17 01:52:19 svnexp Exp $ |
984263bc MD |
28 | */ |
29 | ||
c2b68912 | 30 | #define TWE_DRIVER_VERSION_STRING "1.50.01.002" |
a062d8a7 | 31 | |
984263bc MD |
32 | #ifdef TWE_DEBUG |
33 | #define debug(level, fmt, args...) \ | |
34 | do { \ | |
e3869ec7 | 35 | if (level <= TWE_DEBUG) kprintf("%s: " fmt "\n", __func__ , ##args); \ |
984263bc MD |
36 | } while(0) |
37 | #define debug_called(level) \ | |
38 | do { \ | |
e3869ec7 | 39 | if (level <= TWE_DEBUG) kprintf("%s: called\n", __func__); \ |
984263bc MD |
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 | */ | |
49 | struct twe_drive | |
50 | { | |
51 | /* unit properties */ | |
52 | u_int32_t td_size; | |
53 | int td_cylinders; | |
54 | int td_heads; | |
55 | int td_sectors; | |
c2b68912 SW |
56 | int td_sys_unit; /* device unit number */ |
57 | int td_twe_unit; /* index into sc->twe_drive[] */ | |
984263bc MD |
58 | |
59 | /* unit state and type */ | |
60 | u_int8_t td_state; | |
61 | u_int8_t td_type; | |
62 | ||
63 | /* handle for attached driver */ | |
64 | device_t td_disk; | |
65 | }; | |
66 | ||
a062d8a7 HP |
67 | /* |
68 | * Disk device softc | |
69 | */ | |
c2b68912 | 70 | struct twed_softc |
a062d8a7 HP |
71 | { |
72 | device_t twed_dev; | |
b13267a5 | 73 | cdev_t twed_dev_t; |
a062d8a7 HP |
74 | struct twe_softc *twed_controller; /* parent device softc */ |
75 | struct twe_drive *twed_drive; /* drive data in parent softc */ | |
76 | struct disk twed_disk; /* generic disk handle */ | |
77 | struct devstat twed_stats; /* accounting */ | |
a062d8a7 HP |
78 | int twed_flags; |
79 | #define TWED_OPEN (1<<0) /* drive is open (can't shut down) */ | |
80 | }; | |
81 | ||
984263bc MD |
82 | /* |
83 | * Per-command control structure. | |
84 | * | |
85 | * Note that due to alignment constraints on the tc_command field, this *must* be 64-byte aligned. | |
86 | * We achieve this by placing the command at the beginning of the structure, and using malloc() | |
87 | * to allocate each structure. | |
88 | */ | |
89 | struct twe_request | |
90 | { | |
c2b68912 | 91 | int tr_tag; |
984263bc MD |
92 | /* command payload */ |
93 | void *tr_data; /* data buffer */ | |
94 | void *tr_realdata; /* copy of real data buffer pointer for alignment fixup */ | |
95 | size_t tr_length; | |
96 | ||
97 | TAILQ_ENTRY(twe_request) tr_link; /* list linkage */ | |
98 | struct twe_softc *tr_sc; /* controller that owns us */ | |
99 | int tr_status; /* command status */ | |
100 | #define TWE_CMD_SETUP 0 /* being assembled */ | |
101 | #define TWE_CMD_BUSY 1 /* submitted to controller */ | |
102 | #define TWE_CMD_COMPLETE 2 /* completed by controller (maybe with error) */ | |
a062d8a7 | 103 | #define TWE_CMD_ERROR 3 /* encountered error, even before submission to controller */ |
984263bc MD |
104 | int tr_flags; |
105 | #define TWE_CMD_DATAIN (1<<0) | |
106 | #define TWE_CMD_DATAOUT (1<<1) | |
107 | #define TWE_CMD_ALIGNBUF (1<<2) /* data in bio is misaligned, have to copy to/from private buffer */ | |
108 | #define TWE_CMD_SLEEPER (1<<3) /* owner is sleeping on this command */ | |
c2b68912 SW |
109 | #define TWE_CMD_IMMEDIATE (1<<4) /* immediate request */ |
110 | #define TWE_CMD_MAPPED (1<<5) | |
111 | #define TWE_CMD_IN_PROGRESS (1<<6) /* bus_dmamap_load returned EINPROGRESS */ | |
984263bc MD |
112 | void (* tr_complete)(struct twe_request *tr); /* completion handler */ |
113 | void *tr_private; /* submitter-private data or wait channel */ | |
114 | ||
115 | TWE_PLATFORM_REQUEST /* platform-specific request elements */ | |
116 | }; | |
117 | ||
c2b68912 SW |
118 | #define TWE_FIND_COMMAND(tr) \ |
119 | (TWE_Command *)((u_int8_t *)(tr)->tr_sc->twe_cmd + \ | |
120 | ((tr)->tr_tag * sizeof(TWE_Command))) | |
121 | #define TWE_FIND_COMMANDPHYS(tr) ((tr)->tr_sc->twe_cmdphys + \ | |
122 | ((tr)->tr_tag * sizeof(TWE_Command))) | |
123 | ||
984263bc MD |
124 | /* |
125 | * Per-controller state. | |
126 | */ | |
127 | struct twe_softc | |
128 | { | |
129 | /* controller queues and arrays */ | |
130 | TAILQ_HEAD(, twe_request) twe_free; /* command structures available for reuse */ | |
f21d89e9 | 131 | struct bio_queue_head twe_bioq; /* outstanding I/O operations */ |
984263bc MD |
132 | TAILQ_HEAD(, twe_request) twe_ready; /* requests ready for the controller */ |
133 | TAILQ_HEAD(, twe_request) twe_busy; /* requests busy in the controller */ | |
134 | TAILQ_HEAD(, twe_request) twe_complete; /* active commands (busy or waiting for completion) */ | |
135 | struct twe_request *twe_lookup[TWE_Q_LENGTH]; /* commands indexed by request ID */ | |
136 | struct twe_drive twe_drive[TWE_MAX_UNITS]; /* attached drives */ | |
137 | ||
138 | /* asynchronous event handling */ | |
139 | u_int16_t twe_aen_queue[TWE_Q_LENGTH]; /* AENs queued for userland tool(s) */ | |
140 | int twe_aen_head, twe_aen_tail; /* ringbuffer pointers for AEN queue */ | |
141 | int twe_wait_aen; /* wait-for-aen notification */ | |
f21d89e9 | 142 | char twe_aen_buf[80]; /* AEN format buffer */ |
984263bc MD |
143 | |
144 | /* controller status */ | |
145 | int twe_state; | |
146 | #define TWE_STATE_INTEN (1<<0) /* interrupts have been enabled */ | |
147 | #define TWE_STATE_SHUTDOWN (1<<1) /* controller is shut down */ | |
148 | #define TWE_STATE_OPEN (1<<2) /* control device is open */ | |
149 | #define TWE_STATE_SUSPEND (1<<3) /* controller is suspended */ | |
a062d8a7 HP |
150 | #define TWE_STATE_FRZN (1<<4) /* got EINPROGRESS */ |
151 | #define TWE_STATE_CTLR_BUSY (1<<5) /* controller cmd queue full */ | |
f21d89e9 | 152 | #define TWE_STATE_DETACHING (1<<6) /* controller is being shut down */ |
984263bc MD |
153 | int twe_host_id; |
154 | struct twe_qstat twe_qstat[TWEQ_COUNT]; /* queue statistics */ | |
155 | ||
156 | TWE_PLATFORM_SOFTC /* platform-specific softc elements */ | |
157 | }; | |
158 | ||
159 | /* | |
160 | * Interface betwen driver core and platform-dependant code. | |
161 | */ | |
162 | extern int twe_setup(struct twe_softc *sc); /* do early driver/controller setup */ | |
163 | extern void twe_init(struct twe_softc *sc); /* init controller */ | |
164 | extern void twe_deinit(struct twe_softc *sc); /* stop controller */ | |
165 | extern void twe_intr(struct twe_softc *sc); /* hardware interrupt signalled */ | |
166 | extern void twe_startio(struct twe_softc *sc); | |
a062d8a7 | 167 | extern int twe_start(struct twe_request *tr); |
984263bc | 168 | extern int twe_dump_blocks(struct twe_softc *sc, int unit, /* crashdump block write */ |
e0fc5693 | 169 | u_int64_t lba, void *data, int nblks); |
c2b68912 | 170 | extern int twe_ioctl(struct twe_softc *sc, u_long cmd, |
984263bc MD |
171 | void *addr); /* handle user request */ |
172 | extern void twe_describe_controller(struct twe_softc *sc); /* print controller info */ | |
173 | extern void twe_print_controller(struct twe_softc *sc); | |
174 | extern void twe_enable_interrupts(struct twe_softc *sc); /* enable controller interrupts */ | |
175 | extern void twe_disable_interrupts(struct twe_softc *sc); /* disable controller interrupts */ | |
176 | ||
a062d8a7 HP |
177 | extern int twe_attach_drive(struct twe_softc *sc, |
178 | struct twe_drive *dr); /* attach drive when found in twe_init */ | |
179 | extern int twe_detach_drive(struct twe_softc *sc, | |
0a62b1be | 180 | int unit); /* detach drive */ |
984263bc MD |
181 | extern void twe_clear_pci_parity_error(struct twe_softc *sc); |
182 | extern void twe_clear_pci_abort(struct twe_softc *sc); | |
f21d89e9 | 183 | extern void twed_intr(struct bio *bp); /* return bio from core */ |
c2b68912 SW |
184 | extern struct twe_request *twe_allocate_request(struct twe_softc *sc, int tag); /* allocate request structure */ |
185 | extern void twe_free_request(struct twe_request *tr); /* free request structure */ | |
a062d8a7 | 186 | extern int twe_map_request(struct twe_request *tr); /* make request visible to controller, do s/g */ |
984263bc MD |
187 | extern void twe_unmap_request(struct twe_request *tr); /* cleanup after transfer, unmap */ |
188 | ||
189 | /******************************************************************************** | |
190 | * Queue primitives | |
191 | */ | |
192 | #define TWEQ_ADD(sc, qname) \ | |
193 | do { \ | |
194 | struct twe_qstat *qs = &(sc)->twe_qstat[qname]; \ | |
195 | \ | |
196 | qs->q_length++; \ | |
197 | if (qs->q_length > qs->q_max) \ | |
198 | qs->q_max = qs->q_length; \ | |
199 | } while(0) | |
200 | ||
a062d8a7 HP |
201 | #define TWEQ_REMOVE(sc, qname) \ |
202 | do { \ | |
203 | struct twe_qstat *qs = &(sc)->twe_qstat[qname]; \ | |
204 | \ | |
205 | qs->q_length--; \ | |
206 | if (qs->q_length < qs->q_min) \ | |
207 | qs->q_min = qs->q_length; \ | |
208 | } while(0) | |
209 | ||
c2b68912 SW |
210 | #define TWEQ_INIT(sc, qname) \ |
211 | do { \ | |
212 | sc->twe_qstat[qname].q_length = 0; \ | |
213 | sc->twe_qstat[qname].q_max = 0; \ | |
214 | sc->twe_qstat[qname].q_min = 0xFFFFFFFF; \ | |
984263bc MD |
215 | } while(0) |
216 | ||
217 | ||
218 | #define TWEQ_REQUEST_QUEUE(name, index) \ | |
219 | static __inline void \ | |
220 | twe_initq_ ## name (struct twe_softc *sc) \ | |
221 | { \ | |
222 | TAILQ_INIT(&sc->twe_ ## name); \ | |
223 | TWEQ_INIT(sc, index); \ | |
224 | } \ | |
225 | static __inline void \ | |
226 | twe_enqueue_ ## name (struct twe_request *tr) \ | |
227 | { \ | |
984263bc MD |
228 | TAILQ_INSERT_TAIL(&tr->tr_sc->twe_ ## name, tr, tr_link); \ |
229 | TWEQ_ADD(tr->tr_sc, index); \ | |
984263bc MD |
230 | } \ |
231 | static __inline void \ | |
232 | twe_requeue_ ## name (struct twe_request *tr) \ | |
233 | { \ | |
984263bc MD |
234 | TAILQ_INSERT_HEAD(&tr->tr_sc->twe_ ## name, tr, tr_link); \ |
235 | TWEQ_ADD(tr->tr_sc, index); \ | |
984263bc MD |
236 | } \ |
237 | static __inline struct twe_request * \ | |
238 | twe_dequeue_ ## name (struct twe_softc *sc) \ | |
239 | { \ | |
240 | struct twe_request *tr; \ | |
984263bc | 241 | \ |
984263bc MD |
242 | if ((tr = TAILQ_FIRST(&sc->twe_ ## name)) != NULL) { \ |
243 | TAILQ_REMOVE(&sc->twe_ ## name, tr, tr_link); \ | |
244 | TWEQ_REMOVE(sc, index); \ | |
245 | } \ | |
984263bc MD |
246 | return(tr); \ |
247 | } \ | |
248 | static __inline void \ | |
249 | twe_remove_ ## name (struct twe_request *tr) \ | |
250 | { \ | |
984263bc MD |
251 | TAILQ_REMOVE(&tr->tr_sc->twe_ ## name, tr, tr_link); \ |
252 | TWEQ_REMOVE(tr->tr_sc, index); \ | |
984263bc MD |
253 | } |
254 | ||
255 | TWEQ_REQUEST_QUEUE(free, TWEQ_FREE) | |
256 | TWEQ_REQUEST_QUEUE(ready, TWEQ_READY) | |
257 | TWEQ_REQUEST_QUEUE(busy, TWEQ_BUSY) | |
258 | TWEQ_REQUEST_QUEUE(complete, TWEQ_COMPLETE) | |
259 | ||
984263bc MD |
260 | /* |
261 | * outstanding bio queue | |
262 | */ | |
263 | static __inline void | |
264 | twe_initq_bio(struct twe_softc *sc) | |
265 | { | |
81b5c339 | 266 | bioq_init(&sc->twe_bioq); |
984263bc MD |
267 | TWEQ_INIT(sc, TWEQ_BIO); |
268 | } | |
269 | ||
270 | static __inline void | |
81b5c339 | 271 | twe_enqueue_bio(struct twe_softc *sc, struct bio *bio) |
984263bc | 272 | { |
ec1b64f8 MD |
273 | bioqdisksort(&sc->twe_bioq, bio); |
274 | /* bioq_insert_tail(&sc->twe_bioq, bio); */ | |
984263bc | 275 | TWEQ_ADD(sc, TWEQ_BIO); |
984263bc MD |
276 | } |
277 | ||
81b5c339 MD |
278 | static __inline |
279 | struct bio * | |
984263bc MD |
280 | twe_dequeue_bio(struct twe_softc *sc) |
281 | { | |
81b5c339 | 282 | struct bio *bio; |
984263bc | 283 | |
81b5c339 MD |
284 | if ((bio = bioq_first(&sc->twe_bioq)) != NULL) { |
285 | bioq_remove(&sc->twe_bioq, bio); | |
984263bc MD |
286 | TWEQ_REMOVE(sc, TWEQ_BIO); |
287 | } | |
81b5c339 | 288 | return(bio); |
984263bc | 289 | } |