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
scinit(hc)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
screset(unit)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
issue_select(hd,target)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
ixfer_start(hd,len,phase,wait)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
ixfer_out(hd,len,buf)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
ixfer_in(hd,len,buf)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
scrun(ctlr,slave,cdb,cdblen,buf,len,lock)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
scfinish(ctlr)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
scabort(hs,hd)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
scsi_test_unit_rdy(ctlr,slave,unit)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
scsi_request_sense(ctlr,slave,unit,buf,len)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
scsi_immed_command(ctlr,slave,unit,cdb,buf,len)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
scsi_format_unit(ctlr,slave,unit)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
scstart()485 scstart()
486 {
487 }
488
489 int
scgo()490 scgo()
491 {
492 }
493
494 int
scdone()495 scdone()
496 {
497 }
498
499
500 /*
501 * Interrupt Routine
502 */
503
504 int
scintr()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