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