xref: /original-bsd/sys/luna68k/stand/sc.c (revision 3705696b)
1 /*
2  * Copyright (c) 1992 OMRON Corporation.
3  * Copyright (c) 1992, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * OMRON Corporation.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)sc.c	8.1 (Berkeley) 06/10/93
12  */
13 
14 /*
15  * sc.c -- SCSI Protocole Controller (SPC)  driver
16  * remaked by A.Fujita, MAR-11-199
17  */
18 
19 
20 #define NSC	1
21 
22 #include <sys/param.h>
23 #include <luna68k/dev/scsireg.h>
24 #include <luna68k/stand/device.h>
25 #include <luna68k/stand/scsivar.h>
26 
27 #define SCSI_IPL	2
28 #define SCSI_ID		7
29 
30 int	scinit(), scstart(), scgo(), scintr(), scdone();
31 void	screset();
32 struct	driver scdriver = {
33 	scinit, "sc", scstart, scgo, scintr, scdone
34 };
35 
36 struct	scsi_softc scsi_softc[NSC];
37 
38 /*
39  * Initialize SPC & Data Structure
40  */
41 
42 int
43 scinit(hc)
44 	register struct hp_ctlr *hc;
45 {
46 	register struct scsi_softc *hs = &scsi_softc[hc->hp_unit];
47 	register int i;
48 
49 	hc->hp_ipl    = SCSI_IPL;
50 	hs->sc_hc     = hc;
51 
52 	hs->sc_flags  = 0;
53 	hs->sc_phase  = BUS_FREE_PHASE;
54 	hs->sc_target = SCSI_ID;
55 
56 	hs->sc_cdb    = NULL;
57 	hs->sc_cdblen = 0;
58 	hs->sc_buf    = NULL;
59 	hs->sc_len    = 0;
60 	hs->sc_lock   = NULL;
61 
62 	hs->sc_stat   = 0;
63 	hs->sc_msg[0] = 0;
64 
65 	screset(hc->hp_unit);
66 	return(1);
67 }
68 
69 void
70 screset(unit)
71 	register int unit;
72 {
73 	register struct scsi_softc *hs = &scsi_softc[unit];
74 	volatile register struct scsidevice *hd =
75 				(struct scsidevice *)hs->sc_hc->hp_addr;
76 
77 	printf("sc%d: ", unit);
78 
79 	/*
80 	 * Disable interrupts then reset the FUJI chip.
81 	 */
82 
83 	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
84 	hd->scsi_scmd = 0;
85 	hd->scsi_pctl = 0;
86 	hd->scsi_temp = 0;
87 	hd->scsi_tch  = 0;
88 	hd->scsi_tcm  = 0;
89 	hd->scsi_tcl  = 0;
90 	hd->scsi_ints = 0;
91 
92 	/* We can use Asynchronous Transfer only */
93 	printf("async");
94 
95 	/*
96 	 * Configure MB89352 with its SCSI address, all
97 	 * interrupts enabled & appropriate parity.
98 	 */
99 	hd->scsi_bdid = SCSI_ID;
100 	hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB|
101 			SCTL_PARITY_ENAB | SCTL_RESEL_ENAB |
102 			SCTL_INTR_ENAB;
103 	printf(", parity");
104 
105 	DELAY(400);
106 	hd->scsi_sctl &= ~SCTL_DISABLE;
107 
108 	printf(", scsi id %d\n", SCSI_ID);
109 }
110 
111 
112 /*
113  * SPC Arbitration/Selection routine
114  */
115 
116 int
117 issue_select(hd, target)
118 	volatile register struct scsidevice *hd;
119 	u_char target;
120 {
121 	hd->scsi_pctl = 0;
122 	hd->scsi_temp = (1 << SCSI_ID) | (1 << target);
123 
124 	/* select timeout is hardcoded to 2ms */
125 	hd->scsi_tch = 0;
126 	hd->scsi_tcm = 32;
127 	hd->scsi_tcl = 4;
128 
129 	hd->scsi_scmd = SCMD_SELECT;
130 
131 	return (1);
132 }
133 
134 
135 /*
136  * SPC Manual Transfer routines
137  */
138 
139 /* not yet */
140 
141 
142 /*
143  * SPC Program Transfer routines
144  */
145 
146 int
147 ixfer_start(hd, len, phase, wait)
148 	volatile register struct scsidevice *hd;
149 	int len;
150 	u_char phase;
151 	register int wait;
152 {
153 	hd->scsi_tch  = ((len & 0xff0000) >> 16);
154 	hd->scsi_tcm  = ((len & 0x00ff00) >>  8);
155 	hd->scsi_tcl  =  (len & 0x0000ff);
156 	hd->scsi_pctl = phase;
157 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
158 }
159 
160 int
161 ixfer_out(hd, len, buf)
162 	volatile register struct scsidevice *hd;
163 	int len;
164 	register u_char *buf;
165 {
166 	for(; len > 0; len--) {
167 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
168 			DELAY(5);
169 		}
170 		hd->scsi_dreg = *buf++;
171 	}
172 }
173 
174 int
175 ixfer_in(hd, len, buf)
176 	volatile register struct scsidevice *hd;
177 	int len;
178 	register u_char *buf;
179 {
180 	for (; len > 0; len--) {
181 		int i;
182 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
183 			DELAY(5);
184 		}
185 		*buf++ = hd->scsi_dreg;
186 	}
187 }
188 
189 
190 /*
191  * SPC drive routines
192  */
193 
194 int
195 scrun(ctlr, slave, cdb, cdblen, buf, len, lock)
196 	int ctlr, slave;
197 	u_char *cdb;
198 	int cdblen;
199 	u_char *buf;
200 	int len;
201 	int *lock;
202 {
203 	register struct scsi_softc *hs = &scsi_softc[ctlr];
204 	volatile register struct scsidevice *hd =
205 		(struct scsidevice *) hs->sc_hc->hp_addr;
206 
207 	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
208 		return(0);
209 
210 	hs->sc_flags  = 0;
211 	hs->sc_phase  = ARB_SEL_PHASE;
212 	hs->sc_target = slave;
213 
214 	hs->sc_cdb    = cdb;
215 	hs->sc_cdblen = cdblen;
216 	hs->sc_buf    = buf;
217 	hs->sc_len    = len;
218 	hs->sc_lock   = lock;
219 
220 	hs->sc_stat   = 0;
221 	hs->sc_msg[0] = 0;
222 
223 	*(hs->sc_lock) = SC_IN_PROGRESS;
224 	issue_select(hd, hs->sc_target);
225 
226 	return(1);
227 }
228 
229 int
230 scfinish(ctlr)
231 	int ctlr;
232 {
233 	register struct scsi_softc *hs = &scsi_softc[ctlr];
234 	int status = hs->sc_stat;
235 
236 	hs->sc_flags  = 0;
237 	hs->sc_phase  = BUS_FREE_PHASE;
238 	hs->sc_target = SCSI_ID;
239 
240 	hs->sc_cdb    = NULL;
241 	hs->sc_cdblen = 0;
242 	hs->sc_buf    = NULL;
243 	hs->sc_len    = 0;
244 	hs->sc_lock   = NULL;
245 
246 	hs->sc_stat   = 0;
247 	hs->sc_msg[0] = 0;
248 
249 	return(status);
250 }
251 
252 int
253 scabort(hs, hd)
254 	register struct scsi_softc *hs;
255 	volatile register struct scsidevice *hd;
256 {
257 	int len;
258 	u_char junk;
259 
260 	printf("sc%d: abort  phase=0x%x, ssts=0x%x, ints=0x%x\n",
261 		hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts,
262 		hd->scsi_ints);
263 
264 	if (hd->scsi_ints != 0)
265 		hd->scsi_ints = hd->scsi_ints;
266 
267 	if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
268 		/* no longer connected to scsi target */
269 		return;
270 
271 	/* get the number of bytes remaining in current xfer + fudge */
272 	len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
273 
274 	/* for that many bus cycles, try to send an abort msg */
275 	for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
276 		hd->scsi_scmd = SCMD_SET_ATN;
277 
278 		while ((hd->scsi_psns & PSNS_REQ) == 0) {
279 			if (! (hd->scsi_ssts & SSTS_INITIATOR))
280 				goto out;
281 			DELAY(1);
282 		}
283 
284 		if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
285 			hd->scsi_scmd = SCMD_RST_ATN;
286 		hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE;
287 
288 		if (hd->scsi_psns & PHASE_IO) {
289 			/* one of the input phases - read & discard a byte */
290 			hd->scsi_scmd = SCMD_SET_ACK;
291 			while (hd->scsi_psns & PSNS_REQ)
292 				DELAY(1);
293 			junk = hd->scsi_temp;
294 		} else {
295 			/* one of the output phases - send an abort msg */
296 			hd->scsi_temp = MSG_ABORT;
297 			hd->scsi_scmd = SCMD_SET_ACK;
298 			while (hd->scsi_psns & PSNS_REQ)
299 				DELAY(1);
300 		}
301 
302 		hd->scsi_scmd = SCMD_RST_ACK;
303 	}
304 out:
305 	/*
306 	 * Either the abort was successful & the bus is disconnected or
307 	 * the device didn't listen.  If the latter, announce the problem.
308 	 * Either way, reset the card & the SPC.
309 	 */
310 	if (len < 0 && hs)
311 		printf("sc%d: abort failed.  phase=0x%x, ssts=0x%x\n",
312 			hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts);
313 }
314 
315 
316 /*
317  * SCSI Command Handler
318  */
319 
320 int
321 scsi_test_unit_rdy(ctlr, slave, unit)
322 	int ctlr, slave, unit;
323 {
324 	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
325 	int status, lock;
326 
327 #ifdef DEBUG
328 	printf("scsi_test_unit_rdy( %d, %d, %d): Start\n", ctlr, slave, unit);
329 #endif
330 
331 	cdb.lun = unit;
332 
333 	if (!(scrun(ctlr, slave, &cdb, 6, (u_char *) 0, 0, &lock))) {
334 #ifdef DEBUG
335 		printf("scsi_test_unit_rdy: Command Transfer Failed.\n");
336 #endif
337 		return(-1);
338 	}
339 
340 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
341 		DELAY(10);
342 
343 	status = scfinish(ctlr);
344 
345 	if (lock == SC_IO_COMPLETE) {
346 #ifdef DEBUG
347 		printf("scsi_test_unit_rdy: Status -- 0x%x\n", status);
348 #endif
349 		return(status);
350 	} else {
351 		return(lock);
352 	}
353 }
354 
355 int
356 scsi_request_sense(ctlr, slave, unit, buf, len)
357 	int ctlr, slave, unit;
358 	u_char *buf;
359 	unsigned len;
360 {
361 	static struct scsi_cdb6 cdb = {	CMD_REQUEST_SENSE };
362 	int status, lock;
363 
364 #ifdef DEBUG
365 	printf("scsi_request_sense: Start\n");
366 #endif
367 
368 	/* Request Sense$N>l9g!"E>Aw$5$l$k%G!<%?D9$O%?!<%2368H$K0MB8$7!"        */
369 	/* %;%s%9%G!<%?$N#8/usr/home/csrg/sccs/sys/luna68k/stand/SCCS/s.sc.c$%HL\$NAddtional Sens Length$K$h$jF0E*$K7hDj$9$k!#*/
370 	/* $3$3$G$O%G!<%?!<E>Aw?t$rcdb$NAllocation Length$K:GDcD9$G$"$k#8/usr/home/csrg/sccs/sys/luna68k/stand/SCCS/s.sc.c$%H */
371 	/* $r8GDj$7$F!"#S#P#C$N=hM}%7!<%1%s%9$rJx$5$J$$$h$&$K$7$F$$$k!#         */
372 
373 	/* %F!<@(#)sc.c	8.1f%K373H$N>uBV$rD4$Y$k$?$a!"Addtional Sens Field$r%"%/%;%9$9$k */
374 	/* I,MW$,$"$k$N$G06/10/93P%$%98.1i%$%PB&$Glen$r7hDj$9$k$3$H$K$9$k            */
375 
376 	cdb.lun = unit;
377 	cdb.len = len;
378 
379 	if (!(scrun(ctlr, slave, &cdb, 6, buf, len, &lock))) {
380 #ifdef DEBUG
381 		printf("scsi_request_sense: Command Transfer Failed.\n");
382 #endif
383 		return(-1);
384 	}
385 
386 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
387 		DELAY(10);
388 
389 	status = scfinish(ctlr);
390 
391 	if (lock == SC_IO_COMPLETE) {
392 #ifdef DEBUG
393 		printf("scsi_request_sense: Status -- 0x%x\n", status);
394 #endif
395 		return(status);
396 	} else {
397 		return(lock);
398 	}
399 }
400 
401 int
402 scsi_immed_command(ctlr, slave, unit, cdb, buf, len)
403 	int ctlr, slave, unit;
404 	struct scsi_fmt_cdb *cdb;
405 	u_char *buf;
406 	unsigned len;
407 {
408 	int lock, status;
409 
410 #ifdef DEBUG
411 	printf("scsi_immed_command( %d, %d, %d, cdb(%d), buf, %d): Start\n",
412 	       ctlr, slave, unit, cdb->len, len);
413 #endif
414 
415 	cdb->cdb[1] |= unit << 5;
416 
417 	if (!(scrun(ctlr, slave, &cdb->cdb[0], cdb->len, buf, len, &lock))) {
418 #ifdef DEBUG
419 		printf("scsi_immed_command: Command Transfer Failed.\n");
420 #endif
421 		return(-1);
422 	}
423 
424 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
425 		DELAY(10);
426 
427 	status = scfinish(ctlr);
428 
429 	if (lock == SC_IO_COMPLETE) {
430 #ifdef DEBUG
431 		printf("scsi_immed_command: Status -- 0x%x\n", status);
432 #endif
433 		return(status);
434 	} else {
435 		return(lock);
436 	}
437 }
438 
439 int
440 scsi_format_unit(ctlr, slave, unit)
441 	int ctlr, slave, unit;
442 {
443 	static struct scsi_cdb6 cdb = { CMD_FORMAT_UNIT, 0, 0, 0, 0, 0 };
444 	int status, lock, count = 0;
445 
446 #ifdef DEBUG
447 	printf("scsi_format_unit( %d, %d, %d): Start\n", ctlr, slave, unit);
448 #endif
449 
450 	cdb.lun = unit;
451 
452 	if (!(scrun(ctlr, slave, &cdb, 6, (u_char *) 0, 0, &lock))) {
453 #ifdef DEBUG
454 		printf("scsi_format_unit: Command Transfer Failed.\n");
455 #endif
456 		return(-1);
457 	}
458 
459 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) {
460 		DELAY(1000000);
461 #ifdef DEBUG
462 		if ((count % 60) == 0)
463 			printf("scsi_format_unit: %d\n");
464 #endif
465 	}
466 
467 	status = scfinish(ctlr);
468 
469 	if (lock == SC_IO_COMPLETE) {
470 #ifdef DEBUG
471 		printf("scsi_format_unit: Status -- 0x%x\n", status);
472 #endif
473 		return(status);
474 	} else {
475 		return(lock);
476 	}
477 }
478 
479 
480 /*
481  * ????
482  */
483 
484 int
485 scstart()
486 {
487 }
488 
489 int
490 scgo()
491 {
492 }
493 
494 int
495 scdone()
496 {
497 }
498 
499 
500 /*
501  * Interrupt Routine
502  */
503 
504 int
505 scintr()
506 {
507 	register struct scsi_softc *hs;
508 	volatile register struct scsidevice *hd;
509 	register u_char ints, temp;
510 	register int i;
511 	u_char *buf;
512 	int len;
513 
514 	for (i = 0; i < NSC; i++) {
515 		hs = &scsi_softc[i];
516 		hd = (struct scsidevice *) hs->sc_hc->hp_addr;
517 		if ((ints = hd->scsi_ints) != 0)
518 			goto get_intr;
519 	}
520 
521 	/* Unknown Interrupt occured */
522 	return;
523 
524 
525 	/*
526 	 * Interrupt
527 	 */
528 
529  get_intr:
530 #ifdef DEBUG
531 	printf("scintr: INTS 0x%x, SSTS 0x%x,  PCTL 0x%x,  PSNS 0x%x    0x%x\n",
532 	        ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns,
533 	        hs->sc_phase);
534 #endif
535 	if (ints & INTS_RESEL) {
536 		if (hs->sc_phase == BUS_FREE_PHASE) {
537 			temp = hd->scsi_temp & ~(1 << SCSI_ID);
538 			for (i = 0; temp != 1; i++) {
539 				temp >>= 1;
540 			}
541 			hs->sc_target = i;
542 			*(hs->sc_lock) = SC_IN_PROGRESS;
543 		} else
544 			goto abort;
545 	} else if (ints & INTS_DISCON) {
546 		if ((hs->sc_msg[0] == MSG_CMD_COMPLETE) || (hs->sc_msg[0] == MSG_DISCONNECT)) {
547 			hs->sc_phase  = BUS_FREE_PHASE;
548 			hs->sc_target = SCSI_ID;
549 			if (hs->sc_msg[0] == MSG_CMD_COMPLETE)
550 				/* SCSI IO complete */
551 				*(hs->sc_lock) = SC_IO_COMPLETE;
552 			else
553 				/* Cisconnected from Target */
554 				*(hs->sc_lock) = SC_DISCONNECTED;
555 			hd->scsi_ints = ints;
556 			return;
557 		} else
558 			goto abort;
559 	} else if (ints & INTS_CMD_DONE) {
560 		if (hs->sc_phase == BUS_FREE_PHASE)
561 			goto abort;
562 		else if (hs->sc_phase == MESG_IN_PHASE) {
563 			hd->scsi_scmd = SCMD_RST_ACK;
564 			hd->scsi_ints = ints;
565 			hs->sc_phase  = hd->scsi_psns & PHASE;
566 			return;
567 		}
568 		if (hs->sc_flags & SC_SEL_TIMEOUT)
569 			hs->sc_flags &= ~SC_SEL_TIMEOUT;
570 	} else if (ints & INTS_SRV_REQ) {
571 		if (hs->sc_phase != MESG_IN_PHASE)
572 			goto abort;
573 	} else if (ints & INTS_TIMEOUT) {
574 		if (hs->sc_phase == ARB_SEL_PHASE) {
575 			if (hs->sc_flags & SC_SEL_TIMEOUT) {
576 				hs->sc_flags &= ~SC_SEL_TIMEOUT;
577 				hs->sc_phase  = BUS_FREE_PHASE;
578 				hs->sc_target = SCSI_ID;
579 				/* Such SCSI Device is not conected. */
580 				*(hs->sc_lock) = SC_DEV_NOT_FOUND;
581 				hd->scsi_ints = ints;
582 				return;
583 			} else {
584 				/* wait more 250 usec */
585 				hs->sc_flags |= SC_SEL_TIMEOUT;
586 				hd->scsi_temp = 0;
587 				hd->scsi_tch  = 0;
588 				hd->scsi_tcm  = 0x06;
589 				hd->scsi_tcl  = 0x40;
590 				hd->scsi_ints = ints;
591 				return;
592 			}
593 		} else
594 			goto abort;
595 	} else
596 		goto abort;
597 
598 	hd->scsi_ints = ints;
599 
600 	/*
601 	 * Next SCSI Transfer
602 	 */
603 
604 	while ((hd->scsi_psns & PSNS_REQ) == 0) {
605 		DELAY(1);
606 	}
607 
608 	hs->sc_phase = hd->scsi_psns & PHASE;
609 
610 	if ((hs->sc_phase == DATA_OUT_PHASE) || (hs->sc_phase == DATA_IN_PHASE)) {
611 		len = hs->sc_len;
612 		buf = hs->sc_buf;
613 	} else if (hs->sc_phase == CMD_PHASE) {
614 		len = hs->sc_cdblen;
615 		buf = hs->sc_cdb;
616 	} else if (hs->sc_phase == STATUS_PHASE) {
617 		len = 1;
618 		buf = &hs->sc_stat;
619 	} else {
620 		len = 1;
621 		buf = hs->sc_msg;
622 	}
623 
624 	ixfer_start(hd, len, hs->sc_phase, 0);
625 	if (hs->sc_phase & PHASE_IO)
626 		ixfer_in(hd, len, buf);
627 	else
628 		ixfer_out(hd, len, buf);
629 
630 	return;
631 
632 	/*
633 	 * SCSI Abort
634 	 */
635  abort:
636 	/* SCSI IO failed */
637 	scabort(hs, hd);
638 	hd->scsi_ints = ints;
639 	*(hs->sc_lock) = SC_IO_FAILED;
640 	return;
641 }
642