1 /* $OpenBSD: oosiop.c,v 1.37 2024/02/13 17:51:17 miod 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 *
oosiop_cb_alloc(void * xsc)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
oosiop_cb_free(void * xsc,void * xcb)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
oosiop_attach(struct oosiop_softc * sc)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
oosiop_alloc_cb(struct oosiop_softc * sc,int ncb)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
oosiop_relocate_io(struct oosiop_softc * sc,bus_addr_t addr)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
oosiop_relocate_tc(struct oosiop_softc * sc,bus_addr_t addr)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
oosiop_fixup_select(struct oosiop_softc * sc,bus_addr_t addr,int id)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
oosiop_fixup_jump(struct oosiop_softc * sc,bus_addr_t addr,bus_addr_t dst)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
oosiop_fixup_move(struct oosiop_softc * sc,bus_addr_t addr,bus_size_t dbc,bus_addr_t dsps)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
oosiop_load_script(struct oosiop_softc * sc)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
oosiop_setup_sgdma(struct oosiop_softc * sc,struct oosiop_cb * cb)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
oosiop_setup_dma(struct oosiop_softc * sc)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
oosiop_flush_fifo(struct oosiop_softc * sc)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
oosiop_clear_fifo(struct oosiop_softc * sc)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
oosiop_phasemismatch(struct oosiop_softc * sc)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
oosiop_setup_syncxfer(struct oosiop_softc * sc)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
oosiop_set_syncparam(struct oosiop_softc * sc,int id,int period,int offset)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
oosiop_scsicmd(struct scsi_xfer * xs)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 cb = xs->io;
730
731 cb->xs = xs;
732 cb->xsflags = xs->flags;
733 cb->cmdlen = xs->cmdlen;
734 cb->datalen = 0;
735 cb->flags = 0;
736 cb->id = xs->sc_link->target;
737 cb->lun = xs->sc_link->lun;
738 xfer = cb->xfer;
739
740 /* Setup SCSI command buffer DMA */
741 err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, &xs->cmd,
742 xs->cmdlen, NULL, ((xs->flags & SCSI_NOSLEEP) ?
743 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
744 BUS_DMA_STREAMING | BUS_DMA_WRITE);
745 if (err) {
746 printf("%s: unable to load cmd DMA map: %d",
747 sc->sc_dev.dv_xname, err);
748 xs->error = XS_DRIVER_STUFFUP;
749 scsi_done(xs);
750 return;
751 }
752 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
753 BUS_DMASYNC_PREWRITE);
754
755 /* Setup data buffer DMA */
756 if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
757 cb->datalen = xs->datalen;
758 err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
759 xs->data, xs->datalen, NULL,
760 ((xs->flags & SCSI_NOSLEEP) ?
761 BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
762 BUS_DMA_STREAMING |
763 ((xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ :
764 BUS_DMA_WRITE));
765 if (err) {
766 printf("%s: unable to load data DMA map: %d",
767 sc->sc_dev.dv_xname, err);
768 bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
769 xs->error = XS_DRIVER_STUFFUP;
770 scsi_done(xs);
771 return;
772 }
773 bus_dmamap_sync(sc->sc_dmat, cb->datadma,
774 0, xs->datalen,
775 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
776 }
777
778 xfer->status = SCSI_OOSIOP_NOSTATUS;
779
780 /*
781 * Always initialize timeout so it does not contain trash
782 * that could confuse timeout_del().
783 */
784 timeout_set(&xs->stimeout, oosiop_timeout, cb);
785
786 oosiop_setup(sc, cb);
787
788 s = splbio();
789
790 TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain);
791
792 if (xs->flags & SCSI_POLL)
793 dopoll = 1;
794 else {
795 dopoll = 0;
796 /* start expire timer */
797 timeout_add_msec(&xs->stimeout, xs->timeout);
798 }
799
800 if (!sc->sc_active) {
801 /* Abort script to start selection */
802 oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
803 }
804
805 splx(s);
806
807 if (dopoll)
808 oosiop_poll(sc, cb);
809 }
810
811 void
oosiop_poll(struct oosiop_softc * sc,struct oosiop_cb * cb)812 oosiop_poll(struct oosiop_softc *sc, struct oosiop_cb *cb)
813 {
814 struct scsi_xfer *xs = cb->xs;
815 int i, s, to;
816 u_int8_t istat;
817
818 s = splbio();
819 to = xs->timeout / 1000;
820 for (;;) {
821 i = 1000;
822 while (((istat = oosiop_read_1(sc, OOSIOP_ISTAT)) &
823 (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) {
824 if (i <= 0) {
825 i = 1000;
826 to--;
827 if (to <= 0) {
828 oosiop_reset(sc, TRUE);
829 splx(s);
830 return;
831 }
832 }
833 delay(1000);
834 i--;
835 }
836 oosiop_processintr(sc, istat);
837
838 if (xs->flags & ITSDONE)
839 break;
840 }
841
842 splx(s);
843 }
844
845 void
oosiop_setup(struct oosiop_softc * sc,struct oosiop_cb * cb)846 oosiop_setup(struct oosiop_softc *sc, struct oosiop_cb *cb)
847 {
848 struct oosiop_xfer *xfer = cb->xfer;
849
850 cb->curdp = 0;
851 cb->savedp = 0;
852
853 oosiop_setup_sgdma(sc, cb);
854
855 /* Setup msgout buffer */
856 OOSIOP_XFERMSG_SYNC(sc, cb,
857 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
858 xfer->msgout[0] = MSG_IDENTIFY(cb->lun,
859 (cb->xs->cmd.opcode != REQUEST_SENSE));
860 cb->msgoutlen = 1;
861
862 if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) {
863 sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG;
864 /* Send SDTR */
865 xfer->msgout[1] = MSG_EXTENDED;
866 xfer->msgout[2] = MSG_EXT_SDTR_LEN;
867 xfer->msgout[3] = MSG_EXT_SDTR;
868 xfer->msgout[4] = sc->sc_minperiod;
869 xfer->msgout[5] = OOSIOP_MAX_OFFSET;
870 cb->msgoutlen = 6;
871 sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR;
872 }
873
874 OOSIOP_XFERMSG_SYNC(sc, cb,
875 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
876 }
877
878 void
oosiop_done(struct oosiop_softc * sc,struct oosiop_cb * cb)879 oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb)
880 {
881 struct scsi_xfer *xs;
882 struct scsi_link *periph;
883 int autosense;
884
885 xs = cb->xs;
886 periph = xs->sc_link;
887
888 /*
889 * Record if this is the completion of an auto sense
890 * scsi command, and then reset the flag so we don't loop
891 * when such a command fails or times out.
892 */
893 autosense = cb->flags & CBF_AUTOSENSE;
894 cb->flags &= ~CBF_AUTOSENSE;
895
896 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
897 BUS_DMASYNC_POSTWRITE);
898 bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
899
900 if (cb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
901 bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, cb->datalen,
902 (cb->xsflags & SCSI_DATA_IN) ?
903 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
904 bus_dmamap_unload(sc->sc_dmat, cb->datadma);
905 }
906
907 timeout_del(&xs->stimeout);
908
909 xs->status = cb->xfer->status;
910
911 if (cb->flags & CBF_SELTOUT)
912 xs->error = XS_SELTIMEOUT;
913 else if (cb->flags & CBF_TIMEOUT)
914 xs->error = XS_TIMEOUT;
915 else switch (xs->status) {
916 case SCSI_OK:
917 if (autosense == 0)
918 xs->error = XS_NOERROR;
919 else
920 xs->error = XS_SENSE;
921 break;
922
923 case SCSI_BUSY:
924 xs->error = XS_BUSY;
925 break;
926 case SCSI_CHECK:
927 #ifdef notyet
928 if (autosense == 0)
929 cb->flags |= CBF_AUTOSENSE;
930 else
931 #endif
932 xs->error = XS_DRIVER_STUFFUP;
933 break;
934 case SCSI_OOSIOP_NOSTATUS:
935 /* the status byte was not updated, cmd was aborted. */
936 xs->error = XS_SELTIMEOUT;
937 break;
938
939 default:
940 xs->error = XS_RESET;
941 break;
942 }
943
944 if ((cb->flags & CBF_AUTOSENSE) == 0) {
945 /* Put it on the free list. */
946 FREE:
947 xs->resid = 0;
948 scsi_done(xs);
949
950 if (cb == sc->sc_curcb)
951 sc->sc_curcb = NULL;
952 if (cb == sc->sc_lastcb)
953 sc->sc_lastcb = NULL;
954 sc->sc_tgt[cb->id].nexus = NULL;
955 } else {
956 /* Set up REQUEST_SENSE command */
957 struct scsi_sense *cmd = (struct scsi_sense *)&xs->cmd;
958 int err;
959
960 bzero(cmd, sizeof(*cmd));
961 cmd->opcode = REQUEST_SENSE;
962 cmd->byte2 = xs->sc_link->lun << 5;
963 cb->cmdlen = cmd->length = sizeof(xs->sense);
964
965 cb->xsflags &= SCSI_POLL | SCSI_NOSLEEP;
966 cb->xsflags |= SCSI_DATA_IN;
967 cb->datalen = sizeof xs->sense;
968
969 /* Setup SCSI command buffer DMA */
970 err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, cmd,
971 cb->cmdlen, NULL,
972 BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE);
973 if (err) {
974 printf("%s: unable to load REQUEST_SENSE cmd DMA map: %d",
975 sc->sc_dev.dv_xname, err);
976 xs->error = XS_DRIVER_STUFFUP;
977 goto FREE;
978 }
979 bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
980 BUS_DMASYNC_PREWRITE);
981
982 /* Setup data buffer DMA */
983 err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
984 &xs->sense, sizeof(xs->sense), NULL,
985 BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_READ);
986 if (err) {
987 printf("%s: unable to load REQUEST_SENSE data DMA map: %d",
988 sc->sc_dev.dv_xname, err);
989 xs->error = XS_DRIVER_STUFFUP;
990 bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
991 goto FREE;
992 }
993 bus_dmamap_sync(sc->sc_dmat, cb->datadma,
994 0, sizeof(xs->sense), BUS_DMASYNC_PREREAD);
995
996 oosiop_setup(sc, cb);
997
998 TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
999 if ((cb->xs->flags & SCSI_POLL) == 0) {
1000 /* start expire timer */
1001 timeout_add_msec(&xs->stimeout, xs->timeout);
1002 }
1003 }
1004 }
1005
1006 void
oosiop_timeout(void * arg)1007 oosiop_timeout(void *arg)
1008 {
1009 struct oosiop_cb *cb = arg;
1010 struct scsi_xfer *xs = cb->xs;
1011 struct oosiop_softc *sc = xs->sc_link->bus->sb_adapter_softc;
1012 int s;
1013
1014 sc_print_addr(xs->sc_link);
1015 printf("command 0x%02x timeout on xs %p\n", xs->cmd.opcode, xs);
1016
1017 s = splbio();
1018
1019 oosiop_reset_bus(sc);
1020
1021 cb->flags |= CBF_TIMEOUT;
1022 oosiop_done(sc, cb);
1023
1024 splx(s);
1025 }
1026
1027 void
oosiop_reset(struct oosiop_softc * sc,int allflags)1028 oosiop_reset(struct oosiop_softc *sc, int allflags)
1029 {
1030 int i, s;
1031
1032 s = splbio();
1033
1034 /* Stop SCRIPTS processor */
1035 oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
1036 delay(100);
1037 oosiop_write_1(sc, OOSIOP_ISTAT, 0);
1038
1039 /* Reset the chip */
1040 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST);
1041 delay(100);
1042 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
1043 delay(10000);
1044
1045 /* Set up various chip parameters */
1046 oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | sc->sc_scntl0);
1047 oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR);
1048 oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
1049 oosiop_write_1(sc, OOSIOP_DMODE, sc->sc_dmode);
1050 oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id));
1051 oosiop_write_1(sc, OOSIOP_DWT, sc->sc_dwt);
1052 oosiop_write_1(sc, OOSIOP_CTEST7, sc->sc_ctest7);
1053 oosiop_write_1(sc, OOSIOP_SXFER, 0);
1054
1055 /* Clear all interrupts */
1056 (void)oosiop_read_1(sc, OOSIOP_SSTAT0);
1057 (void)oosiop_read_1(sc, OOSIOP_SSTAT1);
1058 (void)oosiop_read_1(sc, OOSIOP_DSTAT);
1059
1060 /* Enable interrupts */
1061 oosiop_write_1(sc, OOSIOP_SIEN,
1062 OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE |
1063 OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR);
1064 oosiop_write_1(sc, OOSIOP_DIEN,
1065 OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR |
1066 OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID);
1067
1068 /* Set target state to asynchronous */
1069 for (i = 0; i < OOSIOP_NTGT; i++) {
1070 if (allflags)
1071 sc->sc_tgt[i].flags = 0;
1072 else
1073 sc->sc_tgt[i].flags |= TGTF_SYNCNEG;
1074 sc->sc_tgt[i].scf = 0;
1075 sc->sc_tgt[i].sxfer = 0;
1076 }
1077
1078 splx(s);
1079 }
1080
1081 void
oosiop_reset_bus(struct oosiop_softc * sc)1082 oosiop_reset_bus(struct oosiop_softc *sc)
1083 {
1084 int s, i;
1085
1086 s = splbio();
1087
1088 /* Assert SCSI RST */
1089 oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST);
1090 delay(25); /* Reset hold time (25us) */
1091 oosiop_write_1(sc, OOSIOP_SCNTL1, 0);
1092
1093 /* Remove all nexuses */
1094 for (i = 0; i < OOSIOP_NTGT; i++) {
1095 if (sc->sc_tgt[i].nexus) {
1096 sc->sc_tgt[i].nexus->xfer->status =
1097 SCSI_OOSIOP_NOSTATUS; /* XXX */
1098 oosiop_done(sc, sc->sc_tgt[i].nexus);
1099 }
1100 }
1101
1102 sc->sc_curcb = NULL;
1103
1104 delay(250000); /* Reset to selection (250ms) */
1105
1106 splx(s);
1107 }
1108
1109 /*
1110 * interrupt handler
1111 */
1112 int
oosiop_intr(struct oosiop_softc * sc)1113 oosiop_intr(struct oosiop_softc *sc)
1114 {
1115 u_int8_t istat;
1116
1117 istat = oosiop_read_1(sc, OOSIOP_ISTAT);
1118
1119 if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0)
1120 return (0);
1121
1122 oosiop_processintr(sc, istat);
1123 return (1);
1124 }
1125
1126 void
oosiop_processintr(struct oosiop_softc * sc,u_int8_t istat)1127 oosiop_processintr(struct oosiop_softc *sc, u_int8_t istat)
1128 {
1129 struct oosiop_cb *cb;
1130 u_int32_t dcmd;
1131 u_int8_t dstat, sstat0;
1132
1133 sc->sc_nextdsp = Ent_wait_reselect;
1134
1135 /* DMA interrupts */
1136 if (istat & OOSIOP_ISTAT_DIP) {
1137 oosiop_write_1(sc, OOSIOP_ISTAT, 0);
1138
1139 dstat = oosiop_read_1(sc, OOSIOP_DSTAT);
1140
1141 if (dstat & OOSIOP_DSTAT_ABRT) {
1142 sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
1143 sc->sc_scrbase - 8;
1144
1145 if (sc->sc_nextdsp == Ent_p_resel_msgin_move &&
1146 (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) {
1147 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1148 oosiop_flush_fifo(sc);
1149 sc->sc_nextdsp += 8;
1150 }
1151 }
1152
1153 if (dstat & OOSIOP_DSTAT_SSI) {
1154 sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
1155 sc->sc_scrbase;
1156 printf("%s: single step %08x\n", sc->sc_dev.dv_xname,
1157 sc->sc_nextdsp);
1158 }
1159
1160 if (dstat & OOSIOP_DSTAT_SIR) {
1161 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1162 oosiop_flush_fifo(sc);
1163 oosiop_scriptintr(sc);
1164 }
1165
1166 if (dstat & OOSIOP_DSTAT_WTD) {
1167 printf("%s: DMA time out\n", sc->sc_dev.dv_xname);
1168 oosiop_reset(sc, TRUE);
1169 }
1170
1171 if (dstat & OOSIOP_DSTAT_IID) {
1172 dcmd = oosiop_read_4(sc, OOSIOP_DBC);
1173 if ((dcmd & 0xf8000000) == 0x48000000) {
1174 printf("%s: REQ asserted on WAIT DISCONNECT\n",
1175 sc->sc_dev.dv_xname);
1176 sc->sc_nextdsp = Ent_phasedispatch; /* XXX */
1177 } else {
1178 printf("%s: invalid SCRIPTS instruction "
1179 "addr=%08x dcmd=%08x dsps=%08x\n",
1180 sc->sc_dev.dv_xname,
1181 oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd,
1182 oosiop_read_4(sc, OOSIOP_DSPS));
1183 oosiop_reset(sc, TRUE);
1184 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1185 oosiop_load_script(sc);
1186 }
1187 }
1188
1189 if ((dstat & OOSIOP_DSTAT_DFE) == 0)
1190 oosiop_clear_fifo(sc);
1191 }
1192
1193 /* SCSI interrupts */
1194 if (istat & OOSIOP_ISTAT_SIP) {
1195 if (istat & OOSIOP_ISTAT_DIP)
1196 delay(1);
1197 sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0);
1198
1199 if (sstat0 & OOSIOP_SSTAT0_M_A) {
1200 /* SCSI phase mismatch during MOVE operation */
1201 oosiop_phasemismatch(sc);
1202 sc->sc_nextdsp = Ent_phasedispatch;
1203 }
1204
1205 if (sstat0 & OOSIOP_SSTAT0_STO) {
1206 if (sc->sc_curcb) {
1207 sc->sc_curcb->flags |= CBF_SELTOUT;
1208 oosiop_done(sc, sc->sc_curcb);
1209 }
1210 }
1211
1212 if (sstat0 & OOSIOP_SSTAT0_SGE) {
1213 printf("%s: SCSI gross error\n", sc->sc_dev.dv_xname);
1214 oosiop_reset(sc, TRUE);
1215 }
1216
1217 if (sstat0 & OOSIOP_SSTAT0_UDC) {
1218 /* XXX */
1219 if (sc->sc_curcb) {
1220 printf("%s: unexpected disconnect\n",
1221 sc->sc_dev.dv_xname);
1222 oosiop_done(sc, sc->sc_curcb);
1223 }
1224 }
1225
1226 if (sstat0 & OOSIOP_SSTAT0_RST) {
1227 /*
1228 * This may happen during sync request negotiation;
1229 * be sure not to reset TGTF_WAITSDTR in that case.
1230 */
1231 oosiop_reset(sc, FALSE);
1232 }
1233
1234 if (sstat0 & OOSIOP_SSTAT0_PAR)
1235 printf("%s: parity error\n", sc->sc_dev.dv_xname);
1236 }
1237
1238 /* Start next command if available */
1239 if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) {
1240 cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq);
1241 TAILQ_REMOVE(&sc->sc_cbq, cb, chain);
1242 sc->sc_tgt[cb->id].nexus = cb;
1243
1244 oosiop_setup_dma(sc);
1245 oosiop_setup_syncxfer(sc);
1246 sc->sc_lastcb = cb;
1247 sc->sc_nextdsp = Ent_start_select;
1248
1249 /* Schedule timeout */
1250 if ((cb->xs->flags & SCSI_POLL) == 0) {
1251 /* start expire timer */
1252 timeout_add_msec(&cb->xs->stimeout, cb->xs->timeout);
1253 }
1254 }
1255
1256 sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect);
1257
1258 /* Restart script */
1259 oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase);
1260 }
1261
1262 void
oosiop_scriptintr(struct oosiop_softc * sc)1263 oosiop_scriptintr(struct oosiop_softc *sc)
1264 {
1265 struct oosiop_cb *cb;
1266 u_int32_t icode;
1267 u_int32_t dsp;
1268 int i;
1269 u_int8_t sfbr, resid, resmsg;
1270
1271 cb = sc->sc_curcb;
1272 icode = oosiop_read_4(sc, OOSIOP_DSPS);
1273
1274 switch (icode) {
1275 case A_int_done:
1276 if (cb)
1277 oosiop_done(sc, cb);
1278 break;
1279
1280 case A_int_msgin:
1281 if (cb)
1282 oosiop_msgin(sc, cb);
1283 break;
1284
1285 case A_int_extmsg:
1286 /* extended message in DMA setup request */
1287 sfbr = oosiop_read_1(sc, OOSIOP_SFBR);
1288 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1289 oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr,
1290 cb->xferdma->dm_segs[0].ds_addr +
1291 offsetof(struct oosiop_xfer, msgin[2]));
1292 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
1293 sc->sc_nextdsp = Ent_rcv_extmsg;
1294 break;
1295
1296 case A_int_resel:
1297 /* reselected */
1298 resid = oosiop_read_1(sc, OOSIOP_SFBR);
1299 for (i = 0; i < OOSIOP_NTGT; i++)
1300 if (resid & (1 << i))
1301 break;
1302 if (i == OOSIOP_NTGT) {
1303 printf("%s: missing reselection target id\n",
1304 sc->sc_dev.dv_xname);
1305 break;
1306 }
1307 sc->sc_resid = i;
1308 sc->sc_nextdsp = Ent_wait_resel_identify;
1309
1310 if (cb) {
1311 /* Current command was lost arbitration */
1312 sc->sc_tgt[cb->id].nexus = NULL;
1313 TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
1314 sc->sc_curcb = NULL;
1315 }
1316
1317 break;
1318
1319 case A_int_res_id:
1320 cb = sc->sc_tgt[sc->sc_resid].nexus;
1321 resmsg = oosiop_read_1(sc, OOSIOP_SFBR);
1322 if (MSG_ISIDENTIFY(resmsg) && cb &&
1323 (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) {
1324 sc->sc_curcb = cb;
1325 if (cb != sc->sc_lastcb) {
1326 oosiop_setup_dma(sc);
1327 oosiop_setup_syncxfer(sc);
1328 sc->sc_lastcb = cb;
1329 }
1330 if (cb->curdp != cb->savedp) {
1331 cb->curdp = cb->savedp;
1332 oosiop_setup_sgdma(sc, cb);
1333 }
1334 sc->sc_nextdsp = Ent_ack_msgin;
1335 } else {
1336 /* Reselection from invalid target */
1337 oosiop_reset_bus(sc);
1338 }
1339 break;
1340
1341 case A_int_resfail:
1342 /* reselect failed */
1343 break;
1344
1345 case A_int_disc:
1346 /* disconnected */
1347 sc->sc_curcb = NULL;
1348 break;
1349
1350 case A_int_err:
1351 /* generic error */
1352 dsp = oosiop_read_4(sc, OOSIOP_DSP);
1353 printf("%s: script error at 0x%08x\n", sc->sc_dev.dv_xname,
1354 dsp - 8);
1355 sc->sc_curcb = NULL;
1356 break;
1357
1358 case DATAIN_TRAP:
1359 printf("%s: unexpected datain\n", sc->sc_dev.dv_xname);
1360 /* XXX: need to reset? */
1361 break;
1362
1363 case DATAOUT_TRAP:
1364 printf("%s: unexpected dataout\n", sc->sc_dev.dv_xname);
1365 /* XXX: need to reset? */
1366 break;
1367
1368 default:
1369 printf("%s: unknown intr code %08x\n", sc->sc_dev.dv_xname,
1370 icode);
1371 break;
1372 }
1373 }
1374
1375 void
oosiop_msgin(struct oosiop_softc * sc,struct oosiop_cb * cb)1376 oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb)
1377 {
1378 struct oosiop_xfer *xfer;
1379 int msgout;
1380
1381 xfer = cb->xfer;
1382 sc->sc_nextdsp = Ent_ack_msgin;
1383 msgout = 0;
1384
1385 OOSIOP_XFERMSG_SYNC(sc, cb,
1386 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1387
1388 switch (xfer->msgin[0]) {
1389 case MSG_EXTENDED:
1390 switch (xfer->msgin[2]) {
1391 case MSG_EXT_SDTR:
1392 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
1393 /* Host initiated SDTR */
1394 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
1395 } else {
1396 /* Target initiated SDTR */
1397 if (xfer->msgin[3] < sc->sc_minperiod)
1398 xfer->msgin[3] = sc->sc_minperiod;
1399 if (xfer->msgin[4] > OOSIOP_MAX_OFFSET)
1400 xfer->msgin[4] = OOSIOP_MAX_OFFSET;
1401 xfer->msgout[0] = MSG_EXTENDED;
1402 xfer->msgout[1] = MSG_EXT_SDTR_LEN;
1403 xfer->msgout[2] = MSG_EXT_SDTR;
1404 xfer->msgout[3] = xfer->msgin[3];
1405 xfer->msgout[4] = xfer->msgin[4];
1406 cb->msgoutlen = 5;
1407 msgout = 1;
1408 }
1409 oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3],
1410 (int)xfer->msgin[4]);
1411 oosiop_setup_syncxfer(sc);
1412 break;
1413
1414 default:
1415 /* Reject message */
1416 xfer->msgout[0] = MSG_MESSAGE_REJECT;
1417 cb->msgoutlen = 1;
1418 msgout = 1;
1419 break;
1420 }
1421 break;
1422
1423 case MSG_SAVEDATAPOINTER:
1424 cb->savedp = cb->curdp;
1425 break;
1426
1427 case MSG_RESTOREPOINTERS:
1428 if (cb->curdp != cb->savedp) {
1429 cb->curdp = cb->savedp;
1430 oosiop_setup_sgdma(sc, cb);
1431 }
1432 break;
1433
1434 case MSG_MESSAGE_REJECT:
1435 if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
1436 /* SDTR rejected */
1437 sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
1438 oosiop_set_syncparam(sc, cb->id, 0, 0);
1439 oosiop_setup_syncxfer(sc);
1440 }
1441 break;
1442
1443 default:
1444 /* Reject message */
1445 xfer->msgout[0] = MSG_MESSAGE_REJECT;
1446 cb->msgoutlen = 1;
1447 msgout = 1;
1448 }
1449
1450 OOSIOP_XFERMSG_SYNC(sc, cb,
1451 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1452
1453 if (msgout) {
1454 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
1455 oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen,
1456 cb->xferdma->dm_segs[0].ds_addr +
1457 offsetof(struct oosiop_xfer, msgout[0]));
1458 OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
1459 sc->sc_nextdsp = Ent_sendmsg;
1460 }
1461 }
1462