1 /* $NetBSD: mac68k5380.c,v 1.44 2005/12/24 23:24:00 perry 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.44 2005/12/24 23:24:00 perry 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 const 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 ((volatile 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(void *); 140 141 static inline void scsi_clr_ipend(void); 142 static void scsi_mach_init(struct ncr_softc *); 143 static int machine_match(struct device *, struct cfdata *, void *, 144 struct cfdriver *); 145 static inline int pdma_ready(void); 146 static int transfer_pdma(u_char *, u_char *, u_long *); 147 148 static inline void 149 scsi_clr_ipend(void) 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(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(struct device *parent, struct cfdata *cf, 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(void) 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(void) 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."); 316 } 317 } else 318 PID("pdma_ready4"); 319 #endif 320 return 0; 321 } 322 323 static void 324 ncr5380_irq_intr(void *p) 325 { 326 PID("irq"); 327 328 #if USE_PDMA 329 if (pdma_ready()) { 330 return; 331 } 332 #endif 333 scsi_idisable(); 334 ncr_ctrl_intr(cur_softc); 335 } 336 337 /* 338 * This is the meat of the PDMA transfer. 339 * When we get here, we shove data as fast as the mac can take it. 340 * We depend on several things: 341 * * All macs after the Mac Plus that have a 5380 chip should have a general 342 * logic IC that handshakes data for blind transfers. 343 * * If the SCSI controller finishes sending/receiving data before we do, 344 * the same general logic IC will generate a /BERR for us in short order. 345 * * The fault address for said /BERR minus the base address for the 346 * transfer will be the amount of data that was actually written. 347 * 348 * We use the nofault flag and the setjmp/longjmp in locore.s so we can 349 * detect and handle the bus error for early termination of a command. 350 * This is usually caused by a disconnecting target. 351 */ 352 static void 353 do_ncr5380_drq_intr(void *p) 354 { 355 #if USE_PDMA 356 extern int *nofault, m68k_fault_addr; 357 label_t faultbuf; 358 register int count; 359 volatile u_int32_t *long_drq; 360 u_int32_t *long_data; 361 volatile u_int8_t *drq, tmp_data; 362 u_int8_t *data; 363 364 #if DBG_PID 365 if (pdma_5380_dir == 2) { 366 PID("drq (in)"); 367 } else { 368 PID("drq (out)"); 369 } 370 #endif 371 372 /* 373 * Setup for a possible bus error caused by SCSI controller 374 * switching out of DATA-IN/OUT before we're done with the 375 * current transfer. 376 */ 377 nofault = (int *) &faultbuf; 378 379 if (setjmp((label_t *) nofault)) { 380 PID("drq berr"); 381 nofault = (int *) 0; 382 count = ( (u_long) m68k_fault_addr 383 - (u_long) ncr_5380_with_drq); 384 if ((count < 0) || (count > pending_5380_count)) { 385 printf("pdma %s: cnt = %d (0x%x) (pending cnt %ld)\n", 386 (pdma_5380_dir == 2) ? "in" : "out", 387 count, count, pending_5380_count); 388 panic("something is wrong"); 389 } 390 391 pending_5380_data += count; 392 pending_5380_count -= count; 393 394 m68k_fault_addr = 0; 395 396 PID("end drq early"); 397 398 return; 399 } 400 401 if (pdma_5380_dir == 2) { /* Data In */ 402 int resid; 403 404 /* 405 * Get the dest address aligned. 406 */ 407 resid = count = min(pending_5380_count, 408 4 - (((int) pending_5380_data) & 0x3)); 409 if (count && (count < 4)) { 410 data = (u_int8_t *) pending_5380_data; 411 drq = (volatile u_int8_t *) ncr_5380_with_drq; 412 while (count) { 413 #define R1 *data++ = *drq++ 414 R1; count--; 415 #undef R1 416 } 417 pending_5380_data += resid; 418 pending_5380_count -= resid; 419 } 420 421 /* 422 * Get ready to start the transfer. 423 */ 424 while (pending_5380_count) { 425 int dcount; 426 427 dcount = count = min(pending_5380_count, MIN_PHYS); 428 long_drq = (volatile u_int32_t *) ncr_5380_with_drq; 429 long_data = (u_int32_t *) pending_5380_data; 430 431 #define R4 *long_data++ = *long_drq++ 432 while ( count > 64 ) { 433 R4; R4; R4; R4; R4; R4; R4; R4; 434 R4; R4; R4; R4; R4; R4; R4; R4; /* 64 */ 435 count -= 64; 436 } 437 while (count > 8) { 438 R4; R4; count -= 8; 439 } 440 #undef R4 441 data = (u_int8_t *) long_data; 442 drq = (volatile u_int8_t *) long_drq; 443 while (count) { 444 #define R1 *data++ = *drq++ 445 R1; count--; 446 #undef R1 447 } 448 pending_5380_count -= dcount; 449 pending_5380_data += dcount; 450 } 451 } else { 452 int resid; 453 454 /* 455 * Get the source address aligned. 456 */ 457 resid = count = min(pending_5380_count, 458 4 - (((int) pending_5380_data) & 0x3)); 459 if (count && (count < 4)) { 460 data = (u_int8_t *) pending_5380_data; 461 drq = (volatile u_int8_t *) ncr_5380_with_drq; 462 while (count) { 463 #define W1 *drq++ = *data++ 464 W1; count--; 465 #undef W1 466 } 467 pending_5380_data += resid; 468 pending_5380_count -= resid; 469 } 470 471 /* 472 * Get ready to start the transfer. 473 */ 474 while (pending_5380_count) { 475 int dcount; 476 477 dcount = count = min(pending_5380_count, MIN_PHYS); 478 long_drq = (volatile u_int32_t *) ncr_5380_with_drq; 479 long_data = (u_int32_t *) pending_5380_data; 480 481 #define W4 *long_drq++ = *long_data++ 482 while ( count > 64 ) { 483 W4; W4; W4; W4; W4; W4; W4; W4; 484 W4; W4; W4; W4; W4; W4; W4; W4; /* 64 */ 485 count -= 64; 486 } 487 while ( count > 8 ) { 488 W4; W4; 489 count -= 8; 490 } 491 #undef W4 492 data = (u_int8_t *) long_data; 493 drq = (volatile u_int8_t *) long_drq; 494 while (count) { 495 #define W1 *drq++ = *data++ 496 W1; count--; 497 #undef W1 498 } 499 pending_5380_count -= dcount; 500 pending_5380_data += dcount; 501 } 502 503 PID("write complete"); 504 505 drq = (volatile u_int8_t *) ncr_5380_with_drq; 506 tmp_data = *drq; 507 508 PID("read a byte to force a phase change"); 509 } 510 511 /* 512 * OK. No bus error occurred above. Clear the nofault flag 513 * so we no longer short-circuit bus errors. 514 */ 515 nofault = (int *) 0; 516 517 PID("end drq"); 518 return; 519 #else 520 return; 521 #endif /* if USE_PDMA */ 522 } 523 524 static void 525 ncr5380_drq_intr(void *p) 526 { 527 while (GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ) { 528 do_ncr5380_drq_intr(p); 529 scsi_clear_drq(); 530 } 531 } 532 533 #if USE_PDMA 534 535 #define SCSI_TIMEOUT_VAL 10000000 536 537 static int 538 transfer_pdma(u_char *phasep, u_char *data, u_long *count) 539 { 540 SC_REQ *reqp = connected; 541 int len = *count, s, scsi_timeout = SCSI_TIMEOUT_VAL; 542 543 if (pdma_5380_dir) { 544 panic("ncrscsi: transfer_pdma called when operation already " 545 "pending."); 546 } 547 PID("transfer_pdma0") 548 549 /* 550 * Don't bother with PDMA if we can't sleep or for small transfers. 551 */ 552 if (reqp->dr_flag & DRIVER_NOINT) { 553 PID("pdma, falling back to transfer_pio.") 554 transfer_pio(phasep, data, count, 0); 555 return -1; 556 } 557 558 /* 559 * We are probably already at spl2(), so this is likely a no-op. 560 * Paranoia. 561 */ 562 s = splbio(); 563 564 scsi_idisable(); 565 566 /* 567 * Match phases with target. 568 */ 569 SET_5380_REG(NCR5380_TCOM, *phasep); 570 571 /* 572 * Clear pending interrupts. 573 */ 574 scsi_clr_ipend(); 575 576 /* 577 * Wait until target asserts BSY. 578 */ 579 while ( ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0) 580 && (--scsi_timeout) ); 581 if (!scsi_timeout) { 582 #if DIAGNOSTIC 583 printf("scsi timeout: waiting for BSY in %s.\n", 584 (*phasep == PH_DATAOUT) ? "pdma_out" : "pdma_in"); 585 #endif 586 goto scsi_timeout_error; 587 } 588 589 /* 590 * Tell the driver that we're in DMA mode. 591 */ 592 reqp->dr_flag |= DRIVER_IN_DMA; 593 594 /* 595 * Load transfer values for DRQ interrupt handlers. 596 */ 597 pending_5380_data = data; 598 pending_5380_count = len; 599 600 /* 601 * Set the transfer function to be called on DRQ interrupts. 602 * And note that we're waiting. 603 */ 604 switch (*phasep) { 605 default: 606 panic("Unexpected phase in transfer_pdma."); 607 case PH_DATAOUT: 608 pdma_5380_dir = 1; 609 SET_5380_REG(NCR5380_ICOM, GET_5380_REG(NCR5380_ICOM)|SC_ADTB); 610 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA); 611 SET_5380_REG(NCR5380_DMSTAT, 0); 612 break; 613 case PH_DATAIN: 614 pdma_5380_dir = 2; 615 SET_5380_REG(NCR5380_ICOM, 0); 616 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA); 617 SET_5380_REG(NCR5380_IRCV, 0); 618 break; 619 } 620 621 PID("waiting for interrupt.") 622 623 /* 624 * Now that we're set up, enable interrupts and drop processor 625 * priority back down. 626 */ 627 scsi_ienable(); 628 splx(s); 629 return 0; 630 631 scsi_timeout_error: 632 /* 633 * Clear the DMA mode. 634 */ 635 SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA); 636 return -1; 637 } 638 #endif /* if USE_PDMA */ 639 640 /* Include general routines. */ 641 #include <mac68k/dev/ncr5380.c> 642