File: | dev/ic/twe.c |
Warning: | line 885, column 8 Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: twe.c,v 1.67 2022/04/16 19:19:59 naddy Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2000-2002 Michael Shalayeff. All rights reserved. |
5 | * |
6 | * The SCSI emulation layer is derived from gdt(4) driver, |
7 | * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. |
8 | * |
9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions |
11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 | * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, |
22 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
24 | * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
26 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
27 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
28 | * THE POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
30 | |
31 | /* #define TWE_DEBUG */ |
32 | |
33 | #include <sys/param.h> |
34 | #include <sys/systm.h> |
35 | #include <sys/buf.h> |
36 | #include <sys/device.h> |
37 | #include <sys/malloc.h> |
38 | #include <sys/kthread.h> |
39 | |
40 | #include <machine/bus.h> |
41 | |
42 | #include <scsi/scsi_all.h> |
43 | #include <scsi/scsi_disk.h> |
44 | #include <scsi/scsiconf.h> |
45 | |
46 | #include <dev/ic/twereg.h> |
47 | #include <dev/ic/twevar.h> |
48 | |
49 | #ifdef TWE_DEBUG |
50 | #define TWE_DPRINTF(m,a) if (twe_debug & (m)) printf a |
51 | #define TWE_D_CMD 0x0001 |
52 | #define TWE_D_INTR 0x0002 |
53 | #define TWE_D_MISC 0x0004 |
54 | #define TWE_D_DMA 0x0008 |
55 | #define TWE_D_AEN 0x0010 |
56 | int twe_debug = 0; |
57 | #else |
58 | #define TWE_DPRINTF(m,a) /* m, a */ |
59 | #endif |
60 | |
61 | struct cfdriver twe_cd = { |
62 | NULL((void *)0), "twe", DV_DULL |
63 | }; |
64 | |
65 | void twe_scsi_cmd(struct scsi_xfer *); |
66 | |
67 | const struct scsi_adapter twe_switch = { |
68 | twe_scsi_cmd, NULL((void *)0), NULL((void *)0), NULL((void *)0), NULL((void *)0) |
69 | }; |
70 | |
71 | void *twe_get_ccb(void *); |
72 | void twe_put_ccb(void *, void *); |
73 | void twe_dispose(struct twe_softc *sc); |
74 | int twe_cmd(struct twe_ccb *ccb, int flags, int wait); |
75 | int twe_start(struct twe_ccb *ccb, int wait); |
76 | int twe_complete(struct twe_ccb *ccb); |
77 | int twe_done(struct twe_softc *sc, struct twe_ccb *ccb); |
78 | void twe_thread_create(void *v); |
79 | void twe_thread(void *v); |
80 | void twe_aen(void *, void *); |
81 | |
82 | void * |
83 | twe_get_ccb(void *xsc) |
84 | { |
85 | struct twe_softc *sc = xsc; |
86 | struct twe_ccb *ccb; |
87 | |
88 | mtx_enter(&sc->sc_ccb_mtx); |
89 | ccb = TAILQ_LAST(&sc->sc_free_ccb, twe_queue_head)(*(((struct twe_queue_head *)((&sc->sc_free_ccb)->tqh_last ))->tqh_last)); |
90 | if (ccb != NULL((void *)0)) |
91 | TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&sc->sc_free_ccb)->tqh_last = (ccb) ->ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb)-> ccb_link.tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)- 1); ((ccb)->ccb_link.tqe_next) = ((void *)-1); } while (0); |
92 | mtx_leave(&sc->sc_ccb_mtx); |
93 | |
94 | return (ccb); |
95 | } |
96 | |
97 | void |
98 | twe_put_ccb(void *xsc, void *xccb) |
99 | { |
100 | struct twe_softc *sc = xsc; |
101 | struct twe_ccb *ccb = xccb; |
102 | |
103 | ccb->ccb_state = TWE_CCB_FREE; |
104 | mtx_enter(&sc->sc_ccb_mtx); |
105 | TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (&sc->sc_free_ccb)->tqh_last; *(&sc ->sc_free_ccb)->tqh_last = (ccb); (&sc->sc_free_ccb )->tqh_last = &(ccb)->ccb_link.tqe_next; } while (0 ); |
106 | mtx_leave(&sc->sc_ccb_mtx); |
107 | } |
108 | |
109 | void |
110 | twe_dispose(struct twe_softc *sc) |
111 | { |
112 | register struct twe_ccb *ccb; |
113 | if (sc->sc_cmdmap != NULL((void *)0)) { |
114 | bus_dmamap_destroy(sc->dmat, sc->sc_cmdmap)(*(sc->dmat)->_dmamap_destroy)((sc->dmat), (sc->sc_cmdmap )); |
115 | /* traverse the ccbs and destroy the maps */ |
116 | for (ccb = &sc->sc_ccbs[TWE_MAXCMDS255 - 1]; ccb >= sc->sc_ccbs; ccb--) |
117 | if (ccb->ccb_dmamap) |
118 | bus_dmamap_destroy(sc->dmat, ccb->ccb_dmamap)(*(sc->dmat)->_dmamap_destroy)((sc->dmat), (ccb-> ccb_dmamap)); |
119 | } |
120 | bus_dmamem_unmap(sc->dmat, sc->sc_cmds,(*(sc->dmat)->_dmamem_unmap)((sc->dmat), (sc->sc_cmds ), (sizeof(struct twe_cmd) * 255)) |
121 | sizeof(struct twe_cmd) * TWE_MAXCMDS)(*(sc->dmat)->_dmamem_unmap)((sc->dmat), (sc->sc_cmds ), (sizeof(struct twe_cmd) * 255)); |
122 | bus_dmamem_free(sc->dmat, sc->sc_cmdseg, 1)(*(sc->dmat)->_dmamem_free)((sc->dmat), (sc->sc_cmdseg ), (1)); |
123 | } |
124 | |
125 | int |
126 | twe_attach(struct twe_softc *sc) |
127 | { |
128 | struct scsibus_attach_args saa; |
129 | /* this includes a buffer for drive config req, and a capacity req */ |
130 | u_int8_t param_buf[2 * TWE_SECTOR_SIZE512 + TWE_ALIGN512 - 1]; |
131 | struct twe_param *pb = (void *) |
132 | (((u_long)param_buf + TWE_ALIGN512 - 1) & ~(TWE_ALIGN512 - 1)); |
133 | struct twe_param *cap = (void *)((u_int8_t *)pb + TWE_SECTOR_SIZE512); |
134 | struct twe_ccb *ccb; |
135 | struct twe_cmd *cmd; |
136 | u_int32_t status; |
137 | int error, i, retry, nunits, nseg; |
138 | const char *errstr; |
139 | twe_lock_t lock; |
140 | paddr_t pa; |
141 | |
142 | error = bus_dmamem_alloc(sc->dmat, sizeof(struct twe_cmd) * TWE_MAXCMDS,(*(sc->dmat)->_dmamem_alloc)((sc->dmat), (sizeof(struct twe_cmd) * 255), ((1 << 12)), (0), (sc->sc_cmdseg), (1), (&nseg), (0x0001)) |
143 | PAGE_SIZE, 0, sc->sc_cmdseg, 1, &nseg, BUS_DMA_NOWAIT)(*(sc->dmat)->_dmamem_alloc)((sc->dmat), (sizeof(struct twe_cmd) * 255), ((1 << 12)), (0), (sc->sc_cmdseg), (1), (&nseg), (0x0001)); |
144 | if (error) { |
145 | printf(": cannot allocate commands (%d)\n", error); |
146 | return (1); |
147 | } |
148 | |
149 | error = bus_dmamem_map(sc->dmat, sc->sc_cmdseg, nseg,(*(sc->dmat)->_dmamem_map)((sc->dmat), (sc->sc_cmdseg ), (nseg), (sizeof(struct twe_cmd) * 255), ((caddr_t *)&sc ->sc_cmds), (0x0001)) |
150 | sizeof(struct twe_cmd) * TWE_MAXCMDS,(*(sc->dmat)->_dmamem_map)((sc->dmat), (sc->sc_cmdseg ), (nseg), (sizeof(struct twe_cmd) * 255), ((caddr_t *)&sc ->sc_cmds), (0x0001)) |
151 | (caddr_t *)&sc->sc_cmds, BUS_DMA_NOWAIT)(*(sc->dmat)->_dmamem_map)((sc->dmat), (sc->sc_cmdseg ), (nseg), (sizeof(struct twe_cmd) * 255), ((caddr_t *)&sc ->sc_cmds), (0x0001)); |
152 | if (error) { |
153 | printf(": cannot map commands (%d)\n", error); |
154 | bus_dmamem_free(sc->dmat, sc->sc_cmdseg, 1)(*(sc->dmat)->_dmamem_free)((sc->dmat), (sc->sc_cmdseg ), (1)); |
155 | return (1); |
156 | } |
157 | |
158 | error = bus_dmamap_create(sc->dmat,(*(sc->dmat)->_dmamap_create)((sc->dmat), (sizeof(struct twe_cmd) * 255), (255), (sizeof(struct twe_cmd) * 255), (0), (0x0001 | 0x0002), (&sc->sc_cmdmap)) |
159 | sizeof(struct twe_cmd) * TWE_MAXCMDS, TWE_MAXCMDS,(*(sc->dmat)->_dmamap_create)((sc->dmat), (sizeof(struct twe_cmd) * 255), (255), (sizeof(struct twe_cmd) * 255), (0), (0x0001 | 0x0002), (&sc->sc_cmdmap)) |
160 | sizeof(struct twe_cmd) * TWE_MAXCMDS, 0,(*(sc->dmat)->_dmamap_create)((sc->dmat), (sizeof(struct twe_cmd) * 255), (255), (sizeof(struct twe_cmd) * 255), (0), (0x0001 | 0x0002), (&sc->sc_cmdmap)) |
161 | BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_cmdmap)(*(sc->dmat)->_dmamap_create)((sc->dmat), (sizeof(struct twe_cmd) * 255), (255), (sizeof(struct twe_cmd) * 255), (0), (0x0001 | 0x0002), (&sc->sc_cmdmap)); |
162 | if (error) { |
163 | printf(": cannot create ccb cmd dmamap (%d)\n", error); |
164 | twe_dispose(sc); |
165 | return (1); |
166 | } |
167 | error = bus_dmamap_load(sc->dmat, sc->sc_cmdmap, sc->sc_cmds,(*(sc->dmat)->_dmamap_load)((sc->dmat), (sc->sc_cmdmap ), (sc->sc_cmds), (sizeof(struct twe_cmd) * 255), (((void * )0)), (0x0001)) |
168 | sizeof(struct twe_cmd) * TWE_MAXCMDS, NULL, BUS_DMA_NOWAIT)(*(sc->dmat)->_dmamap_load)((sc->dmat), (sc->sc_cmdmap ), (sc->sc_cmds), (sizeof(struct twe_cmd) * 255), (((void * )0)), (0x0001)); |
169 | if (error) { |
170 | printf(": cannot load command dma map (%d)\n", error); |
171 | twe_dispose(sc); |
172 | return (1); |
173 | } |
174 | |
175 | TAILQ_INIT(&sc->sc_ccb2q)do { (&sc->sc_ccb2q)->tqh_first = ((void *)0); (& sc->sc_ccb2q)->tqh_last = &(&sc->sc_ccb2q)-> tqh_first; } while (0); |
176 | TAILQ_INIT(&sc->sc_ccbq)do { (&sc->sc_ccbq)->tqh_first = ((void *)0); (& sc->sc_ccbq)->tqh_last = &(&sc->sc_ccbq)-> tqh_first; } while (0); |
177 | TAILQ_INIT(&sc->sc_free_ccb)do { (&sc->sc_free_ccb)->tqh_first = ((void *)0); ( &sc->sc_free_ccb)->tqh_last = &(&sc->sc_free_ccb )->tqh_first; } while (0); |
178 | TAILQ_INIT(&sc->sc_done_ccb)do { (&sc->sc_done_ccb)->tqh_first = ((void *)0); ( &sc->sc_done_ccb)->tqh_last = &(&sc->sc_done_ccb )->tqh_first; } while (0); |
179 | mtx_init(&sc->sc_ccb_mtx, IPL_BIO)do { (void)(((void *)0)); (void)(0); __mtx_init((&sc-> sc_ccb_mtx), ((((0x3)) > 0x0 && ((0x3)) < 0x9) ? 0x9 : ((0x3)))); } while (0); |
180 | scsi_iopool_init(&sc->sc_iopool, sc, twe_get_ccb, twe_put_ccb); |
181 | |
182 | scsi_ioh_set(&sc->sc_aen, &sc->sc_iopool, twe_aen, sc); |
183 | |
184 | pa = sc->sc_cmdmap->dm_segs[0].ds_addr + |
185 | sizeof(struct twe_cmd) * (TWE_MAXCMDS255 - 1); |
186 | for (cmd = (struct twe_cmd *)sc->sc_cmds + TWE_MAXCMDS255 - 1; |
187 | cmd >= (struct twe_cmd *)sc->sc_cmds; cmd--, pa -= sizeof(*cmd)) { |
188 | |
189 | cmd->cmd_index = cmd - (struct twe_cmd *)sc->sc_cmds; |
190 | ccb = &sc->sc_ccbs[cmd->cmd_index]; |
191 | error = bus_dmamap_create(sc->dmat,(*(sc->dmat)->_dmamap_create)((sc->dmat), ((62 * (1 << 12))), (62), ((62 * (1 << 12))), (0), (0x0001 | 0x0002 ), (&ccb->ccb_dmamap)) |
192 | TWE_MAXFER, TWE_MAXOFFSETS, TWE_MAXFER, 0,(*(sc->dmat)->_dmamap_create)((sc->dmat), ((62 * (1 << 12))), (62), ((62 * (1 << 12))), (0), (0x0001 | 0x0002 ), (&ccb->ccb_dmamap)) |
193 | BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap)(*(sc->dmat)->_dmamap_create)((sc->dmat), ((62 * (1 << 12))), (62), ((62 * (1 << 12))), (0), (0x0001 | 0x0002 ), (&ccb->ccb_dmamap)); |
194 | if (error) { |
195 | printf(": cannot create ccb dmamap (%d)\n", error); |
196 | twe_dispose(sc); |
197 | return (1); |
198 | } |
199 | ccb->ccb_sc = sc; |
200 | ccb->ccb_cmd = cmd; |
201 | ccb->ccb_cmdpa = pa; |
202 | ccb->ccb_state = TWE_CCB_FREE; |
203 | TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (&sc->sc_free_ccb)->tqh_last; *(&sc ->sc_free_ccb)->tqh_last = (ccb); (&sc->sc_free_ccb )->tqh_last = &(ccb)->ccb_link.tqe_next; } while (0 ); |
204 | } |
205 | |
206 | for (errstr = NULL((void *)0), retry = 3; retry--; ) { |
207 | int veseen_srst; |
208 | u_int16_t aen; |
209 | |
210 | if (errstr) |
211 | TWE_DPRINTF(TWE_D_MISC, ("%s ", errstr)); |
212 | |
213 | for (i = 350000; i--; DELAY(100)(*delay_func)(100)) { |
214 | status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
215 | if (status & TWE_STAT_CPURDY0x00002000) |
216 | break; |
217 | } |
218 | |
219 | if (!(status & TWE_STAT_CPURDY0x00002000)) { |
220 | errstr = ": card CPU is not ready\n"; |
221 | continue; |
222 | } |
223 | |
224 | /* soft reset, disable ints */ |
225 | bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,((sc->iot)->write_4((sc->ioh), (0x00), (0x00000100 | 0x00080000 | 0x00040000 | 0x00000200 | 0x00020000 | 0x00010000 | 0x00000040))) |
226 | TWE_CTRL_SRST |((sc->iot)->write_4((sc->ioh), (0x00), (0x00000100 | 0x00080000 | 0x00040000 | 0x00000200 | 0x00020000 | 0x00010000 | 0x00000040))) |
227 | TWE_CTRL_CHOSTI | TWE_CTRL_CATTNI | TWE_CTRL_CERR |((sc->iot)->write_4((sc->ioh), (0x00), (0x00000100 | 0x00080000 | 0x00040000 | 0x00000200 | 0x00020000 | 0x00010000 | 0x00000040))) |
228 | TWE_CTRL_MCMDI | TWE_CTRL_MRDYI |((sc->iot)->write_4((sc->ioh), (0x00), (0x00000100 | 0x00080000 | 0x00040000 | 0x00000200 | 0x00020000 | 0x00010000 | 0x00000040))) |
229 | TWE_CTRL_MINT)((sc->iot)->write_4((sc->ioh), (0x00), (0x00000100 | 0x00080000 | 0x00040000 | 0x00000200 | 0x00020000 | 0x00010000 | 0x00000040))); |
230 | |
231 | for (i = 350000; i--; DELAY(100)(*delay_func)(100)) { |
232 | status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
233 | if (status & TWE_STAT_ATTNI0x00040000) |
234 | break; |
235 | } |
236 | |
237 | if (!(status & TWE_STAT_ATTNI0x00040000)) { |
238 | errstr = ": cannot get card's attention\n"; |
239 | continue; |
240 | } |
241 | |
242 | /* drain aen queue */ |
243 | for (veseen_srst = 0, aen = -1; aen != TWE_AEN_QEMPTY0x0000; ) { |
244 | |
245 | ccb = scsi_io_get(&sc->sc_iopool, 0); |
246 | if (ccb == NULL((void *)0)) { |
247 | errstr = ": out of ccbs\n"; |
248 | break; |
249 | } |
250 | |
251 | ccb->ccb_xs = NULL((void *)0); |
252 | ccb->ccb_data = pb; |
253 | ccb->ccb_length = TWE_SECTOR_SIZE512; |
254 | ccb->ccb_state = TWE_CCB_READY; |
255 | cmd = ccb->ccb_cmd; |
256 | cmd->cmd_unit_host = TWE_UNITHOST(0, 0)(((0) & 0xf) | ((0) << 4)); |
257 | cmd->cmd_op = TWE_CMD_GPARAM0x0252; |
258 | cmd->cmd_param_._cmd_param.count = 1; |
259 | |
260 | pb->table_id = TWE_PARAM_AEN0x401; |
261 | pb->param_id = 2; |
262 | pb->param_size = 2; |
263 | |
264 | error = twe_cmd(ccb, BUS_DMA_NOWAIT0x0001, 1); |
265 | scsi_io_put(&sc->sc_iopool, ccb); |
266 | if (error) { |
267 | errstr = ": error draining attention queue\n"; |
268 | break; |
269 | } |
270 | |
271 | aen = *(u_int16_t *)pb->data; |
272 | TWE_DPRINTF(TWE_D_AEN, ("aen=%x ", aen)); |
273 | if (aen == TWE_AEN_SRST0x0001) |
274 | veseen_srst++; |
275 | } |
276 | |
277 | if (!veseen_srst) { |
278 | errstr = ": we don't get it\n"; |
279 | continue; |
280 | } |
281 | |
282 | if (status & TWE_STAT_CPUERR0x00200000) { |
283 | errstr = ": card CPU error detected\n"; |
284 | continue; |
285 | } |
286 | |
287 | if (status & TWE_STAT_PCIPAR0x00800000) { |
288 | errstr = ": PCI parity error detected\n"; |
289 | continue; |
290 | } |
291 | |
292 | if (status & TWE_STAT_QUEUEE0x00400000 ) { |
293 | errstr = ": queuing error detected\n"; |
294 | continue; |
295 | } |
296 | |
297 | if (status & TWE_STAT_PCIABR0x00100000) { |
298 | errstr = ": PCI abort\n"; |
299 | continue; |
300 | } |
301 | |
302 | while (!(status & TWE_STAT_RQE0x00004000)) { |
303 | bus_space_read_4(sc->iot, sc->ioh, TWE_READYQUEUE)((sc->iot)->read_4((sc->ioh), (0x0c))); |
304 | status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
305 | } |
306 | |
307 | break; |
308 | } |
309 | |
310 | if (retry < 0) { |
311 | printf("%s", errstr); |
312 | twe_dispose(sc); |
313 | return 1; |
314 | } |
315 | |
316 | ccb = scsi_io_get(&sc->sc_iopool, 0); |
317 | if (ccb == NULL((void *)0)) { |
318 | printf(": out of ccbs\n"); |
319 | twe_dispose(sc); |
320 | return 1; |
321 | } |
322 | |
323 | ccb->ccb_xs = NULL((void *)0); |
324 | ccb->ccb_data = pb; |
325 | ccb->ccb_length = TWE_SECTOR_SIZE512; |
326 | ccb->ccb_state = TWE_CCB_READY; |
327 | cmd = ccb->ccb_cmd; |
328 | cmd->cmd_unit_host = TWE_UNITHOST(0, 0)(((0) & 0xf) | ((0) << 4)); |
329 | cmd->cmd_op = TWE_CMD_GPARAM0x0252; |
330 | cmd->cmd_param_._cmd_param.count = 1; |
331 | |
332 | pb->table_id = TWE_PARAM_UC0x003; |
333 | pb->param_id = TWE_PARAM_UC0x003; |
334 | pb->param_size = TWE_MAX_UNITS16; |
335 | |
336 | error = twe_cmd(ccb, BUS_DMA_NOWAIT0x0001, 1); |
337 | scsi_io_put(&sc->sc_iopool, ccb); |
338 | if (error) { |
339 | printf(": failed to fetch unit parameters\n"); |
340 | twe_dispose(sc); |
341 | return 1; |
342 | } |
343 | |
344 | /* we are assuming last read status was good */ |
345 | printf(": Escalade V%d.%d\n", TWE_MAJV(status)(((status) >> 28) & 0xf), TWE_MINV(status)(((status) >> 24) & 0xf)); |
346 | |
347 | for (nunits = i = 0; i < TWE_MAX_UNITS16; i++) { |
348 | if (pb->data[i] == 0) |
349 | continue; |
350 | |
351 | ccb = scsi_io_get(&sc->sc_iopool, 0); |
352 | if (ccb == NULL((void *)0)) { |
353 | printf(": out of ccbs\n"); |
354 | twe_dispose(sc); |
355 | return 1; |
356 | } |
357 | |
358 | ccb->ccb_xs = NULL((void *)0); |
359 | ccb->ccb_data = cap; |
360 | ccb->ccb_length = TWE_SECTOR_SIZE512; |
361 | ccb->ccb_state = TWE_CCB_READY; |
362 | cmd = ccb->ccb_cmd; |
363 | cmd->cmd_unit_host = TWE_UNITHOST(0, 0)(((0) & 0xf) | ((0) << 4)); |
364 | cmd->cmd_op = TWE_CMD_GPARAM0x0252; |
365 | cmd->cmd_param_._cmd_param.count = 1; |
366 | |
367 | cap->table_id = TWE_PARAM_UI0x300 + i; |
368 | cap->param_id = 4; |
369 | cap->param_size = 4; /* 4 bytes */ |
370 | |
371 | lock = TWE_LOCK(sc)splraise(0x3); |
372 | error = twe_cmd(ccb, BUS_DMA_NOWAIT0x0001, 1); |
373 | TWE_UNLOCK(sc, lock)spllower(lock); |
374 | scsi_io_put(&sc->sc_iopool, ccb); |
375 | if (error) { |
376 | printf("%s: error fetching capacity for unit %d\n", |
377 | sc->sc_dev.dv_xname, i); |
378 | continue; |
379 | } |
380 | |
381 | nunits++; |
382 | sc->sc_hdr[i].hd_present = 1; |
383 | sc->sc_hdr[i].hd_devtype = 0; |
384 | sc->sc_hdr[i].hd_size = letoh32(*(u_int32_t *)cap->data)((__uint32_t)(*(u_int32_t *)cap->data)); |
385 | TWE_DPRINTF(TWE_D_MISC, ("twed%d: size=%d\n", |
386 | i, sc->sc_hdr[i].hd_size)); |
387 | } |
388 | |
389 | if (!nunits) |
390 | nunits++; |
391 | |
392 | /* TODO: fetch & print cache params? */ |
393 | |
394 | saa.saa_adapter_softc = sc; |
395 | saa.saa_adapter = &twe_switch; |
396 | saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET0xffff; |
397 | saa.saa_adapter_buswidth = TWE_MAX_UNITS16; |
398 | saa.saa_luns = 8; |
399 | saa.saa_openings = TWE_MAXCMDS255 / nunits; |
400 | saa.saa_pool = &sc->sc_iopool; |
401 | saa.saa_quirks = saa.saa_flags = 0; |
402 | saa.saa_wwpn = saa.saa_wwnn = 0; |
403 | |
404 | config_found(&sc->sc_dev, &saa, scsiprint)config_found_sm((&sc->sc_dev), (&saa), (scsiprint) , ((void *)0)); |
405 | |
406 | kthread_create_deferred(twe_thread_create, sc); |
407 | |
408 | return (0); |
409 | } |
410 | |
411 | void |
412 | twe_thread_create(void *v) |
413 | { |
414 | struct twe_softc *sc = v; |
415 | |
416 | if (kthread_create(twe_thread, sc, &sc->sc_thread, |
417 | sc->sc_dev.dv_xname)) { |
418 | /* TODO disable twe */ |
419 | printf("%s: failed to create kernel thread, disabled\n", |
420 | sc->sc_dev.dv_xname); |
421 | return; |
422 | } |
423 | |
424 | TWE_DPRINTF(TWE_D_CMD, ("stat=%b ", |
425 | bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS), TWE_STAT_BITS)); |
426 | /* |
427 | * ack all before enable, cannot be done in one |
428 | * operation as it seems clear is not processed |
429 | * if enable is specified. |
430 | */ |
431 | bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,((sc->iot)->write_4((sc->ioh), (0x00), (0x00080000 | 0x00040000 | 0x00000200))) |
432 | TWE_CTRL_CHOSTI | TWE_CTRL_CATTNI | TWE_CTRL_CERR)((sc->iot)->write_4((sc->ioh), (0x00), (0x00080000 | 0x00040000 | 0x00000200))); |
433 | TWE_DPRINTF(TWE_D_CMD, ("stat=%b ", |
434 | bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS), TWE_STAT_BITS)); |
435 | /* enable interrupts */ |
436 | bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,((sc->iot)->write_4((sc->ioh), (0x00), (0x00000080 | 0x00004000 | 0x00020000))) |
437 | TWE_CTRL_EINT | TWE_CTRL_ERDYI |((sc->iot)->write_4((sc->ioh), (0x00), (0x00000080 | 0x00004000 | 0x00020000))) |
438 | /*TWE_CTRL_HOSTI |*/ TWE_CTRL_MCMDI)((sc->iot)->write_4((sc->ioh), (0x00), (0x00000080 | 0x00004000 | 0x00020000))); |
439 | } |
440 | |
441 | void |
442 | twe_thread(void *v) |
443 | { |
444 | struct twe_softc *sc = v; |
445 | struct twe_ccb *ccb; |
446 | twe_lock_t lock; |
447 | u_int32_t status; |
448 | int err; |
449 | |
450 | for (;;) { |
451 | lock = TWE_LOCK(sc)splraise(0x3); |
452 | |
453 | while (!TAILQ_EMPTY(&sc->sc_done_ccb)(((&sc->sc_done_ccb)->tqh_first) == ((void *)0))) { |
454 | ccb = TAILQ_FIRST(&sc->sc_done_ccb)((&sc->sc_done_ccb)->tqh_first); |
455 | TAILQ_REMOVE(&sc->sc_done_ccb, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&sc->sc_done_ccb)->tqh_last = (ccb) ->ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb)-> ccb_link.tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)- 1); ((ccb)->ccb_link.tqe_next) = ((void *)-1); } while (0); |
456 | if ((err = twe_done(sc, ccb))) |
457 | printf("%s: done failed (%d)\n", |
458 | sc->sc_dev.dv_xname, err); |
459 | } |
460 | |
461 | status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
462 | TWE_DPRINTF(TWE_D_INTR, ("twe_thread stat=%b ", |
463 | status & TWE_STAT_FLAGS, TWE_STAT_BITS)); |
464 | while (!(status & TWE_STAT_CQF0x00008000) && |
465 | !TAILQ_EMPTY(&sc->sc_ccb2q)(((&sc->sc_ccb2q)->tqh_first) == ((void *)0))) { |
466 | |
467 | ccb = TAILQ_LAST(&sc->sc_ccb2q, twe_queue_head)(*(((struct twe_queue_head *)((&sc->sc_ccb2q)->tqh_last ))->tqh_last)); |
468 | TAILQ_REMOVE(&sc->sc_ccb2q, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&sc->sc_ccb2q)->tqh_last = (ccb)-> ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb)->ccb_link .tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)-1); ((ccb )->ccb_link.tqe_next) = ((void *)-1); } while (0); |
469 | |
470 | ccb->ccb_state = TWE_CCB_QUEUED; |
471 | TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (&sc->sc_ccbq)->tqh_last; *(&sc-> sc_ccbq)->tqh_last = (ccb); (&sc->sc_ccbq)->tqh_last = &(ccb)->ccb_link.tqe_next; } while (0); |
472 | bus_space_write_4(sc->iot, sc->ioh, TWE_COMMANDQUEUE,((sc->iot)->write_4((sc->ioh), (0x08), (ccb->ccb_cmdpa ))) |
473 | ccb->ccb_cmdpa)((sc->iot)->write_4((sc->ioh), (0x08), (ccb->ccb_cmdpa ))); |
474 | |
475 | status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
476 | TWE_DPRINTF(TWE_D_INTR, ("twe_thread stat=%b ", |
477 | status & TWE_STAT_FLAGS, TWE_STAT_BITS)); |
478 | } |
479 | |
480 | if (!TAILQ_EMPTY(&sc->sc_ccb2q)(((&sc->sc_ccb2q)->tqh_first) == ((void *)0))) |
481 | bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,((sc->iot)->write_4((sc->ioh), (0x00), (0x00008000)) ) |
482 | TWE_CTRL_ECMDI)((sc->iot)->write_4((sc->ioh), (0x00), (0x00008000)) ); |
483 | |
484 | TWE_UNLOCK(sc, lock)spllower(lock); |
485 | sc->sc_thread_on = 1; |
486 | tsleep_nsec(sc, PWAIT32, "twespank", INFSLP0xffffffffffffffffULL); |
487 | } |
488 | } |
489 | |
490 | int |
491 | twe_cmd(struct twe_ccb *ccb, int flags, int wait) |
492 | { |
493 | struct twe_softc *sc = ccb->ccb_sc; |
494 | bus_dmamap_t dmap; |
495 | struct twe_cmd *cmd; |
496 | struct twe_segs *sgp; |
497 | int error, i; |
498 | |
499 | if (ccb->ccb_data && ((u_long)ccb->ccb_data & (TWE_ALIGN512 - 1))) { |
500 | TWE_DPRINTF(TWE_D_DMA, ("data=%p is unaligned ",ccb->ccb_data)); |
501 | ccb->ccb_realdata = ccb->ccb_data; |
502 | |
503 | error = bus_dmamem_alloc(sc->dmat, ccb->ccb_length, PAGE_SIZE,(*(sc->dmat)->_dmamem_alloc)((sc->dmat), (ccb->ccb_length ), ((1 << 12)), (0), (ccb->ccb_2bseg), (62), (&ccb ->ccb_2nseg), (0x0001)) |
504 | 0, ccb->ccb_2bseg, TWE_MAXOFFSETS, &ccb->ccb_2nseg,(*(sc->dmat)->_dmamem_alloc)((sc->dmat), (ccb->ccb_length ), ((1 << 12)), (0), (ccb->ccb_2bseg), (62), (&ccb ->ccb_2nseg), (0x0001)) |
505 | BUS_DMA_NOWAIT)(*(sc->dmat)->_dmamem_alloc)((sc->dmat), (ccb->ccb_length ), ((1 << 12)), (0), (ccb->ccb_2bseg), (62), (&ccb ->ccb_2nseg), (0x0001)); |
506 | if (error) { |
507 | TWE_DPRINTF(TWE_D_DMA, ("2buf alloc failed(%d) ", error)); |
508 | return (ENOMEM12); |
509 | } |
510 | |
511 | error = bus_dmamem_map(sc->dmat, ccb->ccb_2bseg, ccb->ccb_2nseg,(*(sc->dmat)->_dmamem_map)((sc->dmat), (ccb->ccb_2bseg ), (ccb->ccb_2nseg), (ccb->ccb_length), ((caddr_t *)& ccb->ccb_data), (0x0001)) |
512 | ccb->ccb_length, (caddr_t *)&ccb->ccb_data, BUS_DMA_NOWAIT)(*(sc->dmat)->_dmamem_map)((sc->dmat), (ccb->ccb_2bseg ), (ccb->ccb_2nseg), (ccb->ccb_length), ((caddr_t *)& ccb->ccb_data), (0x0001)); |
513 | if (error) { |
514 | TWE_DPRINTF(TWE_D_DMA, ("2buf map failed(%d) ", error)); |
515 | bus_dmamem_free(sc->dmat, ccb->ccb_2bseg, ccb->ccb_2nseg)(*(sc->dmat)->_dmamem_free)((sc->dmat), (ccb->ccb_2bseg ), (ccb->ccb_2nseg)); |
516 | return (ENOMEM12); |
517 | } |
518 | bcopy(ccb->ccb_realdata, ccb->ccb_data, ccb->ccb_length); |
519 | } else |
520 | ccb->ccb_realdata = NULL((void *)0); |
521 | |
522 | dmap = ccb->ccb_dmamap; |
523 | cmd = ccb->ccb_cmd; |
524 | cmd->cmd_status = 0; |
525 | |
526 | if (ccb->ccb_data) { |
527 | error = bus_dmamap_load(sc->dmat, dmap, ccb->ccb_data,(*(sc->dmat)->_dmamap_load)((sc->dmat), (dmap), (ccb ->ccb_data), (ccb->ccb_length), (((void *)0)), (flags)) |
528 | ccb->ccb_length, NULL, flags)(*(sc->dmat)->_dmamap_load)((sc->dmat), (dmap), (ccb ->ccb_data), (ccb->ccb_length), (((void *)0)), (flags)); |
529 | if (error) { |
530 | if (error == EFBIG27) |
531 | printf("more than %d dma segs\n", TWE_MAXOFFSETS62); |
532 | else |
533 | printf("error %d loading dma map\n", error); |
534 | |
535 | if (ccb->ccb_realdata) { |
536 | bus_dmamem_unmap(sc->dmat, ccb->ccb_data,(*(sc->dmat)->_dmamem_unmap)((sc->dmat), (ccb->ccb_data ), (ccb->ccb_length)) |
537 | ccb->ccb_length)(*(sc->dmat)->_dmamem_unmap)((sc->dmat), (ccb->ccb_data ), (ccb->ccb_length)); |
538 | bus_dmamem_free(sc->dmat, ccb->ccb_2bseg,(*(sc->dmat)->_dmamem_free)((sc->dmat), (ccb->ccb_2bseg ), (ccb->ccb_2nseg)) |
539 | ccb->ccb_2nseg)(*(sc->dmat)->_dmamem_free)((sc->dmat), (ccb->ccb_2bseg ), (ccb->ccb_2nseg)); |
540 | } |
541 | return error; |
542 | } |
543 | /* load addresses into command */ |
544 | switch (cmd->cmd_op) { |
545 | case TWE_CMD_GPARAM0x0252: |
546 | case TWE_CMD_SPARAM0x0253: |
547 | sgp = cmd->cmd_param_._cmd_param.segs; |
548 | break; |
549 | case TWE_CMD_READ0x0362: |
550 | case TWE_CMD_WRITE0x0363: |
551 | sgp = cmd->cmd_io_._cmd_io.segs; |
552 | break; |
553 | default: |
554 | /* no data transfer */ |
555 | TWE_DPRINTF(TWE_D_DMA, ("twe_cmd: unknown sgp op=%x\n", |
556 | cmd->cmd_op)); |
557 | sgp = NULL((void *)0); |
558 | break; |
559 | } |
560 | TWE_DPRINTF(TWE_D_DMA, ("data=%p<", ccb->ccb_data)); |
561 | if (sgp) { |
562 | /* |
563 | * we know that size is in the upper byte, |
564 | * and we do not worry about overflow |
565 | */ |
566 | cmd->cmd_op += (2 * dmap->dm_nsegs) << 8; |
567 | bzero (sgp, TWE_MAXOFFSETS * sizeof(*sgp))__builtin_bzero((sgp), (62 * sizeof(*sgp))); |
568 | for (i = 0; i < dmap->dm_nsegs; i++, sgp++) { |
569 | sgp->twes_addr = htole32(dmap->dm_segs[i].ds_addr)((__uint32_t)(dmap->dm_segs[i].ds_addr)); |
570 | sgp->twes_len = htole32(dmap->dm_segs[i].ds_len)((__uint32_t)(dmap->dm_segs[i].ds_len)); |
571 | TWE_DPRINTF(TWE_D_DMA, ("%lx[%lx] ", |
572 | dmap->dm_segs[i].ds_addr, |
573 | dmap->dm_segs[i].ds_len)); |
574 | } |
575 | } |
576 | TWE_DPRINTF(TWE_D_DMA, ("> ")); |
577 | bus_dmamap_sync(sc->dmat, dmap, 0, dmap->dm_mapsize,(*(sc->dmat)->_dmamap_sync)((sc->dmat), (dmap), (0), (dmap->dm_mapsize), (0x04)) |
578 | BUS_DMASYNC_PREWRITE)(*(sc->dmat)->_dmamap_sync)((sc->dmat), (dmap), (0), (dmap->dm_mapsize), (0x04)); |
579 | } |
580 | bus_dmamap_sync(sc->dmat, sc->sc_cmdmap, 0, sc->sc_cmdmap->dm_mapsize,(*(sc->dmat)->_dmamap_sync)((sc->dmat), (sc->sc_cmdmap ), (0), (sc->sc_cmdmap->dm_mapsize), (0x04)) |
581 | BUS_DMASYNC_PREWRITE)(*(sc->dmat)->_dmamap_sync)((sc->dmat), (sc->sc_cmdmap ), (0), (sc->sc_cmdmap->dm_mapsize), (0x04)); |
582 | |
583 | if ((error = twe_start(ccb, wait))) { |
584 | bus_dmamap_unload(sc->dmat, dmap)(*(sc->dmat)->_dmamap_unload)((sc->dmat), (dmap)); |
585 | if (ccb->ccb_realdata) { |
586 | bus_dmamem_unmap(sc->dmat, ccb->ccb_data,(*(sc->dmat)->_dmamem_unmap)((sc->dmat), (ccb->ccb_data ), (ccb->ccb_length)) |
587 | ccb->ccb_length)(*(sc->dmat)->_dmamem_unmap)((sc->dmat), (ccb->ccb_data ), (ccb->ccb_length)); |
588 | bus_dmamem_free(sc->dmat, ccb->ccb_2bseg,(*(sc->dmat)->_dmamem_free)((sc->dmat), (ccb->ccb_2bseg ), (ccb->ccb_2nseg)) |
589 | ccb->ccb_2nseg)(*(sc->dmat)->_dmamem_free)((sc->dmat), (ccb->ccb_2bseg ), (ccb->ccb_2nseg)); |
590 | } |
591 | return (error); |
592 | } |
593 | |
594 | return wait? twe_complete(ccb) : 0; |
595 | } |
596 | |
597 | int |
598 | twe_start(struct twe_ccb *ccb, int wait) |
599 | { |
600 | struct twe_softc*sc = ccb->ccb_sc; |
601 | struct twe_cmd *cmd = ccb->ccb_cmd; |
602 | u_int32_t status; |
603 | int i; |
604 | |
605 | cmd->cmd_op = htole16(cmd->cmd_op)((__uint16_t)(cmd->cmd_op)); |
606 | |
607 | if (!wait) { |
608 | |
609 | TWE_DPRINTF(TWE_D_CMD, ("prequeue(%d) ", cmd->cmd_index)); |
610 | ccb->ccb_state = TWE_CCB_PREQUEUED; |
611 | TAILQ_INSERT_TAIL(&sc->sc_ccb2q, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (&sc->sc_ccb2q)->tqh_last; *(&sc-> sc_ccb2q)->tqh_last = (ccb); (&sc->sc_ccb2q)->tqh_last = &(ccb)->ccb_link.tqe_next; } while (0); |
612 | wakeup(sc); |
613 | return 0; |
614 | } |
615 | |
616 | for (i = 1000; i--; DELAY(10)(*delay_func)(10)) { |
617 | |
618 | status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
619 | if (!(status & TWE_STAT_CQF0x00008000)) |
620 | break; |
621 | TWE_DPRINTF(TWE_D_CMD, ("twe_start stat=%b ", |
622 | status & TWE_STAT_FLAGS, TWE_STAT_BITS)); |
623 | } |
624 | |
625 | if (!(status & TWE_STAT_CQF0x00008000)) { |
626 | bus_space_write_4(sc->iot, sc->ioh, TWE_COMMANDQUEUE,((sc->iot)->write_4((sc->ioh), (0x08), (ccb->ccb_cmdpa ))) |
627 | ccb->ccb_cmdpa)((sc->iot)->write_4((sc->ioh), (0x08), (ccb->ccb_cmdpa ))); |
628 | |
629 | TWE_DPRINTF(TWE_D_CMD, ("queue(%d) ", cmd->cmd_index)); |
630 | ccb->ccb_state = TWE_CCB_QUEUED; |
631 | TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (&sc->sc_ccbq)->tqh_last; *(&sc-> sc_ccbq)->tqh_last = (ccb); (&sc->sc_ccbq)->tqh_last = &(ccb)->ccb_link.tqe_next; } while (0); |
632 | return 0; |
633 | |
634 | } else { |
635 | |
636 | printf("%s: twe_start(%d) timed out\n", |
637 | sc->sc_dev.dv_xname, cmd->cmd_index); |
638 | |
639 | return EPERM1; |
640 | } |
641 | } |
642 | |
643 | int |
644 | twe_complete(struct twe_ccb *ccb) |
645 | { |
646 | struct twe_softc *sc = ccb->ccb_sc; |
647 | struct scsi_xfer *xs = ccb->ccb_xs; |
648 | int i; |
649 | |
650 | for (i = 100 * (xs? xs->timeout : 35000); i--; DELAY(10)(*delay_func)(10)) { |
651 | u_int32_t status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
652 | |
653 | /* TWE_DPRINTF(TWE_D_CMD, ("twe_intr stat=%b ", |
654 | status & TWE_STAT_FLAGS, TWE_STAT_BITS)); */ |
655 | |
656 | while (!(status & TWE_STAT_RQE0x00004000)) { |
657 | struct twe_ccb *ccb1; |
658 | u_int32_t ready; |
659 | |
660 | ready = bus_space_read_4(sc->iot, sc->ioh,((sc->iot)->read_4((sc->ioh), (0x0c))) |
661 | TWE_READYQUEUE)((sc->iot)->read_4((sc->ioh), (0x0c))); |
662 | |
663 | TWE_DPRINTF(TWE_D_CMD, ("ready=%x ", ready)); |
664 | |
665 | ccb1 = &sc->sc_ccbs[TWE_READYID(ready)(((ready) >> 4) & 0xff)]; |
666 | TAILQ_REMOVE(&sc->sc_ccbq, ccb1, ccb_link)do { if (((ccb1)->ccb_link.tqe_next) != ((void *)0)) (ccb1 )->ccb_link.tqe_next->ccb_link.tqe_prev = (ccb1)->ccb_link .tqe_prev; else (&sc->sc_ccbq)->tqh_last = (ccb1)-> ccb_link.tqe_prev; *(ccb1)->ccb_link.tqe_prev = (ccb1)-> ccb_link.tqe_next; ((ccb1)->ccb_link.tqe_prev) = ((void *) -1); ((ccb1)->ccb_link.tqe_next) = ((void *)-1); } while ( 0); |
667 | ccb1->ccb_state = TWE_CCB_DONE; |
668 | if (!twe_done(sc, ccb1) && ccb1 == ccb) { |
669 | TWE_DPRINTF(TWE_D_CMD, ("complete\n")); |
670 | return 0; |
671 | } |
672 | |
673 | status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
674 | /* TWE_DPRINTF(TWE_D_CMD, ("twe_intr stat=%b ", |
675 | status & TWE_STAT_FLAGS, TWE_STAT_BITS)); */ |
676 | } |
677 | } |
678 | |
679 | return 1; |
680 | } |
681 | |
682 | int |
683 | twe_done(struct twe_softc *sc, struct twe_ccb *ccb) |
684 | { |
685 | struct twe_cmd *cmd = ccb->ccb_cmd; |
686 | struct scsi_xfer *xs = ccb->ccb_xs; |
687 | bus_dmamap_t dmap; |
688 | twe_lock_t lock; |
689 | |
690 | TWE_DPRINTF(TWE_D_CMD, ("done(%d) ", cmd->cmd_index)); |
691 | |
692 | if (ccb->ccb_state != TWE_CCB_DONE) { |
693 | printf("%s: undone ccb %d ready\n", |
694 | sc->sc_dev.dv_xname, cmd->cmd_index); |
695 | return 1; |
696 | } |
697 | |
698 | dmap = ccb->ccb_dmamap; |
699 | if (xs) { |
700 | if (xs->cmd.opcode != PREVENT_ALLOW0x1e && |
701 | xs->cmd.opcode != SYNCHRONIZE_CACHE0x35) { |
702 | bus_dmamap_sync(sc->dmat, dmap, 0,(*(sc->dmat)->_dmamap_sync)((sc->dmat), (dmap), (0), (dmap->dm_mapsize), ((xs->flags & 0x00800) ? 0x02 : 0x08)) |
703 | dmap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ?(*(sc->dmat)->_dmamap_sync)((sc->dmat), (dmap), (0), (dmap->dm_mapsize), ((xs->flags & 0x00800) ? 0x02 : 0x08)) |
704 | BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE)(*(sc->dmat)->_dmamap_sync)((sc->dmat), (dmap), (0), (dmap->dm_mapsize), ((xs->flags & 0x00800) ? 0x02 : 0x08)); |
705 | bus_dmamap_unload(sc->dmat, dmap)(*(sc->dmat)->_dmamap_unload)((sc->dmat), (dmap)); |
706 | } |
707 | } else { |
708 | switch (letoh16(cmd->cmd_op)((__uint16_t)(cmd->cmd_op))) { |
709 | case TWE_CMD_GPARAM0x0252: |
710 | case TWE_CMD_READ0x0362: |
711 | bus_dmamap_sync(sc->dmat, dmap, 0,(*(sc->dmat)->_dmamap_sync)((sc->dmat), (dmap), (0), (dmap->dm_mapsize), (0x02)) |
712 | dmap->dm_mapsize, BUS_DMASYNC_POSTREAD)(*(sc->dmat)->_dmamap_sync)((sc->dmat), (dmap), (0), (dmap->dm_mapsize), (0x02)); |
713 | bus_dmamap_unload(sc->dmat, dmap)(*(sc->dmat)->_dmamap_unload)((sc->dmat), (dmap)); |
714 | break; |
715 | case TWE_CMD_SPARAM0x0253: |
716 | case TWE_CMD_WRITE0x0363: |
717 | bus_dmamap_sync(sc->dmat, dmap, 0,(*(sc->dmat)->_dmamap_sync)((sc->dmat), (dmap), (0), (dmap->dm_mapsize), (0x08)) |
718 | dmap->dm_mapsize, BUS_DMASYNC_POSTWRITE)(*(sc->dmat)->_dmamap_sync)((sc->dmat), (dmap), (0), (dmap->dm_mapsize), (0x08)); |
719 | bus_dmamap_unload(sc->dmat, dmap)(*(sc->dmat)->_dmamap_unload)((sc->dmat), (dmap)); |
720 | break; |
721 | default: |
722 | /* no data */ |
723 | break; |
724 | } |
725 | } |
726 | |
727 | if (ccb->ccb_realdata) { |
728 | bcopy(ccb->ccb_data, ccb->ccb_realdata, ccb->ccb_length); |
729 | bus_dmamem_unmap(sc->dmat, ccb->ccb_data, ccb->ccb_length)(*(sc->dmat)->_dmamem_unmap)((sc->dmat), (ccb->ccb_data ), (ccb->ccb_length)); |
730 | bus_dmamem_free(sc->dmat, ccb->ccb_2bseg, ccb->ccb_2nseg)(*(sc->dmat)->_dmamem_free)((sc->dmat), (ccb->ccb_2bseg ), (ccb->ccb_2nseg)); |
731 | } |
732 | |
733 | lock = TWE_LOCK(sc)splraise(0x3); |
734 | |
735 | if (xs) { |
736 | xs->resid = 0; |
737 | scsi_done(xs); |
738 | } |
739 | TWE_UNLOCK(sc, lock)spllower(lock); |
740 | |
741 | return 0; |
742 | } |
743 | |
744 | void |
745 | twe_scsi_cmd(struct scsi_xfer *xs) |
746 | { |
747 | struct scsi_link *link = xs->sc_link; |
748 | struct twe_softc *sc = link->bus->sb_adapter_softc; |
749 | struct twe_ccb *ccb = xs->io; |
750 | struct twe_cmd *cmd; |
751 | struct scsi_inquiry_data inq; |
752 | struct scsi_sense_data sd; |
753 | struct scsi_read_cap_data rcd; |
754 | u_int8_t target = link->target; |
755 | u_int32_t blockno, blockcnt; |
756 | struct scsi_rw *rw; |
757 | struct scsi_rw_10 *rw10; |
758 | int error, op, flags, wait; |
759 | twe_lock_t lock; |
760 | |
761 | |
762 | if (target >= TWE_MAX_UNITS16 || !sc->sc_hdr[target].hd_present || |
763 | link->lun != 0) { |
764 | xs->error = XS_DRIVER_STUFFUP2; |
765 | scsi_done(xs); |
766 | return; |
767 | } |
768 | |
769 | TWE_DPRINTF(TWE_D_CMD, ("twe_scsi_cmd ")); |
770 | |
771 | xs->error = XS_NOERROR0; |
772 | |
773 | switch (xs->cmd.opcode) { |
774 | case TEST_UNIT_READY0x00: |
775 | case START_STOP0x1b: |
776 | #if 0 |
777 | case VERIFY: |
778 | #endif |
779 | TWE_DPRINTF(TWE_D_CMD, ("opc %d tgt %d ", xs->cmd.opcode, |
780 | target)); |
781 | break; |
782 | |
783 | case REQUEST_SENSE0x03: |
784 | TWE_DPRINTF(TWE_D_CMD, ("REQUEST SENSE tgt %d ", target)); |
785 | bzero(&sd, sizeof sd)__builtin_bzero((&sd), (sizeof sd)); |
786 | sd.error_code = SSD_ERRCODE_CURRENT0x70; |
787 | sd.segment = 0; |
788 | sd.flags = SKEY_NO_SENSE0x00; |
789 | *(u_int32_t*)sd.info = htole32(0)((__uint32_t)(0)); |
790 | sd.extra_len = 0; |
791 | scsi_copy_internal_data(xs, &sd, sizeof(sd)); |
792 | break; |
793 | |
794 | case INQUIRY0x12: |
795 | TWE_DPRINTF(TWE_D_CMD, ("INQUIRY tgt %d devtype %x ", target, |
796 | sc->sc_hdr[target].hd_devtype)); |
797 | bzero(&inq, sizeof inq)__builtin_bzero((&inq), (sizeof inq)); |
798 | inq.device = |
799 | (sc->sc_hdr[target].hd_devtype & 4) ? T_CDROM0x05 : T_DIRECT0x00; |
800 | inq.dev_qual2 = |
801 | (sc->sc_hdr[target].hd_devtype & 1) ? SID_REMOVABLE0x80 : 0; |
802 | inq.version = SCSI_REV_20x02; |
803 | inq.response_format = SID_SCSI2_RESPONSE0x02; |
804 | inq.additional_length = SID_SCSI2_ALEN31; |
805 | strlcpy(inq.vendor, "3WARE ", sizeof inq.vendor); |
806 | snprintf(inq.product, sizeof inq.product, "Host drive #%02d", |
807 | target); |
808 | strlcpy(inq.revision, " ", sizeof inq.revision); |
809 | scsi_copy_internal_data(xs, &inq, sizeof(inq)); |
810 | break; |
811 | |
812 | case READ_CAPACITY0x25: |
813 | TWE_DPRINTF(TWE_D_CMD, ("READ CAPACITY tgt %d ", target)); |
814 | bzero(&rcd, sizeof rcd)__builtin_bzero((&rcd), (sizeof rcd)); |
815 | _lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr); |
816 | _lto4b(TWE_SECTOR_SIZE512, rcd.length); |
817 | scsi_copy_internal_data(xs, &rcd, sizeof(rcd)); |
818 | break; |
819 | |
820 | case PREVENT_ALLOW0x1e: |
821 | TWE_DPRINTF(TWE_D_CMD, ("PREVENT/ALLOW ")); |
822 | scsi_done(xs); |
823 | return; |
824 | |
825 | case READ_COMMAND0x08: |
826 | case READ_100x28: |
827 | case WRITE_COMMAND0x0a: |
828 | case WRITE_100x2a: |
829 | case SYNCHRONIZE_CACHE0x35: |
830 | lock = TWE_LOCK(sc)splraise(0x3); |
831 | |
832 | flags = 0; |
833 | if (xs->cmd.opcode == SYNCHRONIZE_CACHE0x35) { |
834 | blockno = blockcnt = 0; |
835 | } else { |
836 | /* A read or write operation. */ |
837 | if (xs->cmdlen == 6) { |
838 | rw = (struct scsi_rw *)&xs->cmd; |
839 | blockno = _3btol(rw->addr) & |
840 | (SRW_TOPADDR0x1F << 16 | 0xffff); |
841 | blockcnt = rw->length ? rw->length : 0x100; |
842 | } else { |
843 | rw10 = (struct scsi_rw_10 *)&xs->cmd; |
844 | blockno = _4btol(rw10->addr); |
845 | blockcnt = _2btol(rw10->length); |
846 | /* reflect DPO & FUA flags */ |
847 | if (xs->cmd.opcode == WRITE_100x2a && |
848 | rw10->byte2 & 0x18) |
849 | flags = TWE_FLAGS_CACHEDISABLE0x01; |
850 | } |
851 | if (blockno >= sc->sc_hdr[target].hd_size || |
852 | blockno + blockcnt > sc->sc_hdr[target].hd_size) { |
853 | printf("%s: out of bounds %u-%u >= %u\n", |
854 | sc->sc_dev.dv_xname, blockno, blockcnt, |
855 | sc->sc_hdr[target].hd_size); |
856 | xs->error = XS_DRIVER_STUFFUP2; |
857 | scsi_done(xs); |
858 | TWE_UNLOCK(sc, lock)spllower(lock); |
859 | return; |
860 | } |
861 | } |
862 | |
863 | switch (xs->cmd.opcode) { |
864 | case READ_COMMAND0x08: op = TWE_CMD_READ0x0362; break; |
865 | case READ_100x28: op = TWE_CMD_READ0x0362; break; |
866 | case WRITE_COMMAND0x0a: op = TWE_CMD_WRITE0x0363; break; |
867 | case WRITE_100x2a: op = TWE_CMD_WRITE0x0363; break; |
868 | default: op = TWE_CMD_NOP0x0200; break; |
869 | } |
870 | |
871 | ccb->ccb_xs = xs; |
872 | ccb->ccb_data = xs->data; |
873 | ccb->ccb_length = xs->datalen; |
874 | ccb->ccb_state = TWE_CCB_READY; |
875 | cmd = ccb->ccb_cmd; |
876 | cmd->cmd_unit_host = TWE_UNITHOST(target, 0)(((target) & 0xf) | ((0) << 4)); /* XXX why 0? */ |
877 | cmd->cmd_op = op; |
878 | cmd->cmd_flags = flags; |
879 | cmd->cmd_io_._cmd_io.count = htole16(blockcnt)((__uint16_t)(blockcnt)); |
880 | cmd->cmd_io_._cmd_io.lba = htole32(blockno)((__uint32_t)(blockno)); |
881 | wait = xs->flags & SCSI_POLL0x00002; |
882 | if (!sc->sc_thread_on) |
883 | wait |= SCSI_POLL0x00002; |
884 | |
885 | if ((error = twe_cmd(ccb, ((xs->flags & SCSI_NOSLEEP0x00001)? |
Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' | |
886 | BUS_DMA_NOWAIT0x0001 : BUS_DMA_WAITOK0x0000), wait))) { |
887 | |
888 | TWE_DPRINTF(TWE_D_CMD, ("failed %p ", xs)); |
889 | xs->error = XS_DRIVER_STUFFUP2; |
890 | scsi_done(xs); |
891 | } |
892 | |
893 | TWE_UNLOCK(sc, lock)spllower(lock); |
894 | return; |
895 | |
896 | default: |
897 | TWE_DPRINTF(TWE_D_CMD, ("unsupported scsi command %#x tgt %d ", |
898 | xs->cmd.opcode, target)); |
899 | xs->error = XS_DRIVER_STUFFUP2; |
900 | } |
901 | |
902 | scsi_done(xs); |
903 | } |
904 | |
905 | int |
906 | twe_intr(void *v) |
907 | { |
908 | struct twe_softc *sc = v; |
909 | struct twe_ccb *ccb; |
910 | u_int32_t status; |
911 | int rv = 0; |
912 | |
913 | status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
914 | TWE_DPRINTF(TWE_D_INTR, ("twe_intr stat=%b ", |
915 | status & TWE_STAT_FLAGS, TWE_STAT_BITS)); |
916 | #if 0 |
917 | if (status & TWE_STAT_HOSTI0x00080000) { |
918 | |
919 | bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,((sc->iot)->write_4((sc->ioh), (0x00), (0x00080000)) ) |
920 | TWE_CTRL_CHOSTI)((sc->iot)->write_4((sc->ioh), (0x00), (0x00080000)) ); |
921 | } |
922 | #endif |
923 | |
924 | if (status & TWE_STAT_RDYI0x00010000) { |
925 | |
926 | while (!(status & TWE_STAT_RQE0x00004000)) { |
927 | |
928 | u_int32_t ready; |
929 | |
930 | /* |
931 | * it seems that reading ready queue |
932 | * we get all the status bits in each ready word. |
933 | * i wonder if it's legal to use those for |
934 | * status and avoid extra read below |
935 | */ |
936 | ready = bus_space_read_4(sc->iot, sc->ioh,((sc->iot)->read_4((sc->ioh), (0x0c))) |
937 | TWE_READYQUEUE)((sc->iot)->read_4((sc->ioh), (0x0c))); |
938 | |
939 | ccb = &sc->sc_ccbs[TWE_READYID(ready)(((ready) >> 4) & 0xff)]; |
940 | TAILQ_REMOVE(&sc->sc_ccbq, ccb, ccb_link)do { if (((ccb)->ccb_link.tqe_next) != ((void *)0)) (ccb)-> ccb_link.tqe_next->ccb_link.tqe_prev = (ccb)->ccb_link. tqe_prev; else (&sc->sc_ccbq)->tqh_last = (ccb)-> ccb_link.tqe_prev; *(ccb)->ccb_link.tqe_prev = (ccb)->ccb_link .tqe_next; ((ccb)->ccb_link.tqe_prev) = ((void *)-1); ((ccb )->ccb_link.tqe_next) = ((void *)-1); } while (0); |
941 | ccb->ccb_state = TWE_CCB_DONE; |
942 | TAILQ_INSERT_TAIL(&sc->sc_done_ccb, ccb, ccb_link)do { (ccb)->ccb_link.tqe_next = ((void *)0); (ccb)->ccb_link .tqe_prev = (&sc->sc_done_ccb)->tqh_last; *(&sc ->sc_done_ccb)->tqh_last = (ccb); (&sc->sc_done_ccb )->tqh_last = &(ccb)->ccb_link.tqe_next; } while (0 ); |
943 | rv++; |
944 | |
945 | status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS)((sc->iot)->read_4((sc->ioh), (0x04))); |
946 | TWE_DPRINTF(TWE_D_INTR, ("twe_intr stat=%b ", |
947 | status & TWE_STAT_FLAGS, TWE_STAT_BITS)); |
948 | } |
949 | } |
950 | |
951 | if (status & TWE_STAT_CMDI0x00020000) { |
952 | rv++; |
953 | bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,((sc->iot)->write_4((sc->ioh), (0x00), (0x00020000)) ) |
954 | TWE_CTRL_MCMDI)((sc->iot)->write_4((sc->ioh), (0x00), (0x00020000)) ); |
955 | } |
956 | |
957 | if (rv) |
958 | wakeup(sc); |
959 | |
960 | if (status & TWE_STAT_ATTNI0x00040000) { |
961 | /* |
962 | * we know no attentions of interest right now. |
963 | * one of those would be mirror degradation i think. |
964 | * or, what else exists in there? |
965 | * maybe 3ware can answer that? |
966 | */ |
967 | bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,((sc->iot)->write_4((sc->ioh), (0x00), (0x00040000)) ) |
968 | TWE_CTRL_CATTNI)((sc->iot)->write_4((sc->ioh), (0x00), (0x00040000)) ); |
969 | |
970 | scsi_ioh_add(&sc->sc_aen); |
971 | } |
972 | |
973 | return rv; |
974 | } |
975 | |
976 | void |
977 | twe_aen(void *cookie, void *io) |
978 | { |
979 | struct twe_softc *sc = cookie; |
980 | struct twe_ccb *ccb = io; |
981 | struct twe_cmd *cmd = ccb->ccb_cmd; |
982 | |
983 | u_int8_t param_buf[2 * TWE_SECTOR_SIZE512 + TWE_ALIGN512 - 1]; |
984 | struct twe_param *pb = (void *) (((u_long)param_buf + |
985 | TWE_ALIGN512 - 1) & ~(TWE_ALIGN512 - 1)); |
986 | u_int16_t aen; |
987 | |
988 | twe_lock_t lock; |
989 | int error; |
990 | |
991 | ccb->ccb_xs = NULL((void *)0); |
992 | ccb->ccb_data = pb; |
993 | ccb->ccb_length = TWE_SECTOR_SIZE512; |
994 | ccb->ccb_state = TWE_CCB_READY; |
995 | cmd->cmd_unit_host = TWE_UNITHOST(0, 0)(((0) & 0xf) | ((0) << 4)); |
996 | cmd->cmd_op = TWE_CMD_GPARAM0x0252; |
997 | cmd->cmd_flags = 0; |
998 | cmd->cmd_param_._cmd_param.count = 1; |
999 | |
1000 | pb->table_id = TWE_PARAM_AEN0x401; |
1001 | pb->param_id = 2; |
1002 | pb->param_size = 2; |
1003 | |
1004 | lock = TWE_LOCK(sc)splraise(0x3); |
1005 | error = twe_cmd(ccb, BUS_DMA_NOWAIT0x0001, 1); |
1006 | TWE_UNLOCK(sc, lock)spllower(lock); |
1007 | scsi_io_put(&sc->sc_iopool, ccb); |
1008 | |
1009 | if (error) { |
1010 | printf("%s: error draining attention queue\n", |
1011 | sc->sc_dev.dv_xname); |
1012 | return; |
1013 | } |
1014 | |
1015 | aen = *(u_int16_t *)pb->data; |
1016 | if (aen != TWE_AEN_QEMPTY0x0000) |
1017 | scsi_ioh_add(&sc->sc_aen); |
1018 | } |