No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / ic / oosiop.c
blob6d7ac3a194c904bb2cba4ada23b14b9266a34db2
1 /* $NetBSD: oosiop.c,v 1.11 2007/10/19 11:59:58 ad Exp $ */
3 /*
4 * Copyright (c) 2001 Shuichiro URATA. All rights reserved.
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 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * NCR53C700 SCSI I/O processor (OOSIOP) driver
32 * TODO:
33 * - More better error handling.
34 * - Implement tagged queuing.
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: oosiop.c,v 1.11 2007/10/19 11:59:58 ad Exp $");
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/callout.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
45 #include <sys/buf.h>
46 #include <sys/malloc.h>
47 #include <sys/queue.h>
49 #include <uvm/uvm_extern.h>
51 #include <dev/scsipi/scsi_all.h>
52 #include <dev/scsipi/scsipi_all.h>
53 #include <dev/scsipi/scsiconf.h>
54 #include <dev/scsipi/scsi_message.h>
56 #include <sys/cpu.h>
57 #include <sys/bus.h>
59 #include <dev/ic/oosiopreg.h>
60 #include <dev/ic/oosiopvar.h>
61 #include <dev/microcode/siop/oosiop.out>
63 static int oosiop_alloc_cb(struct oosiop_softc *, int);
65 static inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t);
66 static inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t);
67 static inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t,
68 int);
69 static inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t,
70 bus_addr_t);
71 static inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t,
72 bus_size_t, bus_addr_t);
74 static void oosiop_load_script(struct oosiop_softc *);
75 static void oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *);
76 static void oosiop_setup_dma(struct oosiop_softc *);
77 static void oosiop_flush_fifo(struct oosiop_softc *);
78 static void oosiop_clear_fifo(struct oosiop_softc *);
79 static void oosiop_phasemismatch(struct oosiop_softc *);
80 static void oosiop_setup_syncxfer(struct oosiop_softc *);
81 static void oosiop_set_syncparam(struct oosiop_softc *, int, int, int);
82 static void oosiop_minphys(struct buf *);
83 static void oosiop_scsipi_request(struct scsipi_channel *,
84 scsipi_adapter_req_t, void *);
85 static void oosiop_done(struct oosiop_softc *, struct oosiop_cb *);
86 static void oosiop_timeout(void *);
87 static void oosiop_reset(struct oosiop_softc *);
88 static void oosiop_reset_bus(struct oosiop_softc *);
89 static void oosiop_scriptintr(struct oosiop_softc *);
90 static void oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *);
92 /* Trap interrupt code for unexpected data I/O */
93 #define DATAIN_TRAP 0xdead0001
94 #define DATAOUT_TRAP 0xdead0002
96 /* Possible TP and SCF conbination */
97 static const struct {
98 uint8_t tp;
99 uint8_t scf;
100 } synctbl[] = {
101 {0, 1}, /* SCLK / 4.0 */
102 {1, 1}, /* SCLK / 5.0 */
103 {2, 1}, /* SCLK / 6.0 */
104 {3, 1}, /* SCLK / 7.0 */
105 {1, 2}, /* SCLK / 7.5 */
106 {4, 1}, /* SCLK / 8.0 */
107 {5, 1}, /* SCLK / 9.0 */
108 {6, 1}, /* SCLK / 10.0 */
109 {3, 2}, /* SCLK / 10.5 */
110 {7, 1}, /* SCLK / 11.0 */
111 {4, 2}, /* SCLK / 12.0 */
112 {5, 2}, /* SCLK / 13.5 */
113 {3, 3}, /* SCLK / 14.0 */
114 {6, 2}, /* SCLK / 15.0 */
115 {4, 3}, /* SCLK / 16.0 */
116 {7, 2}, /* SCLK / 16.5 */
117 {5, 3}, /* SCLK / 18.0 */
118 {6, 3}, /* SCLK / 20.0 */
119 {7, 3} /* SCLK / 22.0 */
121 #define NSYNCTBL (sizeof(synctbl) / sizeof(synctbl[0]))
123 #define oosiop_period(sc, tp, scf) \
124 (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40)
126 void
127 oosiop_attach(struct oosiop_softc *sc)
129 bus_size_t scrsize;
130 bus_dma_segment_t seg;
131 struct oosiop_cb *cb;
132 int err, i, nseg;
135 * Allocate DMA-safe memory for the script and map it.
137 scrsize = sizeof(oosiop_script);
138 err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1,
139 &nseg, BUS_DMA_NOWAIT);
140 if (err) {
141 aprint_error(": failed to allocate script memory, err=%d\n",
142 err);
143 return;
145 err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize,
146 (void **)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
147 if (err) {
148 aprint_error(": failed to map script memory, err=%d\n", err);
149 return;
151 err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0,
152 BUS_DMA_NOWAIT, &sc->sc_scrdma);
153 if (err) {
154 aprint_error(": failed to create script map, err=%d\n", err);
155 return;
157 err = bus_dmamap_load(sc->sc_dmat, sc->sc_scrdma, sc->sc_scr, scrsize,
158 NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
159 if (err) {
160 aprint_error(": failed to load script map, err=%d\n", err);
161 return;
163 sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr;
165 /* Initialize command block array */
166 TAILQ_INIT(&sc->sc_free_cb);
167 TAILQ_INIT(&sc->sc_cbq);
168 if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0)
169 return;
171 /* Use first cb to reselection msgin buffer */
172 cb = TAILQ_FIRST(&sc->sc_free_cb);
173 sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr +
174 offsetof(struct oosiop_xfer, msgin[0]);
176 for (i = 0; i < OOSIOP_NTGT; i++) {
177 sc->sc_tgt[i].nexus = NULL;
178 sc->sc_tgt[i].flags = 0;
181 /* Setup asynchronous clock divisor parameters */
182 if (sc->sc_freq <= 25000000) {
183 sc->sc_ccf = 10;
184 sc->sc_dcntl = OOSIOP_DCNTL_CF_1;
185 } else if (sc->sc_freq <= 37500000) {
186 sc->sc_ccf = 15;
187 sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5;
188 } else if (sc->sc_freq <= 50000000) {
189 sc->sc_ccf = 20;
190 sc->sc_dcntl = OOSIOP_DCNTL_CF_2;
191 } else {
192 sc->sc_ccf = 30;
193 sc->sc_dcntl = OOSIOP_DCNTL_CF_3;
196 if (sc->sc_chip == OOSIOP_700)
197 sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf);
198 else
199 sc->sc_minperiod = oosiop_period(sc, 4, 10);
201 if (sc->sc_minperiod < 25)
202 sc->sc_minperiod = 25; /* limit to 10MB/s */
204 aprint_normal(": NCR53C700%s rev %d, %dMHz, SCSI ID %d\n",
205 sc->sc_chip == OOSIOP_700_66 ? "-66" : "",
206 oosiop_read_1(sc, OOSIOP_CTEST7) >> 4,
207 sc->sc_freq / 1000000, sc->sc_id);
209 * Reset all
211 oosiop_reset(sc);
212 oosiop_reset_bus(sc);
215 * Start SCRIPTS processor
217 oosiop_load_script(sc);
218 sc->sc_active = 0;
219 oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect);
222 * Fill in the scsipi_adapter.
224 sc->sc_adapter.adapt_dev = sc->sc_dev;
225 sc->sc_adapter.adapt_nchannels = 1;
226 sc->sc_adapter.adapt_openings = OOSIOP_NCB;
227 sc->sc_adapter.adapt_max_periph = 1;
228 sc->sc_adapter.adapt_ioctl = NULL;
229 sc->sc_adapter.adapt_minphys = oosiop_minphys;
230 sc->sc_adapter.adapt_request = oosiop_scsipi_request;
233 * Fill in the scsipi_channel.
235 sc->sc_channel.chan_adapter = &sc->sc_adapter;
236 sc->sc_channel.chan_bustype = &scsi_bustype;
237 sc->sc_channel.chan_channel = 0;
238 sc->sc_channel.chan_ntargets = OOSIOP_NTGT;
239 sc->sc_channel.chan_nluns = 8;
240 sc->sc_channel.chan_id = sc->sc_id;
243 * Now try to attach all the sub devices.
245 config_found(sc->sc_dev, &sc->sc_channel, scsiprint);
248 static int
249 oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
251 struct oosiop_cb *cb;
252 struct oosiop_xfer *xfer;
253 bus_size_t xfersize;
254 bus_dma_segment_t seg;
255 int i, s, err, nseg;
258 * Allocate oosiop_cb.
260 cb = malloc(sizeof(struct oosiop_cb) * ncb, M_DEVBUF, M_NOWAIT|M_ZERO);
261 if (cb == NULL) {
262 printf(": failed to allocate cb memory\n");
263 return (ENOMEM);
267 * Allocate DMA-safe memory for the oosiop_xfer and map it.
269 xfersize = sizeof(struct oosiop_xfer) * ncb;
270 err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1,
271 &nseg, BUS_DMA_NOWAIT);
272 if (err) {
273 printf(": failed to allocate xfer block memory, err=%d\n", err);
274 return (err);
276 err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize,
277 (void **)(void *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
278 if (err) {
279 printf(": failed to map xfer block memory, err=%d\n", err);
280 return (err);
283 /* Initialize each command block */
284 for (i = 0; i < ncb; i++) {
285 err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
286 0, BUS_DMA_NOWAIT, &cb->cmddma);
287 if (err) {
288 printf(": failed to create cmddma map, err=%d\n", err);
289 return (err);
291 err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
292 OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
293 &cb->datadma);
294 if (err) {
295 printf(": failed to create datadma map, err=%d\n", err);
296 return (err);
299 err = bus_dmamap_create(sc->sc_dmat,
300 sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
301 0, BUS_DMA_NOWAIT, &cb->xferdma);
302 if (err) {
303 printf(": failed to create xfer block map, err=%d\n",
304 err);
305 return (err);
307 err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer,
308 sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
309 if (err) {
310 printf(": failed to load xfer block, err=%d\n", err);
311 return (err);
314 cb->xfer = xfer;
316 s = splbio();
317 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
318 splx(s);
320 cb++;
321 xfer++;
324 return (0);
327 static inline void
328 oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr)
330 uint32_t dcmd;
331 int32_t dsps;
333 dcmd = le32toh(sc->sc_scr[addr / 4 + 0]);
334 dsps = le32toh(sc->sc_scr[addr / 4 + 1]);
336 /* convert relative to absolute */
337 if (dcmd & 0x04000000) {
338 dcmd &= ~0x04000000;
339 #if 0
341 * sign extension isn't needed here because
342 * ncr53cxxx.c generates 32 bit dsps.
344 dsps <<= 8;
345 dsps >>= 8;
346 #endif
347 sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
348 dsps += addr + 8;
351 sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
354 static inline void
355 oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr)
357 uint32_t dcmd;
358 int32_t dsps;
360 dcmd = le32toh(sc->sc_scr[addr / 4 + 0]);
361 dsps = le32toh(sc->sc_scr[addr / 4 + 1]);
363 /* convert relative to absolute */
364 if (dcmd & 0x00800000) {
365 dcmd &= ~0x00800000;
366 sc->sc_scr[addr / 4] = htole32(dcmd);
367 #if 0
369 * sign extension isn't needed here because
370 * ncr53cxxx.c generates 32 bit dsps.
372 dsps <<= 8;
373 dsps >>= 8;
374 #endif
375 dsps += addr + 8;
378 sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
381 static inline void
382 oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id)
384 uint32_t dcmd;
386 dcmd = le32toh(sc->sc_scr[addr / 4]);
387 dcmd &= 0xff00ffff;
388 dcmd |= 0x00010000 << id;
389 sc->sc_scr[addr / 4] = htole32(dcmd);
392 static inline void
393 oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst)
396 sc->sc_scr[addr / 4 + 1] = htole32(dst);
399 static inline void
400 oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc,
401 bus_addr_t dsps)
403 uint32_t dcmd;
405 dcmd = le32toh(sc->sc_scr[addr / 4]);
406 dcmd &= 0xff000000;
407 dcmd |= dbc & 0x00ffffff;
408 sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
409 sc->sc_scr[addr / 4 + 1] = htole32(dsps);
412 static void
413 oosiop_load_script(struct oosiop_softc *sc)
415 int i;
417 /* load script */
418 for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++)
419 sc->sc_scr[i] = htole32(oosiop_script[i]);
421 /* relocate script */
422 for (i = 0; i < (sizeof(oosiop_script) / 8); i++) {
423 switch (oosiop_script[i * 2] >> 27) {
424 case 0x08: /* select */
425 case 0x0a: /* wait reselect */
426 oosiop_relocate_io(sc, i * 8);
427 break;
428 case 0x10: /* jump */
429 case 0x11: /* call */
430 oosiop_relocate_tc(sc, i * 8);
431 break;
435 oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf);
436 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
439 static void
440 oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb)
442 int i, n, off, control;
443 struct oosiop_xfer *xfer;
445 OOSIOP_XFERSCR_SYNC(sc, cb,
446 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
448 off = cb->curdp;
449 xfer = cb->xfer;
450 control = cb->xs->xs_control;
452 if (control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
453 /* Find start segment */
454 for (i = 0; i < cb->datadma->dm_nsegs; i++) {
455 if (off < cb->datadma->dm_segs[i].ds_len)
456 break;
457 off -= cb->datadma->dm_segs[i].ds_len;
460 /* build MOVE block */
461 if (control & XS_CTL_DATA_IN) {
462 n = 0;
463 while (i < cb->datadma->dm_nsegs) {
464 xfer->datain_scr[n * 2 + 0] =
465 htole32(0x09000000 |
466 (cb->datadma->dm_segs[i].ds_len - off));
467 xfer->datain_scr[n * 2 + 1] =
468 htole32(cb->datadma->dm_segs[i].ds_addr +
469 off);
470 n++;
471 i++;
472 off = 0;
474 xfer->datain_scr[n * 2 + 0] = htole32(0x80080000);
475 xfer->datain_scr[n * 2 + 1] =
476 htole32(sc->sc_scrbase + Ent_phasedispatch);
478 if (control & XS_CTL_DATA_OUT) {
479 n = 0;
480 while (i < cb->datadma->dm_nsegs) {
481 xfer->dataout_scr[n * 2 + 0] =
482 htole32(0x08000000 |
483 (cb->datadma->dm_segs[i].ds_len - off));
484 xfer->dataout_scr[n * 2 + 1] =
485 htole32(cb->datadma->dm_segs[i].ds_addr +
486 off);
487 n++;
488 i++;
489 off = 0;
491 xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000);
492 xfer->dataout_scr[n * 2 + 1] =
493 htole32(sc->sc_scrbase + Ent_phasedispatch);
496 if ((control & XS_CTL_DATA_IN) == 0) {
497 xfer->datain_scr[0] = htole32(0x98080000);
498 xfer->datain_scr[1] = htole32(DATAIN_TRAP);
500 if ((control & XS_CTL_DATA_OUT) == 0) {
501 xfer->dataout_scr[0] = htole32(0x98080000);
502 xfer->dataout_scr[1] = htole32(DATAOUT_TRAP);
504 OOSIOP_XFERSCR_SYNC(sc, cb,
505 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
509 * Setup DMA pointer into script.
511 static void
512 oosiop_setup_dma(struct oosiop_softc *sc)
514 struct oosiop_cb *cb;
515 bus_addr_t xferbase;
517 cb = sc->sc_curcb;
518 xferbase = cb->xferdma->dm_segs[0].ds_addr;
520 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
522 oosiop_fixup_select(sc, Ent_p_select, cb->id);
523 oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase +
524 offsetof(struct oosiop_xfer, datain_scr[0]));
525 oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase +
526 offsetof(struct oosiop_xfer, dataout_scr[0]));
527 oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase +
528 offsetof(struct oosiop_xfer, msgin[0]));
529 oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase +
530 offsetof(struct oosiop_xfer, msgin[1]));
531 oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase +
532 offsetof(struct oosiop_xfer, msgout[0]));
533 oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase +
534 offsetof(struct oosiop_xfer, status));
535 oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->xs->cmdlen,
536 cb->cmddma->dm_segs[0].ds_addr);
538 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
541 static void
542 oosiop_flush_fifo(struct oosiop_softc *sc)
545 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
546 OOSIOP_DFIFO_FLF);
547 while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
548 OOSIOP_CTEST1_FMT)
550 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
551 ~OOSIOP_DFIFO_FLF);
554 static void
555 oosiop_clear_fifo(struct oosiop_softc *sc)
558 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
559 OOSIOP_DFIFO_CLF);
560 while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
561 OOSIOP_CTEST1_FMT)
563 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
564 ~OOSIOP_DFIFO_CLF);
567 static void
568 oosiop_phasemismatch(struct oosiop_softc *sc)
570 struct oosiop_cb *cb;
571 uint32_t dsp, dbc, n, i, len;
572 uint8_t dfifo, sstat1;
574 cb = sc->sc_curcb;
575 if (cb == NULL)
576 return;
578 dsp = oosiop_read_4(sc, OOSIOP_DSP);
579 dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX;
580 len = 0;
582 n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8;
583 if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) &&
584 n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) {
585 n -= offsetof(struct oosiop_xfer, datain_scr[0]);
586 n >>= 3;
587 OOSIOP_DINSCR_SYNC(sc, cb,
588 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
589 for (i = 0; i <= n; i++)
590 len += le32toh(cb->xfer->datain_scr[i * 2]) &
591 0x00ffffff;
592 OOSIOP_DINSCR_SYNC(sc, cb,
593 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
594 /* All data in the chip are already flushed */
595 } else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) &&
596 n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) {
597 n -= offsetof(struct oosiop_xfer, dataout_scr[0]);
598 n >>= 3;
599 OOSIOP_DOUTSCR_SYNC(sc, cb,
600 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
601 for (i = 0; i <= n; i++)
602 len += le32toh(cb->xfer->dataout_scr[i * 2]) &
603 0x00ffffff;
604 OOSIOP_DOUTSCR_SYNC(sc, cb,
605 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
607 dfifo = oosiop_read_1(sc, OOSIOP_DFIFO);
608 dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) &
609 OOSIOP_DFIFO_BO;
611 sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1);
612 if (sstat1 & OOSIOP_SSTAT1_OLF)
613 dbc++;
614 if ((sc->sc_tgt[cb->id].sxfer != 0) &&
615 (sstat1 & OOSIOP_SSTAT1_ORF) != 0)
616 dbc++;
618 oosiop_clear_fifo(sc);
619 } else {
620 printf("%s: phase mismatch addr=%08x\n",
621 device_xname(sc->sc_dev),
622 oosiop_read_4(sc, OOSIOP_DSP) - 8);
623 oosiop_clear_fifo(sc);
624 return;
627 len -= dbc;
628 if (len) {
629 cb->curdp += len;
630 oosiop_setup_sgdma(sc, cb);
634 static void
635 oosiop_setup_syncxfer(struct oosiop_softc *sc)
637 int id;
639 id = sc->sc_curcb->id;
640 if (sc->sc_chip != OOSIOP_700)
641 oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf);
643 oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer);
646 static void
647 oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset)
649 int i, p;
650 struct scsipi_xfer_mode xm;
652 xm.xm_target = id;
653 xm.xm_mode = 0;
654 xm.xm_period = 0;
655 xm.xm_offset = 0;
657 if (offset == 0) {
658 /* Asynchronous */
659 sc->sc_tgt[id].scf = 0;
660 sc->sc_tgt[id].sxfer = 0;
661 } else {
662 /* Synchronous */
663 if (sc->sc_chip == OOSIOP_700) {
664 for (i = 4; i < 12; i++) {
665 p = oosiop_period(sc, i, sc->sc_ccf);
666 if (p >= period)
667 break;
669 if (i == 12) {
670 printf("%s: target %d period too large\n",
671 device_xname(sc->sc_dev), id);
672 i = 11; /* XXX */
674 sc->sc_tgt[id].scf = 0;
675 sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset;
676 } else {
677 for (i = 0; i < NSYNCTBL; i++) {
678 p = oosiop_period(sc, synctbl[i].tp + 4,
679 (synctbl[i].scf + 1) * 5);
680 if (p >= period)
681 break;
683 if (i == NSYNCTBL) {
684 printf("%s: target %d period too large\n",
685 device_xname(sc->sc_dev), id);
686 i = NSYNCTBL - 1; /* XXX */
688 sc->sc_tgt[id].scf = synctbl[i].scf;
689 sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset;
692 xm.xm_mode |= PERIPH_CAP_SYNC;
693 xm.xm_period = period;
694 xm.xm_offset = offset;
697 scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
700 static void
701 oosiop_minphys(struct buf *bp)
704 if (bp->b_bcount > OOSIOP_MAX_XFER)
705 bp->b_bcount = OOSIOP_MAX_XFER;
706 minphys(bp);
709 static void
710 oosiop_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
711 void *arg)
713 struct scsipi_xfer *xs;
714 struct oosiop_softc *sc;
715 struct oosiop_cb *cb;
716 struct oosiop_xfer *xfer;
717 struct scsipi_xfer_mode *xm;
718 int s, err;
720 sc = device_private(chan->chan_adapter->adapt_dev);
722 switch (req) {
723 case ADAPTER_REQ_RUN_XFER:
724 xs = arg;
726 s = splbio();
727 cb = TAILQ_FIRST(&sc->sc_free_cb);
728 TAILQ_REMOVE(&sc->sc_free_cb, cb, chain);
729 splx(s);
731 cb->xs = xs;
732 cb->flags = 0;
733 cb->id = xs->xs_periph->periph_target;
734 cb->lun = xs->xs_periph->periph_lun;
735 cb->curdp = 0;
736 cb->savedp = 0;
737 xfer = cb->xfer;
739 /* Setup SCSI command buffer DMA */
740 err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, xs->cmd,
741 xs->cmdlen, NULL, ((xs->xs_control & XS_CTL_NOSLEEP) ?
742 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_WRITE);
743 if (err) {
744 printf("%s: unable to load cmd DMA map: %d",
745 device_xname(sc->sc_dev), err);
746 xs->error = XS_RESOURCE_SHORTAGE;
747 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
748 scsipi_done(xs);
749 return;
751 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
752 BUS_DMASYNC_PREWRITE);
754 /* Setup data buffer DMA */
755 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
756 err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
757 xs->data, xs->datalen, NULL,
758 ((xs->xs_control & XS_CTL_NOSLEEP) ?
759 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
760 BUS_DMA_STREAMING |
761 ((xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMA_READ :
762 BUS_DMA_WRITE));
763 if (err) {
764 printf("%s: unable to load data DMA map: %d",
765 device_xname(sc->sc_dev), err);
766 xs->error = XS_RESOURCE_SHORTAGE;
767 bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
768 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
769 scsipi_done(xs);
770 return;
772 bus_dmamap_sync(sc->sc_dmat, cb->datadma,
773 0, xs->datalen,
774 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
777 oosiop_setup_sgdma(sc, cb);
779 /* Setup msgout buffer */
780 OOSIOP_XFERMSG_SYNC(sc, cb,
781 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
782 xfer->msgout[0] = MSG_IDENTIFY(cb->lun,
783 (xs->xs_control & XS_CTL_REQSENSE) == 0);
784 cb->msgoutlen = 1;
786 if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) {
787 /* Send SDTR */
788 xfer->msgout[1] = MSG_EXTENDED;
789 xfer->msgout[2] = MSG_EXT_SDTR_LEN;
790 xfer->msgout[3] = MSG_EXT_SDTR;
791 xfer->msgout[4] = sc->sc_minperiod;
792 xfer->msgout[5] = OOSIOP_MAX_OFFSET;
793 cb->msgoutlen = 6;
794 sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG;
795 sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR;
798 xfer->status = SCSI_OOSIOP_NOSTATUS;
800 OOSIOP_XFERMSG_SYNC(sc, cb,
801 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
803 s = splbio();
805 TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain);
807 if (!sc->sc_active) {
808 /* Abort script to start selection */
809 oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
811 if (xs->xs_control & XS_CTL_POLL) {
812 /* Poll for command completion */
813 while ((xs->xs_status & XS_STS_DONE) == 0) {
814 delay(1000);
815 oosiop_intr(sc);
819 splx(s);
821 return;
823 case ADAPTER_REQ_GROW_RESOURCES:
824 return;
826 case ADAPTER_REQ_SET_XFER_MODE:
827 xm = arg;
828 if (xm->xm_mode & PERIPH_CAP_SYNC)
829 sc->sc_tgt[xm->xm_target].flags |= TGTF_SYNCNEG;
830 else
831 oosiop_set_syncparam(sc, xm->xm_target, 0, 0);
833 return;
837 static void
838 oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb)
840 struct scsipi_xfer *xs;
842 xs = cb->xs;
843 if (cb == sc->sc_curcb)
844 sc->sc_curcb = NULL;
845 if (cb == sc->sc_lastcb)
846 sc->sc_lastcb = NULL;
847 sc->sc_tgt[cb->id].nexus = NULL;
849 callout_stop(&xs->xs_callout);
851 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
852 BUS_DMASYNC_POSTWRITE);
853 bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
855 if (xs->datalen > 0) {
856 bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, xs->datalen,
857 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
858 bus_dmamap_unload(sc->sc_dmat, cb->datadma);
861 xs->status = cb->xfer->status;
862 xs->resid = 0; /* XXX */
864 if (cb->flags & CBF_SELTOUT)
865 xs->error = XS_SELTIMEOUT;
866 else if (cb->flags & CBF_TIMEOUT)
867 xs->error = XS_TIMEOUT;
868 else switch (xs->status) {
869 case SCSI_OK:
870 xs->error = XS_NOERROR;
871 break;
873 case SCSI_BUSY:
874 case SCSI_CHECK:
875 xs->error = XS_BUSY;
876 break;
877 case SCSI_OOSIOP_NOSTATUS:
878 /* the status byte was not updated, cmd was aborted. */
879 xs->error = XS_SELTIMEOUT;
880 break;
882 default:
883 xs->error = XS_RESET;
884 break;
887 scsipi_done(xs);
889 /* Put it on the free list. */
890 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
893 static void
894 oosiop_timeout(void *arg)
896 struct oosiop_cb *cb;
897 struct scsipi_periph *periph;
898 struct oosiop_softc *sc;
899 int s;
901 cb = arg;
902 periph = cb->xs->xs_periph;
903 sc = device_private(periph->periph_channel->chan_adapter->adapt_dev);
904 scsipi_printaddr(periph);
905 printf("timed out\n");
907 s = splbio();
909 cb->flags |= CBF_TIMEOUT;
910 oosiop_done(sc, cb);
912 splx(s);
915 static void
916 oosiop_reset(struct oosiop_softc *sc)
918 int i, s;
920 s = splbio();
922 /* Stop SCRIPTS processor */
923 oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
924 delay(100);
925 oosiop_write_1(sc, OOSIOP_ISTAT, 0);
927 /* Reset the chip */
928 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST);
929 delay(100);
930 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
931 delay(10000);
933 /* Set up various chip parameters */
934 oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | OOSIOP_SCNTL0_EPG);
935 oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR);
936 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
937 oosiop_write_1(sc, OOSIOP_DMODE, OOSIOP_DMODE_BL_8);
938 oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id));
939 oosiop_write_1(sc, OOSIOP_DWT, 0xff); /* Enable DMA timeout */
940 oosiop_write_1(sc, OOSIOP_CTEST7, 0);
941 oosiop_write_1(sc, OOSIOP_SXFER, 0);
943 /* Clear all interrupts */
944 (void)oosiop_read_1(sc, OOSIOP_SSTAT0);
945 (void)oosiop_read_1(sc, OOSIOP_SSTAT1);
946 (void)oosiop_read_1(sc, OOSIOP_DSTAT);
948 /* Enable interrupts */
949 oosiop_write_1(sc, OOSIOP_SIEN,
950 OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE |
951 OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR);
952 oosiop_write_1(sc, OOSIOP_DIEN,
953 OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR |
954 OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID);
956 /* Set target state to asynchronous */
957 for (i = 0; i < OOSIOP_NTGT; i++) {
958 sc->sc_tgt[i].flags = 0;
959 sc->sc_tgt[i].scf = 0;
960 sc->sc_tgt[i].sxfer = 0;
963 splx(s);
966 static void
967 oosiop_reset_bus(struct oosiop_softc *sc)
969 int s, i;
971 s = splbio();
973 /* Assert SCSI RST */
974 oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST);
975 delay(25); /* Reset hold time (25us) */
976 oosiop_write_1(sc, OOSIOP_SCNTL1, 0);
978 /* Remove all nexuses */
979 for (i = 0; i < OOSIOP_NTGT; i++) {
980 if (sc->sc_tgt[i].nexus) {
981 sc->sc_tgt[i].nexus->xfer->status =
982 SCSI_OOSIOP_NOSTATUS; /* XXX */
983 oosiop_done(sc, sc->sc_tgt[i].nexus);
987 sc->sc_curcb = NULL;
989 delay(250000); /* Reset to selection (250ms) */
991 splx(s);
995 * interrupt handler
998 oosiop_intr(struct oosiop_softc *sc)
1000 struct oosiop_cb *cb;
1001 uint32_t dcmd;
1002 int timeout;
1003 uint8_t istat, dstat, sstat0;
1005 istat = oosiop_read_1(sc, OOSIOP_ISTAT);
1007 if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0)
1008 return (0);
1010 sc->sc_nextdsp = Ent_wait_reselect;
1012 /* DMA interrupts */
1013 if (istat & OOSIOP_ISTAT_DIP) {
1014 oosiop_write_1(sc, OOSIOP_ISTAT, 0);
1016 dstat = oosiop_read_1(sc, OOSIOP_DSTAT);
1018 if (dstat & OOSIOP_DSTAT_ABRT) {
1019 sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
1020 sc->sc_scrbase - 8;
1022 if (sc->sc_nextdsp == Ent_p_resel_msgin_move &&
1023 (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) {
1024 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1025 oosiop_flush_fifo(sc);
1026 sc->sc_nextdsp += 8;
1030 if (dstat & OOSIOP_DSTAT_SSI) {
1031 sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
1032 sc->sc_scrbase;
1033 printf("%s: single step %08x\n",
1034 device_xname(sc->sc_dev), sc->sc_nextdsp);
1037 if (dstat & OOSIOP_DSTAT_SIR) {
1038 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1039 oosiop_flush_fifo(sc);
1040 oosiop_scriptintr(sc);
1043 if (dstat & OOSIOP_DSTAT_WTD) {
1044 printf("%s: DMA time out\n", device_xname(sc->sc_dev));
1045 oosiop_reset(sc);
1048 if (dstat & OOSIOP_DSTAT_IID) {
1049 dcmd = oosiop_read_4(sc, OOSIOP_DBC);
1050 if ((dcmd & 0xf8000000) == 0x48000000) {
1051 printf("%s: REQ asserted on WAIT DISCONNECT\n",
1052 device_xname(sc->sc_dev));
1053 sc->sc_nextdsp = Ent_phasedispatch; /* XXX */
1054 } else {
1055 printf("%s: invalid SCRIPTS instruction "
1056 "addr=%08x dcmd=%08x dsps=%08x\n",
1057 device_xname(sc->sc_dev),
1058 oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd,
1059 oosiop_read_4(sc, OOSIOP_DSPS));
1060 oosiop_reset(sc);
1061 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1062 oosiop_load_script(sc);
1066 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1067 oosiop_clear_fifo(sc);
1070 /* SCSI interrupts */
1071 if (istat & OOSIOP_ISTAT_SIP) {
1072 if (istat & OOSIOP_ISTAT_DIP)
1073 delay(1);
1074 sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0);
1076 if (sstat0 & OOSIOP_SSTAT0_M_A) {
1077 /* SCSI phase mismatch during MOVE operation */
1078 oosiop_phasemismatch(sc);
1079 sc->sc_nextdsp = Ent_phasedispatch;
1082 if (sstat0 & OOSIOP_SSTAT0_STO) {
1083 if (sc->sc_curcb) {
1084 sc->sc_curcb->flags |= CBF_SELTOUT;
1085 oosiop_done(sc, sc->sc_curcb);
1089 if (sstat0 & OOSIOP_SSTAT0_SGE) {
1090 printf("%s: SCSI gross error\n",
1091 device_xname(sc->sc_dev));
1092 oosiop_reset(sc);
1095 if (sstat0 & OOSIOP_SSTAT0_UDC) {
1096 /* XXX */
1097 if (sc->sc_curcb) {
1098 printf("%s: unexpected disconnect\n",
1099 device_xname(sc->sc_dev));
1100 oosiop_done(sc, sc->sc_curcb);
1104 if (sstat0 & OOSIOP_SSTAT0_RST)
1105 oosiop_reset(sc);
1107 if (sstat0 & OOSIOP_SSTAT0_PAR)
1108 printf("%s: parity error\n", device_xname(sc->sc_dev));
1111 /* Start next command if available */
1112 if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) {
1113 cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq);
1114 TAILQ_REMOVE(&sc->sc_cbq, cb, chain);
1115 sc->sc_tgt[cb->id].nexus = cb;
1117 oosiop_setup_dma(sc);
1118 oosiop_setup_syncxfer(sc);
1119 sc->sc_lastcb = cb;
1120 sc->sc_nextdsp = Ent_start_select;
1122 /* Schedule timeout */
1123 if ((cb->xs->xs_control & XS_CTL_POLL) == 0) {
1124 timeout = mstohz(cb->xs->timeout) + 1;
1125 callout_reset(&cb->xs->xs_callout, timeout,
1126 oosiop_timeout, cb);
1130 sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect);
1132 /* Restart script */
1133 oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase);
1135 return (1);
1138 static void
1139 oosiop_scriptintr(struct oosiop_softc *sc)
1141 struct oosiop_cb *cb;
1142 uint32_t icode;
1143 uint32_t dsp;
1144 int i;
1145 uint8_t sfbr, resid, resmsg;
1147 cb = sc->sc_curcb;
1148 icode = oosiop_read_4(sc, OOSIOP_DSPS);
1150 switch (icode) {
1151 case A_int_done:
1152 if (cb)
1153 oosiop_done(sc, cb);
1154 break;
1156 case A_int_msgin:
1157 if (cb)
1158 oosiop_msgin(sc, cb);
1159 break;
1161 case A_int_extmsg:
1162 /* extended message in DMA setup request */
1163 sfbr = oosiop_read_1(sc, OOSIOP_SFBR);
1164 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1165 oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr,
1166 cb->xferdma->dm_segs[0].ds_addr +
1167 offsetof(struct oosiop_xfer, msgin[2]));
1168 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
1169 sc->sc_nextdsp = Ent_rcv_extmsg;
1170 break;
1172 case A_int_resel:
1173 /* reselected */
1174 resid = oosiop_read_1(sc, OOSIOP_SFBR);
1175 for (i = 0; i < OOSIOP_NTGT; i++)
1176 if (resid & (1 << i))
1177 break;
1178 if (i == OOSIOP_NTGT) {
1179 printf("%s: missing reselection target id\n",
1180 device_xname(sc->sc_dev));
1181 break;
1183 sc->sc_resid = i;
1184 sc->sc_nextdsp = Ent_wait_resel_identify;
1186 if (cb) {
1187 /* Current command was lost arbitration */
1188 sc->sc_tgt[cb->id].nexus = NULL;
1189 TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
1190 sc->sc_curcb = NULL;
1193 break;
1195 case A_int_res_id:
1196 cb = sc->sc_tgt[sc->sc_resid].nexus;
1197 resmsg = oosiop_read_1(sc, OOSIOP_SFBR);
1198 if (MSG_ISIDENTIFY(resmsg) && cb &&
1199 (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) {
1200 sc->sc_curcb = cb;
1201 if (cb != sc->sc_lastcb) {
1202 oosiop_setup_dma(sc);
1203 oosiop_setup_syncxfer(sc);
1204 sc->sc_lastcb = cb;
1206 if (cb->curdp != cb->savedp) {
1207 cb->curdp = cb->savedp;
1208 oosiop_setup_sgdma(sc, cb);
1210 sc->sc_nextdsp = Ent_ack_msgin;
1211 } else {
1212 /* Reselection from invalid target */
1213 oosiop_reset_bus(sc);
1215 break;
1217 case A_int_resfail:
1218 /* reselect failed */
1219 break;
1221 case A_int_disc:
1222 /* disconnected */
1223 sc->sc_curcb = NULL;
1224 break;
1226 case A_int_err:
1227 /* generic error */
1228 dsp = oosiop_read_4(sc, OOSIOP_DSP);
1229 printf("%s: script error at 0x%08x\n",
1230 device_xname(sc->sc_dev), dsp - 8);
1231 sc->sc_curcb = NULL;
1232 break;
1234 case DATAIN_TRAP:
1235 printf("%s: unexpected datain\n", device_xname(sc->sc_dev));
1236 /* XXX: need to reset? */
1237 break;
1239 case DATAOUT_TRAP:
1240 printf("%s: unexpected dataout\n", device_xname(sc->sc_dev));
1241 /* XXX: need to reset? */
1242 break;
1244 default:
1245 printf("%s: unknown intr code %08x\n",
1246 device_xname(sc->sc_dev), icode);
1247 break;
1251 static void
1252 oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb)
1254 struct oosiop_xfer *xfer;
1255 int msgout;
1257 xfer = cb->xfer;
1258 sc->sc_nextdsp = Ent_ack_msgin;
1259 msgout = 0;
1261 OOSIOP_XFERMSG_SYNC(sc, cb,
1262 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1264 switch (xfer->msgin[0]) {
1265 case MSG_EXTENDED:
1266 switch (xfer->msgin[2]) {
1267 case MSG_EXT_SDTR:
1268 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
1269 /* Host initiated SDTR */
1270 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
1271 } else {
1272 /* Target initiated SDTR */
1273 if (xfer->msgin[3] < sc->sc_minperiod)
1274 xfer->msgin[3] = sc->sc_minperiod;
1275 if (xfer->msgin[4] > OOSIOP_MAX_OFFSET)
1276 xfer->msgin[4] = OOSIOP_MAX_OFFSET;
1277 xfer->msgout[0] = MSG_EXTENDED;
1278 xfer->msgout[1] = MSG_EXT_SDTR_LEN;
1279 xfer->msgout[2] = MSG_EXT_SDTR;
1280 xfer->msgout[3] = xfer->msgin[3];
1281 xfer->msgout[4] = xfer->msgin[4];
1282 cb->msgoutlen = 5;
1283 msgout = 1;
1285 oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3],
1286 (int)xfer->msgin[4]);
1287 oosiop_setup_syncxfer(sc);
1288 break;
1290 default:
1291 /* Reject message */
1292 xfer->msgout[0] = MSG_MESSAGE_REJECT;
1293 cb->msgoutlen = 1;
1294 msgout = 1;
1295 break;
1297 break;
1299 case MSG_SAVEDATAPOINTER:
1300 cb->savedp = cb->curdp;
1301 break;
1303 case MSG_RESTOREPOINTERS:
1304 if (cb->curdp != cb->savedp) {
1305 cb->curdp = cb->savedp;
1306 oosiop_setup_sgdma(sc, cb);
1308 break;
1310 case MSG_MESSAGE_REJECT:
1311 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
1312 /* SDTR rejected */
1313 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
1314 oosiop_set_syncparam(sc, cb->id, 0, 0);
1315 oosiop_setup_syncxfer(sc);
1317 break;
1319 default:
1320 /* Reject message */
1321 xfer->msgout[0] = MSG_MESSAGE_REJECT;
1322 cb->msgoutlen = 1;
1323 msgout = 1;
1326 OOSIOP_XFERMSG_SYNC(sc, cb,
1327 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1329 if (msgout) {
1330 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1331 oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen,
1332 cb->xferdma->dm_segs[0].ds_addr +
1333 offsetof(struct oosiop_xfer, msgout[0]));
1334 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
1335 sc->sc_nextdsp = Ent_sendmsg;