siop.c revision 1.42 1 /* $NetBSD: siop.c,v 1.42 1999/09/06 21:50:48 is Exp $ */
2
3 /*
4 * Copyright (c) 1994 Michael L. Hitch
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Van Jacobson of Lawrence Berkeley Laboratory.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)siop.c 7.5 (Berkeley) 5/4/91
40 */
41
42 /*
43 * AMIGA 53C710 scsi adaptor driver
44 */
45
46 #include "opt_ddb.h"
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51 #include <sys/disklabel.h>
52 #include <sys/dkstat.h>
53 #include <sys/buf.h>
54 #include <sys/malloc.h>
55 #include <dev/scsipi/scsi_all.h>
56 #include <dev/scsipi/scsipi_all.h>
57 #include <dev/scsipi/scsiconf.h>
58 #include <machine/cpu.h>
59 #ifdef __m68k__
60 #include <m68k/cacheops.h>
61 #endif
62 #include <amiga/amiga/custom.h>
63 #include <amiga/amiga/isr.h>
64 #include <amiga/dev/siopreg.h>
65 #include <amiga/dev/siopvar.h>
66
67 /*
68 * SCSI delays
69 * In u-seconds, primarily for state changes on the SPC.
70 */
71 #define SCSI_CMD_WAIT 500000 /* wait per step of 'immediate' cmds */
72 #define SCSI_DATA_WAIT 500000 /* wait per data in/out step */
73 #define SCSI_INIT_WAIT 500000 /* wait per step (both) during init */
74
75 void siop_select __P((struct siop_softc *));
76 void siopabort __P((struct siop_softc *, siop_regmap_p, char *));
77 void sioperror __P((struct siop_softc *, siop_regmap_p, u_char));
78 void siopstart __P((struct siop_softc *));
79 int siop_checkintr __P((struct siop_softc *, u_char, u_char, u_char, int *));
80 void siopreset __P((struct siop_softc *));
81 void siopsetdelay __P((int));
82 void siop_scsidone __P((struct siop_acb *, int));
83 void siop_sched __P((struct siop_softc *));
84 int siop_poll __P((struct siop_softc *, struct siop_acb *));
85 void siopintr __P((struct siop_softc *));
86 void scsi_period_to_siop __P((struct siop_softc *, int));
87 void siop_start __P((struct siop_softc *, int, int, u_char *, int, u_char *, int));
88 void siop_dump_acb __P((struct siop_acb *));
89
90 /* 53C710 script */
91 const
92 #include <amiga/dev/siop_script.out>
93
94 /* default to not inhibit sync negotiation on any drive */
95 u_char siop_inhibit_sync[8] = { 0, 0, 0, 0, 0, 0, 0 }; /* initialize, so patchable */
96 u_char siop_allow_disc[8] = {3, 3, 3, 3, 3, 3, 3, 3};
97 int siop_no_dma = 0;
98
99 int siop_reset_delay = 250; /* delay after reset, in milleseconds */
100
101 int siop_cmd_wait = SCSI_CMD_WAIT;
102 int siop_data_wait = SCSI_DATA_WAIT;
103 int siop_init_wait = SCSI_INIT_WAIT;
104
105 #ifdef DEBUG_SYNC
106 /*
107 * sync period transfer lookup - only valid for 66Mhz clock
108 */
109 static struct {
110 unsigned char p; /* period from sync request message */
111 unsigned char r; /* siop_period << 4 | sbcl */
112 } sync_tab[] = {
113 { 60/4, 0<<4 | 1},
114 { 76/4, 1<<4 | 1},
115 { 92/4, 2<<4 | 1},
116 { 92/4, 0<<4 | 2},
117 {108/4, 3<<4 | 1},
118 {116/4, 1<<4 | 2},
119 {120/4, 4<<4 | 1},
120 {120/4, 0<<4 | 3},
121 {136/4, 5<<4 | 1},
122 {140/4, 2<<4 | 2},
123 {152/4, 6<<4 | 1},
124 {152/4, 1<<4 | 3},
125 {164/4, 3<<4 | 2},
126 {168/4, 7<<4 | 1},
127 {180/4, 2<<4 | 3},
128 {184/4, 4<<4 | 2},
129 {208/4, 5<<4 | 2},
130 {212/4, 3<<4 | 3},
131 {232/4, 6<<4 | 2},
132 {240/4, 4<<4 | 3},
133 {256/4, 7<<4 | 2},
134 {272/4, 5<<4 | 3},
135 {300/4, 6<<4 | 3},
136 {332/4, 7<<4 | 3}
137 };
138 #endif
139
140 #ifdef DEBUG
141 /*
142 * 0x01 - full debug
143 * 0x02 - DMA chaining
144 * 0x04 - siopintr
145 * 0x08 - phase mismatch
146 * 0x10 - <not used>
147 * 0x20 - panic on unhandled exceptions
148 * 0x100 - disconnect/reselect
149 */
150 int siop_debug = 0;
151 int siopsync_debug = 0;
152 int siopdma_hits = 0;
153 int siopdma_misses = 0;
154 int siopchain_ints = 0;
155 int siopstarts = 0;
156 int siopints = 0;
157 int siopphmm = 0;
158 #define SIOP_TRACE_SIZE 128
159 #define SIOP_TRACE(a,b,c,d) \
160 siop_trbuf[siop_trix] = (a); \
161 siop_trbuf[siop_trix+1] = (b); \
162 siop_trbuf[siop_trix+2] = (c); \
163 siop_trbuf[siop_trix+3] = (d); \
164 siop_trix = (siop_trix + 4) & (SIOP_TRACE_SIZE - 1);
165 u_char siop_trbuf[SIOP_TRACE_SIZE];
166 int siop_trix;
167 void siop_dump __P((struct siop_softc *));
168 void siop_dump_trace __P((void));
169 #else
170 #define SIOP_TRACE(a,b,c,d)
171 #endif
172
173
174 /*
175 * default minphys routine for siop based controllers
176 */
177 void
178 siop_minphys(bp)
179 struct buf *bp;
180 {
181
182 /*
183 * No max transfer at this level.
184 */
185 minphys(bp);
186 }
187
188 /*
189 * used by specific siop controller
190 *
191 */
192 int
193 siop_scsicmd(xs)
194 struct scsipi_xfer *xs;
195 {
196 struct siop_acb *acb;
197 struct siop_softc *sc;
198 struct scsipi_link *slp;
199 int flags, s;
200
201 slp = xs->sc_link;
202 sc = slp->adapter_softc;
203 flags = xs->flags;
204
205 /* XXXX ?? */
206 if (flags & SCSI_DATA_UIO)
207 panic("siop: scsi data uio requested");
208
209 /* XXXX ?? */
210 if (sc->sc_nexus && flags & SCSI_POLL)
211 /* panic("siop_scsicmd: busy");*/
212 printf("siop_scsicmd: busy\n");
213
214 s = splbio();
215 acb = sc->free_list.tqh_first;
216 if (acb) {
217 TAILQ_REMOVE(&sc->free_list, acb, chain);
218 }
219 splx(s);
220
221 if (acb == NULL) {
222 xs->error = XS_DRIVER_STUFFUP;
223 return(TRY_AGAIN_LATER);
224 }
225
226 acb->flags = ACB_ACTIVE;
227 acb->xs = xs;
228 bcopy(xs->cmd, &acb->cmd, xs->cmdlen);
229 acb->clen = xs->cmdlen;
230 acb->daddr = xs->data;
231 acb->dleft = xs->datalen;
232
233 s = splbio();
234 TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
235
236 if (sc->sc_nexus == NULL)
237 siop_sched(sc);
238
239 splx(s);
240
241 if (flags & SCSI_POLL || siop_no_dma)
242 return(siop_poll(sc, acb));
243 return(SUCCESSFULLY_QUEUED);
244 }
245
246 int
247 siop_poll(sc, acb)
248 struct siop_softc *sc;
249 struct siop_acb *acb;
250 {
251 siop_regmap_p rp = sc->sc_siopp;
252 struct scsipi_xfer *xs = acb->xs;
253 int i;
254 int status;
255 u_char istat;
256 u_char dstat;
257 u_char sstat0;
258 int s;
259 int to;
260
261 s = splbio();
262 to = xs->timeout / 1000;
263 if (sc->nexus_list.tqh_first)
264 printf("%s: siop_poll called with disconnected device\n",
265 sc->sc_dev.dv_xname);
266 for (;;) {
267 /* use cmd_wait values? */
268 i = 50000;
269 /* XXX spl0(); */
270 while (((istat = rp->siop_istat) &
271 (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) {
272 if (--i <= 0) {
273 #ifdef DEBUG
274 printf ("waiting: tgt %d cmd %02x sbcl %02x dsp %lx (+%lx) dcmd %lx ds %p timeout %d\n",
275 xs->sc_link->scsipi_scsi.target, acb->cmd.opcode,
276 rp->siop_sbcl, rp->siop_dsp,
277 rp->siop_dsp - sc->sc_scriptspa,
278 *((long *)&rp->siop_dcmd), &acb->ds, acb->xs->timeout);
279 #endif
280 i = 50000;
281 --to;
282 if (to <= 0) {
283 siopreset(sc);
284 return(COMPLETE);
285 }
286 }
287 delay(20);
288 }
289 sstat0 = rp->siop_sstat0;
290 dstat = rp->siop_dstat;
291 if (siop_checkintr(sc, istat, dstat, sstat0, &status)) {
292 if (acb != sc->sc_nexus)
293 printf("%s: siop_poll disconnected device completed\n",
294 sc->sc_dev.dv_xname);
295 else if ((sc->sc_flags & SIOP_INTDEFER) == 0) {
296 sc->sc_flags &= ~SIOP_INTSOFF;
297 rp->siop_sien = sc->sc_sien;
298 rp->siop_dien = sc->sc_dien;
299 }
300 siop_scsidone(sc->sc_nexus, status);
301 }
302 if (xs->flags & ITSDONE)
303 break;
304 }
305 splx(s);
306 return (COMPLETE);
307 }
308
309 /*
310 * start next command that's ready
311 */
312 void
313 siop_sched(sc)
314 struct siop_softc *sc;
315 {
316 struct scsipi_link *slp;
317 struct siop_acb *acb;
318 int i;
319
320 #ifdef DEBUG
321 if (sc->sc_nexus) {
322 printf("%s: siop_sched- nexus %p/%d ready %p/%d\n",
323 sc->sc_dev.dv_xname, sc->sc_nexus,
324 sc->sc_nexus->xs->sc_link->scsipi_scsi.target,
325 sc->ready_list.tqh_first,
326 sc->ready_list.tqh_first->xs->sc_link->scsipi_scsi.target);
327 return;
328 }
329 #endif
330 for (acb = sc->ready_list.tqh_first; acb; acb = acb->chain.tqe_next) {
331 slp = acb->xs->sc_link;
332 i = slp->scsipi_scsi.target;
333 if(!(sc->sc_tinfo[i].lubusy & (1 << slp->scsipi_scsi.lun))) {
334 struct siop_tinfo *ti = &sc->sc_tinfo[i];
335
336 TAILQ_REMOVE(&sc->ready_list, acb, chain);
337 sc->sc_nexus = acb;
338 slp = acb->xs->sc_link;
339 ti = &sc->sc_tinfo[slp->scsipi_scsi.target];
340 ti->lubusy |= (1 << slp->scsipi_scsi.lun);
341 break;
342 }
343 }
344
345 if (acb == NULL) {
346 #ifdef DEBUGXXX
347 printf("%s: siop_sched didn't find ready command\n",
348 sc->sc_dev.dv_xname);
349 #endif
350 return;
351 }
352
353 if (acb->xs->flags & SCSI_RESET)
354 siopreset(sc);
355
356 #if 0
357 acb->cmd.bytes[0] |= slp->scsipi_scsi.lun << 5; /* XXXX */
358 #endif
359 ++sc->sc_active;
360 siop_select(sc);
361 }
362
363 void
364 siop_scsidone(acb, stat)
365 struct siop_acb *acb;
366 int stat;
367 {
368 struct scsipi_xfer *xs;
369 struct scsipi_link *slp;
370 struct siop_softc *sc;
371 int dosched = 0;
372
373 if (acb == NULL || (xs = acb->xs) == NULL) {
374 #ifdef DIAGNOSTIC
375 printf("siop_scsidone: NULL acb or scsipi_xfer\n");
376 #if defined(DEBUG) && defined(DDB)
377 Debugger();
378 #endif
379 #endif
380 return;
381 }
382 slp = xs->sc_link;
383 sc = slp->adapter_softc;
384 /*
385 * is this right?
386 */
387 xs->status = stat;
388
389 if (xs->error == XS_NOERROR && !(acb->flags & ACB_CHKSENSE)) {
390 if (stat == SCSI_CHECK) {
391 struct scsipi_sense *ss = (void *)&acb->cmd;
392 bzero(ss, sizeof(*ss));
393 ss->opcode = REQUEST_SENSE;
394 ss->byte2 = slp->scsipi_scsi.lun << 5;
395 ss->length = sizeof(struct scsipi_sense_data);
396 acb->clen = sizeof(*ss);
397 acb->daddr = (char *)&xs->sense.scsi_sense;
398 acb->dleft = sizeof(struct scsipi_sense_data);
399 acb->flags = ACB_ACTIVE | ACB_CHKSENSE;
400 TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
401 --sc->sc_active;
402 sc->sc_tinfo[slp->scsipi_scsi.target].lubusy &=
403 ~(1 << slp->scsipi_scsi.lun);
404 sc->sc_tinfo[slp->scsipi_scsi.target].senses++;
405 if (sc->sc_nexus == acb) {
406 sc->sc_nexus = NULL;
407 siop_sched(sc);
408 }
409 SIOP_TRACE('d','s',0,0)
410 return;
411 }
412 }
413 if (xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE)) {
414 xs->error = XS_SENSE;
415 } else {
416 xs->resid = 0; /* XXXX */
417 }
418 #if whataboutthisone
419 case SCSI_BUSY:
420 xs->error = XS_BUSY;
421 break;
422 #endif
423 xs->flags |= ITSDONE;
424
425 /*
426 * Remove the ACB from whatever queue it's on. We have to do a bit of
427 * a hack to figure out which queue it's on. Note that it is *not*
428 * necessary to cdr down the ready queue, but we must cdr down the
429 * nexus queue and see if it's there, so we can mark the unit as no
430 * longer busy. This code is sickening, but it works.
431 */
432 if (acb == sc->sc_nexus) {
433 sc->sc_nexus = NULL;
434 sc->sc_tinfo[slp->scsipi_scsi.target].lubusy &=
435 ~(1<<slp->scsipi_scsi.lun);
436 if (sc->ready_list.tqh_first)
437 dosched = 1; /* start next command */
438 --sc->sc_active;
439 SIOP_TRACE('d','a',stat,0)
440 } else if (sc->ready_list.tqh_last == &acb->chain.tqe_next) {
441 TAILQ_REMOVE(&sc->ready_list, acb, chain);
442 SIOP_TRACE('d','r',stat,0)
443 } else {
444 register struct siop_acb *acb2;
445 for (acb2 = sc->nexus_list.tqh_first; acb2;
446 acb2 = acb2->chain.tqe_next)
447 if (acb2 == acb) {
448 TAILQ_REMOVE(&sc->nexus_list, acb, chain);
449 sc->sc_tinfo[slp->scsipi_scsi.target].lubusy
450 &= ~(1<<slp->scsipi_scsi.lun);
451 --sc->sc_active;
452 break;
453 }
454 if (acb2)
455 ;
456 else if (acb->chain.tqe_next) {
457 TAILQ_REMOVE(&sc->ready_list, acb, chain);
458 --sc->sc_active;
459 } else {
460 printf("%s: can't find matching acb\n",
461 sc->sc_dev.dv_xname);
462 #ifdef DDB
463 /* Debugger(); */
464 #endif
465 }
466 SIOP_TRACE('d','n',stat,0);
467 }
468 /* Put it on the free list. */
469 acb->flags = ACB_FREE;
470 TAILQ_INSERT_HEAD(&sc->free_list, acb, chain);
471
472 sc->sc_tinfo[slp->scsipi_scsi.target].cmds++;
473
474 scsipi_done(xs);
475
476 if (dosched && sc->sc_nexus == NULL)
477 siop_sched(sc);
478 }
479
480 void
481 siopabort(sc, rp, where)
482 register struct siop_softc *sc;
483 siop_regmap_p rp;
484 char *where;
485 {
486 #ifdef fix_this
487 int i;
488 #endif
489
490 printf ("%s: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
491 sc->sc_dev.dv_xname,
492 where, rp->siop_dstat, rp->siop_sstat0, rp->siop_sbcl);
493
494 if (sc->sc_active > 0) {
495 #ifdef TODO
496 SET_SBIC_cmd (rp, SBIC_CMD_ABORT);
497 WAIT_CIP (rp);
498
499 GET_SBIC_asr (rp, asr);
500 if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI))
501 {
502 /* ok, get more drastic.. */
503
504 SET_SBIC_cmd (rp, SBIC_CMD_RESET);
505 delay(25);
506 SBIC_WAIT(rp, SBIC_ASR_INT, 0);
507 GET_SBIC_csr (rp, csr); /* clears interrupt also */
508
509 return;
510 }
511
512 do
513 {
514 SBIC_WAIT (rp, SBIC_ASR_INT, 0);
515 GET_SBIC_csr (rp, csr);
516 }
517 while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
518 && (csr != SBIC_CSR_CMD_INVALID));
519 #endif
520
521 /* lets just hope it worked.. */
522 #ifdef fix_this
523 for (i = 0; i < 2; ++i) {
524 if (sc->sc_iob[i].sc_xs && &sc->sc_iob[i] !=
525 sc->sc_cur) {
526 printf ("siopabort: cleanup!\n");
527 sc->sc_iob[i].sc_xs = NULL;
528 }
529 }
530 #endif /* fix_this */
531 /* sc->sc_active = 0; */
532 }
533 }
534
535 void
536 siopinitialize(sc)
537 struct siop_softc *sc;
538 {
539 int i;
540 u_int inhibit_sync;
541 extern u_long scsi_nosync;
542 extern int shift_nosync;
543
544 /*
545 * Need to check that scripts is on a long word boundary
546 * Also should verify that dev doesn't span non-contiguous
547 * physical pages.
548 */
549 sc->sc_scriptspa = kvtop((caddr_t)scripts);
550
551 /*
552 * malloc sc_acb to ensure that DS is on a long word boundary.
553 */
554
555 MALLOC(sc->sc_acb, struct siop_acb *,
556 sizeof(struct siop_acb) * SIOP_NACB, M_DEVBUF, M_NOWAIT);
557 if (sc->sc_acb == NULL)
558 panic("siopinitialize: ACB malloc failed!");
559
560 sc->sc_tcp[1] = 1000 / sc->sc_clock_freq;
561 sc->sc_tcp[2] = 1500 / sc->sc_clock_freq;
562 sc->sc_tcp[3] = 2000 / sc->sc_clock_freq;
563 sc->sc_minsync = sc->sc_tcp[1]; /* in 4ns units */
564 if (sc->sc_minsync < 25)
565 sc->sc_minsync = 25;
566 if (sc->sc_clock_freq <= 25) {
567 sc->sc_dcntl |= 0x80; /* SCLK/1 */
568 sc->sc_tcp[0] = sc->sc_tcp[1];
569 } else if (sc->sc_clock_freq <= 37) {
570 sc->sc_dcntl |= 0x40; /* SCLK/1.5 */
571 sc->sc_tcp[0] = sc->sc_tcp[2];
572 } else if (sc->sc_clock_freq <= 50) {
573 sc->sc_dcntl |= 0x00; /* SCLK/2 */
574 sc->sc_tcp[0] = sc->sc_tcp[3];
575 } else {
576 sc->sc_dcntl |= 0xc0; /* SCLK/3 */
577 sc->sc_tcp[0] = 3000 / sc->sc_clock_freq;
578 }
579
580 if (scsi_nosync) {
581 inhibit_sync = (scsi_nosync >> shift_nosync) & 0xff;
582 shift_nosync += 8;
583 #ifdef DEBUG
584 if (inhibit_sync)
585 printf("%s: Inhibiting synchronous transfer %02x\n",
586 sc->sc_dev.dv_xname, inhibit_sync);
587 #endif
588 for (i = 0; i < 8; ++i)
589 if (inhibit_sync & (1 << i))
590 siop_inhibit_sync[i] = 1;
591 }
592
593 siopreset (sc);
594 }
595
596 void
597 siopreset(sc)
598 struct siop_softc *sc;
599 {
600 siop_regmap_p rp;
601 u_int i, s;
602 u_char dummy;
603 struct siop_acb *acb;
604
605 rp = sc->sc_siopp;
606
607 if (sc->sc_flags & SIOP_ALIVE)
608 siopabort(sc, rp, "reset");
609
610 printf("%s: ", sc->sc_dev.dv_xname); /* XXXX */
611
612 s = splbio();
613
614 /*
615 * Reset the chip
616 * XXX - is this really needed?
617 */
618 rp->siop_istat |= SIOP_ISTAT_ABRT; /* abort current script */
619 rp->siop_istat |= SIOP_ISTAT_RST; /* reset chip */
620 rp->siop_istat &= ~SIOP_ISTAT_RST;
621 /*
622 * Reset SCSI bus (do we really want this?)
623 */
624 rp->siop_sien = 0;
625 rp->siop_scntl1 |= SIOP_SCNTL1_RST;
626 delay(1);
627 rp->siop_scntl1 &= ~SIOP_SCNTL1_RST;
628
629 /*
630 * Set up various chip parameters
631 */
632 rp->siop_scntl0 = SIOP_ARB_FULL | SIOP_SCNTL0_EPC | SIOP_SCNTL0_EPG;
633 rp->siop_scntl1 = SIOP_SCNTL1_ESR;
634 rp->siop_dcntl = sc->sc_dcntl;
635 rp->siop_dmode = 0x80; /* burst length = 4 */
636 rp->siop_sien = 0x00; /* don't enable interrupts yet */
637 rp->siop_dien = 0x00; /* don't enable interrupts yet */
638 rp->siop_scid = 1 << sc->sc_link.scsipi_scsi.adapter_target;
639 rp->siop_dwt = 0x00;
640 rp->siop_ctest0 |= SIOP_CTEST0_BTD | SIOP_CTEST0_EAN;
641 rp->siop_ctest7 |= sc->sc_ctest7;
642
643 /* will need to re-negotiate sync xfers */
644 bzero(&sc->sc_sync, sizeof (sc->sc_sync));
645
646 i = rp->siop_istat;
647 if (i & SIOP_ISTAT_SIP)
648 dummy = rp->siop_sstat0;
649 if (i & SIOP_ISTAT_DIP)
650 dummy = rp->siop_dstat;
651
652 splx (s);
653
654 delay (siop_reset_delay * 1000);
655 printf("siop id %d reset V%d\n", sc->sc_link.scsipi_scsi.adapter_target,
656 rp->siop_ctest8 >> 4);
657
658 if ((sc->sc_flags & SIOP_ALIVE) == 0) {
659 TAILQ_INIT(&sc->ready_list);
660 TAILQ_INIT(&sc->nexus_list);
661 TAILQ_INIT(&sc->free_list);
662 sc->sc_nexus = NULL;
663 acb = sc->sc_acb;
664 bzero(acb, sizeof(struct siop_acb) * SIOP_NACB);
665 for (i = 0; i < SIOP_NACB; i++) {
666 TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
667 acb++;
668 }
669 bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
670 } else {
671 if (sc->sc_nexus != NULL) {
672 sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
673 siop_scsidone(sc->sc_nexus, sc->sc_nexus->stat[0]);
674 }
675 while ((acb = sc->nexus_list.tqh_first) > 0) {
676 acb->xs->error = XS_DRIVER_STUFFUP;
677 siop_scsidone(acb, acb->stat[0]);
678 }
679 }
680
681 sc->sc_flags |= SIOP_ALIVE;
682 sc->sc_flags &= ~(SIOP_INTDEFER|SIOP_INTSOFF);
683 /* enable SCSI and DMA interrupts */
684 sc->sc_sien = SIOP_SIEN_M_A | SIOP_SIEN_STO | /*SIOP_SIEN_SEL |*/ SIOP_SIEN_SGE |
685 SIOP_SIEN_UDC | SIOP_SIEN_RST | SIOP_SIEN_PAR;
686 sc->sc_dien = SIOP_DIEN_BF | SIOP_DIEN_ABRT | SIOP_DIEN_SIR |
687 /*SIOP_DIEN_WTD |*/ SIOP_DIEN_IID;
688 rp->siop_sien = sc->sc_sien;
689 rp->siop_dien = sc->sc_dien;
690 }
691
692 /*
693 * Setup Data Storage for 53C710 and start SCRIPTS processing
694 */
695
696 void
697 siop_start (sc, target, lun, cbuf, clen, buf, len)
698 struct siop_softc *sc;
699 int target;
700 int lun;
701 u_char *cbuf;
702 int clen;
703 u_char *buf;
704 int len;
705 {
706 siop_regmap_p rp = sc->sc_siopp;
707 int nchain;
708 int count, tcount;
709 char *addr, *dmaend;
710 struct siop_acb *acb = sc->sc_nexus;
711 #ifdef DEBUG
712 int i;
713 #endif
714
715 #ifdef DEBUG
716 if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
717 printf ("ACK! siop was busy: rp %p script %p dsa %p active %ld\n",
718 rp, &scripts, &acb->ds, sc->sc_active);
719 printf ("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n",
720 rp->siop_istat, rp->siop_sfbr, rp->siop_lcrc,
721 rp->siop_sien, rp->siop_dien);
722 #ifdef DDB
723 /*Debugger();*/
724 #endif
725 }
726 #endif
727 acb->msgout[0] = MSG_IDENTIFY | lun;
728 if (siop_allow_disc[target] & 2 ||
729 (siop_allow_disc[target] && len == 0))
730 acb->msgout[0] = MSG_IDENTIFY_DR | lun;
731 acb->status = 0;
732 acb->stat[0] = -1;
733 acb->msg[0] = -1;
734 acb->ds.scsi_addr = (0x10000 << target) | (sc->sc_sync[target].sxfer << 8);
735 acb->ds.idlen = 1;
736 acb->ds.idbuf = (char *) kvtop(&acb->msgout[0]);
737 acb->ds.cmdlen = clen;
738 acb->ds.cmdbuf = (char *) kvtop(cbuf);
739 acb->ds.stslen = 1;
740 acb->ds.stsbuf = (char *) kvtop(&acb->stat[0]);
741 acb->ds.msglen = 1;
742 acb->ds.msgbuf = (char *) kvtop(&acb->msg[0]);
743 acb->msg[1] = -1;
744 acb->ds.msginlen = 1;
745 acb->ds.extmsglen = 1;
746 acb->ds.synmsglen = 3;
747 acb->ds.msginbuf = (char *) kvtop(&acb->msg[1]);
748 acb->ds.extmsgbuf = (char *) kvtop(&acb->msg[2]);
749 acb->ds.synmsgbuf = (char *) kvtop(&acb->msg[3]);
750 bzero(&acb->ds.chain, sizeof (acb->ds.chain));
751
752 /*
753 * Negotiate wide is the initial negotiation state; since the 53c710
754 * doesn't do wide transfers, just begin the synchronous transfer
755 * negotation here.
756 */
757 if (sc->sc_sync[target].state == NEG_WIDE) {
758 if (siop_inhibit_sync[target]) {
759 sc->sc_sync[target].state = NEG_DONE;
760 sc->sc_sync[target].sbcl = 0;
761 sc->sc_sync[target].sxfer = 0;
762 #ifdef DEBUG
763 if (siopsync_debug)
764 printf ("Forcing target %d asynchronous\n", target);
765 #endif
766 }
767 else {
768 acb->msg[2] = -1;
769 acb->msgout[1] = MSG_EXT_MESSAGE;
770 acb->msgout[2] = 3;
771 acb->msgout[3] = MSG_SYNC_REQ;
772 #ifdef MAXTOR_SYNC_KLUDGE
773 acb->msgout[4] = 50 / 4; /* ask for ridiculous period */
774 #else
775 acb->msgout[4] = sc->sc_minsync;
776 #endif
777 acb->msgout[5] = SIOP_MAX_OFFSET;
778 acb->ds.idlen = 6;
779 sc->sc_sync[target].state = NEG_WAITS;
780 #ifdef DEBUG
781 if (siopsync_debug)
782 printf ("Sending sync request to target %d\n", target);
783 #endif
784 }
785 }
786
787 /*
788 * Build physical DMA addresses for scatter/gather I/O
789 */
790 acb->iob_buf = buf;
791 acb->iob_len = len;
792 acb->iob_curbuf = acb->iob_curlen = 0;
793 nchain = 0;
794 count = len;
795 addr = buf;
796 dmaend = NULL;
797 while (count > 0) {
798 acb->ds.chain[nchain].databuf = (char *) kvtop (addr);
799 if (count < (tcount = NBPG - ((int) addr & PGOFSET)))
800 tcount = count;
801 acb->ds.chain[nchain].datalen = tcount;
802 addr += tcount;
803 count -= tcount;
804 if (acb->ds.chain[nchain].databuf == dmaend) {
805 dmaend += acb->ds.chain[nchain].datalen;
806 acb->ds.chain[nchain].datalen = 0;
807 acb->ds.chain[--nchain].datalen += tcount;
808 #ifdef DEBUG
809 ++siopdma_hits;
810 #endif
811 }
812 else {
813 dmaend = acb->ds.chain[nchain].databuf +
814 acb->ds.chain[nchain].datalen;
815 acb->ds.chain[nchain].datalen = tcount;
816 #ifdef DEBUG
817 if (nchain) /* Don't count miss on first one */
818 ++siopdma_misses;
819 #endif
820 }
821 ++nchain;
822 }
823 #ifdef DEBUG
824 if (nchain != 1 && len != 0 && siop_debug & 3) {
825 printf ("DMA chaining set: %d\n", nchain);
826 for (i = 0; i < nchain; ++i) {
827 printf (" [%d] %8p %lx\n", i, acb->ds.chain[i].databuf,
828 acb->ds.chain[i].datalen);
829 }
830 }
831 #endif
832
833 /* push data cache for all data the 53c710 needs to access */
834 dma_cachectl ((caddr_t)acb, sizeof (struct siop_acb));
835 dma_cachectl (cbuf, clen);
836 if (buf != NULL && len != 0)
837 dma_cachectl (buf, len);
838 #ifdef DEBUG
839 if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
840 printf ("ACK! siop was busy at start: rp %p script %p dsa %p active %ld\n",
841 rp, &scripts, &acb->ds, sc->sc_active);
842 #ifdef DDB
843 /*Debugger();*/
844 #endif
845 }
846 #endif
847 if (sc->nexus_list.tqh_first == NULL) {
848 if (rp->siop_istat & SIOP_ISTAT_CON)
849 printf("%s: siop_select while connected?\n",
850 sc->sc_dev.dv_xname);
851 rp->siop_temp = 0;
852 rp->siop_sbcl = sc->sc_sync[target].sbcl;
853 rp->siop_dsa = kvtop((caddr_t)&acb->ds);
854 rp->siop_dsp = sc->sc_scriptspa;
855 SIOP_TRACE('s',1,0,0)
856 } else {
857 if ((rp->siop_istat & SIOP_ISTAT_CON) == 0) {
858 rp->siop_istat = SIOP_ISTAT_SIGP;
859 SIOP_TRACE('s',2,0,0);
860 }
861 else {
862 SIOP_TRACE('s',3,rp->siop_istat,0);
863 }
864 }
865 #ifdef DEBUG
866 ++siopstarts;
867 #endif
868 }
869
870 /*
871 * Process a DMA or SCSI interrupt from the 53C710 SIOP
872 */
873
874 int
875 siop_checkintr(sc, istat, dstat, sstat0, status)
876 struct siop_softc *sc;
877 u_char istat;
878 u_char dstat;
879 u_char sstat0;
880 int *status;
881 {
882 siop_regmap_p rp = sc->sc_siopp;
883 struct siop_acb *acb = sc->sc_nexus;
884 int target = 0;
885 int dfifo, dbc, sstat1;
886
887 dfifo = rp->siop_dfifo;
888 dbc = rp->siop_dbc0;
889 sstat1 = rp->siop_sstat1;
890 rp->siop_ctest8 |= SIOP_CTEST8_CLF;
891 while ((rp->siop_ctest1 & SIOP_CTEST1_FMT) != SIOP_CTEST1_FMT)
892 ;
893 rp->siop_ctest8 &= ~SIOP_CTEST8_CLF;
894 #ifdef DEBUG
895 ++siopints;
896 #if 0
897 if (siop_debug & 0x100) {
898 DCIAS(&acb->stat[0]); /* XXX */
899 printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
900 istat, dstat, sstat0, rp->siop_dsps, rp->siop_sbcl, acb->stat[0], acb->msg[0]);
901 printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
902 acb->msg[0], acb->msg[1], acb->msg[2],
903 acb->msg[3], acb->msg[4], acb->msg[5]);
904 }
905 #endif
906 if (rp->siop_dsp && (rp->siop_dsp < sc->sc_scriptspa ||
907 rp->siop_dsp >= sc->sc_scriptspa + sizeof(scripts))) {
908 printf ("%s: dsp not within script dsp %lx scripts %lx:%lx",
909 sc->sc_dev.dv_xname, rp->siop_dsp, sc->sc_scriptspa,
910 sc->sc_scriptspa + sizeof(scripts));
911 printf(" istat %x dstat %x sstat0 %x\n",
912 istat, dstat, sstat0);
913 #ifdef DDB
914 Debugger();
915 #endif
916 }
917 #endif
918 SIOP_TRACE('i',dstat,istat,(istat&SIOP_ISTAT_DIP)?rp->siop_dsps&0xff:sstat0);
919 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff00) {
920 /* Normal completion status, or check condition */
921 #ifdef DEBUG
922 if (rp->siop_dsa != kvtop((caddr_t)&acb->ds)) {
923 printf ("siop: invalid dsa: %lx %x\n", rp->siop_dsa,
924 kvtop((caddr_t)&acb->ds));
925 panic("*** siop DSA invalid ***");
926 }
927 #endif
928 target = acb->xs->sc_link->scsipi_scsi.target;
929 if (sc->sc_sync[target].state == NEG_WAITS) {
930 if (acb->msg[1] == 0xff)
931 printf ("%s: target %d ignored sync request\n",
932 sc->sc_dev.dv_xname, target);
933 else if (acb->msg[1] == MSG_REJECT)
934 printf ("%s: target %d rejected sync request\n",
935 sc->sc_dev.dv_xname, target);
936 else
937 /* XXX - need to set sync transfer parameters */
938 printf("%s: target %d (sync) %02x %02x %02x\n",
939 sc->sc_dev.dv_xname, target, acb->msg[1],
940 acb->msg[2], acb->msg[3]);
941 sc->sc_sync[target].state = NEG_DONE;
942 }
943 dma_cachectl(&acb->stat[0], 1);
944 *status = acb->stat[0];
945 #ifdef DEBUG
946 if (rp->siop_sbcl & SIOP_BSY) {
947 /*printf ("ACK! siop was busy at end: rp %x script %x dsa %x\n",
948 rp, &scripts, &acb->ds);*/
949 #ifdef DDB
950 /*Debugger();*/
951 #endif
952 }
953 if (acb->msg[0] != 0x00)
954 printf("%s: message was not COMMAND COMPLETE: %x\n",
955 sc->sc_dev.dv_xname, acb->msg[0]);
956 #endif
957 if (sc->nexus_list.tqh_first)
958 rp->siop_dcntl |= SIOP_DCNTL_STD;
959 return 1;
960 }
961 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff0b) {
962 target = acb->xs->sc_link->scsipi_scsi.target;
963 if (acb->msg[1] == MSG_EXT_MESSAGE && acb->msg[2] == 3 &&
964 acb->msg[3] == MSG_SYNC_REQ) {
965 #ifdef DEBUG
966 if (siopsync_debug)
967 printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
968 acb->msg[0], acb->msg[1], acb->msg[2],
969 acb->msg[3], acb->msg[4], acb->msg[5]);
970 #endif
971 sc->sc_sync[target].sxfer = 0;
972 sc->sc_sync[target].sbcl = 0;
973 if (acb->msg[2] == 3 &&
974 acb->msg[3] == MSG_SYNC_REQ &&
975 acb->msg[5] != 0) {
976 #ifdef MAXTOR_KLUDGE
977 /*
978 * Kludge for my Maxtor XT8580S
979 * It accepts whatever we request, even
980 * though it won't work. So we ask for
981 * a short period than we can handle. If
982 * the device says it can do it, use 208ns.
983 * If the device says it can do less than
984 * 100ns, then we limit it to 100ns.
985 */
986 if (acb->msg[4] && acb->msg[4] < 100 / 4) {
987 #ifdef DEBUG
988 printf ("%d: target %d wanted %dns period\n",
989 sc->sc_dev.dv_xname, target,
990 acb->msg[4] * 4);
991 #endif
992 if (acb->msg[4] == 50 / 4)
993 acb->msg[4] = 208 / 4;
994 else
995 acb->msg[4] = 100 / 4;
996 }
997 #endif /* MAXTOR_KLUDGE */
998 printf ("%s: target %d now synchronous, period=%dns, offset=%d\n",
999 sc->sc_dev.dv_xname, target,
1000 acb->msg[4] * 4, acb->msg[5]);
1001 scsi_period_to_siop (sc, target);
1002 }
1003 rp->siop_sxfer = sc->sc_sync[target].sxfer;
1004 rp->siop_sbcl = sc->sc_sync[target].sbcl;
1005 if (sc->sc_sync[target].state == NEG_WAITS) {
1006 sc->sc_sync[target].state = NEG_DONE;
1007 rp->siop_dsp = sc->sc_scriptspa + Ent_clear_ack;
1008 return(0);
1009 }
1010 rp->siop_dcntl |= SIOP_DCNTL_STD;
1011 sc->sc_sync[target].state = NEG_DONE;
1012 return (0);
1013 }
1014 /* XXX - not SDTR message */
1015 }
1016 if (sstat0 & SIOP_SSTAT0_M_A) { /* Phase mismatch */
1017 #ifdef DEBUG
1018 ++siopphmm;
1019 if (acb == NULL)
1020 printf("%s: Phase mismatch with no active command?\n",
1021 sc->sc_dev.dv_xname);
1022 #endif
1023 if (acb->iob_len) {
1024 int adjust;
1025 adjust = ((dfifo - (dbc & 0x7f)) & 0x7f);
1026 if (sstat1 & SIOP_SSTAT1_ORF)
1027 ++adjust;
1028 if (sstat1 & SIOP_SSTAT1_OLF)
1029 ++adjust;
1030 acb->iob_curlen = *((long *)&rp->siop_dcmd) & 0xffffff;
1031 acb->iob_curlen += adjust;
1032 acb->iob_curbuf = *((long *)&rp->siop_dnad) - adjust;
1033 #ifdef DEBUG
1034 if (siop_debug & 0x100) {
1035 int i;
1036 printf ("Phase mismatch: curbuf %lx curlen %lx dfifo %x dbc %x sstat1 %x adjust %x sbcl %x starts %d acb %p\n",
1037 acb->iob_curbuf, acb->iob_curlen, dfifo,
1038 dbc, sstat1, adjust, rp->siop_sbcl, siopstarts, acb);
1039 if (acb->ds.chain[1].datalen) {
1040 for (i = 0; acb->ds.chain[i].datalen; ++i)
1041 printf("chain[%d] addr %p len %lx\n",
1042 i, acb->ds.chain[i].databuf,
1043 acb->ds.chain[i].datalen);
1044 }
1045 }
1046 #endif
1047 dma_cachectl ((caddr_t)acb, sizeof(*acb));
1048 }
1049 #ifdef DEBUG
1050 SIOP_TRACE('m',rp->siop_sbcl,(rp->siop_dsp>>8),rp->siop_dsp);
1051 if (siop_debug & 9)
1052 printf ("Phase mismatch: %x dsp +%lx dcmd %lx\n",
1053 rp->siop_sbcl,
1054 rp->siop_dsp - sc->sc_scriptspa,
1055 *((long *)&rp->siop_dcmd));
1056 #endif
1057 if ((rp->siop_sbcl & SIOP_REQ) == 0) {
1058 printf ("Phase mismatch: REQ not asserted! %02x dsp %lx\n",
1059 rp->siop_sbcl, rp->siop_dsp);
1060 #if defined(DEBUG) && defined(DDB)
1061 /*Debugger(); XXX is*/
1062 #endif
1063 }
1064 switch (rp->siop_sbcl & 7) {
1065 case 0: /* data out */
1066 case 1: /* data in */
1067 case 2: /* status */
1068 case 3: /* command */
1069 case 6: /* message in */
1070 case 7: /* message out */
1071 rp->siop_dsp = sc->sc_scriptspa + Ent_switch;
1072 break;
1073 default:
1074 goto bad_phase;
1075 }
1076 return 0;
1077 }
1078 if (sstat0 & SIOP_SSTAT0_STO) { /* Select timed out */
1079 #ifdef DEBUG
1080 if (acb == NULL)
1081 printf("%s: Select timeout with no active command?\n",
1082 sc->sc_dev.dv_xname);
1083 if (rp->siop_sbcl & SIOP_BSY) {
1084 printf ("ACK! siop was busy at timeout: rp %p script %p dsa %p\n",
1085 rp, &scripts, &acb->ds);
1086 printf(" sbcl %x sdid %x istat %x dstat %x sstat0 %x\n",
1087 rp->siop_sbcl, rp->siop_sdid, istat, dstat, sstat0);
1088 if (!(rp->siop_sbcl & SIOP_BSY)) {
1089 printf ("Yikes, it's not busy now!\n");
1090 #if 0
1091 *status = -1;
1092 if (sc->nexus_list.tqh_first)
1093 rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
1094 return 1;
1095 #endif
1096 }
1097 /* rp->siop_dcntl |= SIOP_DCNTL_STD;*/
1098 return (0);
1099 #ifdef DDB
1100 Debugger();
1101 #endif
1102 }
1103 #endif
1104 *status = -1;
1105 acb->xs->error = XS_SELTIMEOUT;
1106 if (sc->nexus_list.tqh_first)
1107 rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
1108 return 1;
1109 }
1110 if (acb)
1111 target = acb->xs->sc_link->scsipi_scsi.target;
1112 else
1113 target = 7;
1114 if (sstat0 & SIOP_SSTAT0_UDC) {
1115 #ifdef DEBUG
1116 if (acb == NULL)
1117 printf("%s: Unexpected disconnect with no active command?\n",
1118 sc->sc_dev.dv_xname);
1119 printf ("%s: target %d disconnected unexpectedly\n",
1120 sc->sc_dev.dv_xname, target);
1121 #endif
1122 #if 0
1123 siopabort (sc, rp, "siopchkintr");
1124 #endif
1125 *status = STS_BUSY;
1126 if (sc->nexus_list.tqh_first)
1127 rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
1128 return (acb != NULL);
1129 }
1130 if (dstat & SIOP_DSTAT_SIR && (rp->siop_dsps == 0xff01 ||
1131 rp->siop_dsps == 0xff02)) {
1132 #ifdef DEBUG
1133 if (siop_debug & 0x100)
1134 printf ("%s: ID %02x disconnected TEMP %lx (+%lx) curbuf %lx curlen %lx buf %p len %lx dfifo %x dbc %x sstat1 %x starts %d acb %p\n",
1135 sc->sc_dev.dv_xname, 1 << target, rp->siop_temp,
1136 rp->siop_temp ? rp->siop_temp - sc->sc_scriptspa : 0,
1137 acb->iob_curbuf, acb->iob_curlen,
1138 acb->ds.chain[0].databuf, acb->ds.chain[0].datalen, dfifo, dbc, sstat1, siopstarts, acb);
1139 #endif
1140 if (acb == NULL) {
1141 printf("%s: Disconnect with no active command?\n",
1142 sc->sc_dev.dv_xname);
1143 return (0);
1144 }
1145 /*
1146 * XXXX need to update iob_curbuf/iob_curlen to reflect
1147 * current data transferred. If device disconnected in
1148 * the middle of a DMA block, they should already be set
1149 * by the phase change interrupt. If the disconnect
1150 * occurs on a DMA block boundary, we have to figure out
1151 * which DMA block it was.
1152 */
1153 if (acb->iob_len && rp->siop_temp) {
1154 int n = rp->siop_temp - sc->sc_scriptspa;
1155
1156 if (acb->iob_curlen && acb->iob_curlen != acb->ds.chain[0].datalen)
1157 printf("%s: iob_curbuf/len already set? n %x iob %lx/%lx chain[0] %p/%lx\n",
1158 sc->sc_dev.dv_xname, n, acb->iob_curbuf, acb->iob_curlen,
1159 acb->ds.chain[0].databuf, acb->ds.chain[0].datalen);
1160 if (n < Ent_datain)
1161 n = (n - Ent_dataout) / 16;
1162 else
1163 n = (n - Ent_datain) / 16;
1164 if (n <= 0 && n > DMAMAXIO)
1165 printf("TEMP invalid %d\n", n);
1166 else {
1167 acb->iob_curbuf = (u_long)acb->ds.chain[n].databuf;
1168 acb->iob_curlen = acb->ds.chain[n].datalen;
1169 }
1170 #ifdef DEBUG
1171 if (siop_debug & 0x100) {
1172 printf("%s: TEMP offset %d", sc->sc_dev.dv_xname, n);
1173 printf(" curbuf %lx curlen %lx\n", acb->iob_curbuf,
1174 acb->iob_curlen);
1175 }
1176 #endif
1177 }
1178 /*
1179 * If data transfer was interrupted by disconnect, iob_curbuf
1180 * and iob_curlen should reflect the point of interruption.
1181 * Adjust the DMA chain so that the data transfer begins
1182 * at the appropriate place upon reselection.
1183 * XXX This should only be done on save data pointer message?
1184 */
1185 if (acb->iob_curlen) {
1186 int i, j;
1187
1188 #ifdef DEBUG
1189 if (siop_debug & 0x100)
1190 printf ("%s: adjusting DMA chain\n",
1191 sc->sc_dev.dv_xname);
1192 if (rp->siop_dsps == 0xff02)
1193 printf ("%s: ID %02x disconnected without Save Data Pointers\n",
1194 sc->sc_dev.dv_xname, 1 << target);
1195 #endif
1196 for (i = 0; i < DMAMAXIO; ++i) {
1197 if (acb->ds.chain[i].datalen == 0)
1198 break;
1199 if (acb->iob_curbuf >= (long)acb->ds.chain[i].databuf &&
1200 acb->iob_curbuf < (long)(acb->ds.chain[i].databuf +
1201 acb->ds.chain[i].datalen))
1202 break;
1203 }
1204 if (i >= DMAMAXIO || acb->ds.chain[i].datalen == 0) {
1205 printf("couldn't find saved data pointer: ");
1206 printf("curbuf %lx curlen %lx i %d\n",
1207 acb->iob_curbuf, acb->iob_curlen, i);
1208 #ifdef DDB
1209 Debugger();
1210 #endif
1211 }
1212 #ifdef DEBUG
1213 if (siop_debug & 0x100)
1214 printf(" chain[0]: %p/%lx -> %lx/%lx\n",
1215 acb->ds.chain[0].databuf,
1216 acb->ds.chain[0].datalen,
1217 acb->iob_curbuf,
1218 acb->iob_curlen);
1219 #endif
1220 acb->ds.chain[0].databuf = (char *)acb->iob_curbuf;
1221 acb->ds.chain[0].datalen = acb->iob_curlen;
1222 for (j = 1, ++i; i < DMAMAXIO && acb->ds.chain[i].datalen; ++i, ++j) {
1223 #ifdef DEBUG
1224 if (siop_debug & 0x100)
1225 printf(" chain[%d]: %p/%lx -> %p/%lx\n", j,
1226 acb->ds.chain[j].databuf,
1227 acb->ds.chain[j].datalen,
1228 acb->ds.chain[i].databuf,
1229 acb->ds.chain[i].datalen);
1230 #endif
1231 acb->ds.chain[j].databuf = acb->ds.chain[i].databuf;
1232 acb->ds.chain[j].datalen = acb->ds.chain[i].datalen;
1233 }
1234 if (j < DMAMAXIO)
1235 acb->ds.chain[j].datalen = 0;
1236 DCIAS(kvtop((caddr_t)&acb->ds.chain));
1237 }
1238 ++sc->sc_tinfo[target].dconns;
1239 /*
1240 * add nexus to waiting list
1241 * clear nexus
1242 * try to start another command for another target/lun
1243 */
1244 acb->status = sc->sc_flags & SIOP_INTSOFF;
1245 TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain);
1246 sc->sc_nexus = NULL; /* no current device */
1247 /* start script to wait for reselect */
1248 if (sc->sc_nexus == NULL)
1249 rp->siop_dsp = sc->sc_scriptspa + Ent_wait_reselect;
1250 /* XXXX start another command ? */
1251 if (sc->ready_list.tqh_first)
1252 siop_sched(sc);
1253 return (0);
1254 }
1255 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff03) {
1256 int reselid = rp->siop_scratch & 0x7f;
1257 int reselun = rp->siop_sfbr & 0x07;
1258
1259 sc->sc_sstat1 = rp->siop_sbcl; /* XXXX save current SBCL */
1260 #ifdef DEBUG
1261 if (siop_debug & 0x100)
1262 printf ("%s: target ID %02x reselected dsps %lx\n",
1263 sc->sc_dev.dv_xname, reselid,
1264 rp->siop_dsps);
1265 if ((rp->siop_sfbr & 0x80) == 0)
1266 printf("%s: Reselect message in was not identify: %x\n",
1267 sc->sc_dev.dv_xname, rp->siop_sfbr);
1268 #endif
1269 if (sc->sc_nexus) {
1270 #ifdef DEBUG
1271 if (siop_debug & 0x100)
1272 printf ("%s: reselect ID %02x w/active\n",
1273 sc->sc_dev.dv_xname, reselid);
1274 #endif
1275 TAILQ_INSERT_HEAD(&sc->ready_list, sc->sc_nexus, chain);
1276 sc->sc_tinfo[sc->sc_nexus->xs->sc_link->scsipi_scsi.target].lubusy
1277 &= ~(1 << sc->sc_nexus->xs->sc_link->scsipi_scsi.lun);
1278 --sc->sc_active;
1279 }
1280 /*
1281 * locate acb of reselecting device
1282 * set sc->sc_nexus to acb
1283 */
1284 for (acb = sc->nexus_list.tqh_first; acb;
1285 acb = acb->chain.tqe_next) {
1286 if (reselid != (acb->ds.scsi_addr >> 16) ||
1287 reselun != (acb->msgout[0] & 0x07))
1288 continue;
1289 TAILQ_REMOVE(&sc->nexus_list, acb, chain);
1290 sc->sc_nexus = acb;
1291 sc->sc_flags |= acb->status;
1292 acb->status = 0;
1293 DCIAS(kvtop(&acb->stat[0]));
1294 rp->siop_dsa = kvtop((caddr_t)&acb->ds);
1295 rp->siop_sxfer =
1296 sc->sc_sync[acb->xs->sc_link->scsipi_scsi.target].sxfer;
1297 rp->siop_sbcl =
1298 sc->sc_sync[acb->xs->sc_link->scsipi_scsi.target].sbcl;
1299 break;
1300 }
1301 if (acb == NULL) {
1302 printf("%s: target ID %02x reselect nexus_list %p\n",
1303 sc->sc_dev.dv_xname, reselid,
1304 sc->nexus_list.tqh_first);
1305 panic("unable to find reselecting device");
1306 }
1307 dma_cachectl ((caddr_t)acb, sizeof(*acb));
1308 rp->siop_temp = 0;
1309 rp->siop_dcntl |= SIOP_DCNTL_STD;
1310 return (0);
1311 }
1312 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff04) {
1313 #ifdef DEBUG
1314 u_short ctest2 = rp->siop_ctest2;
1315
1316 /* reselect was interrupted (by Sig_P or select) */
1317 if (siop_debug & 0x100 ||
1318 (ctest2 & SIOP_CTEST2_SIGP) == 0)
1319 printf ("%s: reselect interrupted (Sig_P?) scntl1 %x ctest2 %x sfbr %x istat %x/%x\n",
1320 sc->sc_dev.dv_xname, rp->siop_scntl1,
1321 ctest2, rp->siop_sfbr, istat, rp->siop_istat);
1322 #endif
1323 /* XXX assumes it was not select */
1324 if (sc->sc_nexus == NULL) {
1325 #ifdef DEBUG
1326 printf("%s: reselect interrupted, sc_nexus == NULL\n",
1327 sc->sc_dev.dv_xname);
1328 #if 0
1329 siop_dump(sc);
1330 #ifdef DDB
1331 Debugger();
1332 #endif
1333 #endif
1334 #endif
1335 rp->siop_dcntl |= SIOP_DCNTL_STD;
1336 return(0);
1337 }
1338 target = sc->sc_nexus->xs->sc_link->scsipi_scsi.target;
1339 rp->siop_temp = 0;
1340 rp->siop_dsa = kvtop((caddr_t)&sc->sc_nexus->ds);
1341 rp->siop_sxfer = sc->sc_sync[target].sxfer;
1342 rp->siop_sbcl = sc->sc_sync[target].sbcl;
1343 rp->siop_dsp = sc->sc_scriptspa;
1344 return (0);
1345 }
1346 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff06) {
1347 if (acb == NULL)
1348 printf("%s: Bad message-in with no active command?\n",
1349 sc->sc_dev.dv_xname);
1350 /* Unrecognized message in byte */
1351 dma_cachectl (&acb->msg[1],1);
1352 printf ("%s: Unrecognized message in data sfbr %x msg %x sbcl %x\n",
1353 sc->sc_dev.dv_xname, rp->siop_sfbr, acb->msg[1], rp->siop_sbcl);
1354 /* what should be done here? */
1355 DCIAS(kvtop(&acb->msg[1]));
1356 rp->siop_dsp = sc->sc_scriptspa + Ent_switch;
1357 return (0);
1358 }
1359 if (dstat & SIOP_DSTAT_SIR && rp->siop_dsps == 0xff0a) {
1360 /* Status phase wasn't followed by message in phase? */
1361 printf ("%s: Status phase not followed by message in phase? sbcl %x sbdl %x\n",
1362 sc->sc_dev.dv_xname, rp->siop_sbcl, rp->siop_sbdl);
1363 if (rp->siop_sbcl == 0xa7) {
1364 /* It is now, just continue the script? */
1365 rp->siop_dcntl |= SIOP_DCNTL_STD;
1366 return (0);
1367 }
1368 }
1369 if (sstat0 == 0 && dstat & SIOP_DSTAT_SIR) {
1370 dma_cachectl (&acb->stat[0], 1);
1371 dma_cachectl (&acb->msg[0], 1);
1372 printf ("SIOP interrupt: %lx sts %x msg %x %x sbcl %x\n",
1373 rp->siop_dsps, acb->stat[0], acb->msg[0], acb->msg[1],
1374 rp->siop_sbcl);
1375 siopreset (sc);
1376 *status = -1;
1377 return 0; /* siopreset has cleaned up */
1378 }
1379 if (sstat0 & SIOP_SSTAT0_SGE)
1380 printf ("SIOP: SCSI Gross Error\n");
1381 if (sstat0 & SIOP_SSTAT0_PAR)
1382 printf ("SIOP: Parity Error\n");
1383 if (dstat & SIOP_DSTAT_IID)
1384 printf ("SIOP: Invalid instruction detected\n");
1385 bad_phase:
1386 /*
1387 * temporary panic for unhandled conditions
1388 * displays various things about the 53C710 status and registers
1389 * then panics.
1390 * XXXX need to clean this up to print out the info, reset, and continue
1391 */
1392 printf ("siopchkintr: target %x ds %p\n", target, &acb->ds);
1393 printf ("scripts %lx ds %x rp %x dsp %lx dcmd %lx\n", sc->sc_scriptspa,
1394 kvtop((caddr_t)&acb->ds), kvtop((caddr_t)rp), rp->siop_dsp,
1395 *((long *)&rp->siop_dcmd));
1396 printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %lx dsa %lx sbcl %x sts %x msg %x %x sfbr %x\n",
1397 istat, dstat, sstat0, rp->siop_dsps, rp->siop_dsa,
1398 rp->siop_sbcl, acb->stat[0], acb->msg[0], acb->msg[1], rp->siop_sfbr);
1399 #ifdef DEBUG
1400 if (siop_debug & 0x20)
1401 panic("siopchkintr: **** temp ****");
1402 #endif
1403 #ifdef DDB
1404 Debugger ();
1405 #endif
1406 siopreset (sc); /* hard reset */
1407 *status = -1;
1408 return 0; /* siopreset cleaned up */
1409 }
1410
1411 void
1412 siop_select(sc)
1413 struct siop_softc *sc;
1414 {
1415 siop_regmap_p rp;
1416 struct siop_acb *acb = sc->sc_nexus;
1417
1418 #ifdef DEBUG
1419 if (siop_debug & 1)
1420 printf ("%s: select ", sc->sc_dev.dv_xname);
1421 #endif
1422
1423 rp = sc->sc_siopp;
1424 if (acb->xs->flags & SCSI_POLL || siop_no_dma) {
1425 sc->sc_flags |= SIOP_INTSOFF;
1426 sc->sc_flags &= ~SIOP_INTDEFER;
1427 if ((rp->siop_istat & 0x08) == 0) {
1428 rp->siop_sien = 0;
1429 rp->siop_dien = 0;
1430 }
1431 #if 0
1432 } else if ((sc->sc_flags & SIOP_INTDEFER) == 0) {
1433 sc->sc_flags &= ~SIOP_INTSOFF;
1434 if ((rp->siop_istat & 0x08) == 0) {
1435 rp->siop_sien = sc->sc_sien;
1436 rp->siop_dien = sc->sc_dien;
1437 }
1438 #endif
1439 }
1440 #ifdef DEBUG
1441 if (siop_debug & 1)
1442 printf ("siop_select: target %x cmd %02x ds %p\n",
1443 acb->xs->sc_link->scsipi_scsi.target, acb->cmd.opcode,
1444 &sc->sc_nexus->ds);
1445 #endif
1446
1447 siop_start(sc, acb->xs->sc_link->scsipi_scsi.target,
1448 acb->xs->sc_link->scsipi_scsi.lun,
1449 (u_char *)&acb->cmd, acb->clen, acb->daddr, acb->dleft);
1450
1451 return;
1452 }
1453
1454 /*
1455 * 53C710 interrupt handler
1456 */
1457
1458 void
1459 siopintr (sc)
1460 register struct siop_softc *sc;
1461 {
1462 siop_regmap_p rp;
1463 register u_char istat, dstat, sstat0;
1464 int status;
1465 int s = splbio();
1466
1467 istat = sc->sc_istat;
1468 if ((istat & (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) {
1469 splx(s);
1470 return;
1471 }
1472
1473 /* Got a valid interrupt on this device */
1474 rp = sc->sc_siopp;
1475 dstat = sc->sc_dstat;
1476 sstat0 = sc->sc_sstat0;
1477 if (dstat & SIOP_DSTAT_SIR)
1478 sc->sc_intcode = rp->siop_dsps;
1479 sc->sc_istat = 0;
1480 #ifdef DEBUG
1481 if (siop_debug & 1)
1482 printf ("%s: intr istat %x dstat %x sstat0 %x\n",
1483 sc->sc_dev.dv_xname, istat, dstat, sstat0);
1484 if (!sc->sc_active) {
1485 printf ("%s: spurious interrupt? istat %x dstat %x sstat0 %x nexus %p status %x\n",
1486 sc->sc_dev.dv_xname, istat, dstat, sstat0,
1487 sc->sc_nexus, sc->sc_nexus ? sc->sc_nexus->stat[0] : 0);
1488 }
1489 #endif
1490
1491 #ifdef DEBUG
1492 if (siop_debug & 5) {
1493 DCIAS(kvtop(&sc->sc_nexus->stat[0]));
1494 printf ("%s: intr istat %x dstat %x sstat0 %x dsps %lx sbcl %x sts %x msg %x\n",
1495 sc->sc_dev.dv_xname, istat, dstat, sstat0,
1496 rp->siop_dsps, rp->siop_sbcl,
1497 sc->sc_nexus->stat[0], sc->sc_nexus->msg[0]);
1498 }
1499 #endif
1500 if (sc->sc_flags & SIOP_INTDEFER) {
1501 sc->sc_flags &= ~(SIOP_INTDEFER | SIOP_INTSOFF);
1502 rp->siop_sien = sc->sc_sien;
1503 rp->siop_dien = sc->sc_dien;
1504 }
1505 if (siop_checkintr (sc, istat, dstat, sstat0, &status)) {
1506 #if 1
1507 if (status == 0xff)
1508 printf ("siopintr: status == 0xff\n");
1509 #endif
1510 if ((sc->sc_flags & (SIOP_INTSOFF | SIOP_INTDEFER)) != SIOP_INTSOFF) {
1511 #if 0
1512 if (rp->siop_sbcl & SIOP_BSY) {
1513 printf ("%s: SCSI bus busy at completion",
1514 sc->sc_dev.dv_xname);
1515 printf(" targ %d sbcl %02x sfbr %x lcrc %02x dsp +%x\n",
1516 sc->sc_nexus->xs->sc_link->scsipi_scsi.target,
1517 rp->siop_sbcl, rp->siop_sfbr, rp->siop_lcrc,
1518 rp->siop_dsp - sc->sc_scriptspa);
1519 }
1520 #endif
1521 siop_scsidone(sc->sc_nexus, sc->sc_nexus ?
1522 sc->sc_nexus->stat[0] : -1);
1523 }
1524 }
1525 splx(s);
1526 }
1527
1528 /*
1529 * This is based on the Progressive Peripherals 33Mhz Zeus driver and will
1530 * not be correct for other 53c710 boards.
1531 *
1532 */
1533 void
1534 scsi_period_to_siop (sc, target)
1535 struct siop_softc *sc;
1536 int target;
1537 {
1538 int period, offset, sxfer, sbcl = 0;
1539 #ifdef DEBUG_SYNC
1540 int i;
1541 #endif
1542
1543 period = sc->sc_nexus->msg[4];
1544 offset = sc->sc_nexus->msg[5];
1545 #ifdef DEBUG_SYNC
1546 sxfer = 0;
1547 if (offset <= SIOP_MAX_OFFSET)
1548 sxfer = offset;
1549 for (i = 0; i < sizeof (sync_tab) / 2; ++i) {
1550 if (period <= sync_tab[i].p) {
1551 sxfer |= sync_tab[i].r & 0x70;
1552 sbcl = sync_tab[i].r & 0x03;
1553 break;
1554 }
1555 }
1556 printf ("siop sync old: siop_sxfr %02x, siop_sbcl %02x\n", sxfer, sbcl);
1557 #endif
1558 for (sbcl = 1; sbcl < 4; ++sbcl) {
1559 sxfer = (period * 4 - 1) / sc->sc_tcp[sbcl] - 3;
1560 if (sxfer >= 0 && sxfer <= 7)
1561 break;
1562 }
1563 if (sbcl > 3) {
1564 printf("siop sync: unable to compute sync params for period %dns\n",
1565 period * 4);
1566 /*
1567 * XXX need to pick a value we can do and renegotiate
1568 */
1569 sxfer = sbcl = 0;
1570 } else {
1571 sxfer = (sxfer << 4) | ((offset <= SIOP_MAX_OFFSET) ?
1572 offset : SIOP_MAX_OFFSET);
1573 #ifdef DEBUG_SYNC
1574 printf("siop sync: params for period %dns: sxfer %x sbcl %x",
1575 period * 4, sxfer, sbcl);
1576 printf(" actual period %dns\n",
1577 sc->sc_tcp[sbcl] * ((sxfer >> 4) + 4));
1578 #endif
1579 }
1580 sc->sc_sync[target].sxfer = sxfer;
1581 sc->sc_sync[target].sbcl = sbcl;
1582 #ifdef DEBUG_SYNC
1583 printf ("siop sync: siop_sxfr %02x, siop_sbcl %02x\n", sxfer, sbcl);
1584 #endif
1585 }
1586
1587 #ifdef DEBUG
1588
1589 #if SIOP_TRACE_SIZE
1590 void
1591 siop_dump_trace()
1592 {
1593 int i;
1594
1595 printf("siop trace: next index %d\n", siop_trix);
1596 i = siop_trix;
1597 do {
1598 printf("%3d: '%c' %02x %02x %02x\n", i, siop_trbuf[i],
1599 siop_trbuf[i + 1], siop_trbuf[i + 2], siop_trbuf[i + 3]);
1600 i = (i + 4) & (SIOP_TRACE_SIZE - 1);
1601 } while (i != siop_trix);
1602 }
1603 #endif
1604
1605 void
1606 siop_dump_acb(acb)
1607 struct siop_acb *acb;
1608 {
1609 u_char *b = (u_char *) &acb->cmd;
1610 int i;
1611
1612 printf("acb@%p ", acb);
1613 if (acb->xs == NULL) {
1614 printf("<unused>\n");
1615 return;
1616 }
1617 printf("(%d:%d) flags %2x clen %2d cmd ",
1618 acb->xs->sc_link->scsipi_scsi.target,
1619 acb->xs->sc_link->scsipi_scsi.lun, acb->flags, acb->clen);
1620 for (i = acb->clen; i; --i)
1621 printf(" %02x", *b++);
1622 printf("\n");
1623 printf(" xs: %p data %p:%04x ", acb->xs, acb->xs->data,
1624 acb->xs->datalen);
1625 printf("va %p:%lx ", acb->iob_buf, acb->iob_len);
1626 printf("cur %lx:%lx\n", acb->iob_curbuf, acb->iob_curlen);
1627 }
1628
1629 void
1630 siop_dump(sc)
1631 struct siop_softc *sc;
1632 {
1633 struct siop_acb *acb;
1634 siop_regmap_p rp = sc->sc_siopp;
1635 int s;
1636 int i;
1637
1638 s = splbio();
1639 #if SIOP_TRACE_SIZE
1640 siop_dump_trace();
1641 #endif
1642 printf("%s@%p regs %p istat %x\n",
1643 sc->sc_dev.dv_xname, sc, rp, rp->siop_istat);
1644 if ((acb = sc->free_list.tqh_first) > 0) {
1645 printf("Free list:\n");
1646 while (acb) {
1647 siop_dump_acb(acb);
1648 acb = acb->chain.tqe_next;
1649 }
1650 }
1651 if ((acb = sc->ready_list.tqh_first) > 0) {
1652 printf("Ready list:\n");
1653 while (acb) {
1654 siop_dump_acb(acb);
1655 acb = acb->chain.tqe_next;
1656 }
1657 }
1658 if ((acb = sc->nexus_list.tqh_first) > 0) {
1659 printf("Nexus list:\n");
1660 while (acb) {
1661 siop_dump_acb(acb);
1662 acb = acb->chain.tqe_next;
1663 }
1664 }
1665 if (sc->sc_nexus) {
1666 printf("Nexus:\n");
1667 siop_dump_acb(sc->sc_nexus);
1668 }
1669 for (i = 0; i < 8; ++i) {
1670 if (sc->sc_tinfo[i].cmds > 2) {
1671 printf("tgt %d: cmds %d disc %d senses %d lubusy %x\n",
1672 i, sc->sc_tinfo[i].cmds,
1673 sc->sc_tinfo[i].dconns,
1674 sc->sc_tinfo[i].senses,
1675 sc->sc_tinfo[i].lubusy);
1676 }
1677 }
1678 splx(s);
1679 }
1680 #endif
1681