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