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