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