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 /* センスデータの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 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