1 /* $NetBSD: mac68k5380.c,v 1.27 1996/10/13 03:21:23 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Allen Briggs 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Allen Briggs 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * Derived from atari5380.c for the mac68k port of NetBSD. 33 * 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 #include <sys/dkstat.h> 41 #include <sys/syslog.h> 42 #include <sys/buf.h> 43 #include <scsi/scsi_all.h> 44 #include <scsi/scsi_message.h> 45 #include <scsi/scsiconf.h> 46 47 /* 48 * Include the driver definitions 49 */ 50 #include "ncr5380reg.h" 51 52 #include <machine/stdarg.h> 53 #include <machine/viareg.h> 54 55 #include "ncr5380var.h" 56 57 /* 58 * Set the various driver options 59 */ 60 #define NREQ 18 /* Size of issue queue */ 61 #define AUTO_SENSE 1 /* Automatically issue a request-sense */ 62 63 #define DRNAME ncrscsi /* used in various prints */ 64 #undef DBG_SEL /* Show the selection process */ 65 #undef DBG_REQ /* Show enqueued/ready requests */ 66 #undef DBG_NOWRITE /* Do not allow writes to the targets */ 67 #undef DBG_PIO /* Show the polled-I/O process */ 68 #undef DBG_INF /* Show information transfer process */ 69 #define DBG_NOSTATIC /* No static functions, all in DDB trace*/ 70 #define DBG_PID 25 /* Keep track of driver */ 71 #ifdef DBG_NOSTATIC 72 # define static 73 #endif 74 #ifdef DBG_SEL 75 # define DBG_SELPRINT(a,b) printf(a,b) 76 #else 77 # define DBG_SELPRINT(a,b) 78 #endif 79 #ifdef DBG_PIO 80 # define DBG_PIOPRINT(a,b,c) printf(a,b,c) 81 #else 82 # define DBG_PIOPRINT(a,b,c) 83 #endif 84 #ifdef DBG_INF 85 # define DBG_INFPRINT(a,b,c) a(b,c) 86 #else 87 # define DBG_INFPRINT(a,b,c) 88 #endif 89 #ifdef DBG_PID 90 /* static char *last_hit = NULL, *olast_hit = NULL; */ 91 static char *last_hit[DBG_PID]; 92 # define PID(a) \ 93 { int i; \ 94 for (i=0; i< DBG_PID-1; i++) \ 95 last_hit[i] = last_hit[i+1]; \ 96 last_hit[DBG_PID-1] = a; } 97 #else 98 # define PID(a) 99 #endif 100 101 #undef REAL_DMA /* Use DMA if sensible */ 102 #define scsi_ipending() (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET) 103 #define fair_to_keep_dma() 1 104 #define claimed_dma() 1 105 #define reconsider_dma() 106 #define USE_PDMA 1 /* Use special pdma-transfer function */ 107 #define MIN_PHYS 0x2000 /* pdma space w/ /DSACK is only 0x2000 */ 108 109 #define ENABLE_NCR5380(sc) cur_softc = sc; 110 111 /* 112 * softc of currently active controller (well, we only have one for now). 113 */ 114 115 static struct ncr_softc *cur_softc; 116 117 struct scsi_5380 { 118 volatile u_char scsi_5380[8*16]; /* 8 regs, 1 every 16th byte. */ 119 }; 120 121 extern vm_offset_t SCSIBase; 122 static volatile u_char *ncr = (volatile u_char *) 0x10000; 123 static volatile u_char *ncr_5380_with_drq = (volatile u_char *) 0x6000; 124 static volatile u_char *ncr_5380_without_drq = (volatile u_char *) 0x12000; 125 126 #define SCSI_5380 ((struct scsi_5380 *) ncr) 127 #define GET_5380_REG(rnum) SCSI_5380->scsi_5380[((rnum)<<4)] 128 #define SET_5380_REG(rnum,val) (SCSI_5380->scsi_5380[((rnum)<<4)] = (val)) 129 130 static void ncr5380_irq_intr(void *); 131 static void ncr5380_drq_intr(void *); 132 static void do_ncr5380_drq_intr __P((void *)); 133 134 static __inline__ void scsi_clr_ipend __P((void)); 135 static void scsi_mach_init __P((struct ncr_softc *sc)); 136 static int machine_match __P((struct device *pdp, void *match, 137 void *auxp, struct cfdriver *cd)); 138 static __inline__ int pdma_ready __P((void)); 139 static int transfer_pdma __P((u_char *phasep, u_char *data, 140 u_long *count)); 141 142 static __inline__ void 143 scsi_clr_ipend() 144 { 145 int tmp; 146 147 tmp = GET_5380_REG(NCR5380_IRCV); 148 scsi_clear_irq(); 149 } 150 151 static void 152 scsi_mach_init(sc) 153 struct ncr_softc *sc; 154 { 155 static int initted = 0; 156 157 if (initted++) 158 panic("scsi_mach_init called again.\n"); 159 160 ncr = (volatile u_char *) 161 (SCSIBase + (u_long) ncr); 162 ncr_5380_with_drq = (volatile u_char *) 163 (SCSIBase + (u_int) ncr_5380_with_drq); 164 ncr_5380_without_drq = (volatile u_char *) 165 (SCSIBase + (u_int) ncr_5380_without_drq); 166 167 if (VIA2 == VIA2OFF) { 168 scsi_enable = Via1Base + VIA2 * 0x2000 + vIER; 169 scsi_flag = Via1Base + VIA2 * 0x2000 + vIFR; 170 } else { 171 scsi_enable = Via1Base + VIA2 * 0x2000 + rIER; 172 scsi_flag = Via1Base + VIA2 * 0x2000 + rIFR; 173 } 174 175 mac68k_register_scsi_irq(ncr5380_irq_intr, sc); 176 mac68k_register_scsi_drq(ncr5380_drq_intr, sc); 177 } 178 179 static int 180 machine_match(pdp, match, auxp, cd) 181 struct device *pdp; 182 void *match, *auxp; 183 struct cfdriver *cd; 184 { 185 if (!mac68k_machine.scsi80) 186 return 0; 187 return 1; 188 } 189 190 #if USE_PDMA 191 int pdma_5380_dir = 0; 192 193 u_char *pending_5380_data; 194 u_long pending_5380_count; 195 196 #define NCR5380_PDMA_DEBUG 1 /* Maybe we try with this off eventually. */ 197 198 #if NCR5380_PDMA_DEBUG 199 int pdma_5380_sends = 0; 200 int pdma_5380_bytes = 0; 201 202 void 203 pdma_stat() 204 { 205 printf("PDMA SCSI: %d xfers completed for %d bytes.\n", 206 pdma_5380_sends, pdma_5380_bytes); 207 printf("pdma_5380_dir = %d\t", 208 pdma_5380_dir); 209 printf("datap = %p, remainder = %ld.\n", 210 pending_5380_data, pending_5380_count); 211 scsi_show(); 212 } 213 #endif 214 215 void 216 pdma_cleanup(void) 217 { 218 SC_REQ *reqp = connected; 219 int s; 220 221 s = splbio(); 222 PID("pdma_cleanup0"); 223 224 pdma_5380_dir = 0; 225 226 #if NCR5380_PDMA_DEBUG 227 pdma_5380_sends++; 228 pdma_5380_bytes+=(reqp->xdata_len - pending_5380_count); 229 #endif 230 231 /* 232 * Update pointers. 233 */ 234 reqp->xdata_ptr += reqp->xdata_len - pending_5380_count; 235 reqp->xdata_len = pending_5380_count; 236 237 /* 238 * Reset DMA mode. 239 */ 240 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA); 241 242 /* 243 * Clear any pending interrupts. 244 */ 245 scsi_clr_ipend(); 246 247 /* 248 * Tell interrupt functions that DMA has ended. 249 */ 250 reqp->dr_flag &= ~DRIVER_IN_DMA; 251 252 SET_5380_REG(NCR5380_MODE, IMODE_BASE); 253 SET_5380_REG(NCR5380_ICOM, 0); 254 255 splx(s); 256 257 /* 258 * Back for more punishment. 259 */ 260 PID("pdma_cleanup1"); 261 run_main(cur_softc); 262 PID("pdma_cleanup2"); 263 } 264 #endif 265 266 static __inline__ int 267 pdma_ready() 268 { 269 #if USE_PDMA 270 SC_REQ *reqp = connected; 271 int dmstat, idstat; 272 extern u_char ncr5380_no_parchk; 273 274 PID("pdma_ready0"); 275 if (pdma_5380_dir) { 276 PID("pdma_ready1."); 277 /* 278 * For a phase mis-match, ATN is a "don't care," IRQ is 1 and 279 * all other bits in the Bus & Status Register are 0. Also, 280 * the current SCSI Bus Status Register has a 1 for BSY and 281 * REQ. Since we're just checking that this interrupt isn't a 282 * reselection or a reset, we just check for either. 283 */ 284 dmstat = GET_5380_REG(NCR5380_DMSTAT); 285 idstat = GET_5380_REG(NCR5380_IDSTAT); 286 if ( ((dmstat & (0xff & ~SC_ATN_STAT)) == SC_IRQ_SET) 287 && ((idstat & (SC_S_BSY|SC_S_REQ)) 288 == (SC_S_BSY | SC_S_REQ)) ) { 289 PID("pdma_ready2"); 290 pdma_cleanup(); 291 return 1; 292 } else if (PH_IN(reqp->phase) && (dmstat & SC_PAR_ERR)) { 293 if (!(ncr5380_no_parchk & (1 << reqp->targ_id))) 294 /* XXX: Should be parity error ???? */ 295 reqp->xs->error = XS_DRIVER_STUFFUP; 296 PID("pdma_ready3"); 297 /* XXX: is this the right reaction? */ 298 pdma_cleanup(); 299 return 1; 300 } else if ( !(idstat & SC_S_REQ) 301 || (((idstat>>2) & 7) != reqp->phase)) { 302 #ifdef DIAGNOSTIC 303 /* XXX: is this the right reaction? Can this happen? */ 304 scsi_show(); 305 printf("Unexpected phase change.\n"); 306 #endif 307 reqp->xs->error = XS_DRIVER_STUFFUP; 308 pdma_cleanup(); 309 return 1; 310 } else { 311 scsi_show(); 312 panic("Spurious interrupt during PDMA xfer.\n"); 313 } 314 } else 315 PID("pdma_ready4"); 316 #endif 317 return 0; 318 } 319 320 static void 321 ncr5380_irq_intr(p) 322 void *p; 323 { 324 PID("irq"); 325 326 #if USE_PDMA 327 if (pdma_ready()) { 328 return; 329 } 330 #endif 331 scsi_idisable(); 332 ncr_ctrl_intr(cur_softc); 333 } 334 335 /* 336 * This is the meat of the PDMA transfer. 337 * When we get here, we shove data as fast as the mac can take it. 338 * We depend on several things: 339 * * All macs after the Mac Plus that have a 5380 chip should have a general 340 * logic IC that handshakes data for blind transfers. 341 * * If the SCSI controller finishes sending/receiving data before we do, 342 * the same general logic IC will generate a /BERR for us in short order. 343 * * The fault address for said /BERR minus the base address for the 344 * transfer will be the amount of data that was actually written. 345 * 346 * We use the nofault flag and the setjmp/longjmp in locore.s so we can 347 * detect and handle the bus error for early termination of a command. 348 * This is usually caused by a disconnecting target. 349 */ 350 static void 351 do_ncr5380_drq_intr(p) 352 void *p; 353 { 354 #if USE_PDMA 355 extern int *nofault, mac68k_buserr_addr; 356 label_t faultbuf; 357 register int count; 358 volatile u_int32_t *long_drq; 359 u_int32_t *long_data; 360 volatile u_int8_t *drq, tmp_data; 361 u_int8_t *data; 362 363 #if DBG_PID 364 if (pdma_5380_dir == 2) { 365 PID("drq (in)"); 366 } else { 367 PID("drq (out)"); 368 } 369 #endif 370 371 /* 372 * Setup for a possible bus error caused by SCSI controller 373 * switching out of DATA-IN/OUT before we're done with the 374 * current transfer. 375 */ 376 nofault = (int *) &faultbuf; 377 378 if (setjmp((label_t *) nofault)) { 379 PID("drq berr"); 380 nofault = (int *) 0; 381 count = ( (u_long) mac68k_buserr_addr 382 - (u_long) ncr_5380_with_drq); 383 if ((count < 0) || (count > pending_5380_count)) { 384 printf("pdma %s: cnt = %d (0x%x) (pending cnt %ld)\n", 385 (pdma_5380_dir == 2) ? "in" : "out", 386 count, count, pending_5380_count); 387 panic("something is wrong"); 388 } 389 390 pending_5380_data += count; 391 pending_5380_count -= count; 392 393 mac68k_buserr_addr = 0; 394 395 PID("end drq early"); 396 397 return; 398 } 399 400 if (pdma_5380_dir == 2) { /* Data In */ 401 int resid; 402 403 /* 404 * Get the dest address aligned. 405 */ 406 resid = count = min(pending_5380_count, 407 4 - (((int) pending_5380_data) & 0x3)); 408 if (count && (count < 4)) { 409 data = (u_int8_t *) pending_5380_data; 410 drq = (u_int8_t *) ncr_5380_with_drq; 411 while (count) { 412 #define R1 *data++ = *drq++ 413 R1; count--; 414 #undef R1 415 } 416 pending_5380_data += resid; 417 pending_5380_count -= resid; 418 } 419 420 /* 421 * Get ready to start the transfer. 422 */ 423 while (pending_5380_count) { 424 int dcount; 425 426 dcount = count = min(pending_5380_count, MIN_PHYS); 427 long_drq = (volatile u_int32_t *) ncr_5380_with_drq; 428 long_data = (u_int32_t *) pending_5380_data; 429 430 #define R4 *long_data++ = *long_drq++ 431 while ( count >= 64 ) { 432 R4; R4; R4; R4; R4; R4; R4; R4; 433 R4; R4; R4; R4; R4; R4; R4; R4; /* 64 */ 434 count -= 64; 435 } 436 while (count >= 4) { 437 R4; count -= 4; 438 } 439 #undef R4 440 data = (u_int8_t *) long_data; 441 drq = (u_int8_t *) long_drq; 442 while (count) { 443 #define R1 *data++ = *drq++ 444 R1; count--; 445 #undef R1 446 } 447 pending_5380_count -= dcount; 448 pending_5380_data += dcount; 449 } 450 } else { 451 int resid; 452 453 /* 454 * Get the source address aligned. 455 */ 456 resid = count = min(pending_5380_count, 457 4 - (((int) pending_5380_data) & 0x3)); 458 if (count && (count < 4)) { 459 data = (u_int8_t *) pending_5380_data; 460 drq = (u_int8_t *) ncr_5380_with_drq; 461 while (count) { 462 #define W1 *drq++ = *data++ 463 W1; count--; 464 #undef W1 465 } 466 pending_5380_data += resid; 467 pending_5380_count -= resid; 468 } 469 470 /* 471 * Get ready to start the transfer. 472 */ 473 while (pending_5380_count) { 474 int dcount; 475 476 dcount = count = min(pending_5380_count, MIN_PHYS); 477 long_drq = (volatile u_int32_t *) ncr_5380_with_drq; 478 long_data = (u_int32_t *) pending_5380_data; 479 480 #define W4 *long_drq++ = *long_data++ 481 while ( count >= 64 ) { 482 W4; W4; W4; W4; W4; W4; W4; W4; 483 W4; W4; W4; W4; W4; W4; W4; W4; /* 64 */ 484 count -= 64; 485 } 486 while (count >= 4) { 487 W4; count -= 4; 488 } 489 #undef W4 490 data = (u_int8_t *) long_data; 491 drq = (u_int8_t *) long_drq; 492 while (count) { 493 #define W1 *drq++ = *data++ 494 W1; count--; 495 #undef W1 496 } 497 pending_5380_count -= dcount; 498 pending_5380_data += dcount; 499 } 500 PID("write complete"); 501 502 drq = (volatile u_int8_t *) ncr_5380_with_drq; 503 tmp_data = *drq; 504 505 PID("read a byte?"); 506 507 nofault = (int *) 0; 508 } 509 510 /* 511 * OK. No bus error occurred above. Clear the nofault flag 512 * so we no longer short-circuit bus errors. 513 */ 514 nofault = (int *) 0; 515 516 PID("end drq"); 517 return; 518 #else 519 return; 520 #endif /* if USE_PDMA */ 521 } 522 523 static void 524 ncr5380_drq_intr(p) 525 void *p; 526 { 527 while (GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ) { 528 do_ncr5380_drq_intr(p); 529 scsi_clear_drq(); 530 } 531 } 532 533 #if USE_PDMA 534 535 #define SCSI_TIMEOUT_VAL 10000000 536 537 static int 538 transfer_pdma(phasep, data, count) 539 u_char *phasep; 540 u_char *data; 541 u_long *count; 542 { 543 SC_REQ *reqp = connected; 544 int len = *count, s, scsi_timeout = SCSI_TIMEOUT_VAL; 545 546 if (pdma_5380_dir) { 547 panic("ncrscsi: transfer_pdma called when operation already " 548 "pending.\n"); 549 } 550 PID("transfer_pdma0") 551 552 /* 553 * Don't bother with PDMA if we can't sleep or for small transfers. 554 */ 555 if (reqp->dr_flag & DRIVER_NOINT) { 556 PID("pdma, falling back to transfer_pio.") 557 transfer_pio(phasep, data, count, 0); 558 return -1; 559 } 560 561 /* 562 * We are probably already at spl2(), so this is likely a no-op. 563 * Paranoia. 564 */ 565 s = splbio(); 566 567 scsi_idisable(); 568 569 /* 570 * Match phases with target. 571 */ 572 SET_5380_REG(NCR5380_TCOM, *phasep); 573 574 /* 575 * Clear pending interrupts. 576 */ 577 scsi_clr_ipend(); 578 579 /* 580 * Wait until target asserts BSY. 581 */ 582 while ( ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0) 583 && (--scsi_timeout) ); 584 if (!scsi_timeout) { 585 #if DIAGNOSTIC 586 printf("scsi timeout: waiting for BSY in %s.\n", 587 (*phasep == PH_DATAOUT) ? "pdma_out" : "pdma_in"); 588 #endif 589 goto scsi_timeout_error; 590 } 591 592 /* 593 * Tell the driver that we're in DMA mode. 594 */ 595 reqp->dr_flag |= DRIVER_IN_DMA; 596 597 /* 598 * Load transfer values for DRQ interrupt handlers. 599 */ 600 pending_5380_data = data; 601 pending_5380_count = len; 602 603 /* 604 * Set the transfer function to be called on DRQ interrupts. 605 * And note that we're waiting. 606 */ 607 switch (*phasep) { 608 default: 609 panic("Unexpected phase in transfer_pdma.\n"); 610 case PH_DATAOUT: 611 pdma_5380_dir = 1; 612 SET_5380_REG(NCR5380_ICOM, GET_5380_REG(NCR5380_ICOM)|SC_ADTB); 613 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA); 614 SET_5380_REG(NCR5380_DMSTAT, 0); 615 break; 616 case PH_DATAIN: 617 pdma_5380_dir = 2; 618 SET_5380_REG(NCR5380_ICOM, 0); 619 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA); 620 SET_5380_REG(NCR5380_IRCV, 0); 621 break; 622 } 623 624 PID("waiting for interrupt.") 625 626 /* 627 * Now that we're set up, enable interrupts and drop processor 628 * priority back down. 629 */ 630 scsi_ienable(); 631 splx(s); 632 return 0; 633 634 scsi_timeout_error: 635 /* 636 * Clear the DMA mode. 637 */ 638 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA); 639 return -1; 640 } 641 #endif /* if USE_PDMA */ 642 643 /* Include general routines. */ 644 #include <mac68k/dev/ncr5380.c> 645