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