1 /* 2 * Copyright (c) 1992 OMRON Corporation. 3 * Copyright (c) 1992 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * OMRON Corporation. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)sc.c 7.1 (Berkeley) 12/13/92 12 */ 13 14 /* 15 * sc.c -- SCSI Protocole Controller (SPC) driver 16 * remaked by A.Fujita, MAR-11-199 17 */ 18 19 20 #define NSC 1 21 22 #include <sys/param.h> 23 #include <luna68k/dev/scsireg.h> 24 #include <luna68k/stand/device.h> 25 #include <luna68k/stand/scsivar.h> 26 27 #define SCSI_IPL 2 28 #define SCSI_ID 7 29 30 int scinit(), scstart(), scgo(), scintr(), scdone(); 31 void screset(); 32 struct driver scdriver = { 33 scinit, "sc", scstart, scgo, scintr, scdone 34 }; 35 36 struct scsi_softc scsi_softc[NSC]; 37 38 /* 39 * Initialize SPC & Data Structure 40 */ 41 42 int 43 scinit(hc) 44 register struct hp_ctlr *hc; 45 { 46 register struct scsi_softc *hs = &scsi_softc[hc->hp_unit]; 47 register int i; 48 49 hc->hp_ipl = SCSI_IPL; 50 hs->sc_hc = hc; 51 52 hs->sc_flags = 0; 53 hs->sc_phase = BUS_FREE_PHASE; 54 hs->sc_target = SCSI_ID; 55 56 hs->sc_cdb = NULL; 57 hs->sc_cdblen = 0; 58 hs->sc_buf = NULL; 59 hs->sc_len = 0; 60 hs->sc_lock = NULL; 61 62 hs->sc_stat = 0; 63 hs->sc_msg[0] = 0; 64 65 screset(hc->hp_unit); 66 return(1); 67 } 68 69 void 70 screset(unit) 71 register int unit; 72 { 73 register struct scsi_softc *hs = &scsi_softc[unit]; 74 volatile register struct scsidevice *hd = 75 (struct scsidevice *)hs->sc_hc->hp_addr; 76 77 printf("sc%d: ", unit); 78 79 /* 80 * Disable interrupts then reset the FUJI chip. 81 */ 82 83 hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; 84 hd->scsi_scmd = 0; 85 hd->scsi_pctl = 0; 86 hd->scsi_temp = 0; 87 hd->scsi_tch = 0; 88 hd->scsi_tcm = 0; 89 hd->scsi_tcl = 0; 90 hd->scsi_ints = 0; 91 92 /* We can use Asynchronous Transfer only */ 93 printf("async"); 94 95 /* 96 * Configure MB89352 with its SCSI address, all 97 * interrupts enabled & appropriate parity. 98 */ 99 hd->scsi_bdid = SCSI_ID; 100 hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB| 101 SCTL_PARITY_ENAB | SCTL_RESEL_ENAB | 102 SCTL_INTR_ENAB; 103 printf(", parity"); 104 105 DELAY(400); 106 hd->scsi_sctl &= ~SCTL_DISABLE; 107 108 printf(", scsi id %d\n", SCSI_ID); 109 } 110 111 112 /* 113 * SPC Arbitration/Selection routine 114 */ 115 116 int 117 issue_select(hd, target) 118 volatile register struct scsidevice *hd; 119 u_char target; 120 { 121 hd->scsi_pctl = 0; 122 hd->scsi_temp = (1 << SCSI_ID) | (1 << target); 123 124 /* select timeout is hardcoded to 2ms */ 125 hd->scsi_tch = 0; 126 hd->scsi_tcm = 32; 127 hd->scsi_tcl = 4; 128 129 hd->scsi_scmd = SCMD_SELECT; 130 131 return (1); 132 } 133 134 135 /* 136 * SPC Manual Transfer routines 137 */ 138 139 /* not yet */ 140 141 142 /* 143 * SPC Program Transfer routines 144 */ 145 146 int 147 ixfer_start(hd, len, phase, wait) 148 volatile register struct scsidevice *hd; 149 int len; 150 u_char phase; 151 register int wait; 152 { 153 hd->scsi_tch = ((len & 0xff0000) >> 16); 154 hd->scsi_tcm = ((len & 0x00ff00) >> 8); 155 hd->scsi_tcl = (len & 0x0000ff); 156 hd->scsi_pctl = phase; 157 hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; 158 } 159 160 int 161 ixfer_out(hd, len, buf) 162 volatile register struct scsidevice *hd; 163 int len; 164 register u_char *buf; 165 { 166 for(; len > 0; len--) { 167 while (hd->scsi_ssts & SSTS_DREG_FULL) { 168 DELAY(5); 169 } 170 hd->scsi_dreg = *buf++; 171 } 172 } 173 174 int 175 ixfer_in(hd, len, buf) 176 volatile register struct scsidevice *hd; 177 int len; 178 register u_char *buf; 179 { 180 for (; len > 0; len--) { 181 int i; 182 while (hd->scsi_ssts & SSTS_DREG_EMPTY) { 183 DELAY(5); 184 } 185 *buf++ = hd->scsi_dreg; 186 } 187 } 188 189 190 /* 191 * SPC drive routines 192 */ 193 194 int 195 scrun(ctlr, slave, cdb, cdblen, buf, len, lock) 196 int ctlr, slave; 197 u_char *cdb; 198 int cdblen; 199 u_char *buf; 200 int len; 201 int *lock; 202 { 203 register struct scsi_softc *hs = &scsi_softc[ctlr]; 204 volatile register struct scsidevice *hd = 205 (struct scsidevice *) hs->sc_hc->hp_addr; 206 207 if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY)) 208 return(0); 209 210 hs->sc_flags = 0; 211 hs->sc_phase = ARB_SEL_PHASE; 212 hs->sc_target = slave; 213 214 hs->sc_cdb = cdb; 215 hs->sc_cdblen = cdblen; 216 hs->sc_buf = buf; 217 hs->sc_len = len; 218 hs->sc_lock = lock; 219 220 hs->sc_stat = 0; 221 hs->sc_msg[0] = 0; 222 223 *(hs->sc_lock) = SC_IN_PROGRESS; 224 issue_select(hd, hs->sc_target); 225 226 return(1); 227 } 228 229 int 230 scfinish(ctlr) 231 int ctlr; 232 { 233 register struct scsi_softc *hs = &scsi_softc[ctlr]; 234 int status = hs->sc_stat; 235 236 hs->sc_flags = 0; 237 hs->sc_phase = BUS_FREE_PHASE; 238 hs->sc_target = SCSI_ID; 239 240 hs->sc_cdb = NULL; 241 hs->sc_cdblen = 0; 242 hs->sc_buf = NULL; 243 hs->sc_len = 0; 244 hs->sc_lock = NULL; 245 246 hs->sc_stat = 0; 247 hs->sc_msg[0] = 0; 248 249 return(status); 250 } 251 252 int 253 scabort(hs, hd) 254 register struct scsi_softc *hs; 255 volatile register struct scsidevice *hd; 256 { 257 int len; 258 u_char junk; 259 260 printf("sc%d: abort phase=0x%x, ssts=0x%x, ints=0x%x\n", 261 hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts, 262 hd->scsi_ints); 263 264 if (hd->scsi_ints != 0) 265 hd->scsi_ints = hd->scsi_ints; 266 267 if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0) 268 /* no longer connected to scsi target */ 269 return; 270 271 /* get the number of bytes remaining in current xfer + fudge */ 272 len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl; 273 274 /* for that many bus cycles, try to send an abort msg */ 275 for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) { 276 hd->scsi_scmd = SCMD_SET_ATN; 277 278 while ((hd->scsi_psns & PSNS_REQ) == 0) { 279 if (! (hd->scsi_ssts & SSTS_INITIATOR)) 280 goto out; 281 DELAY(1); 282 } 283 284 if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE) 285 hd->scsi_scmd = SCMD_RST_ATN; 286 hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE; 287 288 if (hd->scsi_psns & PHASE_IO) { 289 /* one of the input phases - read & discard a byte */ 290 hd->scsi_scmd = SCMD_SET_ACK; 291 while (hd->scsi_psns & PSNS_REQ) 292 DELAY(1); 293 junk = hd->scsi_temp; 294 } else { 295 /* one of the output phases - send an abort msg */ 296 hd->scsi_temp = MSG_ABORT; 297 hd->scsi_scmd = SCMD_SET_ACK; 298 while (hd->scsi_psns & PSNS_REQ) 299 DELAY(1); 300 } 301 302 hd->scsi_scmd = SCMD_RST_ACK; 303 } 304 out: 305 /* 306 * Either the abort was successful & the bus is disconnected or 307 * the device didn't listen. If the latter, announce the problem. 308 * Either way, reset the card & the SPC. 309 */ 310 if (len < 0 && hs) 311 printf("sc%d: abort failed. phase=0x%x, ssts=0x%x\n", 312 hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts); 313 } 314 315 316 /* 317 * SCSI Command Handler 318 */ 319 320 int 321 scsi_test_unit_rdy(ctlr, slave, unit) 322 int ctlr, slave, unit; 323 { 324 static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY }; 325 int status, lock; 326 327 #ifdef DEBUG 328 printf("scsi_test_unit_rdy( %d, %d, %d): Start\n", ctlr, slave, unit); 329 #endif 330 331 cdb.lun = unit; 332 333 if (!(scrun(ctlr, slave, &cdb, 6, (u_char *) 0, 0, &lock))) { 334 #ifdef DEBUG 335 printf("scsi_test_unit_rdy: Command Transfer Failed.\n"); 336 #endif 337 return(-1); 338 } 339 340 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) 341 DELAY(10); 342 343 status = scfinish(ctlr); 344 345 if (lock == SC_IO_COMPLETE) { 346 #ifdef DEBUG 347 printf("scsi_test_unit_rdy: Status -- 0x%x\n", status); 348 #endif 349 return(status); 350 } else { 351 return(lock); 352 } 353 } 354 355 int 356 scsi_request_sense(ctlr, slave, unit, buf, len) 357 int ctlr, slave, unit; 358 u_char *buf; 359 unsigned len; 360 { 361 static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE }; 362 int status, lock; 363 364 #ifdef DEBUG 365 printf("scsi_request_sense: Start\n"); 366 #endif 367 368 /* Request Sense$N>l9g!"E>Aw$5$l$k%G!<%?D9$O%?!<%2368H$K0MB8$7!" */ 369 /* %;%s%9%G!<%?$N#8/usr/home/csrg/sccs/sys/luna68k/stand/SCCS/s.sc.c$%HL\$NAddtional Sens Length$K$h$jF0E*$K7hDj$9$k!#*/ 370 /* $3$3$G$O%G!<%?!<E>Aw?t$rcdb$NAllocation Length$K:GDcD9$G$"$k#8/usr/home/csrg/sccs/sys/luna68k/stand/SCCS/s.sc.c$%H */ 371 /* $r8GDj$7$F!"#S#P#C$N=hM}%7!<%1%s%9$rJx$5$J$$$h$&$K$7$F$$$k!# */ 372 373 /* %F!<@(#)sc.c 7.1f%K373H$N>uBV$rD4$Y$k$?$a!"Addtional Sens Field$r%"%/%;%9$9$k */ 374 /* I,MW$,$"$k$N$G12/13/92P%$%97.1i%$%PB&$Glen$r7hDj$9$k$3$H$K$9$k */ 375 376 cdb.lun = unit; 377 cdb.len = len; 378 379 if (!(scrun(ctlr, slave, &cdb, 6, buf, len, &lock))) { 380 #ifdef DEBUG 381 printf("scsi_request_sense: Command Transfer Failed.\n"); 382 #endif 383 return(-1); 384 } 385 386 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) 387 DELAY(10); 388 389 status = scfinish(ctlr); 390 391 if (lock == SC_IO_COMPLETE) { 392 #ifdef DEBUG 393 printf("scsi_request_sense: Status -- 0x%x\n", status); 394 #endif 395 return(status); 396 } else { 397 return(lock); 398 } 399 } 400 401 int 402 scsi_immed_command(ctlr, slave, unit, cdb, buf, len) 403 int ctlr, slave, unit; 404 struct scsi_fmt_cdb *cdb; 405 u_char *buf; 406 unsigned len; 407 { 408 int lock, status; 409 410 #ifdef DEBUG 411 printf("scsi_immed_command( %d, %d, %d, cdb(%d), buf, %d): Start\n", 412 ctlr, slave, unit, cdb->len, len); 413 #endif 414 415 cdb->cdb[1] |= unit << 5; 416 417 if (!(scrun(ctlr, slave, &cdb->cdb[0], cdb->len, buf, len, &lock))) { 418 #ifdef DEBUG 419 printf("scsi_immed_command: Command Transfer Failed.\n"); 420 #endif 421 return(-1); 422 } 423 424 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) 425 DELAY(10); 426 427 status = scfinish(ctlr); 428 429 if (lock == SC_IO_COMPLETE) { 430 #ifdef DEBUG 431 printf("scsi_immed_command: Status -- 0x%x\n", status); 432 #endif 433 return(status); 434 } else { 435 return(lock); 436 } 437 } 438 439 int 440 scsi_format_unit(ctlr, slave, unit) 441 int ctlr, slave, unit; 442 { 443 static struct scsi_cdb6 cdb = { CMD_FORMAT_UNIT, 0, 0, 0, 0, 0 }; 444 int status, lock, count = 0; 445 446 #ifdef DEBUG 447 printf("scsi_format_unit( %d, %d, %d): Start\n", ctlr, slave, unit); 448 #endif 449 450 cdb.lun = unit; 451 452 if (!(scrun(ctlr, slave, &cdb, 6, (u_char *) 0, 0, &lock))) { 453 #ifdef DEBUG 454 printf("scsi_format_unit: Command Transfer Failed.\n"); 455 #endif 456 return(-1); 457 } 458 459 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) { 460 DELAY(1000000); 461 #ifdef DEBUG 462 if ((count % 60) == 0) 463 printf("scsi_format_unit: %d\n"); 464 #endif 465 } 466 467 status = scfinish(ctlr); 468 469 if (lock == SC_IO_COMPLETE) { 470 #ifdef DEBUG 471 printf("scsi_format_unit: Status -- 0x%x\n", status); 472 #endif 473 return(status); 474 } else { 475 return(lock); 476 } 477 } 478 479 480 /* 481 * ???? 482 */ 483 484 int 485 scstart() 486 { 487 } 488 489 int 490 scgo() 491 { 492 } 493 494 int 495 scdone() 496 { 497 } 498 499 500 /* 501 * Interrupt Routine 502 */ 503 504 int 505 scintr() 506 { 507 register struct scsi_softc *hs; 508 volatile register struct scsidevice *hd; 509 register u_char ints, temp; 510 register int i; 511 u_char *buf; 512 int len; 513 514 for (i = 0; i < NSC; i++) { 515 hs = &scsi_softc[i]; 516 hd = (struct scsidevice *) hs->sc_hc->hp_addr; 517 if ((ints = hd->scsi_ints) != 0) 518 goto get_intr; 519 } 520 521 /* Unknown Interrupt occured */ 522 return; 523 524 525 /* 526 * Interrupt 527 */ 528 529 get_intr: 530 #ifdef DEBUG 531 printf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x 0x%x\n", 532 ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns, 533 hs->sc_phase); 534 #endif 535 if (ints & INTS_RESEL) { 536 if (hs->sc_phase == BUS_FREE_PHASE) { 537 temp = hd->scsi_temp & ~(1 << SCSI_ID); 538 for (i = 0; temp != 1; i++) { 539 temp >>= 1; 540 } 541 hs->sc_target = i; 542 *(hs->sc_lock) = SC_IN_PROGRESS; 543 } else 544 goto abort; 545 } else if (ints & INTS_DISCON) { 546 if ((hs->sc_msg[0] == MSG_CMD_COMPLETE) || (hs->sc_msg[0] == MSG_DISCONNECT)) { 547 hs->sc_phase = BUS_FREE_PHASE; 548 hs->sc_target = SCSI_ID; 549 if (hs->sc_msg[0] == MSG_CMD_COMPLETE) 550 /* SCSI IO complete */ 551 *(hs->sc_lock) = SC_IO_COMPLETE; 552 else 553 /* Cisconnected from Target */ 554 *(hs->sc_lock) = SC_DISCONNECTED; 555 hd->scsi_ints = ints; 556 return; 557 } else 558 goto abort; 559 } else if (ints & INTS_CMD_DONE) { 560 if (hs->sc_phase == BUS_FREE_PHASE) 561 goto abort; 562 else if (hs->sc_phase == MESG_IN_PHASE) { 563 hd->scsi_scmd = SCMD_RST_ACK; 564 hd->scsi_ints = ints; 565 hs->sc_phase = hd->scsi_psns & PHASE; 566 return; 567 } 568 if (hs->sc_flags & SC_SEL_TIMEOUT) 569 hs->sc_flags &= ~SC_SEL_TIMEOUT; 570 } else if (ints & INTS_SRV_REQ) { 571 if (hs->sc_phase != MESG_IN_PHASE) 572 goto abort; 573 } else if (ints & INTS_TIMEOUT) { 574 if (hs->sc_phase == ARB_SEL_PHASE) { 575 if (hs->sc_flags & SC_SEL_TIMEOUT) { 576 hs->sc_flags &= ~SC_SEL_TIMEOUT; 577 hs->sc_phase = BUS_FREE_PHASE; 578 hs->sc_target = SCSI_ID; 579 /* Such SCSI Device is not conected. */ 580 *(hs->sc_lock) = SC_DEV_NOT_FOUND; 581 hd->scsi_ints = ints; 582 return; 583 } else { 584 /* wait more 250 usec */ 585 hs->sc_flags |= SC_SEL_TIMEOUT; 586 hd->scsi_temp = 0; 587 hd->scsi_tch = 0; 588 hd->scsi_tcm = 0x06; 589 hd->scsi_tcl = 0x40; 590 hd->scsi_ints = ints; 591 return; 592 } 593 } else 594 goto abort; 595 } else 596 goto abort; 597 598 hd->scsi_ints = ints; 599 600 /* 601 * Next SCSI Transfer 602 */ 603 604 while ((hd->scsi_psns & PSNS_REQ) == 0) { 605 DELAY(1); 606 } 607 608 hs->sc_phase = hd->scsi_psns & PHASE; 609 610 if ((hs->sc_phase == DATA_OUT_PHASE) || (hs->sc_phase == DATA_IN_PHASE)) { 611 len = hs->sc_len; 612 buf = hs->sc_buf; 613 } else if (hs->sc_phase == CMD_PHASE) { 614 len = hs->sc_cdblen; 615 buf = hs->sc_cdb; 616 } else if (hs->sc_phase == STATUS_PHASE) { 617 len = 1; 618 buf = &hs->sc_stat; 619 } else { 620 len = 1; 621 buf = hs->sc_msg; 622 } 623 624 ixfer_start(hd, len, hs->sc_phase, 0); 625 if (hs->sc_phase & PHASE_IO) 626 ixfer_in(hd, len, buf); 627 else 628 ixfer_out(hd, len, buf); 629 630 return; 631 632 /* 633 * SCSI Abort 634 */ 635 abort: 636 /* SCSI IO failed */ 637 scabort(hs, hd); 638 hd->scsi_ints = ints; 639 *(hs->sc_lock) = SC_IO_FAILED; 640 return; 641 } 642