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