xref: /netbsd-src/sys/arch/sun3/dev/si.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: si.c,v 1.15 1995/03/26 19:23:12 gwr Exp $	*/
2 
3 /*
4  * Copyright (C) 1994 Adam Glass, Gordon W. Ross
5  * Copyright (C) 1993	Allen K. Briggs, Chris P. Caputo,
6  *			Michael L. Finch, Bradley A. Grantham, and
7  *			Lawrence A. Kesteloot
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the Alice Group.
21  * 4. The names of the Alice Group or any of its members may not be used
22  *    to endorse or promote products derived from this software without
23  *    specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR
26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28  * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 #define DEBUG 1
38 
39 /* XXX - Need to add support for real DMA. -gwr */
40 /* #define PSEUDO_DMA 1 (broken) */
41 
42 #include <sys/types.h>
43 #include <sys/malloc.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/buf.h>
48 #include <sys/proc.h>
49 #include <sys/user.h>
50 #include <sys/device.h>
51 
52 #include <machine/autoconf.h>
53 #include <machine/isr.h>
54 #include <machine/obio.h>
55 
56 #include <scsi/scsi_all.h>
57 #include <scsi/scsi_debug.h>
58 #include <scsi/scsiconf.h>
59 
60 #include "scsi_defs.h"
61 #include "scsi_5380.h"
62 #include "scsi_sunsi.h"
63 
64 #ifdef	DEBUG
65 static int si_debug = 0;
66 static int si_flags = 0 /* | SDEV_DB2 */ ;
67 #endif
68 
69 #define SCI_PHASE_DISC		0	/* sort of ... */
70 #define SCI_CLR_INTR(regs)	((volatile)(regs->sci_iack))
71 #define SCI_ACK(ptr,phase)	(ptr)->sci_tcmd = (phase)
72 #define SCSI_TIMEOUT_VAL	10000000
73 #define WAIT_FOR_NOT_REQ(ptr) {	\
74 	int scsi_timeout = SCSI_TIMEOUT_VAL; \
75 	while ( ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \
76 		 ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \
77 		 ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \
78 		 (--scsi_timeout) ); \
79 	if (!scsi_timeout) { \
80 		printf("scsi timeout--WAIT_FOR_NOT_REQ---%s, line %d.\n", \
81 			__FILE__, __LINE__); \
82 		goto scsi_timeout_error; \
83 	} \
84 	}
85 #define WAIT_FOR_REQ(ptr) {	\
86 	int scsi_timeout = SCSI_TIMEOUT_VAL; \
87 	while ( (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \
88 		(((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \
89 		(((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \
90 		 (--scsi_timeout) ); \
91 	if (!scsi_timeout) { \
92 		printf("scsi timeout--WAIT_FOR_REQ---%s, line %d.\n", \
93 			__FILE__, __LINE__); \
94 		goto scsi_timeout_error; \
95 	} \
96 	}
97 #define WAIT_FOR_BSY(ptr) {	\
98 	int scsi_timeout = SCSI_TIMEOUT_VAL; \
99 	while ( (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \
100 		(((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \
101 		(((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \
102 		 (--scsi_timeout) ); \
103 	if (!scsi_timeout) { \
104 		printf("scsi timeout--WAIT_FOR_BSY---%s, line %d.\n", \
105 			__FILE__, __LINE__); \
106 		goto scsi_timeout_error; \
107 	} \
108 	}
109 
110 #define ARBITRATION_RETRIES 1000
111 
112 #ifdef DDB
113 int Debugger();
114 #else
115 #define Debugger() panic("Should call Debugger here %s:%d", \
116 			 __FILE__, __LINE__)
117 #endif
118 
119 struct ncr5380_softc {
120     struct device sc_dev;
121     volatile void *sc_regs;
122     int sc_adapter_type;
123     struct scsi_link sc_link;
124 };
125 
126 static void		ncr5380_minphys(struct buf *bp);
127 static int		ncr5380_scsi_cmd(struct scsi_xfer *xs);
128 static int		ncr5380_reset_adapter(struct ncr5380_softc *);
129 static int		ncr5380_reset_scsibus(struct ncr5380_softc *);
130 static int		ncr5380_poll(int adapter, int timeout);
131 static int		ncr5380_send_cmd(struct scsi_xfer *xs);
132 
133 static int		ncr_intr(void *);
134 
135 static int	si_generic(int adapter, int id, int lun,
136 			 struct scsi_generic *cmd, int cmdlen,
137 			 void *databuf, int datalen);
138 static int	si_group0(int adapter, int id, int lun,
139 			    int opcode, int addr, int len,
140 			    int flags, caddr_t databuf, int datalen);
141 
142 static char scsi_name[] = "si";
143 
144 struct scsi_adapter	ncr5380_switch = {
145 	ncr5380_scsi_cmd,		/* scsi_cmd()		*/
146 	ncr5380_minphys,		/* scsi_minphys()	*/
147 	NULL,				/* open_target_lu()	*/
148 	NULL,				/* close_target_lu()	*/
149 };
150 
151 /* This is copied from julian's bt driver */
152 /* "so we have a default dev struct for our link struct." */
153 struct scsi_device ncr_dev = {
154 	NULL,		/* Use default error handler.	    */
155 	NULL,		/* Use default start handler.		*/
156 	NULL,		/* Use default async handler.	    */
157 	NULL,		/* Use default "done" routine.	    */
158 };
159 
160 static int	si_match();
161 static void	si_attach();
162 
163 struct cfdriver sicd = {
164 	NULL, "si", si_match, si_attach, DV_DULL,
165 	sizeof(struct ncr5380_softc), NULL, 0,
166 };
167 
168 static int
169 si_print(aux, name)
170 	void *aux;
171 	char *name;
172 {
173 }
174 
175 static int
176 si_match(parent, vcf, args)
177 	struct device	*parent;
178 	void		*vcf, *args;
179 {
180 	struct cfdata	*cf = vcf;
181 	struct confargs *ca = args;
182 	int x;
183 
184 	/* Allow default address for OBIO only. */
185 	switch (ca->ca_bustype) {
186 	case BUS_OBIO:
187 		if (ca->ca_paddr == -1)
188 			ca->ca_paddr = OBIO_NCR_SCSI;
189 		break;
190 	case BUS_VME16:
191 		if (ca->ca_paddr == -1)
192 			return (0);
193 		break;
194 	default:
195 		return (0);
196 	}
197 
198 	/* Default interrupt priority always splbio==2 */
199 	if (ca->ca_intpri == -1)
200 		ca->ca_intpri = 2;
201 
202 	x = bus_peek(ca->ca_bustype, ca->ca_paddr + 1, 1);
203     return (x != -1);
204 }
205 
206 static void
207 si_attach(parent, self, args)
208 	struct device	*parent, *self;
209 	void		*args;
210 {
211 	struct ncr5380_softc *ncr5380 = (struct ncr5380_softc *) self;
212 	volatile sci_regmap_t *regs;
213 	struct confargs *ca = args;
214 
215 	switch (ca->ca_bustype) {
216 
217 	case BUS_OBIO:
218 		regs = (sci_regmap_t *)
219 			obio_alloc(ca->ca_paddr, sizeof(*regs));
220 		isr_add_autovect(ncr_intr, (void *)ncr5380,
221 						 ca->ca_intpri);
222 		break;
223 
224 	case BUS_VME16:
225 		regs = (sci_regmap_t *)
226 			bus_mapin(ca->ca_bustype, ca->ca_paddr, sizeof(*regs));
227 		isr_add_vectored(ncr_intr, (void *)ncr5380,
228 						 ca->ca_intpri, ca->ca_intvec);
229 		break;
230 
231 	default:
232 		printf("unknown\n");
233 		return;
234 	}
235 
236 	ncr5380->sc_adapter_type = ca->ca_bustype;
237 	ncr5380->sc_regs = regs;
238 
239 	/*
240 	 * fill in the prototype scsi_link.
241 	 */
242     ncr5380->sc_link.adapter_softc = ncr5380;
243     ncr5380->sc_link.adapter_target = 7;
244     ncr5380->sc_link.adapter = &ncr5380_switch;
245     ncr5380->sc_link.device = &ncr_dev;
246     ncr5380->sc_link.openings = 2;
247 #ifdef	DEBUG
248     ncr5380->sc_link.flags |= si_flags;
249 #endif
250 
251     printf("\n");
252 	ncr5380_reset_adapter(ncr5380);
253 	ncr5380_reset_scsibus(ncr5380);
254 	config_found(self, &(ncr5380->sc_link), si_print);
255 }
256 
257 #define MIN_PHYS	65536	/*BARF!!!!*/
258 static void
259 ncr5380_minphys(struct buf *bp)
260 {
261 	if (bp->b_bcount > MIN_PHYS) {
262 		printf("Uh-oh...  ncr5380_minphys setting bp->b_bcount = %x.\n", MIN_PHYS);
263 		bp->b_bcount = MIN_PHYS;
264 	}
265 }
266 #undef MIN_PHYS
267 
268 static int
269 ncr5380_scsi_cmd(struct scsi_xfer *xs)
270 {
271 	int flags, s, r;
272 
273 	flags = xs->flags;
274 	if (xs->bp) flags |= (SCSI_NOSLEEP);
275 	if ( flags & ITSDONE ) {
276 		printf("Already done?");
277 		xs->flags &= ~ITSDONE;
278 	}
279 	if ( ! ( flags & INUSE ) ) {
280 		printf("Not in use?");
281 		xs->flags |= INUSE;
282 	}
283 
284 	s = splbio();
285 
286 	if ( flags & SCSI_RESET ) {
287 		printf("flags & SCSIRESET.\n");
288 		ncr5380_reset_scsibus(xs->sc_link->adapter_softc);
289 		r = COMPLETE;
290 	} else {
291 		r = ncr5380_send_cmd(xs);
292 		xs->flags |= ITSDONE;
293 		scsi_done(xs);
294 	}
295 
296 	splx(s);
297 
298 	switch(r) {
299 	case COMPLETE:
300 	case SUCCESSFULLY_QUEUED:
301 		r = SUCCESSFULLY_QUEUED;
302 		if (xs->flags & SCSI_POLL)
303 			r = COMPLETE;
304 		break;
305 	default:
306 		break;
307 	}
308 	return r;
309 }
310 
311 #ifdef	DEBUG
312 static int
313 ncr5380_show_scsi_cmd(struct scsi_xfer *xs)
314 {
315 	u_char	*b = (u_char *) xs->cmd;
316 	int	i  = 0;
317 
318 	if ( ! ( xs->flags & SCSI_RESET ) ) {
319 		printf("si(%d:%d:%d)-",
320 			   xs->sc_link->scsibus,
321 			   xs->sc_link->target,
322 			   xs->sc_link->lun);
323 		while (i < xs->cmdlen) {
324 			if (i) printf(",");
325 			printf("%x",b[i++]);
326 		}
327 		printf("-\n");
328 	} else {
329 		printf("si(%d:%d:%d)-RESET-\n",
330 			   xs->sc_link->scsibus,
331 			   xs->sc_link->target,
332 			   xs->sc_link->lun);
333 	}
334 }
335 #endif
336 
337 /*
338  * Actual chip control.
339  */
340 
341 static void
342 ncr_sbc_intr(struct ncr5380_softc *ncr5380)
343 {
344 	volatile sci_regmap_t *regs = ncr5380->sc_regs;
345 
346 	if ((regs->sci_csr & SCI_CSR_INT) == 0) {
347 #ifdef	DEBUG
348 		printf (" ncr_sbc_intr: spurrious\n");
349 #endif
350 		return;
351 	}
352 
353 	SCI_CLR_INTR(regs);
354 #ifdef	DEBUG
355 	printf (" ncr_sbc_intr\n");
356 #endif
357 }
358 
359 static void
360 ncr_dma_intr(struct ncr5380_softc *ncr5380)
361 {
362 	volatile struct si_regs *regs = ncr5380->sc_regs;
363 
364 #ifdef	DEBUG
365 	printf (" ncr_dma_intr\n");
366 #endif
367 }
368 
369 static int
370 ncr_intr(void *arg)
371 {
372 	struct ncr5380_softc *ncr5380 = arg;
373 	volatile struct si_regs *si = ncr5380->sc_regs;
374 	int rv = 0;
375 
376 	/* Interrupts not enabled?  Can not be for us. */
377 	if ((si->si_csr & SI_CSR_INTR_EN) == 0)
378 		return rv;
379 
380 	if (si->si_csr & SI_CSR_DMA_IP) {
381 		ncr_dma_intr(ncr5380);
382 		rv++;
383 	}
384 	if (si->si_csr & SI_CSR_SBC_IP) {
385 		ncr_sbc_intr(ncr5380);
386 		rv++;
387 	}
388 	return rv;
389 }
390 
391 static int
392 ncr5380_reset_adapter(struct ncr5380_softc *ncr5380)
393 {
394 	volatile struct si_regs *si = ncr5380->sc_regs;
395 
396 #ifdef	DEBUG
397 	if (si_debug) {
398 		printf("si_reset_adapter\n");
399 	}
400 #endif
401 
402 	/* The reset bits are active low. */
403 	si->si_csr = 0;
404 	delay(100);
405 	si->si_csr = SI_CSR_FIFO_RES | SI_CSR_SCSI_RES;
406 }
407 
408 static int
409 ncr5380_reset_scsibus(struct ncr5380_softc *ncr5380)
410 {
411 	volatile sci_regmap_t *regs = ncr5380->sc_regs;
412 
413 #ifdef	DEBUG
414 	if (si_debug) {
415 		printf("si_reset_scsibus\n");
416 	}
417 #endif
418 
419 	regs->sci_icmd = SCI_ICMD_TEST;
420 	regs->sci_icmd = SCI_ICMD_TEST | SCI_ICMD_RST;
421 	delay(2500);
422 	regs->sci_icmd = 0;
423 
424 	regs->sci_mode = 0;
425 	regs->sci_tcmd = SCI_PHASE_DISC;
426 	regs->sci_sel_enb = 0;
427 
428 	SCI_CLR_INTR(regs);
429 	SCI_CLR_INTR(regs);
430 }
431 
432 static int
433 ncr5380_poll(int adapter, int timeout)
434 {
435 }
436 
437 static int
438 ncr5380_send_cmd(struct scsi_xfer *xs)
439 {
440 	int	sense;
441 
442 #ifdef	DIAGNOSTIC
443 	if ((getsr() & PSL_IPL) < PSL_IPL2)
444 		panic("ncr_send_cmd: bad spl");
445 #endif
446 
447 #ifdef	DEBUG
448 	if (si_debug & 2)
449 		ncr5380_show_scsi_cmd(xs);
450 #endif
451 
452 	sense = si_generic( xs->sc_link->scsibus, xs->sc_link->target,
453 			  xs->sc_link->lun, xs->cmd, xs->cmdlen,
454 			  xs->data, xs->datalen );
455 
456 	switch (sense) {
457 	case 0:	/* success */
458 		xs->resid = 0;
459 		xs->error = XS_NOERROR;
460 		break;
461 
462 	case 0x02:	/* Check condition */
463 #ifdef	DEBUG
464 		if (si_debug)
465 			printf("check cond. target %d.\n",
466 				   xs->sc_link->target);
467 #endif
468 		delay(10);	/* Phil's fix for slow devices. */
469 		si_group0(xs->sc_link->scsibus,
470 				  xs->sc_link->target,
471 				  xs->sc_link->lun,
472 				  0x3, 0x0,
473 				  sizeof(struct scsi_sense_data),
474 				  0, (caddr_t) &(xs->sense),
475 				  sizeof(struct scsi_sense_data));
476 		xs->error = XS_SENSE;
477 		break;
478 	case 0x08:	/* Busy */
479 		xs->error = XS_BUSY;
480 		break;
481 	default:
482 		xs->error = XS_DRIVER_STUFFUP;
483 		break;
484 
485 	}
486 	return (COMPLETE);
487 }
488 
489 static int
490 si_select_target(register volatile sci_regmap_t *regs,
491 	      u_char myid, u_char tid, int with_atn)
492 {
493 	register u_char	bid, icmd;
494 	int		ret = SCSI_RET_RETRY;
495 	int 	arb_retries, arb_wait;
496 
497 	/* for our purposes.. */
498 	myid = 1 << myid;
499 	tid = 1 << tid;
500 
501 	regs->sci_sel_enb = 0; /* we don't want any interrupts. */
502 	regs->sci_tcmd = 0;	/* get into a harmless state */
503 
504 	arb_retries = ARBITRATION_RETRIES;
505 
506 retry_arbitration:
507 	regs->sci_mode = 0;	/* get into a harmless state */
508 	if (--arb_retries <= 0) {
509 #ifdef	DEBUG
510 		if (si_debug) {
511 			printf("si_select: arb_retries expended\n");
512 		}
513 #endif
514 		goto lost;
515 	}
516 
517 	if ((regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) &&
518 	    (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) &&
519 	    (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)))
520 	{
521 #ifdef	DEBUG
522 		if (si_debug) {
523 			printf("si_select_target: still BSY|SEL\n");
524 		}
525 #endif
526 		return ret;
527 	}
528 
529 	regs->sci_odata = myid;
530 	regs->sci_mode = SCI_MODE_ARB;
531 /*	regs->sci_mode |= SCI_MODE_ARB;	XXX? */
532 
533 	/* AIP might not set if BSY went true after we checked */
534 	/* Wait up to about 100 usec. for it to appear. */
535 	arb_wait = 50;	/* X2 */
536 	do {
537 		if (regs->sci_icmd & SCI_ICMD_AIP)
538 			break;
539 		delay2us();
540 	} while (--arb_wait > 0);
541 	if (arb_wait <= 0) {
542 		/* XXX - Could have missed it? */
543 		goto retry_arbitration;
544 	}
545 #ifdef	DEBUG
546 	if (si_debug) {
547 		printf("si_select_target: API after %d tries (last wait %d)\n",
548 			   ARBITRATION_RETRIES - arb_retries,
549 			   (50 - arb_wait));
550 	}
551 #endif
552 
553 	delay(3);	/* 2.2 uSec. arbitration delay */
554 
555 	if (regs->sci_icmd & SCI_ICMD_LST) {
556 #ifdef	DEBUG
557 		if (si_debug)
558 			printf ("lost 1\n");
559 #endif
560 		goto retry_arbitration;	/* XXX */
561 	}
562 
563 	regs->sci_mode &= ~SCI_MODE_PAR_CHK;
564 	bid = regs->sci_data;
565 
566 	if ((bid & ~myid) > myid) {
567 #ifdef	DEBUG
568 		if (si_debug)
569 			printf ("lost 2\n");
570 #endif
571 		/* Trying again will not help. */
572 		goto lost;
573 	}
574 	if (regs->sci_icmd & SCI_ICMD_LST) {
575 #ifdef	DEBUG
576 		if (si_debug)
577 			printf ("lost 3\n");
578 #endif
579 		goto lost;
580 	}
581 
582 	/* Won arbitration, enter selection phase now */
583 	icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
584 	icmd |= (with_atn ? (SCI_ICMD_SEL|SCI_ICMD_ATN) : SCI_ICMD_SEL);
585 	regs->sci_icmd = icmd;
586 
587 	if (regs->sci_icmd & SCI_ICMD_LST) {
588 #ifdef	DEBUG
589 		if (si_debug)
590 			printf ("nosel\n");
591 #endif
592 		goto nosel;
593 	}
594 
595 	/* XXX a target that violates specs might still drive the bus XXX */
596 	/* XXX should put our id out, and after the delay check nothi XXX */
597 	/* XXX ng else is out there.				      XXX */
598 
599 	delay2us();
600 
601 	regs->sci_sel_enb = 0;
602 
603 	regs->sci_odata = myid | tid;
604 
605 	icmd |= SCI_ICMD_BSY|SCI_ICMD_DATA;
606 	regs->sci_icmd = icmd;
607 
608 /*	regs->sci_mode &= ~SCI_MODE_ARB;	 2 deskew delays, too */
609 	regs->sci_mode = 0;			/* 2 deskew delays, too */
610 
611 	icmd &= ~SCI_ICMD_BSY;
612 	regs->sci_icmd = icmd;
613 
614 	/* bus settle delay, 400ns */
615 	delay2us(); /* too much (was 2) ? */
616 
617 	regs->sci_mode |= SCI_MODE_PAR_CHK;
618 
619 	{
620 		register int timeo  = 2500;/* 250 msecs in 100 usecs chunks */
621 		while ((regs->sci_bus_csr & SCI_BUS_BSY) == 0) {
622 			if (--timeo > 0) {
623 				delay(100);
624 			} else {
625 				/* This is the "normal" no-such-device select error. */
626 #ifdef	DEBUG
627 				if (si_debug)
628 					printf("si_select: did not see BSY\n");
629 #endif
630 				goto nodev;
631 			}
632 		}
633 	}
634 
635 	icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_SEL);
636 	regs->sci_icmd = icmd;
637 /*	regs->sci_sel_enb = myid;*/	/* looks like we should NOT have it */
638 	/* XXX - SCI_MODE_PAR_CHK ? */
639 	return SCSI_RET_SUCCESS;
640 
641 nodev:
642 	ret = SCSI_RET_DEVICE_DOWN;
643 	regs->sci_sel_enb = myid;
644 nosel:
645 	icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_SEL|SCI_ICMD_ATN);
646 	regs->sci_icmd = icmd;
647 	regs->sci_mode = 0;
648 	return ret;
649 
650 lost:
651 	regs->sci_icmd = 0;
652 	regs->sci_mode = 0;
653 #ifdef	DEBUG
654 	if (si_debug) {
655 		printf("si_select: lost arbitration\n");
656 	}
657 #endif
658 	return ret;
659 }
660 
661 sci_data_out(regs, phase, count, data)
662 	register volatile sci_regmap_t	*regs;
663 	unsigned char		*data;
664 {
665 	register unsigned char	icmd;
666 	register int		cnt=0;
667 
668 	/* ..checks.. */
669 
670 	icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
671 loop:
672 	if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase)
673 		return cnt;
674 
675 	WAIT_FOR_REQ(regs);
676 	icmd |= SCI_ICMD_DATA;
677 	regs->sci_icmd = icmd;
678 	regs->sci_odata = *data++;
679 	icmd |= SCI_ICMD_ACK;
680 	regs->sci_icmd = icmd;
681 
682 	icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_ACK);
683 	WAIT_FOR_NOT_REQ(regs);
684 	regs->sci_icmd = icmd;
685 	++cnt;
686 	if (--count > 0)
687 		goto loop;
688 scsi_timeout_error:
689 	return cnt;
690 }
691 
692 sci_data_in(regs, phase, count, data)
693 	register volatile sci_regmap_t	*regs;
694 	unsigned char		*data;
695 {
696 	register unsigned char	icmd;
697 	register int		cnt=0;
698 
699 	/* ..checks.. */
700 
701 	icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST);
702 
703 loop:
704 	if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase)
705 		return cnt;
706 
707 	WAIT_FOR_REQ(regs);
708 	*data++ = regs->sci_data;
709 	icmd |= SCI_ICMD_ACK;
710 	regs->sci_icmd = icmd;
711 
712 	icmd &= ~SCI_ICMD_ACK;
713 	WAIT_FOR_NOT_REQ(regs);
714 	regs->sci_icmd = icmd;
715 	++cnt;
716 	if (--count > 0)
717 		goto loop;
718 
719 scsi_timeout_error:
720 	return cnt;
721 }
722 
723 static int
724 si_command_transfer(register volatile sci_regmap_t *regs,
725 		 int maxlen, u_char *data, u_char *status, u_char *msg)
726 {
727 	int	xfer=0, phase;
728 
729 /*	printf("command_transfer called for 0x%x.\n", *data); */
730 
731 	regs->sci_icmd = 0;
732 
733 	while (1) {
734 
735 		WAIT_FOR_REQ(regs);
736 
737 		phase = SCI_CUR_PHASE(regs->sci_bus_csr);
738 
739 		switch (phase) {
740 			case SCSI_PHASE_CMD:
741 				SCI_ACK(regs,SCSI_PHASE_CMD);
742 				xfer += sci_data_out(regs, SCSI_PHASE_CMD,
743 						   	maxlen, data);
744 				return xfer;
745 			case SCSI_PHASE_DATA_IN:
746 				printf("Data in phase in command_transfer?\n");
747 				return 0;
748 			case SCSI_PHASE_DATA_OUT:
749 				printf("Data out phase in command_transfer?\n");
750 				return 0;
751 			case SCSI_PHASE_STATUS:
752 				SCI_ACK(regs,SCSI_PHASE_STATUS);
753 				printf("status in command_transfer.\n");
754 				sci_data_in(regs, SCSI_PHASE_STATUS,
755 					  	1, status);
756 				break;
757 			case SCSI_PHASE_MESSAGE_IN:
758 				SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN);
759 				printf("msgin in command_transfer.\n");
760 				sci_data_in(regs, SCSI_PHASE_MESSAGE_IN,
761 					  	1, msg);
762 				break;
763 			case SCSI_PHASE_MESSAGE_OUT:
764 				SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT);
765 				sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT,
766 					  	1, msg);
767 				break;
768 			default:
769 				printf("Unexpected phase 0x%x in "
770 					"command_transfer().\n", phase);
771 scsi_timeout_error:
772 				return xfer;
773 				break;
774 		}
775 	}
776 }
777 
778 static int
779 si_data_transfer(register volatile sci_regmap_t *regs,
780 	      int maxlen, u_char *data, u_char *status, u_char *msg)
781 {
782 	int	retlen = 0, xfer, phase;
783 
784 	regs->sci_icmd = 0;
785 
786 	*status = 0;
787 
788 	while (1) {
789 
790 		WAIT_FOR_REQ(regs);
791 
792 		phase = SCI_CUR_PHASE(regs->sci_bus_csr);
793 
794 		switch (phase) {
795 			case SCSI_PHASE_CMD:
796 				printf("Command phase in data_transfer().\n");
797 				return retlen;
798 			case SCSI_PHASE_DATA_IN:
799 				SCI_ACK(regs,SCSI_PHASE_DATA_IN);
800 #if PSEUDO_DMA
801 				xfer = sci_pdma_in(regs, SCSI_PHASE_DATA_IN,
802 						  	maxlen, data);
803 #else
804 				xfer = sci_data_in(regs, SCSI_PHASE_DATA_IN,
805 						  	maxlen, data);
806 #endif
807 				retlen += xfer;
808 				maxlen -= xfer;
809 				break;
810 			case SCSI_PHASE_DATA_OUT:
811 				SCI_ACK(regs,SCSI_PHASE_DATA_OUT);
812 #if PSEUDO_DMA
813 				xfer = sci_pdma_out(regs, SCSI_PHASE_DATA_OUT,
814 						   	maxlen, data);
815 #else
816 				xfer = sci_data_out(regs, SCSI_PHASE_DATA_OUT,
817 						   	maxlen, data);
818 #endif
819 				retlen += xfer;
820 				maxlen -= xfer;
821 				break;
822 			case SCSI_PHASE_STATUS:
823 				SCI_ACK(regs,SCSI_PHASE_STATUS);
824 				sci_data_in(regs, SCSI_PHASE_STATUS,
825 					  	1, status);
826 				break;
827 			case SCSI_PHASE_MESSAGE_IN:
828 				SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN);
829 				sci_data_in(regs, SCSI_PHASE_MESSAGE_IN,
830 					  	1, msg);
831 				if (*msg == 0) {
832 					return retlen;
833 				} else {
834 					printf( "message 0x%x in "
835 						"data_transfer.\n", *msg);
836 				}
837 				break;
838 			case SCSI_PHASE_MESSAGE_OUT:
839 				SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT);
840 				sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT,
841 					  	1, msg);
842 				break;
843 			default:
844 				printf( "Unexpected phase 0x%x in "
845 					"data_transfer().\n", phase);
846 scsi_timeout_error:
847 				return retlen;
848 				break;
849 		}
850 	}
851 }
852 
853 static int
854 si_dorequest(register volatile sci_regmap_t *regs,
855 		int target, int lun, u_char *cmd, int cmdlen,
856 		char *databuf, int datalen, int *sent, int *ret)
857 {
858 /* Returns 0 on success, -1 on internal error, or the status byte */
859 	int	cmd_bytes_sent, r;
860 	u_char	stat, msg, c;
861 
862 	*sent = 0;
863 
864 	if ( ( r = si_select_target(regs, 7, target, 1) ) != SCSI_RET_SUCCESS) {
865 #ifdef	DEBUG
866 		if (si_debug) {
867 			printf("si_dorequest: select returned %d\n", r);
868 		}
869 #endif
870 		*ret = r;
871 		SCI_CLR_INTR(regs);
872 		switch (r) {
873 		case SCSI_RET_RETRY:
874 			return 0x08;
875 		default:
876 			printf("si_select_target(target %d, lun %d) failed(%d).\n",
877 				target, lun, r);
878 		case SCSI_RET_DEVICE_DOWN:
879 			return -1;
880 		}
881 	}
882 
883 	c = 0x80 | lun;
884 
885 	if ((cmd_bytes_sent = si_command_transfer(regs, cmdlen,
886 				(u_char *) cmd, &stat, &c)) != cmdlen)
887 	{
888 		SCI_CLR_INTR(regs);
889 		*ret = SCSI_RET_COMMAND_FAIL;
890 		printf("Data underrun sending CCB (%d bytes of %d, sent).\n",
891 			cmd_bytes_sent, cmdlen);
892 		return -1;
893 	}
894 
895 	*sent=si_data_transfer(regs, datalen, (u_char *)databuf,
896 				  &stat, &msg);
897 #ifdef	DEBUG
898 	if (si_debug) {
899 		printf("si_dorequest: data transfered = %d\n", *sent);
900 	}
901 #endif
902 
903 	*ret = 0;
904 	return stat;
905 }
906 
907 static int
908 si_generic(int adapter, int id, int lun, struct scsi_generic *cmd,
909   	 int cmdlen, void *databuf, int datalen)
910 {
911 	register struct ncr5380_softc *ncr5380 = sicd.cd_devs[adapter];
912 	register volatile sci_regmap_t *regs = ncr5380->sc_regs;
913 	int i,j,sent,ret;
914 
915 	if (cmd->opcode == TEST_UNIT_READY)	/* XXX */
916 		cmd->bytes[0] = ((u_char) lun << 5);
917 
918 	i = si_dorequest(regs, id, lun, (u_char *) cmd, cmdlen,
919 					 databuf, datalen, &sent, &ret);
920 
921 	return i;
922 }
923 
924 static int
925 si_group0(int adapter, int id, int lun, int opcode, int addr, int len,
926 		int flags, caddr_t databuf, int datalen)
927 {
928 	register struct ncr5380_softc *ncr5380 = sicd.cd_devs[adapter];
929 	register volatile sci_regmap_t *regs = ncr5380->sc_regs;
930 	unsigned char cmd[6];
931 	int i,j,sent,ret;
932 
933 	cmd[0] = opcode;		/* Operation code           		*/
934 	cmd[1] = (lun << 5) | ((addr >> 16) & 0x1F);	/* Lun & MSB of addr	*/
935 	cmd[2] = (addr >> 8) & 0xFF;	/* addr					*/
936 	cmd[3] = addr & 0xFF;		/* LSB of addr				*/
937 	cmd[4] = len;			/* Allocation length			*/
938 	cmd[5] = flags;		/* Link/Flag				*/
939 
940 	i = si_dorequest(regs, id, lun, cmd, 6, databuf, datalen, &sent, &ret);
941 
942 	return i;
943 }
944