mac68k5380.c revision 1.21 1 /* $NetBSD: mac68k5380.c,v 1.21 1996/03/20 05:15:50 scottr Exp $ */
2
3 /*
4 * Copyright (c) 1995 Allen Briggs
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Allen Briggs
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Derived from atari5380.c for the mac68k port of NetBSD.
33 *
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/dkstat.h>
41 #include <sys/syslog.h>
42 #include <sys/buf.h>
43 #include <scsi/scsi_all.h>
44 #include <scsi/scsi_message.h>
45 #include <scsi/scsiconf.h>
46
47 /*
48 * Include the driver definitions
49 */
50 #include <mac68k/dev/ncr5380reg.h>
51
52 #include <machine/stdarg.h>
53
54 #include "../mac68k/via.h"
55
56 /*
57 * Set the various driver options
58 */
59 #define NREQ 18 /* Size of issue queue */
60 #define AUTO_SENSE 1 /* Automatically issue a request-sense */
61
62 #define DRNAME ncrscsi /* used in various prints */
63 #undef DBG_SEL /* Show the selection process */
64 #undef DBG_REQ /* Show enqueued/ready requests */
65 #undef DBG_NOWRITE /* Do not allow writes to the targets */
66 #undef DBG_PIO /* Show the polled-I/O process */
67 #undef DBG_INF /* Show information transfer process */
68 #define DBG_NOSTATIC /* No static functions, all in DDB trace*/
69 #define DBG_PID 25 /* Keep track of driver */
70 #ifdef DBG_NOSTATIC
71 # define static
72 #endif
73 #ifdef DBG_SEL
74 # define DBG_SELPRINT(a,b) printf(a,b)
75 #else
76 # define DBG_SELPRINT(a,b)
77 #endif
78 #ifdef DBG_PIO
79 # define DBG_PIOPRINT(a,b,c) printf(a,b,c)
80 #else
81 # define DBG_PIOPRINT(a,b,c)
82 #endif
83 #ifdef DBG_INF
84 # define DBG_INFPRINT(a,b,c) a(b,c)
85 #else
86 # define DBG_INFPRINT(a,b,c)
87 #endif
88 #ifdef DBG_PID
89 /* static char *last_hit = NULL, *olast_hit = NULL; */
90 static char *last_hit[DBG_PID];
91 # define PID(a) \
92 { int i; \
93 for (i=0; i< DBG_PID-1; i++) \
94 last_hit[i] = last_hit[i+1]; \
95 last_hit[DBG_PID-1] = a; }
96 #else
97 # define PID(a)
98 #endif
99
100 #undef REAL_DMA /* Use DMA if sensible */
101 #define scsi_ipending() (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET)
102 #define fair_to_keep_dma() 1
103 #define claimed_dma() 1
104 #define reconsider_dma()
105 #define USE_PDMA 1 /* Use special pdma-transfer function */
106 #define MIN_PHYS 0x2000 /* pdma space w/ /DSACK is only 0x2000 */
107
108 #define ENABLE_NCR5380(sc) cur_softc = sc;
109
110 /*
111 * softc of currently active controller (well, we only have one for now).
112 */
113
114 static struct ncr_softc *cur_softc;
115
116 struct scsi_5380 {
117 volatile u_char scsi_5380[8*16]; /* 8 regs, 1 every 16th byte. */
118 };
119
120 extern vm_offset_t SCSIBase;
121 static volatile u_char *ncr = (volatile u_char *) 0x10000;
122 static volatile u_char *ncr_5380_with_drq = (volatile u_char *) 0x6000;
123 static volatile u_char *ncr_5380_without_drq = (volatile u_char *) 0x12000;
124
125 static volatile u_char *scsi_enable = NULL;
126
127 #define SCSI_5380 ((struct scsi_5380 *) ncr)
128 #define GET_5380_REG(rnum) SCSI_5380->scsi_5380[((rnum)<<4)]
129 #define SET_5380_REG(rnum,val) (SCSI_5380->scsi_5380[((rnum)<<4)] = (val))
130
131 void ncr5380_irq_intr(void *);
132 void ncr5380_drq_intr(void *);
133
134 static __inline__ void
135 scsi_clr_ipend()
136 {
137 int tmp;
138
139 tmp = GET_5380_REG(NCR5380_IRCV);
140 }
141
142 extern __inline__ void
143 scsi_ienable()
144 {
145 int s;
146
147 s = splhigh();
148 *scsi_enable = 0x80 | (V2IF_SCSIIRQ | V2IF_SCSIDRQ);
149 splx(s);
150 }
151
152 extern __inline__ void
153 scsi_idisable()
154 {
155 int s;
156
157 s = splhigh();
158 *scsi_enable = V2IF_SCSIIRQ | V2IF_SCSIDRQ;
159 splx(s);
160 }
161
162 static void
163 scsi_mach_init(sc)
164 struct ncr_softc *sc;
165 {
166 static int initted = 0;
167
168 if (initted++)
169 panic("scsi_mach_init called again.\n");
170
171 ncr = (volatile u_char *)
172 (SCSIBase + (u_long) ncr);
173 ncr_5380_with_drq = (volatile u_char *)
174 (SCSIBase + (u_int) ncr_5380_with_drq);
175 ncr_5380_without_drq = (volatile u_char *)
176 (SCSIBase + (u_int) ncr_5380_without_drq);
177
178 if (VIA2 == VIA2OFF)
179 scsi_enable = Via1Base + VIA2 * 0x2000 + vIER;
180 else
181 scsi_enable = Via1Base + VIA2 * 0x2000 + rIER;
182
183 mac68k_register_scsi_irq(ncr5380_irq_intr, sc);
184 mac68k_register_scsi_drq(ncr5380_drq_intr, sc);
185 }
186
187 static int
188 machine_match(pdp, match, auxp, cd)
189 struct device *pdp;
190 void *match, *auxp;
191 struct cfdriver *cd;
192 {
193 struct device *self = match; /* XXX mainbus is "indirect" */
194
195 if (matchbyname(pdp, match, auxp) == 0)
196 return 0;
197 if (!mac68k_machine.scsi80)
198 return 0;
199 if (self->dv_cfdata->cf_unit != 0)
200 return 0;
201 return 1;
202 }
203
204 #if USE_PDMA
205 int pdma_5380_dir = 0;
206
207 u_char *pending_5380_data;
208 u_long pending_5380_count;
209
210 #define NCR5380_PDMA_DEBUG 1 /* Maybe we try with this off eventually. */
211
212 #if NCR5380_PDMA_DEBUG
213 int pdma_5380_sends = 0;
214 int pdma_5380_bytes = 0;
215
216 void
217 pdma_stat()
218 {
219 printf("PDMA SCSI: %d xfers completed for %d bytes.\n",
220 pdma_5380_sends, pdma_5380_bytes);
221 printf("pdma_5380_dir = %d\t",
222 pdma_5380_dir);
223 printf("datap = 0x%x, remainder = %d.\n",
224 pending_5380_data, pending_5380_count);
225 scsi_show();
226 }
227 #endif
228
229 void
230 pdma_cleanup(void)
231 {
232 SC_REQ *reqp = connected;
233 int bytes, s;
234
235 s = splbio();
236 PID("pdma_cleanup0");
237
238 pdma_5380_dir = 0;
239
240 #if NCR5380_PDMA_DEBUG
241 pdma_5380_sends++;
242 pdma_5380_bytes+=(reqp->xdata_len - pending_5380_count);
243 #endif
244
245 /*
246 * Update pointers.
247 */
248 reqp->xdata_ptr += reqp->xdata_len - pending_5380_count;
249 reqp->xdata_len = pending_5380_count;
250
251 /*
252 * Reset DMA mode.
253 */
254 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
255
256 /*
257 * Clear any pending interrupts.
258 */
259 scsi_clr_ipend();
260
261 /*
262 * Tell interrupt functions that DMA has ended.
263 */
264 reqp->dr_flag &= ~DRIVER_IN_DMA;
265
266 SET_5380_REG(NCR5380_MODE, IMODE_BASE);
267 SET_5380_REG(NCR5380_ICOM, 0);
268
269 splx(s);
270
271 /*
272 * Back for more punishment.
273 */
274 PID("pdma_cleanup1");
275 run_main(cur_softc);
276 PID("pdma_cleanup2");
277 }
278 #endif
279
280 static __inline__ int
281 pdma_ready()
282 {
283 #if USE_PDMA
284 SC_REQ *reqp = connected;
285 int dmstat, idstat;
286 extern u_char ncr5380_no_parchk;
287
288 PID("pdma_ready0");
289 if (pdma_5380_dir) {
290 PID("pdma_ready1.")
291 /*
292 * If Mr. IRQ isn't set one might wonder how we got
293 * here. It does happen, though.
294 */
295 dmstat = GET_5380_REG(NCR5380_DMSTAT);
296 if (!(dmstat & SC_IRQ_SET)) {
297 PID("pdma_ready2");
298 return 0;
299 }
300 /*
301 * For a phase mis-match, ATN is a "don't care," IRQ is 1 and
302 * all other bits in the Bus & Status Register are 0. Also,
303 * the current SCSI Bus Status Register has a 1 for BSY and
304 * REQ. Since we're just checking that this interrupt isn't a
305 * reselection or a reset, we just check for either.
306 */
307 idstat = GET_5380_REG(NCR5380_IDSTAT);
308 if ( ((dmstat & (0xff & ~SC_ATN_STAT)) == SC_IRQ_SET)
309 && ((idstat & (SC_S_BSY|SC_S_REQ))
310 == (SC_S_BSY | SC_S_REQ)) ) {
311 PID("pdma_ready3");
312 pdma_cleanup();
313 return 1;
314 } else if (PH_IN(reqp->phase) && (dmstat & SC_PAR_ERR)) {
315 if (!(ncr5380_no_parchk & (1 << reqp->targ_id)))
316 /* XXX: Should be parity error ???? */
317 reqp->xs->error = XS_DRIVER_STUFFUP;
318 PID("pdma_ready4");
319 /* XXX: is this the right reaction? */
320 pdma_cleanup();
321 return 1;
322 } else if ( !(idstat & SC_S_REQ)
323 || (((idstat>>2) & 7) != reqp->phase)) {
324 #ifdef DIAGNOSTIC
325 /* XXX: is this the right reaction? Can this happen? */
326 scsi_show();
327 printf("Unexpected phase change.\n");
328 #endif
329 reqp->xs->error = XS_DRIVER_STUFFUP;
330 pdma_cleanup();
331 return 1;
332 } else {
333 scsi_show();
334 panic("Spurious interrupt during PDMA xfer.\n");
335 }
336 } else
337 PID("pdma_ready5");
338 #endif
339 return 0;
340 }
341
342 void
343 ncr5380_irq_intr(p)
344 void *p;
345 {
346 struct ncr_softc *sc = p;
347
348 PID("irq");
349 #if USE_PDMA
350 if (pdma_ready()) {
351 return;
352 }
353 #endif
354 if (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET) {
355 scsi_idisable();
356 ncr_ctrl_intr(cur_softc);
357 }
358 }
359
360 /*
361 * This is the meat of the PDMA transfer.
362 * When we get here, we shove data as fast as the mac can take it.
363 * We depend on several things:
364 * * All macs after the Mac Plus that have a 5380 chip should have a general
365 * logic IC that handshakes data for blind transfers.
366 * * If the SCSI controller finishes sending/receiving data before we do,
367 * the same general logic IC will generate a /BERR for us in short order.
368 * * The fault address for said /BERR minus the base address for the
369 * transfer will be the amount of data that was actually written.
370 *
371 * We use the nofault flag and the setjmp/longjmp in locore.s so we can
372 * detect and handle the bus error for early termination of a command.
373 * This is usually caused by a disconnecting target.
374 */
375 void
376 ncr5380_drq_intr(p)
377 void *p;
378 {
379 #if USE_PDMA
380 extern int *nofault, mac68k_buserr_addr;
381 struct ncr_softc *sc = p;
382 label_t faultbuf;
383 register int count;
384 volatile u_int32_t *long_drq;
385 u_int32_t *long_data;
386 volatile u_int8_t *drq;
387 u_int8_t *data;
388
389 /*
390 * If we're not ready to xfer data, just return.
391 */
392 if ( !(GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ)
393 || !pdma_5380_dir) {
394 PID("drq0");
395 return;
396 }
397
398 /*
399 * I don't think this should be necessary, but it is
400 * for writes--at least to some devices. They don't
401 * let go of PH_DATAOUT until we do pdma_cleanup().
402 */
403 if (pending_5380_count == 0) {
404 #if DBG_PID
405 if (pdma_5380_dir == 2) {
406 PID("drq1 (in)");
407 } else {
408 PID("drq1 (out)");
409 }
410 #endif
411 pdma_cleanup();
412 return;
413 }
414
415 #if DBG_PID
416 if (pdma_5380_dir == 2) {
417 PID("drq (in)");
418 } else {
419 PID("drq (out)");
420 }
421 #endif
422
423 /*
424 * Setup for a possible bus error caused by SCSI controller
425 * switching out of DATA-IN/OUT before we're done with the
426 * current transfer.
427 */
428 nofault = (int *) &faultbuf;
429
430 if (setjmp((label_t *) nofault)) {
431 PID("drq berr");
432 nofault = (int *) 0;
433 count = ( (u_long) mac68k_buserr_addr
434 - (u_long) ncr_5380_with_drq);
435 if ((count < 0) || (count > pending_5380_count)) {
436 printf("pdma %s: count = %d (0x%x) (pending "
437 "count %d)\n",
438 (pdma_5380_dir == 2) ? "in" : "out",
439 count, count, pending_5380_count);
440 panic("something is wrong");
441 }
442
443 pending_5380_data += count;
444 pending_5380_count -= count;
445
446 PID("end drq early");
447 mac68k_buserr_addr = 0;
448 return;
449 }
450
451 if (pdma_5380_dir == 2) { /* Data In */
452 int resid;
453
454 /*
455 * Get the dest address aligned.
456 */
457 resid = count = min(pending_5380_count,
458 4 - (((int) pending_5380_data) & 0x3));
459 if (count && (count < 4)) {
460 data = (u_int8_t *) pending_5380_data;
461 drq = (u_int8_t *) ncr_5380_with_drq;
462 while (count) {
463 #define R1 *data++ = *drq++
464 R1; count--;
465 #undef R1
466 }
467 pending_5380_data += resid;
468 pending_5380_count -= resid;
469 }
470
471 /*
472 * Get ready to start the transfer.
473 */
474 while (pending_5380_count) {
475 int dcount;
476
477 dcount = count = min(pending_5380_count, MIN_PHYS);
478 long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
479 long_data = (u_int32_t *) pending_5380_data;
480
481 #define R4 *long_data++ = *long_drq++
482 while ( count >= 512 ) {
483 if (!(GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ)) {
484 nofault = (int *) 0;
485
486 pending_5380_data += (dcount - count);
487 pending_5380_count -= (dcount - count);
488 return;
489 }
490 R4; R4; R4; R4; R4; R4; R4; R4;
491 R4; R4; R4; R4; R4; R4; R4; R4; /* 64 */
492 R4; R4; R4; R4; R4; R4; R4; R4;
493 R4; R4; R4; R4; R4; R4; R4; R4; /* 128 */
494 R4; R4; R4; R4; R4; R4; R4; R4;
495 R4; R4; R4; R4; R4; R4; R4; R4;
496 R4; R4; R4; R4; R4; R4; R4; R4;
497 R4; R4; R4; R4; R4; R4; R4; R4; /* 256 */
498 R4; R4; R4; R4; R4; R4; R4; R4;
499 R4; R4; R4; R4; R4; R4; R4; R4;
500 R4; R4; R4; R4; R4; R4; R4; R4;
501 R4; R4; R4; R4; R4; R4; R4; R4;
502 R4; R4; R4; R4; R4; R4; R4; R4;
503 R4; R4; R4; R4; R4; R4; R4; R4;
504 R4; R4; R4; R4; R4; R4; R4; R4;
505 R4; R4; R4; R4; R4; R4; R4; R4; /* 512 */
506 count -= 512;
507 }
508 while (count >= 4) {
509 R4; count -= 4;
510 }
511 #undef R4
512 data = (u_int8_t *) long_data;
513 drq = (u_int8_t *) long_drq;
514 while (count) {
515 #define R1 *data++ = *drq++
516 R1; count--;
517 #undef R1
518 }
519 pending_5380_count -= dcount;
520 pending_5380_data += dcount;
521 }
522 } else {
523 int resid;
524
525 /*
526 * Get the source address aligned.
527 */
528 resid = count = min(pending_5380_count,
529 4 - (((int) pending_5380_data) & 0x3));
530 if (count && (count < 4)) {
531 data = (u_int8_t *) pending_5380_data;
532 drq = (u_int8_t *) ncr_5380_with_drq;
533 while (count) {
534 #define W1 *drq++ = *data++
535 W1; count--;
536 #undef W1
537 }
538 pending_5380_data += resid;
539 pending_5380_count -= resid;
540 }
541
542 /*
543 * Get ready to start the transfer.
544 */
545 while (pending_5380_count) {
546 int dcount;
547
548 dcount = count = min(pending_5380_count, MIN_PHYS);
549 long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
550 long_data = (u_int32_t *) pending_5380_data;
551
552 #define W4 *long_drq++ = *long_data++
553 while ( count >= 64 ) {
554 W4; W4; W4; W4; W4; W4; W4; W4;
555 W4; W4; W4; W4; W4; W4; W4; W4; /* 64 */
556 count -= 64;
557 }
558 while (count >= 4) {
559 W4; count -= 4;
560 }
561 #undef W4
562 data = (u_int8_t *) long_data;
563 drq = (u_int8_t *) long_drq;
564 while (count) {
565 #define W1 *drq++ = *data++
566 W1; count--;
567 #undef W1
568 }
569 pending_5380_count -= dcount;
570 pending_5380_data += dcount;
571 }
572 }
573
574 /*
575 * OK. No bus error occurred above. Clear the nofault flag
576 * so we no longer short-circuit bus errors.
577 */
578 nofault = (int *) 0;
579
580 PID("end drq");
581 #endif /* if USE_PDMA */
582 }
583
584 #if USE_PDMA
585
586 #define SCSI_TIMEOUT_VAL 10000000
587
588 static int
589 transfer_pdma(phasep, data, count)
590 u_char *phasep;
591 u_char *data;
592 u_long *count;
593 {
594 SC_REQ *reqp = connected;
595 int len = *count, i, scsi_timeout = SCSI_TIMEOUT_VAL;
596 int s, err;
597
598 if (pdma_5380_dir) {
599 panic("ncrscsi: transfer_pdma called when operation already "
600 "pending.\n");
601 }
602 PID("transfer_pdma0")
603
604 /*
605 * Don't bother with PDMA if we can't sleep or for small transfers.
606 */
607 if (reqp->dr_flag & DRIVER_NOINT) {
608 PID("pdma, falling back to transfer_pio.")
609 transfer_pio(phasep, data, count, 0);
610 return -1;
611 }
612
613 /*
614 * We are probably already at spl2(), so this is likely a no-op.
615 * Paranoia.
616 */
617 s = splbio();
618
619 scsi_idisable();
620
621 /*
622 * Match phases with target.
623 */
624 SET_5380_REG(NCR5380_TCOM, *phasep);
625
626 /*
627 * Clear pending interrupts.
628 */
629 scsi_clr_ipend();
630
631 /*
632 * Wait until target asserts BSY.
633 */
634 while ( ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0)
635 && (--scsi_timeout) );
636 if (!scsi_timeout) {
637 #if DIAGNOSTIC
638 printf("scsi timeout: waiting for BSY in %s.\n",
639 (*phasep == PH_DATAOUT) ? "pdma_out" : "pdma_in");
640 #endif
641 goto scsi_timeout_error;
642 }
643
644 /*
645 * Tell the driver that we're in DMA mode.
646 */
647 reqp->dr_flag |= DRIVER_IN_DMA;
648
649 /*
650 * Load transfer values for DRQ interrupt handlers.
651 */
652 pending_5380_data = data;
653 pending_5380_count = len;
654
655 /*
656 * Set the transfer function to be called on DRQ interrupts.
657 * And note that we're waiting.
658 */
659 switch (*phasep) {
660 default:
661 panic("Unexpected phase in transfer_pdma.\n");
662 case PH_DATAOUT:
663 pdma_5380_dir = 1;
664 SET_5380_REG(NCR5380_ICOM, GET_5380_REG(NCR5380_ICOM)|SC_ADTB);
665 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
666 SET_5380_REG(NCR5380_DMSTAT, 0);
667 break;
668 case PH_DATAIN:
669 pdma_5380_dir = 2;
670 SET_5380_REG(NCR5380_ICOM, 0);
671 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
672 SET_5380_REG(NCR5380_IRCV, 0);
673 break;
674 }
675
676 PID("waiting for interrupt.")
677
678 /*
679 * Now that we're set up, enable interrupts and drop processor
680 * priority back down.
681 */
682 scsi_ienable();
683 splx(s);
684 return 0;
685
686 scsi_timeout_error:
687 /*
688 * Clear the DMA mode.
689 */
690 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
691 return -1;
692 }
693 #endif /* if USE_PDMA */
694
695 /* Include general routines. */
696 #include <mac68k/dev/ncr5380.c>
697