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