1 /* $OpenBSD: sc.c,v 1.4 2021/03/11 11:16:58 jsg Exp $ */ 2 /* $NetBSD: sc.c,v 1.4 2013/01/22 15:48:40 tsutsui Exp $ */ 3 4 /* 5 * Copyright (c) 1992 OMRON Corporation. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * OMRON Corporation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)sc.c 8.1 (Berkeley) 6/10/93 39 */ 40 /* 41 * Copyright (c) 1992, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * OMRON Corporation. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)sc.c 8.1 (Berkeley) 6/10/93 72 */ 73 74 /* 75 * sc.c -- SCSI Protocole Controller (SPC) driver 76 * remaked by A.Fujita, MAR-11-199 77 */ 78 79 #include <sys/param.h> 80 #include <machine/board.h> 81 #include <luna88k/stand/boot/samachdep.h> 82 #include <luna88k/stand/boot/scsireg.h> 83 #include <luna88k/stand/boot/scsivar.h> 84 85 #define SCSI_ID 7 86 87 int scintr(struct scsi_softc *); 88 void screset(struct scsi_softc *); 89 int issue_select(struct scsidevice *, u_char); 90 void ixfer_start(struct scsidevice *, int, u_char, int); 91 void ixfer_out(struct scsidevice *, int, u_char *); 92 void ixfer_in(struct scsidevice *, int, u_char *); 93 int scrun(struct scsi_softc *, uint, u_char *, int, u_char *, int, 94 volatile int *); 95 int scfinish(struct scsi_softc *); 96 void scabort(struct scsi_softc *, struct scsidevice *); 97 98 /* 99 * Initialize SPC & Data Structure 100 */ 101 102 int 103 scinit(struct scsi_softc *hs, uint unit) 104 { 105 void *reg; 106 107 switch (unit) { 108 case 0: 109 reg = (void *)SCSI_ADDR; 110 break; 111 case 1: 112 reg = (void *)(SCSI_ADDR + 0x40); 113 break; 114 default: 115 return 0; 116 } 117 118 if (unit != 0 && machtype != LUNA_88K2) 119 return 0; 120 121 hs->sc_sd = (struct scsidevice *)reg; 122 123 hs->sc_unit = unit; 124 hs->sc_flags = 0; 125 hs->sc_phase = BUS_FREE_PHASE; 126 hs->sc_target = SCSI_ID; 127 128 hs->sc_cdb = NULL; 129 hs->sc_cdblen = 0; 130 hs->sc_buf = NULL; 131 hs->sc_len = 0; 132 hs->sc_lock = NULL; 133 134 hs->sc_stat = 0; 135 hs->sc_msg[0] = 0; 136 137 screset(hs); 138 return(1); 139 } 140 141 void 142 screset(struct scsi_softc *hs) 143 { 144 struct scsidevice *hd = hs->sc_sd; 145 146 #ifdef DEBUG 147 printf("sc%d: ", hs->sc_unit); 148 #endif 149 150 /* 151 * Disable interrupts then reset the FUJI chip. 152 */ 153 154 hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; 155 hd->scsi_scmd = 0; 156 hd->scsi_pctl = 0; 157 hd->scsi_temp = 0; 158 hd->scsi_tch = 0; 159 hd->scsi_tcm = 0; 160 hd->scsi_tcl = 0; 161 hd->scsi_ints = 0; 162 163 #ifdef DEBUG 164 /* We can use Asynchronous Transfer only */ 165 printf("async"); 166 #endif 167 168 /* 169 * Configure MB89352 with its SCSI address, all 170 * interrupts enabled & appropriate parity. 171 */ 172 hd->scsi_bdid = SCSI_ID; 173 hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB| 174 SCTL_PARITY_ENAB | SCTL_RESEL_ENAB | 175 SCTL_INTR_ENAB; 176 #ifdef DEBUG 177 printf(", parity"); 178 #endif 179 180 DELAY(400); 181 hd->scsi_sctl &= ~SCTL_DISABLE; 182 183 #ifdef DEBUG 184 printf(", scsi id %d\n", SCSI_ID); 185 #endif 186 } 187 188 189 /* 190 * SPC Arbitration/Selection routine 191 */ 192 193 int 194 issue_select(struct scsidevice *hd, u_char target) 195 { 196 hd->scsi_pctl = 0; 197 hd->scsi_temp = (1 << SCSI_ID) | (1 << target); 198 199 /* select timeout is hardcoded to 250ms */ 200 hd->scsi_tch = 2; 201 hd->scsi_tcm = 113; 202 hd->scsi_tcl = 3; 203 204 hd->scsi_scmd = SCMD_SELECT; 205 206 return (1); 207 } 208 209 210 /* 211 * SPC Manual Transfer routines 212 */ 213 214 /* not yet */ 215 216 217 /* 218 * SPC Program Transfer routines 219 */ 220 221 void 222 ixfer_start(struct scsidevice *hd, int len, u_char phase, int wait) 223 { 224 hd->scsi_tch = ((len & 0xff0000) >> 16); 225 hd->scsi_tcm = ((len & 0x00ff00) >> 8); 226 hd->scsi_tcl = (len & 0x0000ff); 227 hd->scsi_pctl = phase; 228 hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; 229 } 230 231 void 232 ixfer_out(struct scsidevice *hd, int len, u_char *buf) 233 { 234 for(; len > 0; len--) { 235 while (hd->scsi_ssts & SSTS_DREG_FULL) { 236 DELAY(5); 237 } 238 hd->scsi_dreg = *buf++; 239 } 240 } 241 242 void 243 ixfer_in(struct scsidevice *hd, int len, u_char *buf) 244 { 245 for (; len > 0; len--) { 246 while (hd->scsi_ssts & SSTS_DREG_EMPTY) { 247 DELAY(5); 248 } 249 *buf++ = hd->scsi_dreg; 250 } 251 } 252 253 254 /* 255 * SPC drive routines 256 */ 257 258 int 259 scrun(struct scsi_softc *hs, uint target, u_char *cdb, int cdblen, u_char *buf, 260 int len, volatile int *lock) 261 { 262 struct scsidevice *hd; 263 264 hd = hs->sc_sd; 265 266 if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY)) 267 return(0); 268 269 if (target > 7) 270 return 0; 271 272 hs->sc_flags = 0; 273 hs->sc_phase = ARB_SEL_PHASE; 274 hs->sc_target = target >= 7 ? target : 6 - target; 275 276 hs->sc_cdb = cdb; 277 hs->sc_cdblen = cdblen; 278 hs->sc_buf = buf; 279 hs->sc_len = len; 280 hs->sc_lock = lock; 281 282 hs->sc_stat = 0; 283 hs->sc_msg[0] = 0; 284 285 *(hs->sc_lock) = SC_IN_PROGRESS; 286 issue_select(hd, hs->sc_target); 287 288 return(1); 289 } 290 291 int 292 scfinish(struct scsi_softc *hs) 293 { 294 int status = hs->sc_stat; 295 296 hs->sc_flags = 0; 297 hs->sc_phase = BUS_FREE_PHASE; 298 hs->sc_target = SCSI_ID; 299 300 hs->sc_cdb = NULL; 301 hs->sc_cdblen = 0; 302 hs->sc_buf = NULL; 303 hs->sc_len = 0; 304 hs->sc_lock = NULL; 305 306 hs->sc_stat = 0; 307 hs->sc_msg[0] = 0; 308 309 return(status); 310 } 311 312 void 313 scabort(struct scsi_softc *hs, struct scsidevice *hd) 314 { 315 int len; 316 u_char junk; 317 318 printf("sc%d: abort phase=0x%x, ssts=0x%x, ints=0x%x\n", 319 hs->sc_unit, hd->scsi_psns, hd->scsi_ssts, hd->scsi_ints); 320 321 if (hd->scsi_ints != 0) 322 hd->scsi_ints = hd->scsi_ints; 323 324 if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0) 325 /* no longer connected to scsi target */ 326 return; 327 328 /* get the number of bytes remaining in current xfer + fudge */ 329 len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl; 330 331 /* for that many bus cycles, try to send an abort msg */ 332 for (len += 1024; (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) { 333 hd->scsi_scmd = SCMD_SET_ATN; 334 335 while ((hd->scsi_psns & PSNS_REQ) == 0) { 336 if (! (hd->scsi_ssts & SSTS_INITIATOR)) 337 goto out; 338 DELAY(1); 339 } 340 341 if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE) 342 hd->scsi_scmd = SCMD_RST_ATN; 343 hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE; 344 345 if (hd->scsi_psns & PHASE_IO) { 346 /* one of the input phases - read & discard a byte */ 347 hd->scsi_scmd = SCMD_SET_ACK; 348 while (hd->scsi_psns & PSNS_REQ) 349 DELAY(1); 350 junk = hd->scsi_temp; 351 } else { 352 /* one of the output phases - send an abort msg */ 353 hd->scsi_temp = MSG_ABORT; 354 hd->scsi_scmd = SCMD_SET_ACK; 355 while (hd->scsi_psns & PSNS_REQ) 356 DELAY(1); 357 } 358 359 hd->scsi_scmd = SCMD_RST_ACK; 360 } 361 out: 362 /* 363 * Either the abort was successful & the bus is disconnected or 364 * the device didn't listen. If the latter, announce the problem. 365 * Either way, reset the card & the SPC. 366 */ 367 if (len < 0 && hs) 368 printf("sc%d: abort failed. phase=0x%x, ssts=0x%x\n", 369 hs->sc_unit, hd->scsi_psns, hd->scsi_ssts); 370 } 371 372 373 /* 374 * SCSI Command Handler 375 */ 376 377 int 378 scsi_test_unit_rdy(struct scsi_softc *sc, int target, int unit) 379 { 380 static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY }; 381 int status; 382 volatile int lock; 383 384 #ifdef DEBUG 385 printf("scsi_test_unit_rdy(%d,%d,%d): Start\n", 386 sc->sc_unit, target, unit); 387 #endif 388 389 cdb.lun = unit; 390 391 if (!(scrun(sc, target, (void *)&cdb, 6, NULL, 0, &lock))) { 392 #ifdef DEBUG 393 printf("scsi_test_unit_rdy: Command Transfer Failed.\n"); 394 #endif 395 return(-1); 396 } 397 398 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) { 399 if (scintr(sc)) 400 DELAY(10); 401 } 402 403 status = scfinish(sc); 404 405 if (lock == SC_IO_COMPLETE) { 406 #ifdef DEBUG 407 printf("scsi_test_unit_rdy: Status -- 0x%x\n", status); 408 #endif 409 return(status); 410 } else { 411 return(lock); 412 } 413 } 414 415 int 416 scsi_request_sense(struct scsi_softc *sc, int target, int unit, u_char *buf, 417 unsigned int len) 418 { 419 static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE }; 420 int status; 421 volatile int lock; 422 423 #ifdef DEBUG 424 printf("scsi_request_sense: Start\n"); 425 #endif 426 427 cdb.lun = unit; 428 cdb.len = len; 429 430 if (!(scrun(sc, target, (void *)&cdb, 6, buf, len, &lock))) { 431 #ifdef DEBUG 432 printf("scsi_request_sense: Command Transfer Failed.\n"); 433 #endif 434 return(-1); 435 } 436 437 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) { 438 if (scintr(sc)) 439 DELAY(10); 440 } 441 442 status = scfinish(sc); 443 444 if (lock == SC_IO_COMPLETE) { 445 #ifdef DEBUG 446 printf("scsi_request_sense: Status -- 0x%x\n", status); 447 #endif 448 return(status); 449 } else { 450 return(lock); 451 } 452 } 453 454 int 455 scsi_immed_command(struct scsi_softc *sc, int target, int unit, 456 struct scsi_generic_cdb *cdb, u_char *buf, unsigned int len) 457 { 458 int status; 459 volatile int lock; 460 461 #ifdef DEBUG 462 printf("scsi_immed_command( %d, %d, %d, cdb(%d), buf, %d): Start\n", 463 sc->sc_unit, target, unit, cdb->len, len); 464 #endif 465 466 cdb->cdb[1] |= unit << 5; 467 468 if (!(scrun(sc, target, (void *)&cdb->cdb[0], cdb->len, buf, len, 469 &lock))) { 470 #ifdef DEBUG 471 printf("scsi_immed_command: Command Transfer Failed.\n"); 472 #endif 473 return(-1); 474 } 475 476 while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) { 477 if (scintr(sc)) 478 DELAY(10); 479 } 480 481 status = scfinish(sc); 482 483 if (lock == SC_IO_COMPLETE) { 484 #ifdef DEBUG 485 printf("scsi_immed_command: Status -- 0x%x\n", status); 486 #endif 487 return(status); 488 } else { 489 return(lock); 490 } 491 } 492 493 /* 494 * Interrupt Routine 495 */ 496 497 int 498 scintr(struct scsi_softc *hs) 499 { 500 struct scsidevice *hd; 501 u_char ints, temp; 502 u_char *buf; 503 int i, len; 504 505 hd = hs->sc_sd; 506 if ((ints = hd->scsi_ints) == 0) 507 return -1; 508 509 #ifdef DEBUG 510 printf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x 0x%x\n", 511 ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns, 512 hs->sc_phase); 513 #endif 514 if (ints & INTS_RESEL) { 515 if (hs->sc_phase == BUS_FREE_PHASE) { 516 temp = hd->scsi_temp & ~(1 << SCSI_ID); 517 for (i = 0; temp != 1; i++) { 518 temp >>= 1; 519 } 520 hs->sc_target = i; 521 *(hs->sc_lock) = SC_IN_PROGRESS; 522 } else 523 goto abort; 524 } else if (ints & INTS_DISCON) { 525 if (hs->sc_msg[0] == MSG_CMD_COMPLETE || 526 hs->sc_msg[0] == MSG_DISCONNECT) { 527 hs->sc_phase = BUS_FREE_PHASE; 528 hs->sc_target = SCSI_ID; 529 if (hs->sc_msg[0] == MSG_CMD_COMPLETE) 530 /* SCSI IO complete */ 531 *(hs->sc_lock) = SC_IO_COMPLETE; 532 else 533 /* Cisconnected from Target */ 534 *(hs->sc_lock) = SC_DISCONNECTED; 535 hd->scsi_ints = ints; 536 return 0; 537 } else 538 goto abort; 539 } else if (ints & INTS_CMD_DONE) { 540 if (hs->sc_phase == BUS_FREE_PHASE) 541 goto abort; 542 else if (hs->sc_phase == MESG_IN_PHASE) { 543 hd->scsi_scmd = SCMD_RST_ACK; 544 hd->scsi_ints = ints; 545 hs->sc_phase = hd->scsi_psns & PHASE; 546 return 0; 547 } 548 if (hs->sc_flags & SC_SEL_TIMEOUT) 549 hs->sc_flags &= ~SC_SEL_TIMEOUT; 550 } else if (ints & INTS_SRV_REQ) { 551 if (hs->sc_phase != MESG_IN_PHASE) 552 goto abort; 553 } else if (ints & INTS_TIMEOUT) { 554 if (hs->sc_phase == ARB_SEL_PHASE) { 555 if (hs->sc_flags & SC_SEL_TIMEOUT) { 556 hs->sc_flags &= ~SC_SEL_TIMEOUT; 557 hs->sc_phase = BUS_FREE_PHASE; 558 hs->sc_target = SCSI_ID; 559 /* Such SCSI Device is not connected . */ 560 *(hs->sc_lock) = SC_DEV_NOT_FOUND; 561 hd->scsi_ints = ints; 562 return 0; 563 } else { 564 /* wait more 250 usec */ 565 hs->sc_flags |= SC_SEL_TIMEOUT; 566 hd->scsi_temp = 0; 567 hd->scsi_tch = 0; 568 hd->scsi_tcm = 0x06; 569 hd->scsi_tcl = 0x40; 570 hd->scsi_ints = ints; 571 return 0; 572 } 573 } else 574 goto abort; 575 } else 576 goto abort; 577 578 hd->scsi_ints = ints; 579 580 /* 581 * Next SCSI Transfer 582 */ 583 584 while ((hd->scsi_psns & PSNS_REQ) == 0) { 585 DELAY(1); 586 } 587 588 hs->sc_phase = hd->scsi_psns & PHASE; 589 590 if (hs->sc_phase == DATA_OUT_PHASE || hs->sc_phase == DATA_IN_PHASE) { 591 len = hs->sc_len; 592 buf = hs->sc_buf; 593 } else if (hs->sc_phase == CMD_PHASE) { 594 len = hs->sc_cdblen; 595 buf = hs->sc_cdb; 596 } else if (hs->sc_phase == STATUS_PHASE) { 597 len = 1; 598 buf = &hs->sc_stat; 599 } else { 600 len = 1; 601 buf = hs->sc_msg; 602 } 603 604 ixfer_start(hd, len, hs->sc_phase, 0); 605 if (hs->sc_phase & PHASE_IO) 606 ixfer_in(hd, len, buf); 607 else 608 ixfer_out(hd, len, buf); 609 610 return 0; 611 612 /* 613 * SCSI Abort 614 */ 615 abort: 616 /* SCSI IO failed */ 617 scabort(hs, hd); 618 hd->scsi_ints = ints; 619 *(hs->sc_lock) = SC_IO_FAILED; 620 return -1; 621 } 622