FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/oosiop.c
1 /* $OpenBSD: oosiop.c,v 1.36 2022/04/16 19:19:59 naddy Exp $ */
2 /* $NetBSD: oosiop.c,v 1.4 2003/10/29 17:45:55 tsutsui Exp $ */
3
4 /*
5 * Copyright (c) 2001 Shuichiro URATA. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
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 BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * NCR53C700 SCSI I/O processor (OOSIOP) driver
32 *
33 * TODO:
34 * - Better error handling.
35 * - Implement tagged queuing.
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/timeout.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/buf.h>
44 #include <sys/malloc.h>
45 #include <sys/queue.h>
46
47 #include <scsi/scsi_all.h>
48 #include <scsi/scsiconf.h>
49 #include <scsi/scsi_message.h>
50
51 #include <machine/cpu.h>
52 #include <machine/bus.h>
53
54 #include <dev/ic/oosiopreg.h>
55 #include <dev/ic/oosiopvar.h>
56
57 /* 53C700 script */
58 #include <dev/microcode/siop/oosiop.out>
59
60 int oosiop_alloc_cb(struct oosiop_softc *, int);
61
62 static __inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t);
63 static __inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t);
64 static __inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t,
65 int);
66 static __inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t,
67 bus_addr_t);
68 static __inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t,
69 bus_size_t, bus_addr_t);
70
71 void oosiop_load_script(struct oosiop_softc *);
72 void oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *);
73 void oosiop_setup_dma(struct oosiop_softc *);
74 void oosiop_flush_fifo(struct oosiop_softc *);
75 void oosiop_clear_fifo(struct oosiop_softc *);
76 void oosiop_phasemismatch(struct oosiop_softc *);
77 void oosiop_setup_syncxfer(struct oosiop_softc *);
78 void oosiop_set_syncparam(struct oosiop_softc *, int, int, int);
79 void oosiop_scsicmd(struct scsi_xfer *);
80 void oosiop_done(struct oosiop_softc *, struct oosiop_cb *);
81 void oosiop_timeout(void *);
82 void oosiop_reset(struct oosiop_softc *, int);
83 void oosiop_reset_bus(struct oosiop_softc *);
84 void oosiop_scriptintr(struct oosiop_softc *);
85 void oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *);
86 void oosiop_setup(struct oosiop_softc *, struct oosiop_cb *);
87 void oosiop_poll(struct oosiop_softc *, struct oosiop_cb *);
88 void oosiop_processintr(struct oosiop_softc *, u_int8_t);
89
90 void *oosiop_cb_alloc(void *);
91 void oosiop_cb_free(void *, void *);
92
93 /* Trap interrupt code for unexpected data I/O */
94 #define DATAIN_TRAP 0xdead0001
95 #define DATAOUT_TRAP 0xdead0002
96
97 /* Possible TP and SCF combination */
98 static const struct {
99 u_int8_t tp;
100 u_int8_t scf;
101 } synctbl[] = {
102 {0, 1}, /* SCLK / 4.0 */
103 {1, 1}, /* SCLK / 5.0 */
104 {2, 1}, /* SCLK / 6.0 */
105 {3, 1}, /* SCLK / 7.0 */
106 {1, 2}, /* SCLK / 7.5 */
107 {4, 1}, /* SCLK / 8.0 */
108 {5, 1}, /* SCLK / 9.0 */
109 {6, 1}, /* SCLK / 10.0 */
110 {3, 2}, /* SCLK / 10.5 */
111 {7, 1}, /* SCLK / 11.0 */
112 {4, 2}, /* SCLK / 12.0 */
113 {5, 2}, /* SCLK / 13.5 */
114 {3, 3}, /* SCLK / 14.0 */
115 {6, 2}, /* SCLK / 15.0 */
116 {4, 3}, /* SCLK / 16.0 */
117 {7, 2}, /* SCLK / 16.5 */
118 {5, 3}, /* SCLK / 18.0 */
119 {6, 3}, /* SCLK / 20.0 */
120 {7, 3} /* SCLK / 22.0 */
121 };
122 #define NSYNCTBL (sizeof(synctbl) / sizeof(synctbl[0]))
123
124 #define oosiop_period(sc, tp, scf) \
125 (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40)
126
127 struct cfdriver oosiop_cd = {
128 NULL, "oosiop", DV_DULL
129 };
130
131 const struct scsi_adapter oosiop_switch = {
132 oosiop_scsicmd, NULL, NULL, NULL, NULL
133 };
134
135 void *
136 oosiop_cb_alloc(void *xsc)
137 {
138 struct oosiop_softc *sc = xsc;
139 struct oosiop_cb *cb;
140
141 mtx_enter(&sc->sc_cb_mtx);
142 cb = TAILQ_FIRST(&sc->sc_free_cb);
143 if (cb)
144 TAILQ_REMOVE(&sc->sc_free_cb, cb, chain);
145 mtx_leave(&sc->sc_cb_mtx);
146
147 return (cb);
148 }
149
150 void
151 oosiop_cb_free(void *xsc, void *xcb)
152 {
153 struct oosiop_softc *sc = xsc;
154 struct oosiop_cb *cb = xcb;
155
156 mtx_enter(&sc->sc_cb_mtx);
157 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
158 mtx_leave(&sc->sc_cb_mtx);
159 }
160
161 void
162 oosiop_attach(struct oosiop_softc *sc)
163 {
164 struct scsibus_attach_args saa;
165 bus_size_t scrsize;
166 bus_dma_segment_t seg;
167 struct oosiop_cb *cb;
168 int err, i, nseg;
169
170 /*
171 * Allocate DMA-safe memory for the script and map it.
172 */
173 scrsize = round_page(sizeof(oosiop_script));
174 err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1,
175 &nseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO);
176 if (err) {
177 printf(": failed to allocate script memory, err=%d\n", err);
178 return;
179 }
180 err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize,
181 (caddr_t *)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
182 if (err) {
183 printf(": failed to map script memory, err=%d\n", err);
184 return;
185 }
186 err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0,
187 BUS_DMA_NOWAIT, &sc->sc_scrdma);
188 if (err) {
189 printf(": failed to create script map, err=%d\n", err);
190 return;
191 }
192 err = bus_dmamap_load_raw(sc->sc_dmat, sc->sc_scrdma,
193 &seg, nseg, scrsize, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
194 if (err) {
195 printf(": failed to load script map, err=%d\n", err);
196 return;
197 }
198 sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr;
199
200 /* Initialize command block array */
201 TAILQ_INIT(&sc->sc_free_cb);
202 TAILQ_INIT(&sc->sc_cbq);
203 if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0)
204 return;
205
206 /* Use first cb to reselection msgin buffer */
207 cb = TAILQ_FIRST(&sc->sc_free_cb);
208 sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr +
209 offsetof(struct oosiop_xfer, msgin[0]);
210
211 for (i = 0; i < OOSIOP_NTGT; i++) {
212 sc->sc_tgt[i].nexus = NULL;
213 sc->sc_tgt[i].flags = 0;
214 }
215
216 /* Setup asynchronous clock divisor parameters */
217 if (sc->sc_freq <= 25000000) {
218 sc->sc_ccf = 10;
219 sc->sc_dcntl = OOSIOP_DCNTL_CF_1;
220 } else if (sc->sc_freq <= 37500000) {
221 sc->sc_ccf = 15;
222 sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5;
223 } else if (sc->sc_freq <= 50000000) {
224 sc->sc_ccf = 20;
225 sc->sc_dcntl = OOSIOP_DCNTL_CF_2;
226 } else {
227 sc->sc_ccf = 30;
228 sc->sc_dcntl = OOSIOP_DCNTL_CF_3;
229 }
230
231 if (sc->sc_chip == OOSIOP_700)
232 sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf);
233 else
234 sc->sc_minperiod = oosiop_period(sc, 4, 10);
235
236 if (sc->sc_minperiod < 25)
237 sc->sc_minperiod = 25; /* limit to 10MB/s */
238
239 mtx_init(&sc->sc_cb_mtx, IPL_BIO);
240 scsi_iopool_init(&sc->sc_iopool, sc, oosiop_cb_alloc, oosiop_cb_free);
241
242 printf(": NCR53C700%s rev %d, %dMHz\n",
243 sc->sc_chip == OOSIOP_700_66 ? "-66" : "",
244 oosiop_read_1(sc, OOSIOP_CTEST7) >> 4,
245 sc->sc_freq / 1000000);
246 /*
247 * Reset all
248 */
249 oosiop_reset(sc, TRUE);
250 oosiop_reset_bus(sc);
251
252 /*
253 * Start SCRIPTS processor
254 */
255 oosiop_load_script(sc);
256 sc->sc_active = 0;
257 oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect);
258
259 saa.saa_adapter = &oosiop_switch;
260 saa.saa_adapter_softc = sc;
261 saa.saa_adapter_buswidth = OOSIOP_NTGT;
262 saa.saa_adapter_target = sc->sc_id;
263 saa.saa_luns = 8;
264 saa.saa_openings = 1; /* XXX */
265 saa.saa_pool = &sc->sc_iopool;
266 saa.saa_quirks = ADEV_NODOORLOCK;
267 saa.saa_flags = 0;
268 saa.saa_wwpn = saa.saa_wwnn = 0;
269
270 config_found(&sc->sc_dev, &saa, scsiprint);
271 }
272
273 int
274 oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
275 {
276 struct oosiop_cb *cb;
277 struct oosiop_xfer *xfer;
278 bus_size_t xfersize;
279 bus_dma_segment_t seg;
280 int i, s, err, nseg;
281
282 /*
283 * Allocate oosiop_cb.
284 */
285 cb = mallocarray(ncb, sizeof(*cb), M_DEVBUF, M_NOWAIT | M_ZERO);
286 if (cb == NULL) {
287 printf(": failed to allocate cb memory\n");
288 return (ENOMEM);
289 }
290
291 /*
292 * Allocate DMA-safe memory for the oosiop_xfer and map it.
293 */
294 xfersize = sizeof(struct oosiop_xfer) * ncb;
295 err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1,
296 &nseg, BUS_DMA_NOWAIT);
297 if (err) {
298 printf(": failed to allocate xfer block memory, err=%d\n", err);
299 return (err);
300 }
301 err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize,
302 (caddr_t *)(void *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
303 if (err) {
304 printf(": failed to map xfer block memory, err=%d\n", err);
305 return (err);
306 }
307
308 /* Initialize each command block */
309 for (i = 0; i < ncb; i++) {
310 err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
311 0, BUS_DMA_NOWAIT, &cb->cmddma);
312 if (err) {
313 printf(": failed to create cmddma map, err=%d\n", err);
314 return (err);
315 }
316
317 err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
318 OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
319 &cb->datadma);
320 if (err) {
321 printf(": failed to create datadma map, err=%d\n", err);
322 return (err);
323 }
324
325 err = bus_dmamap_create(sc->sc_dmat,
326 sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
327 0, BUS_DMA_NOWAIT, &cb->xferdma);
328 if (err) {
329 printf(": failed to create xfer block map, err=%d\n",
330 err);
331 return (err);
332 }
333 err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer,
334 sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
335 if (err) {
336 printf(": failed to load xfer block, err=%d\n", err);
337 return (err);
338 }
339
340 cb->xfer = xfer;
341
342 s = splbio();
343 TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
344 splx(s);
345
346 cb++;
347 xfer++;
348 }
349
350 return (0);
351 }
352
353 static __inline void
354 oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr)
355 {
356 u_int32_t dcmd;
357 int32_t dsps;
358
359 dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
360 dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
361
362 /* convert relative to absolute */
363 if (dcmd & 0x04000000) {
364 dcmd &= ~0x04000000;
365 #if 0
366 /*
367 * sign extension isn't needed here because
368 * ncr53cxxx.c generates 32 bit dsps.
369 */
370 dsps <<= 8;
371 dsps >>= 8;
372 #endif
373 sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
374 dsps += addr + 8;
375 }
376
377 sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
378 }
379
380 static __inline void
381 oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr)
382 {
383 u_int32_t dcmd;
384 int32_t dsps;
385
386 dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
387 dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
388
389 /* convert relative to absolute */
390 if (dcmd & 0x00800000) {
391 dcmd &= ~0x00800000;
392 sc->sc_scr[addr / 4] = htole32(dcmd);
393 #if 0
394 /*
395 * sign extension isn't needed here because
396 * ncr53cxxx.c generates 32 bit dsps.
397 */
398 dsps <<= 8;
399 dsps >>= 8;
400 #endif
401 dsps += addr + 8;
402 }
403
404 sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
405 }
406
407 static __inline void
408 oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id)
409 {
410 u_int32_t dcmd;
411
412 dcmd = letoh32(sc->sc_scr[addr / 4]);
413 dcmd &= 0xff00ffff;
414 dcmd |= 0x00010000 << id;
415 sc->sc_scr[addr / 4] = htole32(dcmd);
416 }
417
418 static __inline void
419 oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst)
420 {
421
422 sc->sc_scr[addr / 4 + 1] = htole32(dst);
423 }
424
425 static __inline void
426 oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc,
427 bus_addr_t dsps)
428 {
429 u_int32_t dcmd;
430
431 dcmd = letoh32(sc->sc_scr[addr / 4]);
432 dcmd &= 0xff000000;
433 dcmd |= dbc & 0x00ffffff;
434 sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
435 sc->sc_scr[addr / 4 + 1] = htole32(dsps);
436 }
437
438 void
439 oosiop_load_script(struct oosiop_softc *sc)
440 {
441 int i;
442
443 /* load script */
444 for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++)
445 sc->sc_scr[i] = htole32(oosiop_script[i]);
446
447 /* relocate script */
448 for (i = 0; i < (sizeof(oosiop_script) / 8); i++) {
449 switch (oosiop_script[i * 2] >> 27) {
450 case 0x08: /* select */
451 case 0x0a: /* wait reselect */
452 oosiop_relocate_io(sc, i * 8);
453 break;
454 case 0x10: /* jump */
455 case 0x11: /* call */
456 oosiop_relocate_tc(sc, i * 8);
457 break;
458 }
459 }
460
461 oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf);
462 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
463 }
464
465 void
466 oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb)
467 {
468 struct oosiop_xfer *xfer = cb->xfer;
469 struct scsi_xfer *xs = cb->xs;
470 int i, n, off;
471
472 OOSIOP_XFERSCR_SYNC(sc, cb,
473 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
474
475 off = cb->curdp;
476
477 if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
478 /* Find start segment */
479 for (i = 0; i < cb->datadma->dm_nsegs; i++) {
480 if (off < cb->datadma->dm_segs[i].ds_len)
481 break;
482 off -= cb->datadma->dm_segs[i].ds_len;
483 }
484
485 /* build MOVE block */
486 if (xs->flags & SCSI_DATA_IN) {
487 n = 0;
488 while (i < cb->datadma->dm_nsegs) {
489 xfer->datain_scr[n * 2 + 0] =
490 htole32(0x09000000 |
491 (cb->datadma->dm_segs[i].ds_len - off));
492 xfer->datain_scr[n * 2 + 1] =
493 htole32(cb->datadma->dm_segs[i].ds_addr +
494 off);
495 n++;
496 i++;
497 off = 0;
498 }
499 xfer->datain_scr[n * 2 + 0] = htole32(0x80080000);
500 xfer->datain_scr[n * 2 + 1] =
501 htole32(sc->sc_scrbase + Ent_phasedispatch);
502 }
503 if (xs->flags & SCSI_DATA_OUT) {
504 n = 0;
505 while (i < cb->datadma->dm_nsegs) {
506 xfer->dataout_scr[n * 2 + 0] =
507 htole32(0x08000000 |
508 (cb->datadma->dm_segs[i].ds_len - off));
509 xfer->dataout_scr[n * 2 + 1] =
510 htole32(cb->datadma->dm_segs[i].ds_addr +
511 off);
512 n++;
513 i++;
514 off = 0;
515 }
516 xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000);
517 xfer->dataout_scr[n * 2 + 1] =
518 htole32(sc->sc_scrbase + Ent_phasedispatch);
519 }
520 }
521 if ((xs->flags & SCSI_DATA_IN) == 0) {
522 xfer->datain_scr[0] = htole32(0x98080000);
523 xfer->datain_scr[1] = htole32(DATAIN_TRAP);
524 }
525 if ((xs->flags & SCSI_DATA_OUT) == 0) {
526 xfer->dataout_scr[0] = htole32(0x98080000);
527 xfer->dataout_scr[1] = htole32(DATAOUT_TRAP);
528 }
529 OOSIOP_XFERSCR_SYNC(sc, cb,
530 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
531 }
532
533 /*
534 * Setup DMA pointer into script.
535 */
536 void
537 oosiop_setup_dma(struct oosiop_softc *sc)
538 {
539 struct oosiop_cb *cb;
540 bus_addr_t xferbase;
541
542 cb = sc->sc_curcb;
543 xferbase = cb->xferdma->dm_segs[0].ds_addr;
544
545 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
546
547 oosiop_fixup_select(sc, Ent_p_select, cb->id);
548 oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase +
549 offsetof(struct oosiop_xfer, datain_scr[0]));
550 oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase +
551 offsetof(struct oosiop_xfer, dataout_scr[0]));
552 oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase +
553 offsetof(struct oosiop_xfer, msgin[0]));
554 oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase +
555 offsetof(struct oosiop_xfer, msgin[1]));
556 oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase +
557 offsetof(struct oosiop_xfer, msgout[0]));
558 oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase +
559 offsetof(struct oosiop_xfer, status));
560 oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->cmdlen,
561 cb->cmddma->dm_segs[0].ds_addr);
562
563 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
564 }
565
566 void
567 oosiop_flush_fifo(struct oosiop_softc *sc)
568 {
569
570 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
571 OOSIOP_DFIFO_FLF);
572 while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
573 OOSIOP_CTEST1_FMT)
574 ;
575 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
576 ~OOSIOP_DFIFO_FLF);
577 }
578
579 void
580 oosiop_clear_fifo(struct oosiop_softc *sc)
581 {
582
583 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
584 OOSIOP_DFIFO_CLF);
585 while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
586 OOSIOP_CTEST1_FMT)
587 ;
588 oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
589 ~OOSIOP_DFIFO_CLF);
590 }
591
592 void
593 oosiop_phasemismatch(struct oosiop_softc *sc)
594 {
595 struct oosiop_cb *cb;
596 u_int32_t dsp, dbc, n, i, len;
597 u_int8_t dfifo, sstat1;
598
599 cb = sc->sc_curcb;
600 if (cb == NULL)
601 return;
602
603 dsp = oosiop_read_4(sc, OOSIOP_DSP);
604 dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX;
605 len = 0;
606
607 n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8;
608 if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) &&
609 n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) {
610 n -= offsetof(struct oosiop_xfer, datain_scr[0]);
611 n >>= 3;
612 OOSIOP_DINSCR_SYNC(sc, cb,
613 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
614 for (i = 0; i <= n; i++)
615 len += letoh32(cb->xfer->datain_scr[i * 2]) &
616 0x00ffffff;
617 OOSIOP_DINSCR_SYNC(sc, cb,
618 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
619 /* All data in the chip are already flushed */
620 } else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) &&
621 n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) {
622 n -= offsetof(struct oosiop_xfer, dataout_scr[0]);
623 n >>= 3;
624 OOSIOP_DOUTSCR_SYNC(sc, cb,
625 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
626 for (i = 0; i <= n; i++)
627 len += letoh32(cb->xfer->dataout_scr[i * 2]) &
628 0x00ffffff;
629 OOSIOP_DOUTSCR_SYNC(sc, cb,
630 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
631
632 dfifo = oosiop_read_1(sc, OOSIOP_DFIFO);
633 dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) &
634 OOSIOP_DFIFO_BO;
635
636 sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1);
637 if (sstat1 & OOSIOP_SSTAT1_OLF)
638 dbc++;
639 if ((sc->sc_tgt[cb->id].sxfer != 0) &&
640 (sstat1 & OOSIOP_SSTAT1_ORF) != 0)
641 dbc++;
642
643 oosiop_clear_fifo(sc);
644 } else {
645 printf("%s: phase mismatch addr=%08x\n", sc->sc_dev.dv_xname,
646 oosiop_read_4(sc, OOSIOP_DSP) - 8);
647 oosiop_clear_fifo(sc);
648 return;
649 }
650
651 len -= dbc;
652 if (len) {
653 cb->curdp += len;
654 oosiop_setup_sgdma(sc, cb);
655 }
656 }
657
658 void
659 oosiop_setup_syncxfer(struct oosiop_softc *sc)
660 {
661 int id;
662
663 id = sc->sc_curcb->id;
664 if (sc->sc_chip != OOSIOP_700)
665 oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf);
666
667 oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer);
668 }
669
670 void
671 oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset)
672 {
673 int i, p;
674
675 printf("%s: target %d now using 8 bit ", sc->sc_dev.dv_xname, id);
676
677 if (offset == 0) {
678 /* Asynchronous */
679 sc->sc_tgt[id].scf = 0;
680 sc->sc_tgt[id].sxfer = 0;
681 printf("asynchronous");
682 } else {
683 /* Synchronous */
684 if (sc->sc_chip == OOSIOP_700) {
685 for (i = 4; i < 12; i++) {
686 p = oosiop_period(sc, i, sc->sc_ccf);
687 if (p >= period)
688 break;
689 }
690 if (i == 12) {
691 printf("%s: target %d period too large\n",
692 sc->sc_dev.dv_xname, id);
693 i = 11; /* XXX */
694 }
695 sc->sc_tgt[id].scf = 0;
696 sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset;
697 } else {
698 for (i = 0; i < NSYNCTBL; i++) {
699 p = oosiop_period(sc, synctbl[i].tp + 4,
700 (synctbl[i].scf + 1) * 5);
701 if (p >= period)
702 break;
703 }
704 if (i == NSYNCTBL) {
705 printf("%s: target %d period too large\n",
706 sc->sc_dev.dv_xname, id);
707 i = NSYNCTBL - 1; /* XXX */
708 }
709 sc->sc_tgt[id].scf = synctbl[i].scf;
710 sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset;
711 }
712 /* XXX print actual ns period... */
713 printf("synchronous");
714 }
715 printf(" xfers\n");
716 }
717
718 void
719 oosiop_scsicmd(struct scsi_xfer *xs)
720 {
721 struct oosiop_softc *sc;
722 struct oosiop_cb *cb;
723 struct oosiop_xfer *xfer;
724 int s, err;
725 int dopoll;
726
727 sc = xs->sc_link->bus->sb_adapter_softc;
728
729 s = splbio();
730
731 cb = xs->io;
732
733 cb->xs = xs;
734 cb->xsflags = xs->flags;
735 cb->cmdlen = xs->cmdlen;
736 cb->datalen = 0;
737 cb->flags = 0;
738 cb->id = xs->sc_link->target;
739 cb->lun = xs->sc_link->lun;
740 xfer = cb->xfer;
741
742 /* Setup SCSI command buffer DMA */
743 err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, &xs->cmd,
744 xs->cmdlen, NULL, ((xs->flags & SCSI_NOSLEEP) ?
745 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
746 BUS_DMA_STREAMING | BUS_DMA_WRITE);
747 if (err) {
748 printf("%s: unable to load cmd DMA map: %d",
749 sc->sc_dev.dv_xname, err);
750 splx(s);
751 xs->error = XS_DRIVER_STUFFUP;
752 scsi_done(xs);
753 return;
754 }
755 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
756 BUS_DMASYNC_PREWRITE);
757
758 /* Setup data buffer DMA */
759 if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
760 cb->datalen = xs->datalen;
761 err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
762 xs->data, xs->datalen, NULL,
763 ((xs->flags & SCSI_NOSLEEP) ?
764 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
765 BUS_DMA_STREAMING |
766 ((xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ :
767 BUS_DMA_WRITE));
768 if (err) {
769 printf("%s: unable to load data DMA map: %d",
770 sc->sc_dev.dv_xname, err);
771 bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
772 splx(s);
773 xs->error = XS_DRIVER_STUFFUP;
774 scsi_done(xs);
775 return;
776 }
777 bus_dmamap_sync(sc->sc_dmat, cb->datadma,
778 0, xs->datalen,
779 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
780 }
781
782 xfer->status = SCSI_OOSIOP_NOSTATUS;
783
784 /*
785 * Always initialize timeout so it does not contain trash
786 * that could confuse timeout_del().
787 */
788 timeout_set(&xs->stimeout, oosiop_timeout, cb);
789
790 if (xs->flags & SCSI_POLL)
791 dopoll = 1;
792 else {
793 dopoll = 0;
794 /* start expire timer */
795 timeout_add_msec(&xs->stimeout, xs->timeout);
796 }
797
798 splx(s);
799
800 oosiop_setup(sc, cb);
801
802 TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain);
803
804 if (!sc->sc_active) {
805 /* Abort script to start selection */
806 oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
807 }
808 if (dopoll)
809 oosiop_poll(sc, cb);
810 }
811
812 void
813 oosiop_poll(struct oosiop_softc *sc, struct oosiop_cb *cb)
814 {
815 struct scsi_xfer *xs = cb->xs;
816 int i, s, to;
817 u_int8_t istat;
818
819 s = splbio();
820 to = xs->timeout / 1000;
821 for (;;) {
822 i = 1000;
823 while (((istat = oosiop_read_1(sc, OOSIOP_ISTAT)) &
824 (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) {
825 if (i <= 0) {
826 i = 1000;
827 to--;
828 if (to <= 0) {
829 oosiop_reset(sc, TRUE);
830 splx(s);
831 return;
832 }
833 }
834 delay(1000);
835 i--;
836 }
837 oosiop_processintr(sc, istat);
838
839 if (xs->flags & ITSDONE)
840 break;
841 }
842
843 splx(s);
844 }
845
846 void
847 oosiop_setup(struct oosiop_softc *sc, struct oosiop_cb *cb)
848 {
849 struct oosiop_xfer *xfer = cb->xfer;
850
851 cb->curdp = 0;
852 cb->savedp = 0;
853
854 oosiop_setup_sgdma(sc, cb);
855
856 /* Setup msgout buffer */
857 OOSIOP_XFERMSG_SYNC(sc, cb,
858 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
859 xfer->msgout[0] = MSG_IDENTIFY(cb->lun,
860 (cb->xs->cmd.opcode != REQUEST_SENSE));
861 cb->msgoutlen = 1;
862
863 if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) {
864 sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG;
865 /* Send SDTR */
866 xfer->msgout[1] = MSG_EXTENDED;
867 xfer->msgout[2] = MSG_EXT_SDTR_LEN;
868 xfer->msgout[3] = MSG_EXT_SDTR;
869 xfer->msgout[4] = sc->sc_minperiod;
870 xfer->msgout[5] = OOSIOP_MAX_OFFSET;
871 cb->msgoutlen = 6;
872 sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR;
873 }
874
875 OOSIOP_XFERMSG_SYNC(sc, cb,
876 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
877 }
878
879 void
880 oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb)
881 {
882 struct scsi_xfer *xs;
883 struct scsi_link *periph;
884 int autosense;
885
886 xs = cb->xs;
887 periph = xs->sc_link;
888
889 /*
890 * Record if this is the completion of an auto sense
891 * scsi command, and then reset the flag so we don't loop
892 * when such a command fails or times out.
893 */
894 autosense = cb->flags & CBF_AUTOSENSE;
895 cb->flags &= ~CBF_AUTOSENSE;
896
897 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
898 BUS_DMASYNC_POSTWRITE);
899 bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
900
901 if (cb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
902 bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, cb->datalen,
903 (cb->xsflags & SCSI_DATA_IN) ?
904 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
905 bus_dmamap_unload(sc->sc_dmat, cb->datadma);
906 }
907
908 timeout_del(&xs->stimeout);
909
910 xs->status = cb->xfer->status;
911
912 if (cb->flags & CBF_SELTOUT)
913 xs->error = XS_SELTIMEOUT;
914 else if (cb->flags & CBF_TIMEOUT)
915 xs->error = XS_TIMEOUT;
916 else switch (xs->status) {
917 case SCSI_OK:
918 if (autosense == 0)
919 xs->error = XS_NOERROR;
920 else
921 xs->error = XS_SENSE;
922 break;
923
924 case SCSI_BUSY:
925 xs->error = XS_BUSY;
926 break;
927 case SCSI_CHECK:
928 #ifdef notyet
929 if (autosense == 0)
930 cb->flags |= CBF_AUTOSENSE;
931 else
932 #endif
933 xs->error = XS_DRIVER_STUFFUP;
934 break;
935 case SCSI_OOSIOP_NOSTATUS:
936 /* the status byte was not updated, cmd was aborted. */
937 xs->error = XS_SELTIMEOUT;
938 break;
939
940 default:
941 xs->error = XS_RESET;
942 break;
943 }
944
945 if ((cb->flags & CBF_AUTOSENSE) == 0) {
946 /* Put it on the free list. */
947 FREE:
948 xs->resid = 0;
949 scsi_done(xs);
950
951 if (cb == sc->sc_curcb)
952 sc->sc_curcb = NULL;
953 if (cb == sc->sc_lastcb)
954 sc->sc_lastcb = NULL;
955 sc->sc_tgt[cb->id].nexus = NULL;
956 } else {
957 /* Set up REQUEST_SENSE command */
958 struct scsi_sense *cmd = (struct scsi_sense *)&xs->cmd;
959 int err;
960
961 bzero(cmd, sizeof(*cmd));
962 cmd->opcode = REQUEST_SENSE;
963 cmd->byte2 = xs->sc_link->lun << 5;
964 cb->cmdlen = cmd->length = sizeof(xs->sense);
965
966 cb->xsflags &= SCSI_POLL | SCSI_NOSLEEP;
967 cb->xsflags |= SCSI_DATA_IN;
968 cb->datalen = sizeof xs->sense;
969
970 /* Setup SCSI command buffer DMA */
971 err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, cmd,
972 cb->cmdlen, NULL,
973 BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE);
974 if (err) {
975 printf("%s: unable to load REQUEST_SENSE cmd DMA map: %d",
976 sc->sc_dev.dv_xname, err);
977 xs->error = XS_DRIVER_STUFFUP;
978 goto FREE;
979 }
980 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
981 BUS_DMASYNC_PREWRITE);
982
983 /* Setup data buffer DMA */
984 err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
985 &xs->sense, sizeof(xs->sense), NULL,
986 BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_READ);
987 if (err) {
988 printf("%s: unable to load REQUEST_SENSE data DMA map: %d",
989 sc->sc_dev.dv_xname, err);
990 xs->error = XS_DRIVER_STUFFUP;
991 bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
992 goto FREE;
993 }
994 bus_dmamap_sync(sc->sc_dmat, cb->datadma,
995 0, sizeof(xs->sense), BUS_DMASYNC_PREREAD);
996
997 oosiop_setup(sc, cb);
998
999 TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
1000 if ((cb->xs->flags & SCSI_POLL) == 0) {
1001 /* start expire timer */
1002 timeout_add_msec(&xs->stimeout, xs->timeout);
1003 }
1004 }
1005 }
1006
1007 void
1008 oosiop_timeout(void *arg)
1009 {
1010 struct oosiop_cb *cb = arg;
1011 struct scsi_xfer *xs = cb->xs;
1012 struct oosiop_softc *sc = xs->sc_link->bus->sb_adapter_softc;
1013 int s;
1014
1015 sc_print_addr(xs->sc_link);
1016 printf("command 0x%02x timeout on xs %p\n", xs->cmd.opcode, xs);
1017
1018 s = splbio();
1019
1020 oosiop_reset_bus(sc);
1021
1022 cb->flags |= CBF_TIMEOUT;
1023 oosiop_done(sc, cb);
1024
1025 splx(s);
1026 }
1027
1028 void
1029 oosiop_reset(struct oosiop_softc *sc, int allflags)
1030 {
1031 int i, s;
1032
1033 s = splbio();
1034
1035 /* Stop SCRIPTS processor */
1036 oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
1037 delay(100);
1038 oosiop_write_1(sc, OOSIOP_ISTAT, 0);
1039
1040 /* Reset the chip */
1041 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST);
1042 delay(100);
1043 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
1044 delay(10000);
1045
1046 /* Set up various chip parameters */
1047 oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | sc->sc_scntl0);
1048 oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR);
1049 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
1050 oosiop_write_1(sc, OOSIOP_DMODE, sc->sc_dmode);
1051 oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id));
1052 oosiop_write_1(sc, OOSIOP_DWT, sc->sc_dwt);
1053 oosiop_write_1(sc, OOSIOP_CTEST7, sc->sc_ctest7);
1054 oosiop_write_1(sc, OOSIOP_SXFER, 0);
1055
1056 /* Clear all interrupts */
1057 (void)oosiop_read_1(sc, OOSIOP_SSTAT0);
1058 (void)oosiop_read_1(sc, OOSIOP_SSTAT1);
1059 (void)oosiop_read_1(sc, OOSIOP_DSTAT);
1060
1061 /* Enable interrupts */
1062 oosiop_write_1(sc, OOSIOP_SIEN,
1063 OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE |
1064 OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR);
1065 oosiop_write_1(sc, OOSIOP_DIEN,
1066 OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR |
1067 OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID);
1068
1069 /* Set target state to asynchronous */
1070 for (i = 0; i < OOSIOP_NTGT; i++) {
1071 if (allflags)
1072 sc->sc_tgt[i].flags = 0;
1073 else
1074 sc->sc_tgt[i].flags |= TGTF_SYNCNEG;
1075 sc->sc_tgt[i].scf = 0;
1076 sc->sc_tgt[i].sxfer = 0;
1077 }
1078
1079 splx(s);
1080 }
1081
1082 void
1083 oosiop_reset_bus(struct oosiop_softc *sc)
1084 {
1085 int s, i;
1086
1087 s = splbio();
1088
1089 /* Assert SCSI RST */
1090 oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST);
1091 delay(25); /* Reset hold time (25us) */
1092 oosiop_write_1(sc, OOSIOP_SCNTL1, 0);
1093
1094 /* Remove all nexuses */
1095 for (i = 0; i < OOSIOP_NTGT; i++) {
1096 if (sc->sc_tgt[i].nexus) {
1097 sc->sc_tgt[i].nexus->xfer->status =
1098 SCSI_OOSIOP_NOSTATUS; /* XXX */
1099 oosiop_done(sc, sc->sc_tgt[i].nexus);
1100 }
1101 }
1102
1103 sc->sc_curcb = NULL;
1104
1105 delay(250000); /* Reset to selection (250ms) */
1106
1107 splx(s);
1108 }
1109
1110 /*
1111 * interrupt handler
1112 */
1113 int
1114 oosiop_intr(struct oosiop_softc *sc)
1115 {
1116 u_int8_t istat;
1117
1118 istat = oosiop_read_1(sc, OOSIOP_ISTAT);
1119
1120 if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0)
1121 return (0);
1122
1123 oosiop_processintr(sc, istat);
1124 return (1);
1125 }
1126
1127 void
1128 oosiop_processintr(struct oosiop_softc *sc, u_int8_t istat)
1129 {
1130 struct oosiop_cb *cb;
1131 u_int32_t dcmd;
1132 u_int8_t dstat, sstat0;
1133
1134 sc->sc_nextdsp = Ent_wait_reselect;
1135
1136 /* DMA interrupts */
1137 if (istat & OOSIOP_ISTAT_DIP) {
1138 oosiop_write_1(sc, OOSIOP_ISTAT, 0);
1139
1140 dstat = oosiop_read_1(sc, OOSIOP_DSTAT);
1141
1142 if (dstat & OOSIOP_DSTAT_ABRT) {
1143 sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
1144 sc->sc_scrbase - 8;
1145
1146 if (sc->sc_nextdsp == Ent_p_resel_msgin_move &&
1147 (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) {
1148 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1149 oosiop_flush_fifo(sc);
1150 sc->sc_nextdsp += 8;
1151 }
1152 }
1153
1154 if (dstat & OOSIOP_DSTAT_SSI) {
1155 sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
1156 sc->sc_scrbase;
1157 printf("%s: single step %08x\n", sc->sc_dev.dv_xname,
1158 sc->sc_nextdsp);
1159 }
1160
1161 if (dstat & OOSIOP_DSTAT_SIR) {
1162 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1163 oosiop_flush_fifo(sc);
1164 oosiop_scriptintr(sc);
1165 }
1166
1167 if (dstat & OOSIOP_DSTAT_WTD) {
1168 printf("%s: DMA time out\n", sc->sc_dev.dv_xname);
1169 oosiop_reset(sc, TRUE);
1170 }
1171
1172 if (dstat & OOSIOP_DSTAT_IID) {
1173 dcmd = oosiop_read_4(sc, OOSIOP_DBC);
1174 if ((dcmd & 0xf8000000) == 0x48000000) {
1175 printf("%s: REQ asserted on WAIT DISCONNECT\n",
1176 sc->sc_dev.dv_xname);
1177 sc->sc_nextdsp = Ent_phasedispatch; /* XXX */
1178 } else {
1179 printf("%s: invalid SCRIPTS instruction "
1180 "addr=%08x dcmd=%08x dsps=%08x\n",
1181 sc->sc_dev.dv_xname,
1182 oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd,
1183 oosiop_read_4(sc, OOSIOP_DSPS));
1184 oosiop_reset(sc, TRUE);
1185 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1186 oosiop_load_script(sc);
1187 }
1188 }
1189
1190 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1191 oosiop_clear_fifo(sc);
1192 }
1193
1194 /* SCSI interrupts */
1195 if (istat & OOSIOP_ISTAT_SIP) {
1196 if (istat & OOSIOP_ISTAT_DIP)
1197 delay(1);
1198 sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0);
1199
1200 if (sstat0 & OOSIOP_SSTAT0_M_A) {
1201 /* SCSI phase mismatch during MOVE operation */
1202 oosiop_phasemismatch(sc);
1203 sc->sc_nextdsp = Ent_phasedispatch;
1204 }
1205
1206 if (sstat0 & OOSIOP_SSTAT0_STO) {
1207 if (sc->sc_curcb) {
1208 sc->sc_curcb->flags |= CBF_SELTOUT;
1209 oosiop_done(sc, sc->sc_curcb);
1210 }
1211 }
1212
1213 if (sstat0 & OOSIOP_SSTAT0_SGE) {
1214 printf("%s: SCSI gross error\n", sc->sc_dev.dv_xname);
1215 oosiop_reset(sc, TRUE);
1216 }
1217
1218 if (sstat0 & OOSIOP_SSTAT0_UDC) {
1219 /* XXX */
1220 if (sc->sc_curcb) {
1221 printf("%s: unexpected disconnect\n",
1222 sc->sc_dev.dv_xname);
1223 oosiop_done(sc, sc->sc_curcb);
1224 }
1225 }
1226
1227 if (sstat0 & OOSIOP_SSTAT0_RST) {
1228 /*
1229 * This may happen during sync request negotiation;
1230 * be sure not to reset TGTF_WAITSDTR in that case.
1231 */
1232 oosiop_reset(sc, FALSE);
1233 }
1234
1235 if (sstat0 & OOSIOP_SSTAT0_PAR)
1236 printf("%s: parity error\n", sc->sc_dev.dv_xname);
1237 }
1238
1239 /* Start next command if available */
1240 if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) {
1241 cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq);
1242 TAILQ_REMOVE(&sc->sc_cbq, cb, chain);
1243 sc->sc_tgt[cb->id].nexus = cb;
1244
1245 oosiop_setup_dma(sc);
1246 oosiop_setup_syncxfer(sc);
1247 sc->sc_lastcb = cb;
1248 sc->sc_nextdsp = Ent_start_select;
1249
1250 /* Schedule timeout */
1251 if ((cb->xs->flags & SCSI_POLL) == 0) {
1252 /* start expire timer */
1253 timeout_add_msec(&cb->xs->stimeout, cb->xs->timeout);
1254 }
1255 }
1256
1257 sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect);
1258
1259 /* Restart script */
1260 oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase);
1261 }
1262
1263 void
1264 oosiop_scriptintr(struct oosiop_softc *sc)
1265 {
1266 struct oosiop_cb *cb;
1267 u_int32_t icode;
1268 u_int32_t dsp;
1269 int i;
1270 u_int8_t sfbr, resid, resmsg;
1271
1272 cb = sc->sc_curcb;
1273 icode = oosiop_read_4(sc, OOSIOP_DSPS);
1274
1275 switch (icode) {
1276 case A_int_done:
1277 if (cb)
1278 oosiop_done(sc, cb);
1279 break;
1280
1281 case A_int_msgin:
1282 if (cb)
1283 oosiop_msgin(sc, cb);
1284 break;
1285
1286 case A_int_extmsg:
1287 /* extended message in DMA setup request */
1288 sfbr = oosiop_read_1(sc, OOSIOP_SFBR);
1289 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1290 oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr,
1291 cb->xferdma->dm_segs[0].ds_addr +
1292 offsetof(struct oosiop_xfer, msgin[2]));
1293 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
1294 sc->sc_nextdsp = Ent_rcv_extmsg;
1295 break;
1296
1297 case A_int_resel:
1298 /* reselected */
1299 resid = oosiop_read_1(sc, OOSIOP_SFBR);
1300 for (i = 0; i < OOSIOP_NTGT; i++)
1301 if (resid & (1 << i))
1302 break;
1303 if (i == OOSIOP_NTGT) {
1304 printf("%s: missing reselection target id\n",
1305 sc->sc_dev.dv_xname);
1306 break;
1307 }
1308 sc->sc_resid = i;
1309 sc->sc_nextdsp = Ent_wait_resel_identify;
1310
1311 if (cb) {
1312 /* Current command was lost arbitration */
1313 sc->sc_tgt[cb->id].nexus = NULL;
1314 TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
1315 sc->sc_curcb = NULL;
1316 }
1317
1318 break;
1319
1320 case A_int_res_id:
1321 cb = sc->sc_tgt[sc->sc_resid].nexus;
1322 resmsg = oosiop_read_1(sc, OOSIOP_SFBR);
1323 if (MSG_ISIDENTIFY(resmsg) && cb &&
1324 (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) {
1325 sc->sc_curcb = cb;
1326 if (cb != sc->sc_lastcb) {
1327 oosiop_setup_dma(sc);
1328 oosiop_setup_syncxfer(sc);
1329 sc->sc_lastcb = cb;
1330 }
1331 if (cb->curdp != cb->savedp) {
1332 cb->curdp = cb->savedp;
1333 oosiop_setup_sgdma(sc, cb);
1334 }
1335 sc->sc_nextdsp = Ent_ack_msgin;
1336 } else {
1337 /* Reselection from invalid target */
1338 oosiop_reset_bus(sc);
1339 }
1340 break;
1341
1342 case A_int_resfail:
1343 /* reselect failed */
1344 break;
1345
1346 case A_int_disc:
1347 /* disconnected */
1348 sc->sc_curcb = NULL;
1349 break;
1350
1351 case A_int_err:
1352 /* generic error */
1353 dsp = oosiop_read_4(sc, OOSIOP_DSP);
1354 printf("%s: script error at 0x%08x\n", sc->sc_dev.dv_xname,
1355 dsp - 8);
1356 sc->sc_curcb = NULL;
1357 break;
1358
1359 case DATAIN_TRAP:
1360 printf("%s: unexpected datain\n", sc->sc_dev.dv_xname);
1361 /* XXX: need to reset? */
1362 break;
1363
1364 case DATAOUT_TRAP:
1365 printf("%s: unexpected dataout\n", sc->sc_dev.dv_xname);
1366 /* XXX: need to reset? */
1367 break;
1368
1369 default:
1370 printf("%s: unknown intr code %08x\n", sc->sc_dev.dv_xname,
1371 icode);
1372 break;
1373 }
1374 }
1375
1376 void
1377 oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb)
1378 {
1379 struct oosiop_xfer *xfer;
1380 int msgout;
1381
1382 xfer = cb->xfer;
1383 sc->sc_nextdsp = Ent_ack_msgin;
1384 msgout = 0;
1385
1386 OOSIOP_XFERMSG_SYNC(sc, cb,
1387 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1388
1389 switch (xfer->msgin[0]) {
1390 case MSG_EXTENDED:
1391 switch (xfer->msgin[2]) {
1392 case MSG_EXT_SDTR:
1393 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
1394 /* Host initiated SDTR */
1395 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
1396 } else {
1397 /* Target initiated SDTR */
1398 if (xfer->msgin[3] < sc->sc_minperiod)
1399 xfer->msgin[3] = sc->sc_minperiod;
1400 if (xfer->msgin[4] > OOSIOP_MAX_OFFSET)
1401 xfer->msgin[4] = OOSIOP_MAX_OFFSET;
1402 xfer->msgout[0] = MSG_EXTENDED;
1403 xfer->msgout[1] = MSG_EXT_SDTR_LEN;
1404 xfer->msgout[2] = MSG_EXT_SDTR;
1405 xfer->msgout[3] = xfer->msgin[3];
1406 xfer->msgout[4] = xfer->msgin[4];
1407 cb->msgoutlen = 5;
1408 msgout = 1;
1409 }
1410 oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3],
1411 (int)xfer->msgin[4]);
1412 oosiop_setup_syncxfer(sc);
1413 break;
1414
1415 default:
1416 /* Reject message */
1417 xfer->msgout[0] = MSG_MESSAGE_REJECT;
1418 cb->msgoutlen = 1;
1419 msgout = 1;
1420 break;
1421 }
1422 break;
1423
1424 case MSG_SAVEDATAPOINTER:
1425 cb->savedp = cb->curdp;
1426 break;
1427
1428 case MSG_RESTOREPOINTERS:
1429 if (cb->curdp != cb->savedp) {
1430 cb->curdp = cb->savedp;
1431 oosiop_setup_sgdma(sc, cb);
1432 }
1433 break;
1434
1435 case MSG_MESSAGE_REJECT:
1436 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
1437 /* SDTR rejected */
1438 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
1439 oosiop_set_syncparam(sc, cb->id, 0, 0);
1440 oosiop_setup_syncxfer(sc);
1441 }
1442 break;
1443
1444 default:
1445 /* Reject message */
1446 xfer->msgout[0] = MSG_MESSAGE_REJECT;
1447 cb->msgoutlen = 1;
1448 msgout = 1;
1449 }
1450
1451 OOSIOP_XFERMSG_SYNC(sc, cb,
1452 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1453
1454 if (msgout) {
1455 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1456 oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen,
1457 cb->xferdma->dm_segs[0].ds_addr +
1458 offsetof(struct oosiop_xfer, msgout[0]));
1459 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
1460 sc->sc_nextdsp = Ent_sendmsg;
1461 }
1462 }
Cache object: 21254c75be64feb6551146851071db7c
|