Annotation of sys/dev/ic/osiop.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: osiop.c,v 1.29 2007/06/20 18:02:39 miod Exp $ */
2: /* $NetBSD: osiop.c,v 1.9 2002/04/05 18:27:54 bouyer Exp $ */
3:
4: /*
5: * Copyright (c) 2001 Izumi Tsutsui. 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: * Copyright (c) 1994 Michael L. Hitch
32: * Copyright (c) 1990 The Regents of the University of California.
33: * All rights reserved.
34: *
35: * This code is derived from software contributed to Berkeley by
36: * Van Jacobson of Lawrence Berkeley Laboratory.
37: *
38: * Redistribution and use in source and binary forms, with or without
39: * modification, are permitted provided that the following conditions
40: * are met:
41: * 1. Redistributions of source code must retain the above copyright
42: * notice, this list of conditions and the following disclaimer.
43: * 2. Redistributions in binary form must reproduce the above copyright
44: * notice, this list of conditions and the following disclaimer in the
45: * documentation and/or other materials provided with the distribution.
46: * 3. Neither the name of the University nor the names of its contributors
47: * may be used to endorse or promote products derived from this software
48: * without specific prior written permission.
49: *
50: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60: * SUCH DAMAGE.
61: *
62: * @(#)siop.c 7.5 (Berkeley) 5/4/91
63: */
64:
65: /*
66: * MI NCR53C710 scsi adaptor driver; based on arch/amiga/dev/siop.c:
67: * NetBSD: siop.c,v 1.43 1999/09/30 22:59:53 thorpej Exp
68: *
69: * bus_space/bus_dma'fied by Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
70: */
71:
72: #include <sys/cdefs.h>
73: /* __KERNEL_RCSID(0, "$NetBSD: osiop.c,v 1.9 2002/04/05 18:27:54 bouyer Exp $"); */
74:
75: #include <sys/param.h>
76: #include <sys/systm.h>
77: #include <sys/device.h>
78: #include <sys/malloc.h>
79: #include <sys/buf.h>
80: #include <sys/kernel.h>
81:
82: #include <scsi/scsi_all.h>
83: #include <scsi/scsiconf.h>
84: #include <scsi/scsi_message.h>
85:
86: #include <machine/cpu.h>
87: #include <machine/bus.h>
88:
89: #include <dev/ic/osiopreg.h>
90: #include <dev/ic/osiopvar.h>
91:
92: /* 53C710 script */
93: #include <dev/microcode/siop/osiop.out>
94:
95: void osiop_attach(struct osiop_softc *);
96: void osiop_minphys(struct buf *);
97: int osiop_scsicmd(struct scsi_xfer *xs);
98: void osiop_poll(struct osiop_softc *, struct osiop_acb *);
99: void osiop_sched(struct osiop_softc *);
100: void osiop_scsidone(struct osiop_acb *, int);
101: void osiop_abort(struct osiop_softc *, const char *);
102: void osiop_init(struct osiop_softc *);
103: void osiop_reset(struct osiop_softc *);
104: void osiop_resetbus(struct osiop_softc *);
105: void osiop_start(struct osiop_softc *);
106: int osiop_checkintr(struct osiop_softc *, u_int8_t, u_int8_t, u_int8_t, int *);
107: void osiop_select(struct osiop_softc *);
108: void osiop_update_xfer_mode(struct osiop_softc *, int);
109: void scsi_period_to_osiop(struct osiop_softc *, int);
110: void osiop_timeout(void *);
111:
112: int osiop_reset_delay = 250; /* delay after reset, in milliseconds */
113:
114: /* #define OSIOP_DEBUG */
115: #ifdef OSIOP_DEBUG
116: #define DEBUG_DMA 0x0001
117: #define DEBUG_INT 0x0002
118: #define DEBUG_PHASE 0x0004
119: #define DEBUG_DISC 0x0008
120: #define DEBUG_CMD 0x0010
121: #define DEBUG_SYNC 0x0020
122: #define DEBUG_SCHED 0x0040
123: #define DEBUG_ALL 0xffff
124: int osiop_debug = 0; /*DEBUG_ALL;*/
125: int osiopstarts = 0;
126: int osiopints = 0;
127: int osiopphmm = 0;
128: int osiop_trix = 0;
129: #define OSIOP_TRACE_SIZE 128
130: #define OSIOP_TRACE(a,b,c,d) do { \
131: osiop_trbuf[osiop_trix + 0] = (a); \
132: osiop_trbuf[osiop_trix + 1] = (b); \
133: osiop_trbuf[osiop_trix + 2] = (c); \
134: osiop_trbuf[osiop_trix + 3] = (d); \
135: osiop_trix = (osiop_trix + 4) & (OSIOP_TRACE_SIZE - 1); \
136: } while (0)
137: u_int8_t osiop_trbuf[OSIOP_TRACE_SIZE];
138: void osiop_dump_trace(void);
139: void osiop_dump_acb(struct osiop_acb *);
140: void osiop_dump(struct osiop_softc *);
141: #else
142: #define OSIOP_TRACE(a,b,c,d)
143: #endif
144:
145: #ifdef OSIOP_DEBUG
146: /*
147: * sync period transfer lookup - only valid for 66MHz clock
148: */
149: static struct {
150: u_int8_t p; /* period from sync request message */
151: u_int8_t r; /* siop_period << 4 | sbcl */
152: } sync_tab[] = {
153: { 60/4, 0<<4 | 1},
154: { 76/4, 1<<4 | 1},
155: { 92/4, 2<<4 | 1},
156: { 92/4, 0<<4 | 2},
157: {108/4, 3<<4 | 1},
158: {116/4, 1<<4 | 2},
159: {120/4, 4<<4 | 1},
160: {120/4, 0<<4 | 3},
161: {136/4, 5<<4 | 1},
162: {140/4, 2<<4 | 2},
163: {152/4, 6<<4 | 1},
164: {152/4, 1<<4 | 3},
165: {164/4, 3<<4 | 2},
166: {168/4, 7<<4 | 1},
167: {180/4, 2<<4 | 3},
168: {184/4, 4<<4 | 2},
169: {208/4, 5<<4 | 2},
170: {212/4, 3<<4 | 3},
171: {232/4, 6<<4 | 2},
172: {240/4, 4<<4 | 3},
173: {256/4, 7<<4 | 2},
174: {272/4, 5<<4 | 3},
175: {300/4, 6<<4 | 3},
176: {332/4, 7<<4 | 3}
177: };
178: #endif
179:
180: struct cfdriver osiop_cd = {
181: NULL, "osiop", DV_DULL
182: };
183:
184: struct scsi_adapter osiop_adapter = {
185: osiop_scsicmd,
186: osiop_minphys,
187: NULL,
188: NULL,
189: };
190:
191: struct scsi_device osiop_dev = {
192: NULL,
193: NULL,
194: NULL,
195: NULL,
196: };
197:
198: void
199: osiop_attach(sc)
200: struct osiop_softc *sc;
201: {
202: struct scsibus_attach_args saa;
203: struct osiop_acb *acb;
204: bus_dma_segment_t seg;
205: int nseg;
206: int i, err;
207:
208: /*
209: * Allocate and map DMA-safe memory for the script.
210: */
211: err = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
212: &seg, 1, &nseg, BUS_DMA_NOWAIT);
213: if (err) {
214: printf(": failed to allocate script memory, err=%d\n", err);
215: return;
216: }
217: err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, PAGE_SIZE,
218: (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
219: if (err) {
220: printf(": failed to map script memory, err=%d\n", err);
221: return;
222: }
223: err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
224: BUS_DMA_NOWAIT, &sc->sc_scrdma);
225: if (err) {
226: printf(": failed to create script map, err=%d\n", err);
227: return;
228: }
229: err = bus_dmamap_load_raw(sc->sc_dmat, sc->sc_scrdma,
230: &seg, nseg, PAGE_SIZE, BUS_DMA_NOWAIT);
231: if (err) {
232: printf(": failed to load script map, err=%d\n", err);
233: return;
234: }
235: bzero(sc->sc_script, PAGE_SIZE);
236:
237: /*
238: * Copy and sync script
239: */
240: memcpy(sc->sc_script, osiop_script, sizeof(osiop_script));
241: bus_dmamap_sync(sc->sc_dmat, sc->sc_scrdma, 0, sizeof(osiop_script),
242: BUS_DMASYNC_PREWRITE);
243:
244: /*
245: * Allocate and map DMA-safe memory for the script data structure.
246: */
247: err = bus_dmamem_alloc(sc->sc_dmat,
248: sizeof(struct osiop_ds) * OSIOP_NACB, PAGE_SIZE, 0,
249: &seg, 1, &nseg, BUS_DMA_NOWAIT);
250: if (err) {
251: printf(": failed to allocate ds memory, err=%d\n", err);
252: return;
253: }
254: err = bus_dmamem_map(sc->sc_dmat, &seg, nseg,
255: sizeof(struct osiop_ds) * OSIOP_NACB, (caddr_t *)&sc->sc_ds,
256: BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
257: if (err) {
258: printf(": failed to map ds memory, err=%d\n", err);
259: return;
260: }
261: err = bus_dmamap_create(sc->sc_dmat,
262: sizeof(struct osiop_ds) * OSIOP_NACB, 1,
263: sizeof(struct osiop_ds) * OSIOP_NACB, 0,
264: BUS_DMA_NOWAIT, &sc->sc_dsdma);
265: if (err) {
266: printf(": failed to create ds map, err=%d\n", err);
267: return;
268: }
269: err = bus_dmamap_load_raw(sc->sc_dmat, sc->sc_dsdma,
270: &seg, nseg, sizeof(struct osiop_ds) * OSIOP_NACB, BUS_DMA_NOWAIT);
271: if (err) {
272: printf(": failed to load ds map, err=%d\n", err);
273: return;
274: }
275: bzero(sc->sc_ds, sizeof(struct osiop_ds) * OSIOP_NACB);
276:
277: /*
278: * Allocate (malloc) memory for acb's.
279: */
280: acb = malloc(sizeof(struct osiop_acb) * OSIOP_NACB,
281: M_DEVBUF, M_NOWAIT);
282: if (acb == NULL) {
283: printf(": can't allocate memory for acb\n");
284: return;
285: }
286: bzero(acb, sizeof(struct osiop_acb) * OSIOP_NACB);
287: sc->sc_acb = acb;
288:
289: sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags;
290: sc->sc_nexus = NULL;
291: sc->sc_active = 0;
292:
293: bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
294:
295: /* Initialize command block queue */
296: TAILQ_INIT(&sc->ready_list);
297: TAILQ_INIT(&sc->nexus_list);
298: TAILQ_INIT(&sc->free_list);
299:
300: /* Initialize each command block */
301: for (i = 0; i < OSIOP_NACB; i++, acb++) {
302: bus_addr_t dsa;
303:
304: err = bus_dmamap_create(sc->sc_dmat, OSIOP_MAX_XFER, OSIOP_NSG,
305: OSIOP_MAX_XFER, 0, BUS_DMA_NOWAIT, &acb->datadma);
306: if (err) {
307: printf(": failed to create datadma map, err=%d\n",
308: err);
309: return;
310: }
311:
312: acb->sc = sc;
313: acb->ds = &sc->sc_ds[i];
314: acb->dsoffset = sizeof(struct osiop_ds) * i;
315:
316: dsa = sc->sc_dsdma->dm_segs[0].ds_addr + acb->dsoffset;
317: acb->ds->id.addr = dsa + OSIOP_DSIDOFF;
318: acb->ds->cmd.addr = dsa + OSIOP_DSCMDOFF;
319: acb->ds->status.count = 1;
320: acb->ds->status.addr = dsa + OSIOP_DSSTATOFF;
321: acb->ds->msg.count = 1;
322: acb->ds->msg.addr = dsa + OSIOP_DSMSGOFF;
323: acb->ds->msgin.count = 1;
324: acb->ds->msgin.addr = dsa + OSIOP_DSMSGINOFF;
325: acb->ds->extmsg.count = 1;
326: acb->ds->extmsg.addr = dsa + OSIOP_DSEXTMSGOFF;
327: acb->ds->synmsg.count = 3;
328: acb->ds->synmsg.addr = dsa + OSIOP_DSSYNMSGOFF;
329: TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
330: }
331:
332: printf(": NCR53C710 rev %d, %dMHz, SCSI ID %d\n",
333: osiop_read_1(sc, OSIOP_CTEST8) >> 4, sc->sc_clock_freq, sc->sc_id);
334:
335: /*
336: * Initialize all
337: */
338: osiop_init(sc);
339:
340: /*
341: * Fill in the sc_link.
342: */
343: sc->sc_link.adapter = &osiop_adapter;
344: sc->sc_link.adapter_softc = sc;
345: sc->sc_link.device = &osiop_dev;
346: sc->sc_link.openings = 4;
347: sc->sc_link.adapter_buswidth = OSIOP_NTGT;
348: sc->sc_link.adapter_target = sc->sc_id;
349:
350: bzero(&saa, sizeof(saa));
351: saa.saa_sc_link = &sc->sc_link;
352:
353: /*
354: * Now try to attach all the sub devices.
355: */
356: config_found(&sc->sc_dev, &saa, scsiprint);
357: }
358:
359: /*
360: * default minphys routine for osiop based controllers
361: */
362: void
363: osiop_minphys(bp)
364: struct buf *bp;
365: {
366:
367: if (bp->b_bcount > OSIOP_MAX_XFER)
368: bp->b_bcount = OSIOP_MAX_XFER;
369: minphys(bp);
370: }
371:
372: /*
373: * used by specific osiop controller
374: *
375: */
376: int
377: osiop_scsicmd(xs)
378: struct scsi_xfer *xs;
379: {
380: struct scsi_link *periph = xs->sc_link;
381: struct osiop_acb *acb;
382: struct osiop_softc *sc = periph->adapter_softc;
383: int err, s;
384:
385: /* XXXX ?? */
386: if (xs->flags & SCSI_DATA_UIO)
387: panic("osiop: scsi data uio requested");
388:
389: /* XXXX ?? */
390: if (sc->sc_nexus && (xs->flags & SCSI_POLL))
391: #if 0
392: panic("osiop_scsicmd: busy");
393: #else
394: printf("osiop_scsicmd: busy\n");
395: #endif
396:
397: s = splbio();
398: acb = TAILQ_FIRST(&sc->free_list);
399: if (acb != NULL) {
400: TAILQ_REMOVE(&sc->free_list, acb, chain);
401: }
402: else {
403: #ifdef DIAGNOSTIC
404: sc_print_addr(periph);
405: printf("unable to allocate acb\n");
406: panic("osiop_scsipi_request");
407: #endif
408: splx(s);
409: return (TRY_AGAIN_LATER);
410: }
411:
412: acb->flags = 0;
413: acb->status = ACB_S_READY;
414: acb->xs = xs;
415: acb->xsflags = xs->flags;
416: bcopy(xs->cmd, &acb->ds->scsi_cmd, xs->cmdlen);
417: acb->ds->cmd.count = xs->cmdlen;
418: acb->datalen = 0;
419: #ifdef OSIOP_DEBUG
420: acb->data = xs->data;
421: #endif
422:
423: /* Setup DMA map for data buffer */
424: if (acb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
425: acb->datalen = xs->datalen;
426: err = bus_dmamap_load(sc->sc_dmat, acb->datadma,
427: xs->data, acb->datalen, NULL,
428: BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
429: ((acb->xsflags & SCSI_DATA_IN) ?
430: BUS_DMA_READ : BUS_DMA_WRITE));
431: if (err) {
432: printf("%s: unable to load data DMA map: %d",
433: sc->sc_dev.dv_xname, err);
434: xs->error = XS_DRIVER_STUFFUP;
435: scsi_done(xs);
436: TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
437: splx(s);
438: return (COMPLETE);
439: }
440: bus_dmamap_sync(sc->sc_dmat, acb->datadma,
441: 0, acb->datalen, (acb->xsflags & SCSI_DATA_IN) ?
442: BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
443: }
444:
445: /*
446: * Always initialize timeout so it does not contain trash
447: * that could confuse timeout_del().
448: */
449: timeout_set(&xs->stimeout, osiop_timeout, acb);
450:
451: TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
452:
453: osiop_sched(sc);
454:
455: splx(s);
456:
457: if ((acb->xsflags & SCSI_POLL) || (sc->sc_flags & OSIOP_NODMA))
458: osiop_poll(sc, acb);
459: else
460: /* start expire timer */
461: timeout_add(&xs->stimeout, (xs->timeout/1000) * hz);
462:
463: if ((xs->flags & ITSDONE) == 0)
464: return (SUCCESSFULLY_QUEUED);
465: else
466: return (COMPLETE);
467: }
468:
469: void
470: osiop_poll(sc, acb)
471: struct osiop_softc *sc;
472: struct osiop_acb *acb;
473: {
474: struct scsi_xfer *xs = acb->xs;
475: int status, i, s, to;
476: u_int8_t istat, dstat, sstat0;
477:
478: s = splbio();
479: to = xs->timeout / 1000;
480: if (!TAILQ_EMPTY(&sc->nexus_list))
481: printf("%s: osiop_poll called with disconnected device\n",
482: sc->sc_dev.dv_xname);
483: for (;;) {
484: i = 1000;
485: while (((istat = osiop_read_1(sc, OSIOP_ISTAT)) &
486: (OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP)) == 0) {
487: if (i <= 0) {
488: #ifdef OSIOP_DEBUG
489: printf("waiting: tgt %d cmd %02x sbcl %02x"
490: " dsp %x (+%lx) dcmd %x"
491: " ds %p timeout %d\n",
492: xs->sc_link->target,
493: acb->ds->scsi_cmd.opcode,
494: osiop_read_1(sc, OSIOP_SBCL),
495: osiop_read_4(sc, OSIOP_DSP),
496: osiop_read_4(sc, OSIOP_DSP) -
497: sc->sc_scrdma->dm_segs[0].ds_addr,
498: osiop_read_1(sc, OSIOP_DCMD),
499: acb->ds, acb->xs->timeout);
500: #endif
501: i = 1000;
502: to--;
503: if (to <= 0) {
504: osiop_reset(sc);
505: splx(s);
506: return;
507: }
508: }
509: delay(1000);
510: i--;
511: }
512: sstat0 = osiop_read_1(sc, OSIOP_SSTAT0);
513: delay(25); /* Need delay between SSTAT0 and DSTAT reads */
514: dstat = osiop_read_1(sc, OSIOP_DSTAT);
515: if (osiop_checkintr(sc, istat, dstat, sstat0, &status)) {
516: if (acb != sc->sc_nexus)
517: printf("%s: osiop_poll disconnected device"
518: " completed\n", sc->sc_dev.dv_xname);
519: else if ((sc->sc_flags & OSIOP_INTDEFER) == 0) {
520: sc->sc_flags &= ~OSIOP_INTSOFF;
521: osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
522: osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
523: }
524: osiop_scsidone(sc->sc_nexus, status);
525: }
526:
527: if (xs->flags & ITSDONE)
528: break;
529: }
530:
531: splx(s);
532: return;
533: }
534:
535: /*
536: * start next command that's ready
537: */
538: void
539: osiop_sched(sc)
540: struct osiop_softc *sc;
541: {
542: struct osiop_tinfo *ti;
543: struct scsi_link *periph;
544: struct osiop_acb *acb;
545:
546: if ((sc->sc_nexus != NULL) || TAILQ_EMPTY(&sc->ready_list)) {
547: #ifdef OSIOP_DEBUG
548: if (osiop_debug & DEBUG_SCHED)
549: printf("%s: osiop_sched->nexus %p/%d ready %p/%d\n",
550: sc->sc_dev.dv_xname, sc->sc_nexus,
551: sc->sc_nexus != NULL ?
552: sc->sc_nexus->xs->sc_link->target : 0,
553: TAILQ_FIRST(&sc->ready_list),
554: TAILQ_FIRST(&sc->ready_list) != NULL ?
555: TAILQ_FIRST(&sc->ready_list)->xs->sc_link->target :
556: 0);
557: #endif
558: return;
559: }
560: TAILQ_FOREACH(acb, &sc->ready_list, chain) {
561: periph = acb->xs->sc_link;
562: ti = &sc->sc_tinfo[periph->target];
563: if ((ti->lubusy & (1 << periph->lun)) == 0) {
564: TAILQ_REMOVE(&sc->ready_list, acb, chain);
565: sc->sc_nexus = acb;
566: ti->lubusy |= (1 << periph->lun);
567: break;
568: }
569: }
570:
571: if (acb == NULL) {
572: #ifdef OSIOP_DEBUG
573: if (osiop_debug & DEBUG_SCHED)
574: printf("%s: osiop_sched didn't find ready command\n",
575: sc->sc_dev.dv_xname);
576: #endif
577: return;
578: }
579:
580: if (acb->xsflags & SCSI_RESET)
581: osiop_reset(sc);
582:
583: sc->sc_active++;
584: osiop_select(sc);
585: }
586:
587: void
588: osiop_scsidone(acb, status)
589: struct osiop_acb *acb;
590: int status;
591: {
592: struct scsi_xfer *xs;
593: struct scsi_link *periph;
594: struct osiop_softc *sc;
595: int autosense;
596:
597: #ifdef DIAGNOSTIC
598: if (acb == NULL || acb->xs == NULL) {
599: printf("osiop_scsidone: NULL acb or scsi_xfer\n");
600: #if defined(OSIOP_DEBUG) && defined(DDB)
601: Debugger();
602: #endif
603: return;
604: }
605: #endif
606: xs = acb->xs;
607: sc = acb->sc;
608: periph = xs->sc_link;
609:
610: /*
611: * Record if this is the completion of an auto sense
612: * scsi command, and then reset the flag so we don't loop
613: * when such a command fails or times out.
614: */
615: autosense = acb->flags & ACB_F_AUTOSENSE;
616: acb->flags &= ~ACB_F_AUTOSENSE;
617:
618: #ifdef OSIOP_DEBUG
619: if (acb->status != ACB_S_DONE)
620: printf("%s: acb not done (status %d)\n",
621: sc->sc_dev.dv_xname, acb->status);
622: #endif
623:
624: if (acb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
625: bus_dmamap_sync(sc->sc_dmat, acb->datadma, 0, acb->datalen,
626: (acb->xsflags & SCSI_DATA_IN) ?
627: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
628: bus_dmamap_unload(sc->sc_dmat, acb->datadma);
629: }
630:
631: timeout_del(&xs->stimeout);
632: xs->status = status;
633:
634: switch (status) {
635: case SCSI_OK:
636: if (autosense == 0)
637: xs->error = XS_NOERROR;
638: else
639: xs->error = XS_SENSE;
640: break;
641: case SCSI_BUSY:
642: xs->error = XS_BUSY;
643: break;
644: case SCSI_CHECK:
645: if (autosense == 0)
646: acb->flags |= ACB_F_AUTOSENSE;
647: else
648: xs->error = XS_DRIVER_STUFFUP;
649: break;
650: case SCSI_OSIOP_NOCHECK:
651: /*
652: * don't check status, xs->error is already valid
653: */
654: break;
655: case SCSI_OSIOP_NOSTATUS:
656: /*
657: * the status byte was not updated, cmd was
658: * aborted
659: */
660: xs->error = XS_SELTIMEOUT;
661: break;
662: default:
663: #ifdef OSIOP_DEBUG
664: printf("%s: osiop_scsidone: unknown status code (0x%02x)\n",
665: sc->sc_dev.dv_xname, status);
666: #endif
667: xs->error = XS_DRIVER_STUFFUP;
668: break;
669: }
670:
671: /*
672: * Remove the ACB from whatever queue it's on. We have to do a bit of
673: * a hack to figure out which queue it's on. Note that it is *not*
674: * necessary to cdr down the ready queue, but we must cdr down the
675: * nexus queue and see if it's there, so we can mark the unit as no
676: * longer busy. This code is sickening, but it works.
677: */
678: if (acb == sc->sc_nexus) {
679: sc->sc_nexus = NULL;
680: sc->sc_tinfo[periph->target].lubusy &=
681: ~(1 << periph->lun);
682: sc->sc_active--;
683: OSIOP_TRACE('d', 'a', status, 0);
684: } else if (sc->ready_list.tqh_last == &TAILQ_NEXT(acb, chain)) {
685: TAILQ_REMOVE(&sc->ready_list, acb, chain);
686: OSIOP_TRACE('d', 'r', status, 0);
687: } else {
688: struct osiop_acb *acb2;
689: TAILQ_FOREACH(acb2, &sc->nexus_list, chain) {
690: if (acb2 == acb) {
691: TAILQ_REMOVE(&sc->nexus_list, acb, chain);
692: sc->sc_tinfo[periph->target].lubusy &=
693: ~(1 << periph->lun);
694: sc->sc_active--;
695: break;
696: }
697: }
698: if (acb2 == NULL) {
699: if (TAILQ_NEXT(acb, chain) != NULL) {
700: TAILQ_REMOVE(&sc->ready_list, acb, chain);
701: sc->sc_active--;
702: } else {
703: printf("%s: can't find matching acb\n",
704: sc->sc_dev.dv_xname);
705: #ifdef DDB
706: #if 0
707: Debugger();
708: #endif
709: #endif
710: }
711: }
712: OSIOP_TRACE('d', 'n', status, 0);
713: }
714:
715: if ((acb->flags & ACB_F_AUTOSENSE) == 0) {
716: /* Put it on the free list. */
717: FREE:
718: acb->status = ACB_S_FREE;
719: TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
720: sc->sc_tinfo[periph->target].cmds++;
721:
722: xs->resid = 0;
723: xs->flags |= ITSDONE;
724: scsi_done(xs);
725: } else {
726: /* Set up REQUEST_SENSE command */
727: struct scsi_sense *cmd = (struct scsi_sense *)&acb->ds->scsi_cmd;
728: int err;
729:
730: bzero(cmd, sizeof(*cmd));
731: acb->ds->cmd.count = sizeof(*cmd);
732: cmd->opcode = REQUEST_SENSE;
733: cmd->byte2 = xs->sc_link->lun << 5;
734: cmd->length = sizeof(xs->sense);
735:
736: /* Setup DMA map for data buffer */
737: acb->xsflags &= SCSI_POLL | SCSI_NOSLEEP;
738: acb->xsflags |= SCSI_DATA_IN;
739: acb->datalen = sizeof xs->sense;
740: #ifdef OSIOP_DEBUG
741: acb->data = &xs->sense;
742: #endif
743: err = bus_dmamap_load(sc->sc_dmat, acb->datadma,
744: &xs->sense, sizeof(xs->sense), NULL,
745: BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_READ);
746: if (err) {
747: printf("%s: unable to load REQUEST_SENSE data DMA map: %d",
748: sc->sc_dev.dv_xname, err);
749: xs->error = XS_DRIVER_STUFFUP;
750: goto FREE;
751: }
752: bus_dmamap_sync(sc->sc_dmat, acb->datadma,
753: 0, sizeof(xs->sense), BUS_DMASYNC_PREREAD);
754:
755: sc->sc_tinfo[periph->target].senses++;
756: acb->status = ACB_S_READY;
757: TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
758: if (((acb->xsflags & SCSI_POLL) == 0) && ((sc->sc_flags & OSIOP_NODMA) == 0))
759: /* start expire timer */
760: timeout_add(&xs->stimeout, (xs->timeout/1000) * hz);
761: }
762:
763: osiop_sched(sc);
764: }
765:
766: void
767: osiop_abort(sc, where)
768: struct osiop_softc *sc;
769: const char *where;
770: {
771: u_int8_t dstat, sstat0;
772:
773: sstat0 = osiop_read_1(sc, OSIOP_SSTAT0);
774: delay(25); /* Need delay between SSTAT0 and DSTAT reads */
775: dstat = osiop_read_1(sc, OSIOP_DSTAT);
776:
777: printf("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
778: sc->sc_dev.dv_xname, where,
779: dstat, sstat0,
780: osiop_read_1(sc, OSIOP_SBCL));
781:
782: /* XXX XXX XXX */
783: if (sc->sc_active > 0) {
784: sc->sc_active = 0;
785: }
786: }
787:
788: void
789: osiop_init(sc)
790: struct osiop_softc *sc;
791: {
792: int i, inhibit_sync, inhibit_disc;
793:
794: sc->sc_tcp[1] = 1000 / sc->sc_clock_freq;
795: sc->sc_tcp[2] = 1500 / sc->sc_clock_freq;
796: sc->sc_tcp[3] = 2000 / sc->sc_clock_freq;
797: sc->sc_minsync = sc->sc_tcp[1]; /* in 4ns units */
798:
799: if (sc->sc_minsync < 25)
800: sc->sc_minsync = 25;
801:
802: if (sc->sc_clock_freq <= 25) {
803: sc->sc_dcntl |= OSIOP_DCNTL_CF_1; /* SCLK/1 */
804: sc->sc_tcp[0] = sc->sc_tcp[1];
805: } else if (sc->sc_clock_freq <= 37) {
806: sc->sc_dcntl |= OSIOP_DCNTL_CF_1_5; /* SCLK/1.5 */
807: sc->sc_tcp[0] = sc->sc_tcp[2];
808: } else if (sc->sc_clock_freq <= 50) {
809: sc->sc_dcntl |= OSIOP_DCNTL_CF_2; /* SCLK/2 */
810: sc->sc_tcp[0] = sc->sc_tcp[3];
811: } else {
812: sc->sc_dcntl |= OSIOP_DCNTL_CF_3; /* SCLK/3 */
813: sc->sc_tcp[0] = 3000 / sc->sc_clock_freq;
814: }
815:
816: if ((sc->sc_cfflags & 0x10000) != 0) {
817: sc->sc_flags |= OSIOP_NODMA;
818: #ifdef OSIOP_DEBUG
819: printf("%s: DMA disabled; use polling\n",
820: sc->sc_dev.dv_xname);
821: #endif
822: }
823:
824: inhibit_sync = (sc->sc_cfflags & 0xff00) >> 8; /* XXX */
825: inhibit_disc = sc->sc_cfflags & 0x00ff; /* XXX */
826: #ifdef OSIOP_DEBUG
827: if (inhibit_sync != 0)
828: printf("%s: Inhibiting synchronous transfer: 0x%02x\n",
829: sc->sc_dev.dv_xname, inhibit_sync);
830: if (inhibit_disc != 0)
831: printf("%s: Inhibiting disconnect: 0x%02x\n",
832: sc->sc_dev.dv_xname, inhibit_disc);
833: #endif
834: for (i = 0; i < OSIOP_NTGT; i++) {
835: if (inhibit_sync & (1 << i))
836: sc->sc_tinfo[i].flags |= TI_NOSYNC;
837: if (inhibit_disc & (1 << i))
838: sc->sc_tinfo[i].flags |= TI_NODISC;
839: }
840:
841: osiop_resetbus(sc);
842: osiop_reset(sc);
843: }
844:
845: void
846: osiop_reset(sc)
847: struct osiop_softc *sc;
848: {
849: struct osiop_acb *acb;
850: int i, s;
851: u_int8_t stat;
852:
853: #ifdef OSIOP_DEBUG
854: printf("%s: resetting chip\n", sc->sc_dev.dv_xname);
855: #endif
856: if (sc->sc_flags & OSIOP_ALIVE)
857: osiop_abort(sc, "reset");
858:
859: s = splbio();
860:
861: /*
862: * Reset the chip
863: * XXX - is this really needed?
864: */
865:
866: /* abort current script */
867: osiop_write_1(sc, OSIOP_ISTAT,
868: osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_ABRT);
869: /* reset chip */
870: osiop_write_1(sc, OSIOP_ISTAT,
871: osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_RST);
872: delay(100);
873: osiop_write_1(sc, OSIOP_ISTAT,
874: osiop_read_1(sc, OSIOP_ISTAT) & ~OSIOP_ISTAT_RST);
875: delay(100);
876:
877: /*
878: * Set up various chip parameters
879: */
880: osiop_write_1(sc, OSIOP_SCNTL0,
881: OSIOP_ARB_FULL | OSIOP_SCNTL0_EPC | OSIOP_SCNTL0_EPG);
882: osiop_write_1(sc, OSIOP_SCNTL1, OSIOP_SCNTL1_ESR);
883: osiop_write_1(sc, OSIOP_DCNTL, sc->sc_dcntl);
884: osiop_write_1(sc, OSIOP_DMODE, sc->sc_dmode);
885: /* don't enable interrupts yet */
886: osiop_write_1(sc, OSIOP_SIEN, 0x00);
887: osiop_write_1(sc, OSIOP_DIEN, 0x00);
888: osiop_write_1(sc, OSIOP_SCID, OSIOP_SCID_VALUE(sc->sc_id));
889: osiop_write_1(sc, OSIOP_DWT, 0x00);
890: osiop_write_1(sc, OSIOP_CTEST0, osiop_read_1(sc, OSIOP_CTEST0)
891: | OSIOP_CTEST0_BTD | OSIOP_CTEST0_EAN);
892: osiop_write_1(sc, OSIOP_CTEST7,
893: osiop_read_1(sc, OSIOP_CTEST7) | sc->sc_ctest7);
894:
895: /* will need to re-negotiate sync xfers */
896: for (i = 0; i < OSIOP_NTGT; i++) {
897: sc->sc_tinfo[i].state = NEG_INIT;
898: sc->sc_tinfo[i].period = 0;
899: sc->sc_tinfo[i].offset = 0;
900: }
901:
902: stat = osiop_read_1(sc, OSIOP_ISTAT);
903: if (stat & OSIOP_ISTAT_SIP)
904: osiop_read_1(sc, OSIOP_SSTAT0);
905: if (stat & OSIOP_ISTAT_DIP) {
906: if (stat & OSIOP_ISTAT_SIP)
907: /* Need delay between SSTAT0 and DSTAT reads */
908: delay(25);
909: osiop_read_1(sc, OSIOP_DSTAT);
910: }
911:
912: splx(s);
913:
914: delay(osiop_reset_delay * 1000);
915:
916: s = splbio();
917: if (sc->sc_nexus != NULL) {
918: sc->sc_nexus->xs->error =
919: (sc->sc_nexus->flags & ACB_F_TIMEOUT) ?
920: XS_TIMEOUT : XS_RESET;
921: sc->sc_nexus->status = ACB_S_DONE;
922: osiop_scsidone(sc->sc_nexus, SCSI_OSIOP_NOCHECK);
923: }
924: while ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) {
925: acb->xs->error = (acb->flags & ACB_F_TIMEOUT) ?
926: XS_TIMEOUT : XS_RESET;
927: acb->status = ACB_S_DONE;
928: osiop_scsidone(acb, SCSI_OSIOP_NOCHECK);
929: }
930: splx(s);
931:
932: sc->sc_flags &= ~(OSIOP_INTDEFER | OSIOP_INTSOFF);
933: /* enable SCSI and DMA interrupts */
934: sc->sc_sien = OSIOP_SIEN_M_A | OSIOP_SIEN_STO | /*OSIOP_SIEN_SEL |*/
935: OSIOP_SIEN_SGE | OSIOP_SIEN_UDC | OSIOP_SIEN_RST | OSIOP_SIEN_PAR;
936: sc->sc_dien = OSIOP_DIEN_BF | OSIOP_DIEN_ABRT | OSIOP_DIEN_SIR |
937: /*OSIOP_DIEN_WTD |*/ OSIOP_DIEN_IID;
938: osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
939: osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
940: }
941:
942: void
943: osiop_resetbus(sc)
944: struct osiop_softc *sc;
945: {
946:
947: osiop_write_1(sc, OSIOP_SIEN, 0);
948: osiop_write_1(sc, OSIOP_SCNTL1,
949: osiop_read_1(sc, OSIOP_SCNTL1) | OSIOP_SCNTL1_RST);
950: delay(25);
951: osiop_write_1(sc, OSIOP_SCNTL1,
952: osiop_read_1(sc, OSIOP_SCNTL1) & ~OSIOP_SCNTL1_RST);
953: }
954:
955: /*
956: * Setup Data Storage for 53C710 and start SCRIPTS processing
957: */
958:
959: void
960: osiop_start(sc)
961: struct osiop_softc *sc;
962: {
963: struct osiop_acb *acb = sc->sc_nexus;
964: struct osiop_ds *ds = acb->ds;
965: struct scsi_xfer *xs = acb->xs;
966: bus_dmamap_t dsdma = sc->sc_dsdma, datadma = acb->datadma;
967: struct osiop_tinfo *ti;
968: int target = xs->sc_link->target;
969: int lun = xs->sc_link->lun;
970: int disconnect, i;
971:
972: #ifdef OSIOP_DEBUG
973: if (osiop_debug & DEBUG_DISC &&
974: osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
975: printf("ACK! osiop was busy: script %p dsa %p active %d\n",
976: sc->sc_script, acb->ds, sc->sc_active);
977: printf("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n",
978: osiop_read_1(sc, OSIOP_ISTAT),
979: osiop_read_1(sc, OSIOP_SFBR),
980: osiop_read_1(sc, OSIOP_LCRC),
981: osiop_read_1(sc, OSIOP_SIEN),
982: osiop_read_1(sc, OSIOP_DIEN));
983: #ifdef DDB
984: #if 0
985: Debugger();
986: #endif
987: #endif
988: }
989: #endif
990:
991: #ifdef OSIOP_DEBUG
992: if (acb->status != ACB_S_READY)
993: panic("osiop_start: non-ready cmd in acb");
994: #endif
995:
996: acb->intstat = 0;
997:
998: ti = &sc->sc_tinfo[target];
999: ds->scsi_addr = ((1 << 16) << target) | (ti->sxfer << 8);
1000:
1001: disconnect = (ds->scsi_cmd.opcode != REQUEST_SENSE) &&
1002: (ti->flags & TI_NODISC) == 0;
1003:
1004: ds->msgout[0] = MSG_IDENTIFY(lun, disconnect);
1005: ds->id.count = 1;
1006: ds->stat[0] = SCSI_OSIOP_NOSTATUS; /* set invalid status */
1007: ds->msgbuf[0] = ds->msgbuf[1] = MSG_INVALID;
1008: bzero(&ds->data, sizeof(ds->data));
1009:
1010: /*
1011: * Negotiate wide is the initial negotiation state; since the 53c710
1012: * doesn't do wide transfers, just begin the synchronous transfer
1013: * negotiation here.
1014: */
1015: if (ti->state == NEG_INIT) {
1016: if ((ti->flags & TI_NOSYNC) != 0) {
1017: ti->state = NEG_DONE;
1018: ti->period = 0;
1019: ti->offset = 0;
1020: osiop_update_xfer_mode(sc, target);
1021: #ifdef OSIOP_DEBUG
1022: if (osiop_debug & DEBUG_SYNC)
1023: printf("Forcing target %d asynchronous\n",
1024: target);
1025: #endif
1026: } else {
1027: ds->msgbuf[2] = MSG_INVALID;
1028: ds->msgout[1] = MSG_EXTENDED;
1029: ds->msgout[2] = MSG_EXT_SDTR_LEN;
1030: ds->msgout[3] = MSG_EXT_SDTR;
1031: ds->msgout[4] = sc->sc_minsync;
1032: ds->msgout[5] = OSIOP_MAX_OFFSET;
1033: ds->id.count = MSG_EXT_SDTR_LEN + 3;
1034: ti->state = NEG_WAITS;
1035: #ifdef OSIOP_DEBUG
1036: if (osiop_debug & DEBUG_SYNC)
1037: printf("Sending sync request to target %d\n",
1038: target);
1039: #endif
1040: }
1041: }
1042:
1043: acb->curaddr = 0;
1044: acb->curlen = 0;
1045:
1046: /*
1047: * Build physical DMA addresses for scatter/gather I/O
1048: */
1049: if (acb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
1050: for (i = 0; i < datadma->dm_nsegs; i++) {
1051: ds->data[i].count = datadma->dm_segs[i].ds_len;
1052: ds->data[i].addr = datadma->dm_segs[i].ds_addr;
1053: }
1054: }
1055:
1056: /* sync script data structure */
1057: bus_dmamap_sync(sc->sc_dmat, dsdma,
1058: acb->dsoffset, sizeof(struct osiop_ds),
1059: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1060:
1061: acb->status = ACB_S_ACTIVE;
1062:
1063: #ifdef OSIOP_DEBUG
1064: if (osiop_debug & DEBUG_DISC &&
1065: osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
1066: printf("ACK! osiop was busy at start: "
1067: "script %p dsa %p active %d\n",
1068: sc->sc_script, acb->ds, sc->sc_active);
1069: #ifdef DDB
1070: #if 0
1071: Debugger();
1072: #endif
1073: #endif
1074: }
1075: #endif
1076: if (TAILQ_EMPTY(&sc->nexus_list)) {
1077: if (osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON)
1078: printf("%s: osiop_select while connected?\n",
1079: sc->sc_dev.dv_xname);
1080: osiop_write_4(sc, OSIOP_TEMP, 0);
1081: osiop_write_1(sc, OSIOP_SBCL, ti->sbcl);
1082: osiop_write_4(sc, OSIOP_DSA,
1083: dsdma->dm_segs[0].ds_addr + acb->dsoffset);
1084: osiop_write_4(sc, OSIOP_DSP,
1085: sc->sc_scrdma->dm_segs[0].ds_addr + Ent_scripts);
1086: OSIOP_TRACE('s', 1, 0, 0);
1087: } else {
1088: if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) {
1089: osiop_write_1(sc, OSIOP_ISTAT, OSIOP_ISTAT_SIGP);
1090: OSIOP_TRACE('s', 2, 0, 0);
1091: } else {
1092: OSIOP_TRACE('s', 3,
1093: osiop_read_1(sc, OSIOP_ISTAT), 0);
1094: }
1095: }
1096: #ifdef OSIOP_DEBUG
1097: osiopstarts++;
1098: #endif
1099: }
1100:
1101: /*
1102: * Process a DMA or SCSI interrupt from the 53C710 SIOP
1103: */
1104:
1105: int
1106: osiop_checkintr(sc, istat, dstat, sstat0, status)
1107: struct osiop_softc *sc;
1108: u_int8_t istat;
1109: u_int8_t dstat;
1110: u_int8_t sstat0;
1111: int *status;
1112: {
1113: struct osiop_acb *acb = sc->sc_nexus;
1114: struct osiop_ds *ds;
1115: bus_dmamap_t dsdma = sc->sc_dsdma;
1116: bus_addr_t scraddr = sc->sc_scrdma->dm_segs[0].ds_addr;
1117: int target = 0;
1118: int dfifo, dbc, intcode, sstat1;
1119:
1120: dfifo = osiop_read_1(sc, OSIOP_DFIFO);
1121: dbc = osiop_read_4(sc, OSIOP_DBC) & 0x00ffffff;
1122: sstat1 = osiop_read_1(sc, OSIOP_SSTAT1);
1123: osiop_write_1(sc, OSIOP_CTEST8,
1124: osiop_read_1(sc, OSIOP_CTEST8) | OSIOP_CTEST8_CLF);
1125: while ((osiop_read_1(sc, OSIOP_CTEST1) & OSIOP_CTEST1_FMT) !=
1126: OSIOP_CTEST1_FMT)
1127: ;
1128: osiop_write_1(sc, OSIOP_CTEST8,
1129: osiop_read_1(sc, OSIOP_CTEST8) & ~OSIOP_CTEST8_CLF);
1130: intcode = osiop_read_4(sc, OSIOP_DSPS);
1131: #ifdef OSIOP_DEBUG
1132: osiopints++;
1133: if (osiop_read_4(sc, OSIOP_DSP) != 0 &&
1134: (osiop_read_4(sc, OSIOP_DSP) < scraddr ||
1135: osiop_read_4(sc, OSIOP_DSP) >= scraddr + sizeof(osiop_script))) {
1136: printf("%s: dsp not within script dsp %x scripts %lx:%lx",
1137: sc->sc_dev.dv_xname,
1138: osiop_read_4(sc, OSIOP_DSP),
1139: scraddr, scraddr + sizeof(osiop_script));
1140: printf(" istat %x dstat %x sstat0 %x\n", istat, dstat, sstat0);
1141: #ifdef DDB
1142: Debugger();
1143: #endif
1144: }
1145: #endif
1146: OSIOP_TRACE('i', dstat, istat, (istat & OSIOP_ISTAT_DIP) ?
1147: intcode & 0xff : sstat0);
1148:
1149: ds = NULL;
1150: if (acb != NULL) { /* XXX */
1151: ds = acb->ds;
1152: bus_dmamap_sync(sc->sc_dmat, dsdma,
1153: acb->dsoffset, sizeof(struct osiop_ds),
1154: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1155: #ifdef OSIOP_DEBUG
1156: if (acb->status != ACB_S_ACTIVE)
1157: printf("osiop_checkintr: acb not active (status %d)\n",
1158: acb->status);
1159: #endif
1160: }
1161:
1162: if (dstat & OSIOP_DSTAT_SIR && intcode == A_ok) {
1163: /* Normal completion status, or check condition */
1164: struct osiop_tinfo *ti;
1165: if (acb == NULL) {
1166: printf("%s: COMPLETE with no active command?\n",
1167: sc->sc_dev.dv_xname);
1168: return (0);
1169: }
1170: #ifdef OSIOP_DEBUG
1171: if (osiop_read_4(sc, OSIOP_DSA) !=
1172: dsdma->dm_segs[0].ds_addr + acb->dsoffset) {
1173: printf("osiop: invalid dsa: %x %lx\n",
1174: osiop_read_4(sc, OSIOP_DSA),
1175: dsdma->dm_segs[0].ds_addr + acb->dsoffset);
1176: panic("*** osiop DSA invalid ***");
1177: }
1178: #endif
1179: target = acb->xs->sc_link->target;
1180: ti = &sc->sc_tinfo[target];
1181: if (ti->state == NEG_WAITS) {
1182: if (ds->msgbuf[1] == MSG_INVALID)
1183: printf("%s: target %d ignored sync request\n",
1184: sc->sc_dev.dv_xname, target);
1185: else if (ds->msgbuf[1] == MSG_MESSAGE_REJECT)
1186: printf("%s: target %d rejected sync request\n",
1187: sc->sc_dev.dv_xname, target);
1188: ti->period = 0;
1189: ti->offset = 0;
1190: osiop_update_xfer_mode(sc, target);
1191: ti->state = NEG_DONE;
1192: }
1193: #ifdef OSIOP_DEBUG
1194: if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
1195: #if 0
1196: printf("ACK! osiop was busy at end: "
1197: "script %p dsa %p\n", &osiop_script, ds);
1198: #ifdef DDB
1199: Debugger();
1200: #endif
1201: #endif
1202: }
1203: if (ds->msgbuf[0] != MSG_CMDCOMPLETE)
1204: printf("%s: message was not COMMAND COMPLETE: %02x\n",
1205: sc->sc_dev.dv_xname, ds->msgbuf[0]);
1206: #endif
1207: if (!TAILQ_EMPTY(&sc->nexus_list))
1208: osiop_write_1(sc, OSIOP_DCNTL,
1209: osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1210: *status = ds->stat[0];
1211: acb->status = ACB_S_DONE;
1212: return (1);
1213: }
1214: if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_syncmsg) {
1215: if (acb == NULL) {
1216: printf("%s: Sync message with no active command?\n",
1217: sc->sc_dev.dv_xname);
1218: return (0);
1219: }
1220: target = acb->xs->sc_link->target;
1221: if (ds->msgbuf[1] == MSG_EXTENDED &&
1222: ds->msgbuf[2] == MSG_EXT_SDTR_LEN &&
1223: ds->msgbuf[3] == MSG_EXT_SDTR) {
1224: struct osiop_tinfo *ti = &sc->sc_tinfo[target];
1225: #ifdef OSIOP_DEBUG
1226: if (osiop_debug & DEBUG_SYNC)
1227: printf("sync msg in: "
1228: "%02x %02x %02x %02x %02x %02x\n",
1229: ds->msgbuf[0], ds->msgbuf[1],
1230: ds->msgbuf[2], ds->msgbuf[3],
1231: ds->msgbuf[4], ds->msgbuf[5]);
1232: #endif
1233: ti->period = ds->msgbuf[4];
1234: ti->offset = ds->msgbuf[5];
1235: osiop_update_xfer_mode(sc, target);
1236:
1237: bus_dmamap_sync(sc->sc_dmat, dsdma,
1238: acb->dsoffset, sizeof(struct osiop_ds),
1239: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1240: osiop_write_1(sc, OSIOP_SXFER, ti->sxfer);
1241: osiop_write_1(sc, OSIOP_SBCL, ti->sbcl);
1242: if (ti->state == NEG_WAITS) {
1243: ti->state = NEG_DONE;
1244: osiop_write_4(sc, OSIOP_DSP,
1245: scraddr + Ent_clear_ack);
1246: return (0);
1247: }
1248: osiop_write_1(sc, OSIOP_DCNTL,
1249: osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1250: ti->state = NEG_DONE;
1251: return (0);
1252: }
1253: /* XXX - not SDTR message */
1254: }
1255: if (sstat0 & OSIOP_SSTAT0_M_A) {
1256: /* Phase mismatch */
1257: #ifdef OSIOP_DEBUG
1258: osiopphmm++;
1259: #endif
1260: if (acb == NULL) {
1261: printf("%s: Phase mismatch with no active command?\n",
1262: sc->sc_dev.dv_xname);
1263: return (0);
1264: }
1265: if (acb->datalen > 0) {
1266: int adjust = (dfifo - (dbc & 0x7f)) & 0x7f;
1267: if (sstat1 & OSIOP_SSTAT1_ORF)
1268: adjust++;
1269: if (sstat1 & OSIOP_SSTAT1_OLF)
1270: adjust++;
1271: acb->curaddr = osiop_read_4(sc, OSIOP_DNAD) - adjust;
1272: acb->curlen = dbc + adjust;
1273: #ifdef OSIOP_DEBUG
1274: if (osiop_debug & DEBUG_DISC) {
1275: printf("Phase mismatch: curaddr %lx "
1276: "curlen %lx dfifo %x dbc %x sstat1 %x "
1277: "adjust %x sbcl %x starts %d acb %p\n",
1278: acb->curaddr, acb->curlen, dfifo,
1279: dbc, sstat1, adjust,
1280: osiop_read_1(sc, OSIOP_SBCL),
1281: osiopstarts, acb);
1282: if (ds->data[1].count != 0) {
1283: int i;
1284: for (i = 0; ds->data[i].count != 0; i++)
1285: printf("chain[%d] "
1286: "addr %x len %x\n", i,
1287: ds->data[i].addr,
1288: ds->data[i].count);
1289: }
1290: bus_dmamap_sync(sc->sc_dmat, dsdma,
1291: acb->dsoffset, sizeof(struct osiop_ds),
1292: BUS_DMASYNC_PREREAD |
1293: BUS_DMASYNC_PREWRITE);
1294: }
1295: #endif
1296: }
1297: #ifdef OSIOP_DEBUG
1298: OSIOP_TRACE('m', osiop_read_1(sc, OSIOP_SBCL),
1299: osiop_read_4(sc, OSIOP_DSP) >> 8,
1300: osiop_read_4(sc, OSIOP_DSP));
1301: if (osiop_debug & DEBUG_PHASE)
1302: printf("Phase mismatch: %x dsp +%lx dcmd %x\n",
1303: osiop_read_1(sc, OSIOP_SBCL),
1304: osiop_read_4(sc, OSIOP_DSP) - scraddr,
1305: osiop_read_4(sc, OSIOP_DBC));
1306: #endif
1307: if ((osiop_read_1(sc, OSIOP_SBCL) & OSIOP_REQ) == 0) {
1308: printf("Phase mismatch: "
1309: "REQ not asserted! %02x dsp %x\n",
1310: osiop_read_1(sc, OSIOP_SBCL),
1311: osiop_read_4(sc, OSIOP_DSP));
1312: #if defined(OSIOP_DEBUG) && defined(DDB)
1313: /*Debugger(); XXX is*/
1314: #endif
1315: }
1316: switch (OSIOP_PHASE(osiop_read_1(sc, OSIOP_SBCL))) {
1317: case DATA_OUT_PHASE:
1318: case DATA_IN_PHASE:
1319: case STATUS_PHASE:
1320: case COMMAND_PHASE:
1321: case MSG_IN_PHASE:
1322: case MSG_OUT_PHASE:
1323: osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_switch);
1324: break;
1325: default:
1326: printf("%s: invalid phase\n", sc->sc_dev.dv_xname);
1327: goto bad_phase;
1328: }
1329: return (0);
1330: }
1331: if (sstat0 & OSIOP_SSTAT0_STO) {
1332: /* Select timed out */
1333: if (acb == NULL) {
1334: printf("%s: Select timeout with no active command?\n",
1335: sc->sc_dev.dv_xname);
1336: #if 0
1337: return (0);
1338: #else
1339: goto bad_phase;
1340: #endif
1341: }
1342: #ifdef OSIOP_DEBUG
1343: if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
1344: printf("ACK! osiop was busy at timeout: "
1345: "script %p dsa %lx\n", sc->sc_script,
1346: dsdma->dm_segs[0].ds_addr + acb->dsoffset);
1347: printf(" sbcl %x sdid %x "
1348: "istat %x dstat %x sstat0 %x\n",
1349: osiop_read_1(sc, OSIOP_SBCL),
1350: osiop_read_1(sc, OSIOP_SDID),
1351: istat, dstat, sstat0);
1352: if ((osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) == 0) {
1353: printf("Yikes, it's not busy now!\n");
1354: #if 0
1355: *status = SCSI_OSIOP_NOSTATUS;
1356: if (!TAILQ_EMPTY(&sc->nexus_list))
1357: osiop_write_4(sc, OSIOP_DSP,
1358: scraddr + Ent_wait_reselect);
1359: return (1);
1360: #endif
1361: }
1362: #if 0
1363: osiop_write_1(sc, OSIOP_DCNTL,
1364: osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1365: #endif
1366: #ifdef DDB
1367: Debugger();
1368: #endif
1369: return (0);
1370: }
1371: #endif
1372: acb->status = ACB_S_DONE;
1373: *status = SCSI_OSIOP_NOSTATUS;
1374: acb->xs->error = XS_SELTIMEOUT;
1375: if (!TAILQ_EMPTY(&sc->nexus_list))
1376: osiop_write_4(sc, OSIOP_DSP,
1377: scraddr + Ent_wait_reselect);
1378: return (1);
1379: }
1380: if (acb != NULL)
1381: target = acb->xs->sc_link->target;
1382: else
1383: target = sc->sc_id;
1384: if (sstat0 & OSIOP_SSTAT0_UDC) {
1385: #ifdef OSIOP_DEBUG
1386: if (acb == NULL)
1387: printf("%s: Unexpected disconnect "
1388: "with no active command?\n", sc->sc_dev.dv_xname);
1389: printf("%s: target %d disconnected unexpectedly\n",
1390: sc->sc_dev.dv_xname, target);
1391: #endif
1392: #if 0
1393: osiop_abort(sc, "osiop_chkintr");
1394: #endif
1395: *status = SCSI_CHECK;
1396: if (!TAILQ_EMPTY(&sc->nexus_list))
1397: osiop_write_4(sc, OSIOP_DSP,
1398: scraddr + Ent_wait_reselect);
1399: return (acb != NULL);
1400: }
1401: if (dstat & OSIOP_DSTAT_SIR &&
1402: (intcode == A_int_disc || intcode == A_int_disc_wodp)) {
1403: /* Disconnect */
1404: if (acb == NULL) {
1405: printf("%s: Disconnect with no active command?\n",
1406: sc->sc_dev.dv_xname);
1407: return (0);
1408: }
1409: #ifdef OSIOP_DEBUG
1410: if (osiop_debug & DEBUG_DISC) {
1411: printf("%s: ID %02x disconnected TEMP %x (+%lx) "
1412: "curaddr %lx curlen %lx buf %x len %x dfifo %x "
1413: "dbc %x sstat1 %x starts %d acb %p\n",
1414: sc->sc_dev.dv_xname, 1 << target,
1415: osiop_read_4(sc, OSIOP_TEMP),
1416: (osiop_read_4(sc, OSIOP_TEMP) != 0) ?
1417: osiop_read_4(sc, OSIOP_TEMP) - scraddr : 0,
1418: acb->curaddr, acb->curlen,
1419: ds->data[0].addr, ds->data[0].count,
1420: dfifo, dbc, sstat1, osiopstarts, acb);
1421: bus_dmamap_sync(sc->sc_dmat, dsdma,
1422: acb->dsoffset, sizeof(struct osiop_ds),
1423: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1424: }
1425: #endif
1426: /*
1427: * XXXX need to update curaddr/curlen to reflect
1428: * current data transferred. If device disconnected in
1429: * the middle of a DMA block, they should already be set
1430: * by the phase change interrupt. If the disconnect
1431: * occurs on a DMA block boundary, we have to figure out
1432: * which DMA block it was.
1433: */
1434: if (acb->datalen > 0 &&
1435: osiop_read_4(sc, OSIOP_TEMP) != 0) {
1436: long n = osiop_read_4(sc, OSIOP_TEMP) - scraddr;
1437:
1438: if (acb->curlen != 0 &&
1439: acb->curlen != ds->data[0].count)
1440: printf("%s: curaddr/curlen already set? "
1441: "n %lx iob %lx/%lx chain[0] %x/%x\n",
1442: sc->sc_dev.dv_xname, n,
1443: acb->curaddr, acb->curlen,
1444: ds->data[0].addr, ds->data[0].count);
1445: if (n < Ent_datain)
1446: n = (n - Ent_dataout) / 16;
1447: else
1448: n = (n - Ent_datain) / 16;
1449: if (n < 0 || n >= OSIOP_NSG)
1450: printf("TEMP invalid %ld\n", n);
1451: else {
1452: acb->curaddr = ds->data[n].addr;
1453: acb->curlen = ds->data[n].count;
1454: }
1455: #ifdef OSIOP_DEBUG
1456: if (osiop_debug & DEBUG_DISC) {
1457: printf("%s: TEMP offset %ld",
1458: sc->sc_dev.dv_xname, n);
1459: printf(" curaddr %lx curlen %lx\n",
1460: acb->curaddr, acb->curlen);
1461: }
1462: #endif
1463: }
1464: /*
1465: * If data transfer was interrupted by disconnect, curaddr
1466: * and curlen should reflect the point of interruption.
1467: * Adjust the DMA chain so that the data transfer begins
1468: * at the appropriate place upon reselection.
1469: * XXX This should only be done on save data pointer message?
1470: */
1471: if (acb->curlen > 0) {
1472: int i, j;
1473: #ifdef OSIOP_DEBUG
1474: if (osiop_debug & DEBUG_DISC)
1475: printf("%s: adjusting DMA chain\n",
1476: sc->sc_dev.dv_xname);
1477: if (intcode == A_int_disc_wodp)
1478: printf("%s: ID %02x disconnected "
1479: "without Save Data Pointers\n",
1480: sc->sc_dev.dv_xname, 1 << target);
1481: #endif
1482: for (i = 0; i < OSIOP_NSG; i++) {
1483: if (ds->data[i].count == 0)
1484: break;
1485: if (acb->curaddr >= ds->data[i].addr &&
1486: acb->curaddr <
1487: (ds->data[i].addr + ds->data[i].count))
1488: break;
1489: }
1490: if (i >= OSIOP_NSG || ds->data[i].count == 0) {
1491: printf("couldn't find saved data pointer: "
1492: "curaddr %lx curlen %lx i %d\n",
1493: acb->curaddr, acb->curlen, i);
1494: #if defined(OSIOP_DEBUG) && defined(DDB)
1495: Debugger();
1496: #endif
1497: }
1498: #ifdef OSIOP_DEBUG
1499: if (osiop_debug & DEBUG_DISC)
1500: printf(" chain[0]: %x/%x -> %lx/%lx\n",
1501: ds->data[0].addr, ds->data[0].count,
1502: acb->curaddr, acb->curlen);
1503: #endif
1504: ds->data[0].addr = acb->curaddr;
1505: ds->data[0].count = acb->curlen;
1506: for (j = 1, i = i + 1;
1507: i < OSIOP_NSG && ds->data[i].count > 0;
1508: i++, j++) {
1509: #ifdef OSIOP_DEBUG
1510: if (osiop_debug & DEBUG_DISC)
1511: printf(" chain[%d]: %x/%x -> %x/%x\n",
1512: j,
1513: ds->data[j].addr, ds->data[j].count,
1514: ds->data[i].addr, ds->data[i].count);
1515: #endif
1516: ds->data[j].addr = ds->data[i].addr;
1517: ds->data[j].count = ds->data[i].count;
1518: }
1519: if (j < OSIOP_NSG) {
1520: ds->data[j].addr = 0;
1521: ds->data[j].count = 0;
1522: }
1523: bus_dmamap_sync(sc->sc_dmat, dsdma,
1524: acb->dsoffset, sizeof(struct osiop_ds),
1525: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1526: }
1527: sc->sc_tinfo[target].dconns++;
1528: /*
1529: * add nexus to waiting list
1530: * clear nexus
1531: * try to start another command for another target/lun
1532: */
1533: acb->intstat = sc->sc_flags & OSIOP_INTSOFF;
1534: TAILQ_INSERT_TAIL(&sc->nexus_list, acb, chain);
1535: sc->sc_nexus = NULL; /* no current device */
1536: osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_wait_reselect);
1537: /* XXXX start another command ? */
1538: osiop_sched(sc);
1539: return (0);
1540: }
1541: if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_reconnect) {
1542: int reselid = ffs(osiop_read_4(sc, OSIOP_SCRATCH) & 0xff) - 1;
1543: int reselun = osiop_read_1(sc, OSIOP_SFBR) & 0x07;
1544: #ifdef OSIOP_DEBUG
1545: u_int8_t resmsg;
1546: #endif
1547:
1548: /* Reconnect */
1549: /* XXXX save current SBCL */
1550: sc->sc_sstat1 = osiop_read_1(sc, OSIOP_SBCL);
1551: #ifdef OSIOP_DEBUG
1552: if (osiop_debug & DEBUG_DISC)
1553: printf("%s: target ID %02x reselected dsps %x\n",
1554: sc->sc_dev.dv_xname, reselid, intcode);
1555: resmsg = osiop_read_1(sc, OSIOP_SFBR);
1556: if (!MSG_ISIDENTIFY(resmsg))
1557: printf("%s: Reselect message in was not identify: "
1558: "%02x\n", sc->sc_dev.dv_xname, resmsg);
1559: #endif
1560: if (sc->sc_nexus != NULL) {
1561: struct scsi_link *periph =
1562: sc->sc_nexus->xs->sc_link;
1563: #ifdef OSIOP_DEBUG
1564: if (osiop_debug & DEBUG_DISC)
1565: printf("%s: reselect ID %02x w/active\n",
1566: sc->sc_dev.dv_xname, reselid);
1567: #endif
1568: TAILQ_INSERT_HEAD(&sc->ready_list,
1569: sc->sc_nexus, chain);
1570: sc->sc_tinfo[periph->target].lubusy
1571: &= ~(1 << periph->lun);
1572: sc->sc_active--;
1573: }
1574: /*
1575: * locate acb of reselecting device
1576: * set sc->sc_nexus to acb
1577: */
1578: TAILQ_FOREACH(acb, &sc->nexus_list, chain) {
1579: struct scsi_link *periph = acb->xs->sc_link;
1580: if (reselid != periph->target ||
1581: reselun != periph->lun) {
1582: continue;
1583: }
1584: TAILQ_REMOVE(&sc->nexus_list, acb, chain);
1585: sc->sc_nexus = acb;
1586: sc->sc_flags |= acb->intstat;
1587: acb->intstat = 0;
1588: osiop_write_4(sc, OSIOP_DSA,
1589: dsdma->dm_segs[0].ds_addr + acb->dsoffset);
1590: osiop_write_1(sc, OSIOP_SXFER,
1591: sc->sc_tinfo[reselid].sxfer);
1592: osiop_write_1(sc, OSIOP_SBCL,
1593: sc->sc_tinfo[reselid].sbcl);
1594: break;
1595: }
1596: if (acb == NULL) {
1597: printf("%s: target ID %02x reselect nexus_list %p\n",
1598: sc->sc_dev.dv_xname, reselid,
1599: TAILQ_FIRST(&sc->nexus_list));
1600: panic("unable to find reselecting device");
1601: }
1602:
1603: osiop_write_4(sc, OSIOP_TEMP, 0);
1604: osiop_write_1(sc, OSIOP_DCNTL,
1605: osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1606: return (0);
1607: }
1608: if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_connect) {
1609: #ifdef OSIOP_DEBUG
1610: u_int8_t ctest2 = osiop_read_1(sc, OSIOP_CTEST2);
1611:
1612: /* reselect was interrupted (by Sig_P or select) */
1613: if (osiop_debug & DEBUG_DISC ||
1614: (ctest2 & OSIOP_CTEST2_SIGP) == 0)
1615: printf("%s: reselect interrupted (Sig_P?) "
1616: "scntl1 %x ctest2 %x sfbr %x istat %x/%x\n",
1617: sc->sc_dev.dv_xname,
1618: osiop_read_1(sc, OSIOP_SCNTL1), ctest2,
1619: osiop_read_1(sc, OSIOP_SFBR), istat,
1620: osiop_read_1(sc, OSIOP_ISTAT));
1621: #endif
1622: /* XXX assumes it was not select */
1623: if (sc->sc_nexus == NULL) {
1624: #ifdef OSIOP_DEBUG
1625: printf("%s: reselect interrupted, sc_nexus == NULL\n",
1626: sc->sc_dev.dv_xname);
1627: #if 0
1628: osiop_dump(sc);
1629: #ifdef DDB
1630: Debugger();
1631: #endif
1632: #endif
1633: #endif
1634: osiop_write_1(sc, OSIOP_DCNTL,
1635: osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1636: return (0);
1637: }
1638: target = sc->sc_nexus->xs->sc_link->target;
1639: osiop_write_4(sc, OSIOP_TEMP, 0);
1640: osiop_write_4(sc, OSIOP_DSA,
1641: dsdma->dm_segs[0].ds_addr + sc->sc_nexus->dsoffset);
1642: osiop_write_1(sc, OSIOP_SXFER, sc->sc_tinfo[target].sxfer);
1643: osiop_write_1(sc, OSIOP_SBCL, sc->sc_tinfo[target].sbcl);
1644: osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_scripts);
1645: return (0);
1646: }
1647: if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_msgin) {
1648: /* Unrecognized message in byte */
1649: if (acb == NULL) {
1650: printf("%s: Bad message-in with no active command?\n",
1651: sc->sc_dev.dv_xname);
1652: return (0);
1653: }
1654: printf("%s: Unrecognized message in data "
1655: "sfbr %x msg %x sbcl %x\n", sc->sc_dev.dv_xname,
1656: osiop_read_1(sc, OSIOP_SFBR), ds->msgbuf[1],
1657: osiop_read_1(sc, OSIOP_SBCL));
1658: /* what should be done here? */
1659: osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_switch);
1660: bus_dmamap_sync(sc->sc_dmat, dsdma,
1661: acb->dsoffset, sizeof(struct osiop_ds),
1662: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1663: return (0);
1664: }
1665: if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_status) {
1666: /* Status phase wasn't followed by message in phase? */
1667: printf("%s: Status phase not followed by message in phase? "
1668: "sbcl %x sbdl %x\n", sc->sc_dev.dv_xname,
1669: osiop_read_1(sc, OSIOP_SBCL),
1670: osiop_read_1(sc, OSIOP_SBDL));
1671: if (osiop_read_1(sc, OSIOP_SBCL) == 0xa7) {
1672: /* It is now, just continue the script? */
1673: osiop_write_1(sc, OSIOP_DCNTL,
1674: osiop_read_1(sc, OSIOP_DCNTL) | OSIOP_DCNTL_STD);
1675: return (0);
1676: }
1677: }
1678: if (dstat & OSIOP_DSTAT_SIR && sstat0 == 0) {
1679: printf("OSIOP interrupt: %x sts %x msg %x %x sbcl %x\n",
1680: intcode, ds->stat[0], ds->msgbuf[0], ds->msgbuf[1],
1681: osiop_read_1(sc, OSIOP_SBCL));
1682: osiop_reset(sc);
1683: *status = SCSI_OSIOP_NOSTATUS;
1684: return (0); /* osiop_reset has cleaned up */
1685: }
1686: if (sstat0 & OSIOP_SSTAT0_SGE)
1687: printf("%s: SCSI Gross Error\n", sc->sc_dev.dv_xname);
1688: if (sstat0 & OSIOP_SSTAT0_PAR)
1689: printf("%s: Parity Error\n", sc->sc_dev.dv_xname);
1690: if (dstat & OSIOP_DSTAT_IID)
1691: printf("%s: Invalid instruction detected\n",
1692: sc->sc_dev.dv_xname);
1693: bad_phase:
1694: /*
1695: * temporary panic for unhandled conditions
1696: * displays various things about the 53C710 status and registers
1697: * then panics.
1698: * XXXX need to clean this up to print out the info, reset, and continue
1699: */
1700: printf("osiop_chkintr: target %x ds %p\n", target, ds);
1701: printf("scripts %lx ds %lx dsp %x dcmd %x\n", scraddr,
1702: sc->sc_dsdma->dm_segs[0].ds_addr + acb->dsoffset,
1703: osiop_read_4(sc, OSIOP_DSP),
1704: osiop_read_4(sc, OSIOP_DBC));
1705: printf("osiop_chkintr: istat %x dstat %x sstat0 %x "
1706: "dsps %x dsa %x sbcl %x sts %x msg %x %x sfbr %x\n",
1707: istat, dstat, sstat0, intcode,
1708: osiop_read_4(sc, OSIOP_DSA),
1709: osiop_read_1(sc, OSIOP_SBCL),
1710: ds->stat[0], ds->msgbuf[0], ds->msgbuf[1],
1711: osiop_read_1(sc, OSIOP_SFBR));
1712: #ifdef OSIOP_DEBUG
1713: if (osiop_debug & DEBUG_DMA)
1714: panic("osiop_chkintr: **** temp ****");
1715: #if 0
1716: #ifdef DDB
1717: Debugger();
1718: #endif
1719: #endif
1720: #endif
1721: osiop_reset(sc); /* hard reset */
1722: *status = SCSI_OSIOP_NOSTATUS;
1723: if (acb != NULL)
1724: acb->status = ACB_S_DONE;
1725: return (0); /* osiop_reset cleaned up */
1726: }
1727:
1728: void
1729: osiop_select(sc)
1730: struct osiop_softc *sc;
1731: {
1732: struct osiop_acb *acb = sc->sc_nexus;
1733:
1734: #ifdef OSIOP_DEBUG
1735: if (osiop_debug & DEBUG_CMD)
1736: printf("%s: select ", sc->sc_dev.dv_xname);
1737: #endif
1738:
1739: if (acb->xsflags & SCSI_POLL || sc->sc_flags & OSIOP_NODMA) {
1740: sc->sc_flags |= OSIOP_INTSOFF;
1741: sc->sc_flags &= ~OSIOP_INTDEFER;
1742: if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) {
1743: osiop_write_1(sc, OSIOP_SIEN, 0);
1744: osiop_write_1(sc, OSIOP_DIEN, 0);
1745: }
1746: #if 0
1747: } else if ((sc->sc_flags & OSIOP_INTDEFER) == 0) {
1748: sc->sc_flags &= ~OSIOP_INTSOFF;
1749: if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) {
1750: osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
1751: osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
1752: }
1753: #endif
1754: }
1755: #ifdef OSIOP_DEBUG
1756: if (osiop_debug & DEBUG_CMD)
1757: printf("osiop_select: target %x cmd %02x ds %p\n",
1758: acb->xs->sc_link->target,
1759: acb->ds->scsi_cmd.opcode, sc->sc_nexus->ds);
1760: #endif
1761:
1762: osiop_start(sc);
1763:
1764: return;
1765: }
1766:
1767: /*
1768: * 53C710 interrupt handler
1769: */
1770:
1771: void
1772: osiop_intr(sc)
1773: struct osiop_softc *sc;
1774: {
1775: int status, s;
1776: u_int8_t istat, dstat, sstat0;
1777:
1778: s = splbio();
1779:
1780: istat = sc->sc_istat;
1781: if ((istat & (OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP)) == 0) {
1782: splx(s);
1783: return;
1784: }
1785:
1786: /* Got a valid interrupt on this device; set by MD handler */
1787: dstat = sc->sc_dstat;
1788: sstat0 = sc->sc_sstat0;
1789: sc->sc_istat = 0;
1790: #ifdef OSIOP_DEBUG
1791: if (!sc->sc_active) {
1792: /* XXX needs sync */
1793: printf("%s: spurious interrupt? "
1794: "istat %x dstat %x sstat0 %x nexus %p status %x\n",
1795: sc->sc_dev.dv_xname, istat, dstat, sstat0, sc->sc_nexus,
1796: (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->stat[0] : 0);
1797: }
1798: #endif
1799:
1800: #ifdef OSIOP_DEBUG
1801: if (osiop_debug & (DEBUG_INT|DEBUG_CMD)) {
1802: /* XXX needs sync */
1803: printf("%s: intr istat %x dstat %x sstat0 %x dsps %x "
1804: "sbcl %x dsp %x dcmd %x sts %x msg %x\n",
1805: sc->sc_dev.dv_xname,
1806: istat, dstat, sstat0,
1807: osiop_read_4(sc, OSIOP_DSPS),
1808: osiop_read_1(sc, OSIOP_SBCL),
1809: osiop_read_4(sc, OSIOP_DSP),
1810: osiop_read_4(sc, OSIOP_DBC),
1811: (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->stat[0] : 0,
1812: (sc->sc_nexus != NULL) ? sc->sc_nexus->ds->msgbuf[0] : 0);
1813: }
1814: #endif
1815: if (sc->sc_flags & OSIOP_INTDEFER) {
1816: sc->sc_flags &= ~(OSIOP_INTDEFER | OSIOP_INTSOFF);
1817: osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien);
1818: osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien);
1819: }
1820: if (osiop_checkintr(sc, istat, dstat, sstat0, &status)) {
1821: #if 0
1822: if (status == SCSI_OSIOP_NOSTATUS)
1823: printf("osiop_intr: no valid status \n");
1824: #endif
1825: if ((sc->sc_flags & (OSIOP_INTSOFF | OSIOP_INTDEFER)) !=
1826: OSIOP_INTSOFF) {
1827: #if 0
1828: if (osiop_read_1(sc, OSIOP_SBCL) & OSIOP_BSY) {
1829: struct scsi_link *periph;
1830:
1831: periph = sc->sc_nexus->xs->sc_link;
1832: printf("%s: SCSI bus busy at completion"
1833: " targ %d sbcl %02x sfbr %x lcrc "
1834: "%02x dsp +%x\n", sc->sc_dev.dv_xname,
1835: periph->periphtarget,
1836: osiop_read_1(sc, OSIOP_SBCL),
1837: osiop_read_1(sc, OSIOP_SFBR),
1838: osiop_read_1(sc, OSIOP_LCRC),
1839: osiop_read_4(sc, OSIOP_DSP) -
1840: sc->sc_scrdma->dm_segs[0].ds_addr);
1841: }
1842: #endif
1843: osiop_scsidone(sc->sc_nexus, status);
1844: }
1845: }
1846: splx(s);
1847: }
1848:
1849: void
1850: osiop_update_xfer_mode(sc, target)
1851: struct osiop_softc *sc;
1852: int target;
1853: {
1854: struct osiop_tinfo *ti = &sc->sc_tinfo[target];
1855:
1856: printf("%s: target %d now using 8 bit ", sc->sc_dev.dv_xname, target);
1857:
1858: ti->sxfer = 0;
1859: ti->sbcl = 0;
1860: if (ti->offset != 0) {
1861: scsi_period_to_osiop(sc, target);
1862: switch (ti->period) {
1863: case 0x00:
1864: case 0x01:
1865: case 0x02:
1866: case 0x03:
1867: case 0x04:
1868: case 0x05:
1869: case 0x06:
1870: case 0x07:
1871: case 0x08:
1872: /* Reserved transfer period factor */
1873: printf("??");
1874: break;
1875: case 0x09:
1876: /* Transfer period = 12.5 ns */
1877: printf("80");
1878: break;
1879: case 0x0a:
1880: /* Transfer period = 25 ns */
1881: printf("40");
1882: break;
1883: case 0x0b:
1884: /* Transfer period = 30.3 ns */
1885: printf("33");
1886: break;
1887: case 0x0c:
1888: /* Transfer period = 50 ns */
1889: printf("20");
1890: break;
1891: default:
1892: /* Transfer period = ti->period*4 ns */
1893: printf("%d", 1000/(ti->period*4));
1894: break;
1895: }
1896: printf(" MHz %d REQ/ACK offset", ti->offset);
1897: } else
1898: printf("asynch");
1899:
1900: printf(" xfers\n");
1901: }
1902:
1903: /*
1904: * This is based on the Progressive Peripherals 33MHz Zeus driver and will
1905: * not be correct for other 53c710 boards.
1906: *
1907: */
1908: void
1909: scsi_period_to_osiop(sc, target)
1910: struct osiop_softc *sc;
1911: int target;
1912: {
1913: int period, offset, sxfer, sbcl;
1914: #ifdef OSIOP_DEBUG
1915: int i;
1916: #endif
1917:
1918: period = sc->sc_tinfo[target].period;
1919: offset = sc->sc_tinfo[target].offset;
1920: #ifdef OSIOP_DEBUG
1921: if (osiop_debug & DEBUG_SYNC) {
1922: sxfer = 0;
1923: if (offset <= OSIOP_MAX_OFFSET)
1924: sxfer = offset;
1925: for (i = 0; i < sizeof(sync_tab) / sizeof(sync_tab[0]); i++) {
1926: if (period <= sync_tab[i].p) {
1927: sxfer |= sync_tab[i].r & 0x70;
1928: sbcl = sync_tab[i].r & 0x03;
1929: break;
1930: }
1931: }
1932: printf("osiop sync old: osiop_sxfr %02x, osiop_sbcl %02x\n",
1933: sxfer, sbcl);
1934: }
1935: #endif
1936: for (sbcl = 1; sbcl < 4; sbcl++) {
1937: sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3;
1938: if (sxfer >= 0 && sxfer <= 7)
1939: break;
1940: }
1941: if (sbcl > 3) {
1942: printf("osiop sync: unable to compute sync params "
1943: "for period %d ns\n", period * 4);
1944: /*
1945: * XXX need to pick a value we can do and renegotiate
1946: */
1947: sxfer = sbcl = 0;
1948: } else {
1949: sxfer = (sxfer << 4) | ((offset <= OSIOP_MAX_OFFSET) ?
1950: offset : OSIOP_MAX_OFFSET);
1951: #ifdef OSIOP_DEBUG
1952: if (osiop_debug & DEBUG_SYNC) {
1953: printf("osiop sync: params for period %dns: sxfer %x sbcl %x",
1954: period * 4, sxfer, sbcl);
1955: printf(" actual period %dns\n",
1956: sc->sc_tcp[sbcl] * ((sxfer >> 4) + 4));
1957: }
1958: #endif
1959: }
1960: sc->sc_tinfo[target].sxfer = sxfer;
1961: sc->sc_tinfo[target].sbcl = sbcl;
1962: #ifdef OSIOP_DEBUG
1963: if (osiop_debug & DEBUG_SYNC)
1964: printf("osiop sync: osiop_sxfr %02x, osiop_sbcl %02x\n",
1965: sxfer, sbcl);
1966: #endif
1967: }
1968:
1969: void
1970: osiop_timeout(arg)
1971: void *arg;
1972: {
1973: struct osiop_acb *acb = arg;
1974: struct scsi_xfer *xs = acb->xs;
1975: struct osiop_softc *sc = acb->sc;
1976: int s;
1977:
1978: sc_print_addr(xs->sc_link);
1979: printf("command 0x%02x timeout on xs %p\n", xs->cmd->opcode, xs);
1980:
1981: s = splbio();
1982: /* reset the scsi bus */
1983: osiop_resetbus(sc);
1984:
1985: acb->flags |= ACB_F_TIMEOUT;
1986: osiop_reset(sc);
1987: splx(s);
1988: return;
1989: }
1990:
1991: #ifdef OSIOP_DEBUG
1992:
1993: #if OSIOP_TRACE_SIZE
1994: void
1995: osiop_dump_trace()
1996: {
1997: int i;
1998:
1999: printf("osiop trace: next index %d\n", osiop_trix);
2000: i = osiop_trix;
2001: do {
2002: printf("%3d: '%c' %02x %02x %02x\n", i,
2003: osiop_trbuf[i], osiop_trbuf[i + 1],
2004: osiop_trbuf[i + 2], osiop_trbuf[i + 3]);
2005: i = (i + 4) & (OSIOP_TRACE_SIZE - 1);
2006: } while (i != osiop_trix);
2007: }
2008: #endif
2009:
2010: void
2011: osiop_dump_acb(acb)
2012: struct osiop_acb *acb;
2013: {
2014: u_int8_t *b;
2015: int i;
2016:
2017: printf("acb@%p ", acb);
2018: if (acb->xs == NULL) {
2019: printf("<unused>\n");
2020: return;
2021: }
2022:
2023: b = (u_int8_t *)&acb->ds->scsi_cmd;
2024: printf("(%d:%d) status %2x cmdlen %2ld cmd ",
2025: acb->xs->sc_link->target,
2026: acb->xs->sc_link->lun,
2027: acb->status,
2028: acb->ds->cmd.count);
2029: for (i = acb->ds->cmd.count; i > 0; i--)
2030: printf(" %02x", *b++);
2031: printf("\n");
2032: printf(" xs: %p data %p:%04x ", acb->xs, acb->data,
2033: acb->datalen);
2034: printf("cur %lx:%lx\n", acb->curaddr, acb->curlen);
2035: }
2036:
2037: void
2038: osiop_dump(sc)
2039: struct osiop_softc *sc;
2040: {
2041: struct osiop_acb *acb;
2042: int i, s;
2043:
2044: s = splbio();
2045: #if OSIOP_TRACE_SIZE
2046: osiop_dump_trace();
2047: #endif
2048: printf("%s@%p istat %02x\n",
2049: sc->sc_dev.dv_xname, sc, osiop_read_1(sc, OSIOP_ISTAT));
2050: if ((acb = TAILQ_FIRST(&sc->free_list)) != NULL) {
2051: printf("Free list:\n");
2052: while (acb) {
2053: osiop_dump_acb(acb);
2054: acb = TAILQ_NEXT(acb, chain);
2055: }
2056: }
2057: if ((acb = TAILQ_FIRST(&sc->ready_list)) != NULL) {
2058: printf("Ready list:\n");
2059: while (acb) {
2060: osiop_dump_acb(acb);
2061: acb = TAILQ_NEXT(acb, chain);
2062: }
2063: }
2064: if ((acb = TAILQ_FIRST(&sc->nexus_list)) != NULL) {
2065: printf("Nexus list:\n");
2066: while (acb) {
2067: osiop_dump_acb(acb);
2068: acb = TAILQ_NEXT(acb, chain);
2069: }
2070: }
2071: if (sc->sc_nexus) {
2072: printf("Nexus:\n");
2073: osiop_dump_acb(sc->sc_nexus);
2074: }
2075: for (i = 0; i < OSIOP_NTGT; i++) {
2076: if (sc->sc_tinfo[i].cmds > 2) {
2077: printf("tgt %d: cmds %d disc %d lubusy %x\n",
2078: i, sc->sc_tinfo[i].cmds,
2079: sc->sc_tinfo[i].dconns,
2080: sc->sc_tinfo[i].lubusy);
2081: }
2082: }
2083: splx(s);
2084: }
2085: #endif
CVSweb