1 /*        $NetBSD: sc.c,v 1.20 2024/09/25 09:08:22 rin 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/scsivar.h>
85 
86 #define SCSI_ID               7
87 
88 static void screset(struct scsi_softc *);
89 static void scprobe(struct scsi_softc *, uint, uint);
90 static int issue_select(struct scsidevice *, uint8_t);
91 static void ixfer_start(struct scsidevice *, int, uint8_t, int);
92 static void ixfer_out(struct scsidevice *, int, uint8_t *);
93 static void ixfer_in(struct scsidevice *, int, uint8_t *);
94 static int scrun(int, int, uint8_t *, int, uint8_t *, int, volatile int *);
95 static int scfinish(int);
96 static void scabort(struct scsi_softc *);
97 
98 struct    scsi_softc scsi_softc[NSC];
99 
100 /*
101  * Initialize SPC & Data Structure
102  */
103 
104 int
scinit(int ctlr,void * addr)105 scinit(int ctlr, void *addr)
106 {
107           struct scsi_softc *hs;
108           uint id;
109 
110           if (ctlr < 0 || ctlr >= NSC)
111                     return 0;
112 
113           hs = &scsi_softc[ctlr];
114           hs->sc_ctlr   = ctlr;
115           hs->sc_spc    = addr;
116 
117           hs->sc_flags  = 0;
118           hs->sc_phase  = BUS_FREE_PHASE;
119           hs->sc_target = SCSI_ID;
120 
121           hs->sc_cdb    = NULL;
122           hs->sc_cdblen = 0;
123           hs->sc_buf    = NULL;
124           hs->sc_len    = 0;
125           hs->sc_lock   = NULL;
126 
127           hs->sc_stat   = 0;
128           hs->sc_msg[0] = 0;
129 
130           screset(hs);
131 
132           for (id = 0; id < 7; id++)
133                     scprobe(hs, id, 0);
134 
135           return 1;
136 }
137 
138 static void
screset(struct scsi_softc * hs)139 screset(struct scsi_softc *hs)
140 {
141           struct scsidevice *hd = hs->sc_spc;
142 
143           printf("sc%d at 0x%08lx: ", hs->sc_ctlr, (u_long)hs->sc_spc);
144 
145           /*
146            * Disable interrupts then reset the FUJI chip.
147            */
148 
149           hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;
150           hd->scsi_scmd = 0;
151           hd->scsi_pctl = 0;
152           hd->scsi_temp = 0;
153           hd->scsi_tch  = 0;
154           hd->scsi_tcm  = 0;
155           hd->scsi_tcl  = 0;
156           hd->scsi_ints = 0;
157 
158           /* We can use Asynchronous Transfer only */
159           printf("async");
160 
161           /*
162            * Configure MB89352 with its SCSI address, all
163            * interrupts enabled & appropriate parity.
164            */
165           hd->scsi_bdid = SCSI_ID;
166           hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB|
167                               SCTL_PARITY_ENAB | SCTL_RESEL_ENAB |
168                               SCTL_INTR_ENAB;
169           printf(", parity");
170 
171           DELAY(400);
172           hd->scsi_sctl &= ~SCTL_DISABLE;
173 
174           printf(", ID %d\n", SCSI_ID);
175 }
176 
177 /*
178  * XXX
179  * sensebuf and inqbuf may be uninitialized for some cases.
180  * Real fix should be to check return values everywhere in
181  * scsi_request_sense(), scsi_immed_command(), and functions
182  * called from them.
183  */
184 #pragma GCC diagnostic push                                           /* XXX { */
185 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
186 
187 bool
scident(uint ctlr,uint target,uint lun,struct scsi_inquiry * inqout,uint32_t * capout)188 scident(uint ctlr, uint target, uint lun, struct scsi_inquiry *inqout,
189     uint32_t *capout)
190 {
191           struct scsi_inquiry inqbuf;
192           struct scsi_generic_cdb inq = {
193                     6,
194                     { CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 }
195           };
196           uint32_t capbuf[2];
197           struct scsi_generic_cdb cap = {
198                     10,
199                     { CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
200           };
201           int i;
202           int tries = 10;
203 
204           /*
205            * See if unit exists and is a disk then read block size & nblocks.
206            */
207           while ((i = scsi_test_unit_rdy(ctlr, target, lun)) != 0) {
208                     if (i < 0 || --tries < 0)
209                               return false;
210                     if (i == STS_CHECKCOND) {
211                               uint8_t sensebuf[8];
212                               struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
213 
214                               scsi_request_sense(ctlr, target, lun, sensebuf, 8);
215                               if (sp->class == 7 && sp->key == 6)
216                                         /* drive doing an RTZ -- give it a while */
217                                         DELAY(1000000);
218                     }
219                     DELAY(1000);
220           }
221           if (scsi_immed_command(ctlr, target, lun, &inq, (uint8_t *)&inqbuf,
222                                      sizeof(inqbuf)) ||
223               scsi_immed_command(ctlr, target, lun, &cap, (uint8_t *)&capbuf,
224                                      sizeof(capbuf)))
225                     /* doesn't exist or not a CCS device */
226                     return false;
227 
228           switch (inqbuf.type) {
229           case 0:             /* disk */
230           case 4:             /* WORM */
231           case 5:             /* CD-ROM */
232           case 7:             /* Magneto-optical */
233                     break;
234           default:  /* not a disk */
235                     return false;
236           }
237 
238           if (inqout != NULL)
239                     *inqout = inqbuf;
240           if (capout != NULL) {
241                     /* assume big endian */
242                     capout[0] = capbuf[0];
243                     capout[1] = capbuf[1];
244           }
245 
246           return true;
247 }
248 
249 #pragma GCC diagnostic pop                                            /* XXX } */
250 
251 static void
scprobe(struct scsi_softc * hs,uint target,uint lun)252 scprobe(struct scsi_softc *hs, uint target, uint lun)
253 {
254           struct scsi_inquiry inqbuf;
255           uint32_t capbuf[2], blocks, blksize;
256           char idstr[32];
257           int i;
258 
259           if (!scident(hs->sc_ctlr, target, lun, &inqbuf, capbuf))
260                     return;
261 
262           /* CMD_READ_CAPACITY returns the last logical data block address. */
263           blocks  = capbuf[0] + 1;
264           blksize = capbuf[1];
265 
266           memcpy(idstr, &inqbuf.vendor_id, 28);
267           for (i = 27; i > 23; --i)
268                     if (idstr[i] != ' ')
269                               break;
270           idstr[i + 1] = '\0';
271           for (i = 23; i > 7; --i)
272                     if (idstr[i] != ' ')
273                               break;
274           idstr[i + 1] = '\0';
275           for (i = 7; i >= 0; --i)
276                     if (idstr[i] != ' ')
277                               break;
278           idstr[i + 1] = '\0';
279 
280           printf(" ID %d: %s %s rev %s", target, idstr, &idstr[8], &idstr[24]);
281           printf(", %d bytes/sect x %d sectors\n", blksize, blocks);
282 }
283 
284 
285 /*
286  * SPC Arbitration/Selection routine
287  */
288 
289 static int
issue_select(struct scsidevice * hd,uint8_t target)290 issue_select(struct scsidevice *hd, uint8_t target)
291 {
292 
293           hd->scsi_pctl = 0;
294           hd->scsi_temp = (1 << SCSI_ID) | (1 << target);
295 
296           /* select timeout is hardcoded to 250ms */
297           hd->scsi_tch = 2;
298           hd->scsi_tcm = 113;
299           hd->scsi_tcl = 3;
300 
301           hd->scsi_scmd = SCMD_SELECT;
302 
303           return 1;
304 }
305 
306 
307 /*
308  * SPC Manual Transfer routines
309  */
310 
311 /* not yet */
312 
313 
314 /*
315  * SPC Program Transfer routines
316  */
317 
318 static void
ixfer_start(struct scsidevice * hd,int len,uint8_t phase,int wait)319 ixfer_start(struct scsidevice *hd, int len, uint8_t phase, int wait)
320 {
321 
322           hd->scsi_tch  = ((len & 0xff0000) >> 16);
323           hd->scsi_tcm  = ((len & 0x00ff00) >>  8);
324           hd->scsi_tcl  =  (len & 0x0000ff);
325           hd->scsi_pctl = phase;
326           hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;
327 }
328 
329 static void
ixfer_out(struct scsidevice * hd,int len,uint8_t * buf)330 ixfer_out(struct scsidevice *hd, int len, uint8_t *buf)
331 {
332 
333           for (; len > 0; len--) {
334                     while (hd->scsi_ssts & SSTS_DREG_FULL) {
335                               DELAY(5);
336                     }
337                     hd->scsi_dreg = *buf++;
338           }
339 }
340 
341 static void
ixfer_in(struct scsidevice * hd,int len,uint8_t * buf)342 ixfer_in(struct scsidevice *hd, int len, uint8_t *buf)
343 {
344 
345           for (; len > 0; len--) {
346                     while (hd->scsi_ssts & SSTS_DREG_EMPTY) {
347                               DELAY(5);
348                     }
349                     *buf++ = hd->scsi_dreg;
350           }
351 }
352 
353 
354 /*
355  * SPC drive routines
356  */
357 
358 static int
scrun(int ctlr,int target,uint8_t * cdb,int cdblen,uint8_t * buf,int len,volatile int * lock)359 scrun(int ctlr, int target, uint8_t *cdb, int cdblen, uint8_t *buf, int len,
360     volatile int *lock)
361 {
362           struct scsi_softc *hs;
363           struct scsidevice *hd;
364 
365           if (ctlr < 0 || ctlr >= NSC)
366                     return 0;
367 
368           hs = &scsi_softc[ctlr];
369           hd = hs->sc_spc;
370           if (hd == NULL)
371                     return 0;
372 
373           if ((hd->scsi_ssts & (SSTS_INITIATOR | SSTS_TARGET | SSTS_BUSY)) != 0)
374                     return 0;
375 
376           hs->sc_flags  = 0;
377           hs->sc_phase  = ARB_SEL_PHASE;
378           hs->sc_target = target;
379 
380           hs->sc_cdb    = cdb;
381           hs->sc_cdblen = cdblen;
382           hs->sc_buf    = buf;
383           hs->sc_len    = len;
384           hs->sc_lock   = lock;
385 
386           hs->sc_stat   = 0;
387           hs->sc_msg[0] = 0;
388 
389           *(hs->sc_lock) = SC_IN_PROGRESS;
390           issue_select(hd, hs->sc_target);
391 
392           return 1;
393 }
394 
395 static int
scfinish(int ctlr)396 scfinish(int ctlr)
397 {
398           struct scsi_softc *hs = &scsi_softc[ctlr];
399           int status = hs->sc_stat;
400 
401           hs->sc_flags  = 0;
402           hs->sc_phase  = BUS_FREE_PHASE;
403           hs->sc_target = SCSI_ID;
404 
405           hs->sc_cdb    = NULL;
406           hs->sc_cdblen = 0;
407           hs->sc_buf    = NULL;
408           hs->sc_len    = 0;
409           hs->sc_lock   = NULL;
410 
411           hs->sc_stat   = 0;
412           hs->sc_msg[0] = 0;
413 
414           return status;
415 }
416 
417 static void
scabort(struct scsi_softc * hs)418 scabort(struct scsi_softc *hs)
419 {
420           struct scsidevice *hd = hs->sc_spc;
421           int len;
422 
423           printf("sc%d: abort  phase=0x%x, ssts=0x%x, ints=0x%x\n",
424               hs->sc_ctlr, hd->scsi_psns, hd->scsi_ssts, hd->scsi_ints);
425 
426           if (hd->scsi_ints != 0)
427                     /* write register value back to register */
428                     hd->scsi_ints = hd->scsi_ints;
429 
430           if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
431                     /* no longer connected to scsi target */
432                     return;
433 
434           /* get the number of bytes remaining in current xfer + fudge */
435           len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
436 
437           /* for that many bus cycles, try to send an abort msg */
438           for (len += 1024;
439               ((hd->scsi_ssts & SSTS_INITIATOR)) != 0 && --len >= 0;) {
440                     hd->scsi_scmd = SCMD_SET_ATN;
441 
442                     while ((hd->scsi_psns & PSNS_REQ) == 0) {
443                               if ((hd->scsi_ssts & SSTS_INITIATOR) == 0)
444                                         goto out;
445                               DELAY(1);
446                     }
447 
448                     if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
449                               hd->scsi_scmd = SCMD_RST_ATN;
450                     hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE;
451 
452                     if (hd->scsi_psns & PHASE_IO) {
453                               /* one of the input phases - read & discard a byte */
454                               hd->scsi_scmd = SCMD_SET_ACK;
455                               while ((hd->scsi_psns & PSNS_REQ) != 0)
456                                         DELAY(1);
457                               (void)hd->scsi_temp;
458                     } else {
459                               /* one of the output phases - send an abort msg */
460                               hd->scsi_temp = MSG_ABORT;
461                               hd->scsi_scmd = SCMD_SET_ACK;
462                               while ((hd->scsi_psns & PSNS_REQ) != 0)
463                                         DELAY(1);
464                     }
465 
466                     hd->scsi_scmd = SCMD_RST_ACK;
467           }
468 out:
469           /*
470            * Either the abort was successful & the bus is disconnected or
471            * the device didn't listen.  If the latter, announce the problem.
472            * Either way, reset the card & the SPC.
473            */
474           if (len < 0 && hs)
475                     printf("sc%d: abort failed.  phase=0x%x, ssts=0x%x\n",
476                         hs->sc_ctlr, hd->scsi_psns, hd->scsi_ssts);
477 }
478 
479 
480 /*
481  * SCSI Command Handler
482  */
483 
484 int
scsi_test_unit_rdy(int ctlr,int target,int lun)485 scsi_test_unit_rdy(int ctlr, int target, int lun)
486 {
487           static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
488           int status;
489           volatile int lock;
490 
491 #ifdef DEBUG
492           printf("scsi_test_unit_rdy( %d, %d, %d): Start\n", ctlr, target, lun);
493 #endif
494 
495           cdb.lun = lun;
496 
497           if (scrun(ctlr, target, (void *)&cdb, 6, NULL, 0, &lock) == 0) {
498 #ifdef DEBUG
499                     printf("scsi_test_unit_rdy: Command Transfer Failed.\n");
500 #endif
501                     return -1;
502           }
503 
504           while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
505                     DELAY(10);
506 
507           status = scfinish(ctlr);
508 
509           if (lock == SC_IO_COMPLETE) {
510 #ifdef DEBUG
511                     printf("scsi_test_unit_rdy: Status -- 0x%x\n", status);
512 #endif
513                     return status;
514           } else {
515                     return lock;
516           }
517 }
518 
519 int
scsi_request_sense(int ctlr,int target,int lun,uint8_t * buf,unsigned int len)520 scsi_request_sense(int ctlr, int target, int lun, uint8_t *buf,
521     unsigned int len)
522 {
523           static struct scsi_cdb6 cdb = {         CMD_REQUEST_SENSE };
524           int status;
525           volatile int lock;
526 
527 #ifdef DEBUG
528           printf("scsi_request_sense: Start\n");
529 #endif
530 
531           /* Request Senseの場合、転送されるデータ長はターゲットに依存し、        */
532           /* センスデータの8バイト目のAdditional Sens Lengthにより動的に決定する。*/
533           /* ここではデーター転送数をcdbのAllocation Lengthに最低長である8バイト */
534           /* を固定して、SPCの処理シーケンスを崩さないようにしている。         */
535 
536           /* テープユニットの状態を調べるため、Addtional Sens Fieldをアクセスする */
537           /* 必要があるのでデバイスドライバ側でlenを決定することにする            */
538 
539           cdb.lun = lun;
540           cdb.len = len;
541 
542           if (scrun(ctlr, target, (void *)&cdb, 6, buf, len, &lock) == 0) {
543 #ifdef DEBUG
544                     printf("scsi_request_sense: Command Transfer Failed.\n");
545 #endif
546                     return -1;
547           }
548 
549           while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
550                     DELAY(10);
551 
552           status = scfinish(ctlr);
553 
554           if (lock == SC_IO_COMPLETE) {
555 #ifdef DEBUG
556                     printf("scsi_request_sense: Status -- 0x%x\n", status);
557 #endif
558                     return status;
559           } else {
560                     return lock;
561           }
562 }
563 
564 int
scsi_immed_command(int ctlr,int target,int lun,struct scsi_generic_cdb * cdb,uint8_t * buf,unsigned int len)565 scsi_immed_command(int ctlr, int target, int lun, struct scsi_generic_cdb *cdb,
566     uint8_t *buf, unsigned int len)
567 {
568           int status;
569           volatile int lock;
570 
571 #ifdef DEBUG
572           printf("scsi_immed_command( %d, %d, %d, cdb(%d), buf, %d): Start\n",
573               ctlr, target, lun, cdb->len, len);
574 #endif
575 
576           cdb->cdb[1] |= lun << 5;
577 
578           if (scrun(ctlr, target, (void *)&cdb->cdb[0], cdb->len, buf, len,
579               &lock) == 0) {
580 #ifdef DEBUG
581                     printf("scsi_immed_command: Command Transfer Failed.\n");
582 #endif
583                     return -1;
584           }
585 
586           while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
587                     DELAY(10);
588 
589           status = scfinish(ctlr);
590 
591           if (lock == SC_IO_COMPLETE) {
592 #ifdef DEBUG
593                     printf("scsi_immed_command: Status -- 0x%x\n", status);
594 #endif
595                     return status;
596           } else {
597                     return lock;
598           }
599 }
600 
601 int
scsi_format_unit(int ctlr,int target,int lun)602 scsi_format_unit(int ctlr, int target, int lun)
603 {
604           static struct scsi_cdb6 cdb = { CMD_FORMAT_UNIT, 0, 0, 0, 0, 0 };
605           int status;
606           volatile int lock;
607 #ifdef DEBUG
608           int count = 0;
609 #endif
610 
611 #ifdef DEBUG
612           printf("scsi_format_unit( %d, %d, %d): Start\n", ctlr, target, lun);
613 #endif
614 
615           cdb.lun = lun;
616 
617           if (scrun(ctlr, target, (void *)&cdb, 6, NULL, 0, &lock) == 0) {
618 #ifdef DEBUG
619                     printf("scsi_format_unit: Command Transfer Failed.\n");
620 #endif
621                     return -1;
622           }
623 
624           while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) {
625                     DELAY(1000000);
626 #ifdef DEBUG
627                     if ((++count % 60) == 0)
628                               printf("scsi_format_unit: %d\n", count / 60);
629 #endif
630           }
631 
632           status = scfinish(ctlr);
633 
634           if (lock == SC_IO_COMPLETE) {
635 #ifdef DEBUG
636                     printf("scsi_format_unit: Status -- 0x%x\n", status);
637 #endif
638                     return status;
639           } else {
640                     return lock;
641           }
642 }
643 
644 
645 /*
646  * Interrupt Routine
647  */
648 
649 int
scintr(void)650 scintr(void)
651 {
652           struct scsi_softc *hs;
653           struct scsidevice *hd;
654           uint8_t ints, temp;
655           int i;
656           uint8_t *buf;
657           int len;
658 
659           for (i = 0; i < NSC; i++) {
660                     hs = &scsi_softc[i];
661                     hd = hs->sc_spc;
662                     if ((ints = hd->scsi_ints) != 0)
663                               goto get_intr;
664           }
665 
666           /* Unknown interrupt occurred */
667           return -1;
668 
669 
670           /*
671            * Interrupt
672            */
673 
674  get_intr:
675 #ifdef DEBUG
676           printf("scintr: INTS 0x%x, SSTS 0x%x,  PCTL 0x%x,  PSNS 0x%x    0x%x\n",
677               ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns, hs->sc_phase);
678 #endif
679           if (ints & INTS_RESEL) {
680                     if (hs->sc_phase == BUS_FREE_PHASE) {
681                               temp = hd->scsi_temp & ~(1 << SCSI_ID);
682                               for (i = 0; temp != 1; i++) {
683                                         temp >>= 1;
684                               }
685                               hs->sc_target = i;
686                               *(hs->sc_lock) = SC_IN_PROGRESS;
687                     } else
688                               goto abort;
689           } else if (ints & INTS_DISCON) {
690                     if ((hs->sc_msg[0] == MSG_CMD_COMPLETE) ||
691                         (hs->sc_msg[0] == MSG_DISCONNECT)) {
692                               hs->sc_phase  = BUS_FREE_PHASE;
693                               hs->sc_target = SCSI_ID;
694                               if (hs->sc_msg[0] == MSG_CMD_COMPLETE) {
695                                         /* SCSI IO complete */
696                                         *(hs->sc_lock) = SC_IO_COMPLETE;
697                               } else {
698                                         /* Disconnected from Target */
699                                         *(hs->sc_lock) = SC_DISCONNECTED;
700                               }
701                               hd->scsi_ints = ints;
702                               return 0;
703                     } else
704                               goto abort;
705           } else if (ints & INTS_CMD_DONE) {
706                     if (hs->sc_phase == BUS_FREE_PHASE)
707                               goto abort;
708                     else if (hs->sc_phase == MESG_IN_PHASE) {
709                               hd->scsi_scmd = SCMD_RST_ACK;
710                               hd->scsi_ints = ints;
711                               hs->sc_phase  = hd->scsi_psns & PHASE;
712                               return 0;
713                     }
714                     if (hs->sc_flags & SC_SEL_TIMEOUT)
715                               hs->sc_flags &= ~SC_SEL_TIMEOUT;
716           } else if (ints & INTS_SRV_REQ) {
717                     if (hs->sc_phase != MESG_IN_PHASE)
718                               goto abort;
719           } else if (ints & INTS_TIMEOUT) {
720                     if (hs->sc_phase == ARB_SEL_PHASE) {
721                               if (hs->sc_flags & SC_SEL_TIMEOUT) {
722                                         hs->sc_flags &= ~SC_SEL_TIMEOUT;
723                                         hs->sc_phase  = BUS_FREE_PHASE;
724                                         hs->sc_target = SCSI_ID;
725                                         /* Such SCSI Device is not connected. */
726                                         *(hs->sc_lock) = SC_DEV_NOT_FOUND;
727                                         hd->scsi_ints = ints;
728                                         return 0;
729                               } else {
730                                         /* wait more 250 usec */
731                                         hs->sc_flags |= SC_SEL_TIMEOUT;
732                                         hd->scsi_temp = 0;
733                                         hd->scsi_tch  = 0;
734                                         hd->scsi_tcm  = 0x06;
735                                         hd->scsi_tcl  = 0x40;
736                                         hd->scsi_ints = ints;
737                                         return 0;
738                               }
739                     } else
740                               goto abort;
741           } else
742                     goto abort;
743 
744           hd->scsi_ints = ints;
745 
746           /*
747            * Next SCSI Transfer
748            */
749 
750           while ((hd->scsi_psns & PSNS_REQ) == 0) {
751                     DELAY(1);
752           }
753 
754           hs->sc_phase = hd->scsi_psns & PHASE;
755 
756           if ((hs->sc_phase == DATA_OUT_PHASE) ||
757               (hs->sc_phase == DATA_IN_PHASE)) {
758                     len = hs->sc_len;
759                     buf = hs->sc_buf;
760           } else if (hs->sc_phase == CMD_PHASE) {
761                     len = hs->sc_cdblen;
762                     buf = hs->sc_cdb;
763           } else if (hs->sc_phase == STATUS_PHASE) {
764                     len = 1;
765                     buf = &hs->sc_stat;
766           } else {
767                     len = 1;
768                     buf = hs->sc_msg;
769           }
770 
771           ixfer_start(hd, len, hs->sc_phase, 0);
772           if (hs->sc_phase & PHASE_IO)
773                     ixfer_in(hd, len, buf);
774           else
775                     ixfer_out(hd, len, buf);
776 
777           return 0;
778 
779           /*
780            * SCSI Abort
781            */
782  abort:
783           /* SCSI IO failed */
784           scabort(hs);
785           hd->scsi_ints = ints;
786           *(hs->sc_lock) = SC_IO_FAILED;
787           return -1;
788 }
789