sc.c revision 1.4.6.2 1 /* $NetBSD: sc.c,v 1.4.6.2 2013/02/25 00:28:49 tls 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 2ms */
195 hd->scsi_tch = 0;
196 hd->scsi_tcm = 32;
197 hd->scsi_tcl = 4;
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 = &scsi_softc[ctlr];
258 struct scsidevice *hd = (struct scsidevice *) hs->sc_hc->hp_addr;
259
260 if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))
261 return(0);
262
263 hs->sc_flags = 0;
264 hs->sc_phase = ARB_SEL_PHASE;
265 hs->sc_target = slave;
266
267 hs->sc_cdb = cdb;
268 hs->sc_cdblen = cdblen;
269 hs->sc_buf = buf;
270 hs->sc_len = len;
271 hs->sc_lock = lock;
272
273 hs->sc_stat = 0;
274 hs->sc_msg[0] = 0;
275
276 *(hs->sc_lock) = SC_IN_PROGRESS;
277 issue_select(hd, hs->sc_target);
278
279 return(1);
280 }
281
282 int
283 scfinish(int ctlr)
284 {
285 struct scsi_softc *hs = &scsi_softc[ctlr];
286 int status = hs->sc_stat;
287
288 hs->sc_flags = 0;
289 hs->sc_phase = BUS_FREE_PHASE;
290 hs->sc_target = SCSI_ID;
291
292 hs->sc_cdb = NULL;
293 hs->sc_cdblen = 0;
294 hs->sc_buf = NULL;
295 hs->sc_len = 0;
296 hs->sc_lock = NULL;
297
298 hs->sc_stat = 0;
299 hs->sc_msg[0] = 0;
300
301 return(status);
302 }
303
304 void
305 scabort(struct scsi_softc *hs, struct scsidevice *hd)
306 {
307 int len;
308 u_char junk;
309
310 printf("sc%d: abort phase=0x%x, ssts=0x%x, ints=0x%x\n",
311 hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts,
312 hd->scsi_ints);
313
314 if (hd->scsi_ints != 0)
315 hd->scsi_ints = hd->scsi_ints;
316
317 if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)
318 /* no longer connected to scsi target */
319 return;
320
321 /* get the number of bytes remaining in current xfer + fudge */
322 len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;
323
324 /* for that many bus cycles, try to send an abort msg */
325 for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {
326 hd->scsi_scmd = SCMD_SET_ATN;
327
328 while ((hd->scsi_psns & PSNS_REQ) == 0) {
329 if (! (hd->scsi_ssts & SSTS_INITIATOR))
330 goto out;
331 DELAY(1);
332 }
333
334 if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)
335 hd->scsi_scmd = SCMD_RST_ATN;
336 hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE;
337
338 if (hd->scsi_psns & PHASE_IO) {
339 /* one of the input phases - read & discard a byte */
340 hd->scsi_scmd = SCMD_SET_ACK;
341 while (hd->scsi_psns & PSNS_REQ)
342 DELAY(1);
343 junk = hd->scsi_temp;
344 } else {
345 /* one of the output phases - send an abort msg */
346 hd->scsi_temp = MSG_ABORT;
347 hd->scsi_scmd = SCMD_SET_ACK;
348 while (hd->scsi_psns & PSNS_REQ)
349 DELAY(1);
350 }
351
352 hd->scsi_scmd = SCMD_RST_ACK;
353 }
354 out:
355 /*
356 * Either the abort was successful & the bus is disconnected or
357 * the device didn't listen. If the latter, announce the problem.
358 * Either way, reset the card & the SPC.
359 */
360 if (len < 0 && hs)
361 printf("sc%d: abort failed. phase=0x%x, ssts=0x%x\n",
362 hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts);
363 }
364
365
366 /*
367 * SCSI Command Handler
368 */
369
370 int
371 scsi_test_unit_rdy(int ctlr, int slave, int unit)
372 {
373 static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
374 int status;
375 volatile int lock;
376
377 #ifdef DEBUG
378 printf("scsi_test_unit_rdy( %d, %d, %d): Start\n", ctlr, slave, unit);
379 #endif
380
381 cdb.lun = unit;
382
383 if (!(scrun(ctlr, slave, (void *)&cdb, 6, NULL, 0, &lock))) {
384 #ifdef DEBUG
385 printf("scsi_test_unit_rdy: Command Transfer Failed.\n");
386 #endif
387 return(-1);
388 }
389
390 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
391 DELAY(10);
392
393 status = scfinish(ctlr);
394
395 if (lock == SC_IO_COMPLETE) {
396 #ifdef DEBUG
397 printf("scsi_test_unit_rdy: Status -- 0x%x\n", status);
398 #endif
399 return(status);
400 } else {
401 return(lock);
402 }
403 }
404
405 int
406 scsi_request_sense(int ctlr, int slave, int unit, u_char *buf, unsigned int len)
407 {
408 static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
409 int status;
410 volatile int lock;
411
412 #ifdef DEBUG
413 printf("scsi_request_sense: Start\n");
414 #endif
415
416 /* Request Sense$N>l9g!"E>Aw$5$l$k%G!<%?D9$O%?!<%2368H$K0MB8$7!" */
417 /* %;%s%9%G!<%?$N#8/usr/src/sys/luna68k/stand/SCCS/s.sc.c$%HL\$NAddtional Sens Length$K$h$jF0E*$K7hDj$9$k!#*/
418 /* $3$3$G$O%G!<%?!<E>Aw?t$rcdb$NAllocation Length$K:GDcD9$G$"$k#8/usr/src/sys/luna68k/stand/SCCS/s.sc.c$%H */
419 /* $r8GDj$7$F!"#S#P#C$N=hM}%7!<%1%s%9$rJx$5$J$$$h$&$K$7$F$$$k!# */
420
421 /* %F!<@(#)sc.c 8.1f%K373H$N>uBV$rD4$Y$k$?$a!"Addtional Sens Field$r%"%/%;%9$9$k */
422 /* I,MW$,$"$k$N$G6/10/93P%$%98.1i%$%PB&$Glen$r7hDj$9$k$3$H$K$9$k */
423
424 cdb.lun = unit;
425 cdb.len = len;
426
427 if (!(scrun(ctlr, slave, (void *)&cdb, 6, buf, len, &lock))) {
428 #ifdef DEBUG
429 printf("scsi_request_sense: Command Transfer Failed.\n");
430 #endif
431 return(-1);
432 }
433
434 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
435 DELAY(10);
436
437 status = scfinish(ctlr);
438
439 if (lock == SC_IO_COMPLETE) {
440 #ifdef DEBUG
441 printf("scsi_request_sense: Status -- 0x%x\n", status);
442 #endif
443 return(status);
444 } else {
445 return(lock);
446 }
447 }
448
449 int
450 scsi_immed_command(int ctlr, int slave, int unit, struct scsi_fmt_cdb *cdb,
451 u_char *buf, unsigned int len)
452 {
453 int status;
454 volatile int lock;
455
456 #ifdef DEBUG
457 printf("scsi_immed_command( %d, %d, %d, cdb(%d), buf, %d): Start\n",
458 ctlr, slave, unit, cdb->len, len);
459 #endif
460
461 cdb->cdb[1] |= unit << 5;
462
463 if (!(scrun(ctlr, slave, (void *)&cdb->cdb[0], cdb->len, buf, len, &lock))) {
464 #ifdef DEBUG
465 printf("scsi_immed_command: Command Transfer Failed.\n");
466 #endif
467 return(-1);
468 }
469
470 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED))
471 DELAY(10);
472
473 status = scfinish(ctlr);
474
475 if (lock == SC_IO_COMPLETE) {
476 #ifdef DEBUG
477 printf("scsi_immed_command: Status -- 0x%x\n", status);
478 #endif
479 return(status);
480 } else {
481 return(lock);
482 }
483 }
484
485 int
486 scsi_format_unit(int ctlr, int slave, int unit)
487 {
488 static struct scsi_cdb6 cdb = { CMD_FORMAT_UNIT, 0, 0, 0, 0, 0 };
489 int status;
490 volatile int lock;
491 #ifdef DEBUG
492 int count = 0;
493 #endif
494
495 #ifdef DEBUG
496 printf("scsi_format_unit( %d, %d, %d): Start\n", ctlr, slave, unit);
497 #endif
498
499 cdb.lun = unit;
500
501 if (!(scrun(ctlr, slave, (void *)&cdb, 6, (u_char *) 0, 0, &lock))) {
502 #ifdef DEBUG
503 printf("scsi_format_unit: Command Transfer Failed.\n");
504 #endif
505 return(-1);
506 }
507
508 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) {
509 DELAY(1000000);
510 #ifdef DEBUG
511 if ((++count % 60) == 0)
512 printf("scsi_format_unit: %d\n", count / 60);
513 #endif
514 }
515
516 status = scfinish(ctlr);
517
518 if (lock == SC_IO_COMPLETE) {
519 #ifdef DEBUG
520 printf("scsi_format_unit: Status -- 0x%x\n", status);
521 #endif
522 return(status);
523 } else {
524 return(lock);
525 }
526 }
527
528
529 /*
530 * Interrupt Routine
531 */
532
533 int
534 scintr(void)
535 {
536 struct scsi_softc *hs;
537 struct scsidevice *hd;
538 u_char ints, temp;
539 int i;
540 u_char *buf;
541 int len;
542
543 for (i = 0; i < NSC; i++) {
544 hs = &scsi_softc[i];
545 hd = (struct scsidevice *) hs->sc_hc->hp_addr;
546 if ((ints = hd->scsi_ints) != 0)
547 goto get_intr;
548 }
549
550 /* Unknown Interrupt occured */
551 return -1;
552
553
554 /*
555 * Interrupt
556 */
557
558 get_intr:
559 #ifdef DEBUG
560 printf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x 0x%x\n",
561 ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns,
562 hs->sc_phase);
563 #endif
564 if (ints & INTS_RESEL) {
565 if (hs->sc_phase == BUS_FREE_PHASE) {
566 temp = hd->scsi_temp & ~(1 << SCSI_ID);
567 for (i = 0; temp != 1; i++) {
568 temp >>= 1;
569 }
570 hs->sc_target = i;
571 *(hs->sc_lock) = SC_IN_PROGRESS;
572 } else
573 goto abort;
574 } else if (ints & INTS_DISCON) {
575 if ((hs->sc_msg[0] == MSG_CMD_COMPLETE) || (hs->sc_msg[0] == MSG_DISCONNECT)) {
576 hs->sc_phase = BUS_FREE_PHASE;
577 hs->sc_target = SCSI_ID;
578 if (hs->sc_msg[0] == MSG_CMD_COMPLETE)
579 /* SCSI IO complete */
580 *(hs->sc_lock) = SC_IO_COMPLETE;
581 else
582 /* Cisconnected from Target */
583 *(hs->sc_lock) = SC_DISCONNECTED;
584 hd->scsi_ints = ints;
585 return 0;
586 } else
587 goto abort;
588 } else if (ints & INTS_CMD_DONE) {
589 if (hs->sc_phase == BUS_FREE_PHASE)
590 goto abort;
591 else if (hs->sc_phase == MESG_IN_PHASE) {
592 hd->scsi_scmd = SCMD_RST_ACK;
593 hd->scsi_ints = ints;
594 hs->sc_phase = hd->scsi_psns & PHASE;
595 return 0;
596 }
597 if (hs->sc_flags & SC_SEL_TIMEOUT)
598 hs->sc_flags &= ~SC_SEL_TIMEOUT;
599 } else if (ints & INTS_SRV_REQ) {
600 if (hs->sc_phase != MESG_IN_PHASE)
601 goto abort;
602 } else if (ints & INTS_TIMEOUT) {
603 if (hs->sc_phase == ARB_SEL_PHASE) {
604 if (hs->sc_flags & SC_SEL_TIMEOUT) {
605 hs->sc_flags &= ~SC_SEL_TIMEOUT;
606 hs->sc_phase = BUS_FREE_PHASE;
607 hs->sc_target = SCSI_ID;
608 /* Such SCSI Device is not conected. */
609 *(hs->sc_lock) = SC_DEV_NOT_FOUND;
610 hd->scsi_ints = ints;
611 return 0;
612 } else {
613 /* wait more 250 usec */
614 hs->sc_flags |= SC_SEL_TIMEOUT;
615 hd->scsi_temp = 0;
616 hd->scsi_tch = 0;
617 hd->scsi_tcm = 0x06;
618 hd->scsi_tcl = 0x40;
619 hd->scsi_ints = ints;
620 return 0;
621 }
622 } else
623 goto abort;
624 } else
625 goto abort;
626
627 hd->scsi_ints = ints;
628
629 /*
630 * Next SCSI Transfer
631 */
632
633 while ((hd->scsi_psns & PSNS_REQ) == 0) {
634 DELAY(1);
635 }
636
637 hs->sc_phase = hd->scsi_psns & PHASE;
638
639 if ((hs->sc_phase == DATA_OUT_PHASE) || (hs->sc_phase == DATA_IN_PHASE)) {
640 len = hs->sc_len;
641 buf = hs->sc_buf;
642 } else if (hs->sc_phase == CMD_PHASE) {
643 len = hs->sc_cdblen;
644 buf = hs->sc_cdb;
645 } else if (hs->sc_phase == STATUS_PHASE) {
646 len = 1;
647 buf = &hs->sc_stat;
648 } else {
649 len = 1;
650 buf = hs->sc_msg;
651 }
652
653 ixfer_start(hd, len, hs->sc_phase, 0);
654 if (hs->sc_phase & PHASE_IO)
655 ixfer_in(hd, len, buf);
656 else
657 ixfer_out(hd, len, buf);
658
659 return 0;
660
661 /*
662 * SCSI Abort
663 */
664 abort:
665 /* SCSI IO failed */
666 scabort(hs, hd);
667 hd->scsi_ints = ints;
668 *(hs->sc_lock) = SC_IO_FAILED;
669 return -1;
670 }
671