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