1 /* $NetBSD: sc.c,v 1.4 2013/01/22 15:48:40 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 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