sc.c revision 1.20 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
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
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
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
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
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
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
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
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
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
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
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
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
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 /* Additional Sens Length*/
533 /* cdbAllocation Length */
534 /* */
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
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
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
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