xref: /openbsd/sys/arch/luna88k/stand/boot/sc.c (revision 73471bf0)
1 /*	$OpenBSD: sc.c,v 1.4 2021/03/11 11:16:58 jsg Exp $	*/
2 /*	$NetBSD: sc.c,v 1.4 2013/01/22 15:48:40 tsutsui Exp $	*/
3 
4 /*
5  * Copyright (c) 1992 OMRON Corporation.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * OMRON Corporation.
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 University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)sc.c	8.1 (Berkeley) 6/10/93
39  */
40 /*
41  * Copyright (c) 1992, 1993
42  *	The Regents of the University of California.  All rights reserved.
43  *
44  * This code is derived from software contributed to Berkeley by
45  * OMRON Corporation.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions
49  * are met:
50  * 1. Redistributions of source code must retain the above copyright
51  *    notice, this list of conditions and the following disclaimer.
52  * 2. Redistributions in binary form must reproduce the above copyright
53  *    notice, this list of conditions and the following disclaimer in the
54  *    documentation and/or other materials provided with the distribution.
55  * 3. Neither the name of the University nor the names of its contributors
56  *    may be used to endorse or promote products derived from this software
57  *    without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69  * SUCH DAMAGE.
70  *
71  *	@(#)sc.c	8.1 (Berkeley) 6/10/93
72  */
73 
74 /*
75  * sc.c -- SCSI Protocole Controller (SPC)  driver
76  * remaked by A.Fujita, MAR-11-199
77  */
78 
79 #include <sys/param.h>
80 #include <machine/board.h>
81 #include <luna88k/stand/boot/samachdep.h>
82 #include <luna88k/stand/boot/scsireg.h>
83 #include <luna88k/stand/boot/scsivar.h>
84 
85 #define SCSI_ID		7
86 
87 int scintr(struct scsi_softc *);
88 void screset(struct scsi_softc *);
89 int issue_select(struct scsidevice *, u_char);
90 void ixfer_start(struct scsidevice *, int, u_char, int);
91 void ixfer_out(struct scsidevice *, int, u_char *);
92 void ixfer_in(struct scsidevice *, int, u_char *);
93 int scrun(struct scsi_softc *, uint, u_char *, int, u_char *, int,
94     volatile int *);
95 int scfinish(struct scsi_softc *);
96 void scabort(struct scsi_softc *, struct scsidevice *);
97 
98 /*
99  * Initialize SPC & Data Structure
100  */
101 
102 int
103 scinit(struct scsi_softc *hs, uint unit)
104 {
105 	void *reg;
106 
107 	switch (unit) {
108 	case 0:
109 		reg = (void *)SCSI_ADDR;
110 		break;
111 	case 1:
112 		reg = (void *)(SCSI_ADDR + 0x40);
113 		break;
114 	default:
115 		return 0;
116 	}
117 
118 	if (unit != 0 && machtype != LUNA_88K2)
119 		return 0;
120 
121 	hs->sc_sd     = (struct scsidevice *)reg;
122 
123 	hs->sc_unit   = unit;
124 	hs->sc_flags  = 0;
125 	hs->sc_phase  = BUS_FREE_PHASE;
126 	hs->sc_target = SCSI_ID;
127 
128 	hs->sc_cdb    = NULL;
129 	hs->sc_cdblen = 0;
130 	hs->sc_buf    = NULL;
131 	hs->sc_len    = 0;
132 	hs->sc_lock   = NULL;
133 
134 	hs->sc_stat   = 0;
135 	hs->sc_msg[0] = 0;
136 
137 	screset(hs);
138 	return(1);
139 }
140 
141 void
142 screset(struct scsi_softc *hs)
143 {
144 	struct scsidevice *hd = hs->sc_sd;
145 
146 #ifdef DEBUG
147 	printf("sc%d: ", hs->sc_unit);
148 #endif
149 
150 	/*
151 	 * Disable interrupts then reset the FUJI chip.
152 	 */
153 
154 	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
155 	hd->scsi_scmd = 0;
156 	hd->scsi_pctl = 0;
157 	hd->scsi_temp = 0;
158 	hd->scsi_tch  = 0;
159 	hd->scsi_tcm  = 0;
160 	hd->scsi_tcl  = 0;
161 	hd->scsi_ints = 0;
162 
163 #ifdef DEBUG
164 	/* We can use Asynchronous Transfer only */
165 	printf("async");
166 #endif
167 
168 	/*
169 	 * Configure MB89352 with its SCSI address, all
170 	 * interrupts enabled & appropriate parity.
171 	 */
172 	hd->scsi_bdid = SCSI_ID;
173 	hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB|
174 			SCTL_PARITY_ENAB | SCTL_RESEL_ENAB |
175 			SCTL_INTR_ENAB;
176 #ifdef DEBUG
177 	printf(", parity");
178 #endif
179 
180 	DELAY(400);
181 	hd->scsi_sctl &= ~SCTL_DISABLE;
182 
183 #ifdef DEBUG
184 	printf(", scsi id %d\n", SCSI_ID);
185 #endif
186 }
187 
188 
189 /*
190  * SPC Arbitration/Selection routine
191  */
192 
193 int
194 issue_select(struct scsidevice *hd, u_char target)
195 {
196 	hd->scsi_pctl = 0;
197 	hd->scsi_temp = (1 << SCSI_ID) | (1 << target);
198 
199 	/* select timeout is hardcoded to 250ms */
200 	hd->scsi_tch = 2;
201 	hd->scsi_tcm = 113;
202 	hd->scsi_tcl = 3;
203 
204 	hd->scsi_scmd = SCMD_SELECT;
205 
206 	return (1);
207 }
208 
209 
210 /*
211  * SPC Manual Transfer routines
212  */
213 
214 /* not yet */
215 
216 
217 /*
218  * SPC Program Transfer routines
219  */
220 
221 void
222 ixfer_start(struct scsidevice *hd, int len, u_char phase, int wait)
223 {
224 	hd->scsi_tch  = ((len & 0xff0000) >> 16);
225 	hd->scsi_tcm  = ((len & 0x00ff00) >>  8);
226 	hd->scsi_tcl  =  (len & 0x0000ff);
227 	hd->scsi_pctl = phase;
228 	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
229 }
230 
231 void
232 ixfer_out(struct scsidevice *hd, int len, u_char *buf)
233 {
234 	for(; len > 0; len--) {
235 		while (hd->scsi_ssts & SSTS_DREG_FULL) {
236 			DELAY(5);
237 		}
238 		hd->scsi_dreg = *buf++;
239 	}
240 }
241 
242 void
243 ixfer_in(struct scsidevice *hd, int len, u_char *buf)
244 {
245 	for (; len > 0; len--) {
246 		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
247 			DELAY(5);
248 		}
249 		*buf++ = hd->scsi_dreg;
250 	}
251 }
252 
253 
254 /*
255  * SPC drive routines
256  */
257 
258 int
259 scrun(struct scsi_softc *hs, uint target, u_char *cdb, int cdblen, u_char *buf,
260     int len, volatile int *lock)
261 {
262 	struct scsidevice *hd;
263 
264 	hd = hs->sc_sd;
265 
266 	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
267 		return(0);
268 
269 	if (target > 7)
270 		return 0;
271 
272 	hs->sc_flags  = 0;
273 	hs->sc_phase  = ARB_SEL_PHASE;
274 	hs->sc_target = target >= 7 ? target : 6 - target;
275 
276 	hs->sc_cdb    = cdb;
277 	hs->sc_cdblen = cdblen;
278 	hs->sc_buf    = buf;
279 	hs->sc_len    = len;
280 	hs->sc_lock   = lock;
281 
282 	hs->sc_stat   = 0;
283 	hs->sc_msg[0] = 0;
284 
285 	*(hs->sc_lock) = SC_IN_PROGRESS;
286 	issue_select(hd, hs->sc_target);
287 
288 	return(1);
289 }
290 
291 int
292 scfinish(struct scsi_softc *hs)
293 {
294 	int status = hs->sc_stat;
295 
296 	hs->sc_flags  = 0;
297 	hs->sc_phase  = BUS_FREE_PHASE;
298 	hs->sc_target = SCSI_ID;
299 
300 	hs->sc_cdb    = NULL;
301 	hs->sc_cdblen = 0;
302 	hs->sc_buf    = NULL;
303 	hs->sc_len    = 0;
304 	hs->sc_lock   = NULL;
305 
306 	hs->sc_stat   = 0;
307 	hs->sc_msg[0] = 0;
308 
309 	return(status);
310 }
311 
312 void
313 scabort(struct scsi_softc *hs, struct scsidevice *hd)
314 {
315 	int len;
316 	u_char junk;
317 
318 	printf("sc%d: abort  phase=0x%x, ssts=0x%x, ints=0x%x\n",
319 		hs->sc_unit, hd->scsi_psns, hd->scsi_ssts, hd->scsi_ints);
320 
321 	if (hd->scsi_ints != 0)
322 		hd->scsi_ints = hd->scsi_ints;
323 
324 	if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
325 		/* no longer connected to scsi target */
326 		return;
327 
328 	/* get the number of bytes remaining in current xfer + fudge */
329 	len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
330 
331 	/* for that many bus cycles, try to send an abort msg */
332 	for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
333 		hd->scsi_scmd = SCMD_SET_ATN;
334 
335 		while ((hd->scsi_psns & PSNS_REQ) == 0) {
336 			if (! (hd->scsi_ssts & SSTS_INITIATOR))
337 				goto out;
338 			DELAY(1);
339 		}
340 
341 		if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
342 			hd->scsi_scmd = SCMD_RST_ATN;
343 		hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE;
344 
345 		if (hd->scsi_psns & PHASE_IO) {
346 			/* one of the input phases - read & discard a byte */
347 			hd->scsi_scmd = SCMD_SET_ACK;
348 			while (hd->scsi_psns & PSNS_REQ)
349 				DELAY(1);
350 			junk = hd->scsi_temp;
351 		} else {
352 			/* one of the output phases - send an abort msg */
353 			hd->scsi_temp = MSG_ABORT;
354 			hd->scsi_scmd = SCMD_SET_ACK;
355 			while (hd->scsi_psns & PSNS_REQ)
356 				DELAY(1);
357 		}
358 
359 		hd->scsi_scmd = SCMD_RST_ACK;
360 	}
361 out:
362 	/*
363 	 * Either the abort was successful & the bus is disconnected or
364 	 * the device didn't listen.  If the latter, announce the problem.
365 	 * Either way, reset the card & the SPC.
366 	 */
367 	if (len < 0 && hs)
368 		printf("sc%d: abort failed.  phase=0x%x, ssts=0x%x\n",
369 			hs->sc_unit, hd->scsi_psns, hd->scsi_ssts);
370 }
371 
372 
373 /*
374  * SCSI Command Handler
375  */
376 
377 int
378 scsi_test_unit_rdy(struct scsi_softc *sc, int target, int unit)
379 {
380 	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
381 	int status;
382 	volatile int lock;
383 
384 #ifdef DEBUG
385 	printf("scsi_test_unit_rdy(%d,%d,%d): Start\n",
386 	    sc->sc_unit, target, unit);
387 #endif
388 
389 	cdb.lun = unit;
390 
391 	if (!(scrun(sc, target, (void *)&cdb, 6, NULL, 0, &lock))) {
392 #ifdef DEBUG
393 		printf("scsi_test_unit_rdy: Command Transfer Failed.\n");
394 #endif
395 		return(-1);
396 	}
397 
398 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) {
399 		if (scintr(sc))
400 			DELAY(10);
401 	}
402 
403 	status = scfinish(sc);
404 
405 	if (lock == SC_IO_COMPLETE) {
406 #ifdef DEBUG
407 		printf("scsi_test_unit_rdy: Status -- 0x%x\n", status);
408 #endif
409 		return(status);
410 	} else {
411 		return(lock);
412 	}
413 }
414 
415 int
416 scsi_request_sense(struct scsi_softc *sc, int target, int unit, u_char *buf,
417     unsigned int len)
418 {
419 	static struct scsi_cdb6 cdb = {	CMD_REQUEST_SENSE };
420 	int status;
421 	volatile int lock;
422 
423 #ifdef DEBUG
424 	printf("scsi_request_sense: Start\n");
425 #endif
426 
427 	cdb.lun = unit;
428 	cdb.len = len;
429 
430 	if (!(scrun(sc, target, (void *)&cdb, 6, buf, len, &lock))) {
431 #ifdef DEBUG
432 		printf("scsi_request_sense: Command Transfer Failed.\n");
433 #endif
434 		return(-1);
435 	}
436 
437 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) {
438 		if (scintr(sc))
439 			DELAY(10);
440 	}
441 
442 	status = scfinish(sc);
443 
444 	if (lock == SC_IO_COMPLETE) {
445 #ifdef DEBUG
446 		printf("scsi_request_sense: Status -- 0x%x\n", status);
447 #endif
448 		return(status);
449 	} else {
450 		return(lock);
451 	}
452 }
453 
454 int
455 scsi_immed_command(struct scsi_softc *sc, int target, int unit,
456     struct scsi_generic_cdb *cdb, u_char *buf, unsigned int len)
457 {
458 	int status;
459 	volatile int lock;
460 
461 #ifdef DEBUG
462 	printf("scsi_immed_command( %d, %d, %d, cdb(%d), buf, %d): Start\n",
463 	       sc->sc_unit, target, unit, cdb->len, len);
464 #endif
465 
466 	cdb->cdb[1] |= unit << 5;
467 
468 	if (!(scrun(sc, target, (void *)&cdb->cdb[0], cdb->len, buf, len,
469 	    &lock))) {
470 #ifdef DEBUG
471 		printf("scsi_immed_command: Command Transfer Failed.\n");
472 #endif
473 		return(-1);
474 	}
475 
476 	while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) {
477 		if (scintr(sc))
478 			DELAY(10);
479 	}
480 
481 	status = scfinish(sc);
482 
483 	if (lock == SC_IO_COMPLETE) {
484 #ifdef DEBUG
485 		printf("scsi_immed_command: Status -- 0x%x\n", status);
486 #endif
487 		return(status);
488 	} else {
489 		return(lock);
490 	}
491 }
492 
493 /*
494  * Interrupt Routine
495  */
496 
497 int
498 scintr(struct scsi_softc *hs)
499 {
500 	struct scsidevice *hd;
501 	u_char ints, temp;
502 	u_char *buf;
503 	int i, len;
504 
505 	hd = hs->sc_sd;
506 	if ((ints = hd->scsi_ints) == 0)
507 		return -1;
508 
509 #ifdef DEBUG
510 	printf("scintr: INTS 0x%x, SSTS 0x%x,  PCTL 0x%x,  PSNS 0x%x    0x%x\n",
511 	        ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns,
512 	        hs->sc_phase);
513 #endif
514 	if (ints & INTS_RESEL) {
515 		if (hs->sc_phase == BUS_FREE_PHASE) {
516 			temp = hd->scsi_temp & ~(1 << SCSI_ID);
517 			for (i = 0; temp != 1; i++) {
518 				temp >>= 1;
519 			}
520 			hs->sc_target = i;
521 			*(hs->sc_lock) = SC_IN_PROGRESS;
522 		} else
523 			goto abort;
524 	} else if (ints & INTS_DISCON) {
525 		if (hs->sc_msg[0] == MSG_CMD_COMPLETE ||
526 		    hs->sc_msg[0] == MSG_DISCONNECT) {
527 			hs->sc_phase  = BUS_FREE_PHASE;
528 			hs->sc_target = SCSI_ID;
529 			if (hs->sc_msg[0] == MSG_CMD_COMPLETE)
530 				/* SCSI IO complete */
531 				*(hs->sc_lock) = SC_IO_COMPLETE;
532 			else
533 				/* Cisconnected from Target */
534 				*(hs->sc_lock) = SC_DISCONNECTED;
535 			hd->scsi_ints = ints;
536 			return 0;
537 		} else
538 			goto abort;
539 	} else if (ints & INTS_CMD_DONE) {
540 		if (hs->sc_phase == BUS_FREE_PHASE)
541 			goto abort;
542 		else if (hs->sc_phase == MESG_IN_PHASE) {
543 			hd->scsi_scmd = SCMD_RST_ACK;
544 			hd->scsi_ints = ints;
545 			hs->sc_phase  = hd->scsi_psns & PHASE;
546 			return 0;
547 		}
548 		if (hs->sc_flags & SC_SEL_TIMEOUT)
549 			hs->sc_flags &= ~SC_SEL_TIMEOUT;
550 	} else if (ints & INTS_SRV_REQ) {
551 		if (hs->sc_phase != MESG_IN_PHASE)
552 			goto abort;
553 	} else if (ints & INTS_TIMEOUT) {
554 		if (hs->sc_phase == ARB_SEL_PHASE) {
555 			if (hs->sc_flags & SC_SEL_TIMEOUT) {
556 				hs->sc_flags &= ~SC_SEL_TIMEOUT;
557 				hs->sc_phase  = BUS_FREE_PHASE;
558 				hs->sc_target = SCSI_ID;
559 				/* Such SCSI Device is not connected . */
560 				*(hs->sc_lock) = SC_DEV_NOT_FOUND;
561 				hd->scsi_ints = ints;
562 				return 0;
563 			} else {
564 				/* wait more 250 usec */
565 				hs->sc_flags |= SC_SEL_TIMEOUT;
566 				hd->scsi_temp = 0;
567 				hd->scsi_tch  = 0;
568 				hd->scsi_tcm  = 0x06;
569 				hd->scsi_tcl  = 0x40;
570 				hd->scsi_ints = ints;
571 				return 0;
572 			}
573 		} else
574 			goto abort;
575 	} else
576 		goto abort;
577 
578 	hd->scsi_ints = ints;
579 
580 	/*
581 	 * Next SCSI Transfer
582 	 */
583 
584 	while ((hd->scsi_psns & PSNS_REQ) == 0) {
585 		DELAY(1);
586 	}
587 
588 	hs->sc_phase = hd->scsi_psns & PHASE;
589 
590 	if (hs->sc_phase == DATA_OUT_PHASE || hs->sc_phase == DATA_IN_PHASE) {
591 		len = hs->sc_len;
592 		buf = hs->sc_buf;
593 	} else if (hs->sc_phase == CMD_PHASE) {
594 		len = hs->sc_cdblen;
595 		buf = hs->sc_cdb;
596 	} else if (hs->sc_phase == STATUS_PHASE) {
597 		len = 1;
598 		buf = &hs->sc_stat;
599 	} else {
600 		len = 1;
601 		buf = hs->sc_msg;
602 	}
603 
604 	ixfer_start(hd, len, hs->sc_phase, 0);
605 	if (hs->sc_phase & PHASE_IO)
606 		ixfer_in(hd, len, buf);
607 	else
608 		ixfer_out(hd, len, buf);
609 
610 	return 0;
611 
612 	/*
613 	 * SCSI Abort
614 	 */
615  abort:
616 	/* SCSI IO failed */
617 	scabort(hs, hd);
618 	hd->scsi_ints = ints;
619 	*(hs->sc_lock) = SC_IO_FAILED;
620 	return -1;
621 }
622