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