1 /* $OpenBSD: sc.c,v 1.5 2023/01/10 17:10:57 miod 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 Protocol 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
scinit(struct scsi_softc * hs,uint unit)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
screset(struct scsi_softc * hs)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
issue_select(struct scsidevice * hd,u_char target)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
ixfer_start(struct scsidevice * hd,int len,u_char phase,int wait)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
ixfer_out(struct scsidevice * hd,int len,u_char * buf)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
ixfer_in(struct scsidevice * hd,int len,u_char * buf)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
scrun(struct scsi_softc * hs,uint target,u_char * cdb,int cdblen,u_char * buf,int len,volatile int * lock)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
scfinish(struct scsi_softc * hs)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
scabort(struct scsi_softc * hs,struct scsidevice * hd)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
scsi_test_unit_rdy(struct scsi_softc * sc,int target,int unit)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
scsi_request_sense(struct scsi_softc * sc,int target,int unit,u_char * buf,unsigned int len)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
scsi_immed_command(struct scsi_softc * sc,int target,int unit,struct scsi_generic_cdb * cdb,u_char * buf,unsigned int len)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
scintr(struct scsi_softc * hs)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