1 /* 2 * Generic Macintosh NCR5380 driver 3 * 4 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov> 5 * 6 * derived in part from: 7 */ 8 /* 9 * Generic Generic NCR5380 driver 10 * 11 * Copyright 1995, Russell King 12 * 13 * ALPHA RELEASE 1. 14 * 15 * For more information, please consult 16 * 17 * NCR 5380 Family 18 * SCSI Protocol Controller 19 * Databook 20 * 21 * NCR Microelectronics 22 * 1635 Aeroplaza Drive 23 * Colorado Springs, CO 80916 24 * 1+ (719) 578-3400 25 * 1+ (800) 334-5454 26 */ 27 28 /* 29 * $Log: mac_NCR5380.c,v $ 30 */ 31 32 #include <linux/types.h> 33 #include <linux/stddef.h> 34 #include <linux/ctype.h> 35 #include <linux/delay.h> 36 37 #include <linux/module.h> 38 #include <linux/signal.h> 39 #include <linux/sched.h> 40 #include <linux/ioport.h> 41 #include <linux/init.h> 42 #include <linux/blkdev.h> 43 #include <linux/interrupt.h> 44 45 #include <asm/io.h> 46 #include <asm/irq.h> 47 #include <asm/system.h> 48 49 #include <asm/macintosh.h> 50 #include <asm/macints.h> 51 #include <asm/machw.h> 52 #include <asm/mac_via.h> 53 54 #include "scsi.h" 55 #include <scsi/scsi_host.h> 56 #include "mac_scsi.h" 57 #include "NCR5380.h" 58 59 #if 0 60 #define NDEBUG (NDEBUG_INTR | NDEBUG_PSEUDO_DMA | NDEBUG_ARBITRATION | NDEBUG_SELECTION | NDEBUG_RESELECTION) 61 #else 62 #define NDEBUG (NDEBUG_ABORT) 63 #endif 64 65 #define RESET_BOOT 66 #define DRIVER_SETUP 67 68 extern void via_scsi_clear(void); 69 70 #ifdef RESET_BOOT 71 static void mac_scsi_reset_boot(struct Scsi_Host *instance); 72 #endif 73 74 static int setup_called = 0; 75 static int setup_can_queue = -1; 76 static int setup_cmd_per_lun = -1; 77 static int setup_sg_tablesize = -1; 78 static int setup_use_pdma = -1; 79 #ifdef SUPPORT_TAGS 80 static int setup_use_tagged_queuing = -1; 81 #endif 82 static int setup_hostid = -1; 83 84 /* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms, 85 * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more 86 * need ten times the standard value... */ 87 #define TOSHIBA_DELAY 88 89 #ifdef TOSHIBA_DELAY 90 #define AFTER_RESET_DELAY (5*HZ/2) 91 #else 92 #define AFTER_RESET_DELAY (HZ/2) 93 #endif 94 95 static volatile unsigned char *mac_scsi_regp = NULL; 96 static volatile unsigned char *mac_scsi_drq = NULL; 97 static volatile unsigned char *mac_scsi_nodrq = NULL; 98 99 100 /* 101 * NCR 5380 register access functions 102 */ 103 104 #if 0 105 /* Debug versions */ 106 #define CTRL(p,v) (*ctrl = (v)) 107 108 static char macscsi_read(struct Scsi_Host *instance, int reg) 109 { 110 int iobase = instance->io_port; 111 int i; 112 int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; 113 114 CTRL(iobase, 0); 115 i = in_8(iobase + (reg<<4)); 116 CTRL(iobase, 0x40); 117 118 return i; 119 } 120 121 static void macscsi_write(struct Scsi_Host *instance, int reg, int value) 122 { 123 int iobase = instance->io_port; 124 int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; 125 126 CTRL(iobase, 0); 127 out_8(iobase + (reg<<4), value); 128 CTRL(iobase, 0x40); 129 } 130 #else 131 132 /* Fast versions */ 133 static __inline__ char macscsi_read(struct Scsi_Host *instance, int reg) 134 { 135 return in_8(instance->io_port + (reg<<4)); 136 } 137 138 static __inline__ void macscsi_write(struct Scsi_Host *instance, int reg, int value) 139 { 140 out_8(instance->io_port + (reg<<4), value); 141 } 142 #endif 143 144 145 /* 146 * Function : mac_scsi_setup(char *str) 147 * 148 * Purpose : booter command line initialization of the overrides array, 149 * 150 * Inputs : str - comma delimited list of options 151 * 152 */ 153 154 static int __init mac_scsi_setup(char *str) { 155 #ifdef DRIVER_SETUP 156 int ints[7]; 157 158 (void)get_options( str, ARRAY_SIZE(ints), ints); 159 160 if (setup_called++ || ints[0] < 1 || ints[0] > 6) { 161 printk(KERN_WARNING "scsi: <mac5380>" 162 " Usage: mac5380=<can_queue>[,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>,<use_pdma>]\n"); 163 printk(KERN_ALERT "scsi: <mac5380> Bad Penguin parameters?\n"); 164 return 0; 165 } 166 167 if (ints[0] >= 1) { 168 if (ints[1] > 0) 169 /* no limits on this, just > 0 */ 170 setup_can_queue = ints[1]; 171 } 172 if (ints[0] >= 2) { 173 if (ints[2] > 0) 174 setup_cmd_per_lun = ints[2]; 175 } 176 if (ints[0] >= 3) { 177 if (ints[3] >= 0) { 178 setup_sg_tablesize = ints[3]; 179 /* Must be <= SG_ALL (255) */ 180 if (setup_sg_tablesize > SG_ALL) 181 setup_sg_tablesize = SG_ALL; 182 } 183 } 184 if (ints[0] >= 4) { 185 /* Must be between 0 and 7 */ 186 if (ints[4] >= 0 && ints[4] <= 7) 187 setup_hostid = ints[4]; 188 else if (ints[4] > 7) 189 printk(KERN_WARNING "mac_scsi_setup: invalid host ID %d !\n", ints[4] ); 190 } 191 #ifdef SUPPORT_TAGS 192 if (ints[0] >= 5) { 193 if (ints[5] >= 0) 194 setup_use_tagged_queuing = !!ints[5]; 195 } 196 197 if (ints[0] == 6) { 198 if (ints[6] >= 0) 199 setup_use_pdma = ints[6]; 200 } 201 #else 202 if (ints[0] == 5) { 203 if (ints[5] >= 0) 204 setup_use_pdma = ints[5]; 205 } 206 #endif /* SUPPORT_TAGS */ 207 208 #endif /* DRIVER_SETUP */ 209 return 1; 210 } 211 212 __setup("mac5380=", mac_scsi_setup); 213 214 /* 215 * If you want to find the instance with (k)gdb ... 216 */ 217 #if NDEBUG 218 static struct Scsi_Host *default_instance; 219 #endif 220 221 /* 222 * Function : int macscsi_detect(struct scsi_host_template * tpnt) 223 * 224 * Purpose : initializes mac NCR5380 driver based on the 225 * command line / compile time port and irq definitions. 226 * 227 * Inputs : tpnt - template for this SCSI adapter. 228 * 229 * Returns : 1 if a host adapter was found, 0 if not. 230 * 231 */ 232 233 int macscsi_detect(struct scsi_host_template * tpnt) 234 { 235 static int called = 0; 236 int flags = 0; 237 struct Scsi_Host *instance; 238 239 if (!MACH_IS_MAC || called) 240 return( 0 ); 241 242 if (macintosh_config->scsi_type != MAC_SCSI_OLD) 243 return( 0 ); 244 245 /* setup variables */ 246 tpnt->can_queue = 247 (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE; 248 tpnt->cmd_per_lun = 249 (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN; 250 tpnt->sg_tablesize = 251 (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE; 252 253 if (setup_hostid >= 0) 254 tpnt->this_id = setup_hostid; 255 else { 256 /* use 7 as default */ 257 tpnt->this_id = 7; 258 } 259 260 #ifdef SUPPORT_TAGS 261 if (setup_use_tagged_queuing < 0) 262 setup_use_tagged_queuing = USE_TAGGED_QUEUING; 263 #endif 264 265 /* Once we support multiple 5380s (e.g. DuoDock) we'll do 266 something different here */ 267 instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); 268 #if NDEBUG 269 default_instance = instance; 270 #endif 271 272 if (macintosh_config->ident == MAC_MODEL_IIFX) { 273 mac_scsi_regp = via1+0x8000; 274 mac_scsi_drq = via1+0xE000; 275 mac_scsi_nodrq = via1+0xC000; 276 /* The IIFX should be able to do true DMA, but pseudo-dma doesn't work */ 277 flags = FLAG_NO_PSEUDO_DMA; 278 } else { 279 mac_scsi_regp = via1+0x10000; 280 mac_scsi_drq = via1+0x6000; 281 mac_scsi_nodrq = via1+0x12000; 282 } 283 284 if (! setup_use_pdma) 285 flags = FLAG_NO_PSEUDO_DMA; 286 287 instance->io_port = (unsigned long) mac_scsi_regp; 288 instance->irq = IRQ_MAC_SCSI; 289 290 #ifdef RESET_BOOT 291 mac_scsi_reset_boot(instance); 292 #endif 293 294 NCR5380_init(instance, flags); 295 296 instance->n_io_port = 255; 297 298 ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; 299 300 if (instance->irq != SCSI_IRQ_NONE) 301 if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, 302 "ncr5380", instance)) { 303 printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n", 304 instance->host_no, instance->irq); 305 instance->irq = SCSI_IRQ_NONE; 306 } 307 308 printk(KERN_INFO "scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port); 309 if (instance->irq == SCSI_IRQ_NONE) 310 printk (KERN_INFO "s disabled"); 311 else 312 printk (KERN_INFO " %d", instance->irq); 313 printk(KERN_INFO " options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", 314 instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE); 315 printk(KERN_INFO "\nscsi%d:", instance->host_no); 316 NCR5380_print_options(instance); 317 printk("\n"); 318 called = 1; 319 return 1; 320 } 321 322 int macscsi_release (struct Scsi_Host *shpnt) 323 { 324 if (shpnt->irq != SCSI_IRQ_NONE) 325 free_irq (shpnt->irq, NCR5380_intr); 326 NCR5380_exit(shpnt); 327 328 return 0; 329 } 330 331 #ifdef RESET_BOOT 332 /* 333 * Our 'bus reset on boot' function 334 */ 335 336 static void mac_scsi_reset_boot(struct Scsi_Host *instance) 337 { 338 unsigned long end; 339 340 NCR5380_local_declare(); 341 NCR5380_setup(instance); 342 343 /* 344 * Do a SCSI reset to clean up the bus during initialization. No messing 345 * with the queues, interrupts, or locks necessary here. 346 */ 347 348 printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." ); 349 350 /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ 351 disable_irq(IRQ_MAC_SCSI); 352 353 /* get in phase */ 354 NCR5380_write( TARGET_COMMAND_REG, 355 PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); 356 357 /* assert RST */ 358 NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); 359 /* The min. reset hold time is 25us, so 40us should be enough */ 360 udelay( 50 ); 361 /* reset RST and interrupt */ 362 NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); 363 NCR5380_read( RESET_PARITY_INTERRUPT_REG ); 364 365 for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) 366 barrier(); 367 368 /* switch on SCSI IRQ again */ 369 enable_irq(IRQ_MAC_SCSI); 370 371 printk(KERN_INFO " done\n" ); 372 } 373 #endif 374 375 const char * macscsi_info (struct Scsi_Host *spnt) { 376 return ""; 377 } 378 379 /* 380 Pseudo-DMA: (Ove Edlund) 381 The code attempts to catch bus errors that occur if one for example 382 "trips over the cable". 383 XXX: Since bus errors in the PDMA routines never happen on my 384 computer, the bus error code is untested. 385 If the code works as intended, a bus error results in Pseudo-DMA 386 beeing disabled, meaning that the driver switches to slow handshake. 387 If bus errors are NOT extremely rare, this has to be changed. 388 */ 389 390 #define CP_IO_TO_MEM(s,d,len) \ 391 __asm__ __volatile__ \ 392 (" cmp.w #4,%2\n" \ 393 " bls 8f\n" \ 394 " move.w %1,%%d0\n" \ 395 " neg.b %%d0\n" \ 396 " and.w #3,%%d0\n" \ 397 " sub.w %%d0,%2\n" \ 398 " bra 2f\n" \ 399 " 1: move.b (%0),(%1)+\n" \ 400 " 2: dbf %%d0,1b\n" \ 401 " move.w %2,%%d0\n" \ 402 " lsr.w #5,%%d0\n" \ 403 " bra 4f\n" \ 404 " 3: move.l (%0),(%1)+\n" \ 405 "31: move.l (%0),(%1)+\n" \ 406 "32: move.l (%0),(%1)+\n" \ 407 "33: move.l (%0),(%1)+\n" \ 408 "34: move.l (%0),(%1)+\n" \ 409 "35: move.l (%0),(%1)+\n" \ 410 "36: move.l (%0),(%1)+\n" \ 411 "37: move.l (%0),(%1)+\n" \ 412 " 4: dbf %%d0,3b\n" \ 413 " move.w %2,%%d0\n" \ 414 " lsr.w #2,%%d0\n" \ 415 " and.w #7,%%d0\n" \ 416 " bra 6f\n" \ 417 " 5: move.l (%0),(%1)+\n" \ 418 " 6: dbf %%d0,5b\n" \ 419 " and.w #3,%2\n" \ 420 " bra 8f\n" \ 421 " 7: move.b (%0),(%1)+\n" \ 422 " 8: dbf %2,7b\n" \ 423 " moveq.l #0, %2\n" \ 424 " 9: \n" \ 425 ".section .fixup,\"ax\"\n" \ 426 " .even\n" \ 427 "90: moveq.l #1, %2\n" \ 428 " jra 9b\n" \ 429 ".previous\n" \ 430 ".section __ex_table,\"a\"\n" \ 431 " .align 4\n" \ 432 " .long 1b,90b\n" \ 433 " .long 3b,90b\n" \ 434 " .long 31b,90b\n" \ 435 " .long 32b,90b\n" \ 436 " .long 33b,90b\n" \ 437 " .long 34b,90b\n" \ 438 " .long 35b,90b\n" \ 439 " .long 36b,90b\n" \ 440 " .long 37b,90b\n" \ 441 " .long 5b,90b\n" \ 442 " .long 7b,90b\n" \ 443 ".previous" \ 444 : "=a"(s), "=a"(d), "=d"(len) \ 445 : "0"(s), "1"(d), "2"(len) \ 446 : "d0") 447 448 449 static int macscsi_pread (struct Scsi_Host *instance, 450 unsigned char *dst, int len) 451 { 452 unsigned char *d; 453 volatile unsigned char *s; 454 455 NCR5380_local_declare(); 456 NCR5380_setup(instance); 457 458 s = mac_scsi_drq+0x60; 459 d = dst; 460 461 /* These conditions are derived from MacOS */ 462 463 while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 464 && !(NCR5380_read(STATUS_REG) & SR_REQ)) 465 ; 466 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 467 && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) { 468 printk(KERN_ERR "Error in macscsi_pread\n"); 469 return -1; 470 } 471 472 CP_IO_TO_MEM(s, d, len); 473 474 if (len != 0) { 475 printk(KERN_NOTICE "Bus error in macscsi_pread\n"); 476 return -1; 477 } 478 479 return 0; 480 } 481 482 483 #define CP_MEM_TO_IO(s,d,len) \ 484 __asm__ __volatile__ \ 485 (" cmp.w #4,%2\n" \ 486 " bls 8f\n" \ 487 " move.w %0,%%d0\n" \ 488 " neg.b %%d0\n" \ 489 " and.w #3,%%d0\n" \ 490 " sub.w %%d0,%2\n" \ 491 " bra 2f\n" \ 492 " 1: move.b (%0)+,(%1)\n" \ 493 " 2: dbf %%d0,1b\n" \ 494 " move.w %2,%%d0\n" \ 495 " lsr.w #5,%%d0\n" \ 496 " bra 4f\n" \ 497 " 3: move.l (%0)+,(%1)\n" \ 498 "31: move.l (%0)+,(%1)\n" \ 499 "32: move.l (%0)+,(%1)\n" \ 500 "33: move.l (%0)+,(%1)\n" \ 501 "34: move.l (%0)+,(%1)\n" \ 502 "35: move.l (%0)+,(%1)\n" \ 503 "36: move.l (%0)+,(%1)\n" \ 504 "37: move.l (%0)+,(%1)\n" \ 505 " 4: dbf %%d0,3b\n" \ 506 " move.w %2,%%d0\n" \ 507 " lsr.w #2,%%d0\n" \ 508 " and.w #7,%%d0\n" \ 509 " bra 6f\n" \ 510 " 5: move.l (%0)+,(%1)\n" \ 511 " 6: dbf %%d0,5b\n" \ 512 " and.w #3,%2\n" \ 513 " bra 8f\n" \ 514 " 7: move.b (%0)+,(%1)\n" \ 515 " 8: dbf %2,7b\n" \ 516 " moveq.l #0, %2\n" \ 517 " 9: \n" \ 518 ".section .fixup,\"ax\"\n" \ 519 " .even\n" \ 520 "90: moveq.l #1, %2\n" \ 521 " jra 9b\n" \ 522 ".previous\n" \ 523 ".section __ex_table,\"a\"\n" \ 524 " .align 4\n" \ 525 " .long 1b,90b\n" \ 526 " .long 3b,90b\n" \ 527 " .long 31b,90b\n" \ 528 " .long 32b,90b\n" \ 529 " .long 33b,90b\n" \ 530 " .long 34b,90b\n" \ 531 " .long 35b,90b\n" \ 532 " .long 36b,90b\n" \ 533 " .long 37b,90b\n" \ 534 " .long 5b,90b\n" \ 535 " .long 7b,90b\n" \ 536 ".previous" \ 537 : "=a"(s), "=a"(d), "=d"(len) \ 538 : "0"(s), "1"(d), "2"(len) \ 539 : "d0") 540 541 static int macscsi_pwrite (struct Scsi_Host *instance, 542 unsigned char *src, int len) 543 { 544 unsigned char *s; 545 volatile unsigned char *d; 546 547 NCR5380_local_declare(); 548 NCR5380_setup(instance); 549 550 s = src; 551 d = mac_scsi_drq; 552 553 /* These conditions are derived from MacOS */ 554 555 while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 556 && (!(NCR5380_read(STATUS_REG) & SR_REQ) 557 || (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))) 558 ; 559 if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) { 560 printk(KERN_ERR "Error in macscsi_pwrite\n"); 561 return -1; 562 } 563 564 CP_MEM_TO_IO(s, d, len); 565 566 if (len != 0) { 567 printk(KERN_NOTICE "Bus error in macscsi_pwrite\n"); 568 return -1; 569 } 570 571 return 0; 572 } 573 574 575 /* These control the behaviour of the generic 5380 core */ 576 #define AUTOSENSE 577 #define PSEUDO_DMA 578 579 #include "NCR5380.c" 580 581 static struct scsi_host_template driver_template = { 582 .proc_name = "Mac5380", 583 .proc_info = macscsi_proc_info, 584 .name = "Macintosh NCR5380 SCSI", 585 .detect = macscsi_detect, 586 .release = macscsi_release, 587 .info = macscsi_info, 588 .queuecommand = macscsi_queue_command, 589 .eh_abort_handler = macscsi_abort, 590 .eh_bus_reset_handler = macscsi_bus_reset, 591 .can_queue = CAN_QUEUE, 592 .this_id = 7, 593 .sg_tablesize = SG_ALL, 594 .cmd_per_lun = CMD_PER_LUN, 595 .unchecked_isa_dma = 0, 596 .use_clustering = DISABLE_CLUSTERING 597 }; 598 599 600 #include "scsi_module.c" 601