Linux 2.4.0-test7pre1
[davej-history.git] / drivers / scsi / mac_scsi.c
blob62f7bd3c11c961715cb17c83cbcd7c8230d1c085
1 /*
2 * Generic Macintosh NCR5380 driver
4 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
6 * derived in part from:
7 */
8 /*
9 * Generic Generic NCR5380 driver
11 * Copyright 1995, Russell King
13 * ALPHA RELEASE 1.
15 * For more information, please consult
17 * NCR 5380 Family
18 * SCSI Protocol Controller
19 * Databook
21 * NCR Microelectronics
22 * 1635 Aeroplaza Drive
23 * Colorado Springs, CO 80916
24 * 1+ (719) 578-3400
25 * 1+ (800) 334-5454
30 * Options :
32 * PARITY - enable parity checking. Not supported.
34 * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
36 * USLEEP - enable support for devices that don't disconnect. Untested.
40 * $Log: mac_NCR5380.c,v $
43 #define AUTOSENSE
44 #if 0
45 #define PSEUDO_DMA
46 #endif
48 #include <linux/types.h>
49 #include <linux/stddef.h>
50 #include <linux/ctype.h>
51 #include <linux/delay.h>
53 #include <linux/module.h>
54 #include <linux/signal.h>
55 #include <linux/sched.h>
56 #include <linux/ioport.h>
57 #include <linux/init.h>
58 #include <linux/blk.h>
60 #include <asm/io.h>
61 #include <asm/irq.h>
62 #include <asm/system.h>
64 #include <asm/macintosh.h>
65 #include <asm/macints.h>
66 #include <asm/machw.h>
67 #include <asm/mac_via.h>
69 #include "scsi.h"
70 #include "hosts.h"
71 #include "mac_scsi.h"
72 #include "NCR5380.h"
73 #include "constants.h"
75 #if 0
76 #define NDEBUG (NDEBUG_INTR | NDEBUG_PSEUDO_DMA | NDEBUG_ARBITRATION | NDEBUG_SELECTION | NDEBUG_RESELECTION)
77 #else
78 #define NDEBUG (NDEBUG_ABORT)
79 #endif
81 #define RESET_BOOT
82 #define DRIVER_SETUP
85 * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
87 #ifdef BUG
88 #undef RESET_BOOT
89 #undef DRIVER_SETUP
90 #endif
92 #define ENABLE_IRQ() mac_enable_irq( IRQ_MAC_SCSI );
93 #define DISABLE_IRQ() mac_disable_irq( IRQ_MAC_SCSI );
95 #ifdef RESET_BOOT
96 static void mac_scsi_reset_boot(struct Scsi_Host *instance);
97 #endif
98 static char macscsi_read(struct Scsi_Host *instance, int reg);
99 static void macscsi_write(struct Scsi_Host *instance, int reg, int value);
101 static int setup_can_queue = -1;
102 static int setup_cmd_per_lun = -1;
103 static int setup_sg_tablesize = -1;
104 #ifdef SUPPORT_TAGS
105 static int setup_use_tagged_queuing = -1;
106 #endif
107 static int setup_hostid = -1;
109 static int polled_scsi_on = 0;
111 /* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
112 * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
113 * need ten times the standard value... */
114 #define TOSHIBA_DELAY
116 #ifdef TOSHIBA_DELAY
117 #define AFTER_RESET_DELAY (5*HZ/2)
118 #else
119 #define AFTER_RESET_DELAY (HZ/2)
120 #endif
122 static volatile unsigned char *mac_scsi_regp = NULL;
123 static volatile unsigned char *mac_scsi_drq = NULL;
124 static volatile unsigned char *mac_scsi_nodrq = NULL;
127 * Function : mac_scsi_setup(char *str, int *ints)
129 * Purpose : booter command line initialization of the overrides array,
131 * Inputs : str - unused, ints - array of integer parameters with ints[0]
132 * equal to the number of ints.
136 static int __init mac_scsi_setup(char *str, int *ints) {
137 #ifdef DRIVER_SETUP
138 /* Format of mac5380 parameter is:
139 * mac5380=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
140 * Negative values mean don't change.
143 /* Grmbl... the standard parameter parsing can't handle negative numbers
144 * :-( So let's do it ourselves!
147 int i = ints[0]+1, fact;
149 while( str && (isdigit(*str) || *str == '-') && i <= 10) {
150 if (*str == '-')
151 fact = -1, ++str;
152 else
153 fact = 1;
154 ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
155 if ((str = strchr( str, ',' )) != NULL)
156 ++str;
158 ints[0] = i-1;
160 if (ints[0] < 1) {
161 printk( "mac_scsi_setup: no arguments!\n" );
162 return 0;
165 if (ints[0] >= 1) {
166 if (ints[1] > 0)
167 /* no limits on this, just > 0 */
168 setup_can_queue = ints[1];
170 if (ints[0] >= 2) {
171 if (ints[2] > 0)
172 setup_cmd_per_lun = ints[2];
174 if (ints[0] >= 3) {
175 if (ints[3] >= 0) {
176 setup_sg_tablesize = ints[3];
177 /* Must be <= SG_ALL (255) */
178 if (setup_sg_tablesize > SG_ALL)
179 setup_sg_tablesize = SG_ALL;
182 if (ints[0] >= 4) {
183 /* Must be between 0 and 7 */
184 if (ints[4] >= 0 && ints[4] <= 7)
185 setup_hostid = ints[4];
186 else if (ints[4] > 7)
187 printk( "mac_scsi_setup: invalid host ID %d !\n", ints[4] );
189 #ifdef SUPPORT_TAGS
190 if (ints[0] >= 5) {
191 if (ints[5] >= 0)
192 setup_use_tagged_queuing = !!ints[5];
194 #endif
195 #endif
196 return 1;
199 __setup("mac5380=", mac_scsi_setup);
201 #if 0
202 #define MAC_ADDRESS(card) (ecard_address((card), ECARD_IOC, ECARD_SLOW) + 0x800)
203 #define MAC_IRQ(card) ((card)->irq)
204 #endif
207 * XXX: status debug
209 static struct Scsi_Host *default_instance;
212 * Function : int macscsi_detect(Scsi_Host_Template * tpnt)
214 * Purpose : initializes mac NCR5380 driver based on the
215 * command line / compile time port and irq definitions.
217 * Inputs : tpnt - template for this SCSI adapter.
219 * Returns : 1 if a host adapter was found, 0 if not.
223 int macscsi_detect(Scsi_Host_Template * tpnt)
225 int count = 0;
226 static int called = 0;
227 struct Scsi_Host *instance;
229 if (!MACH_IS_MAC || called)
230 return( 0 );
232 if (macintosh_config->scsi_type != MAC_SCSI_OLD)
233 return( 0 );
235 tpnt->proc_name = "mac5380";
237 /* setup variables */
238 tpnt->can_queue =
239 (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
240 tpnt->cmd_per_lun =
241 (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
242 tpnt->sg_tablesize =
243 (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
245 if (setup_hostid >= 0)
246 tpnt->this_id = setup_hostid;
247 else {
248 /* use 7 as default */
249 tpnt->this_id = 7;
252 #ifdef SUPPORT_TAGS
253 if (setup_use_tagged_queuing < 0)
254 setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
255 #endif
257 #if 0 /* loop over multiple adapters (Powerbooks ??) */
258 for (count = 0; count < mac_num_scsi; count++) {
259 #endif
260 instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
261 default_instance = instance;
263 if (macintosh_config->ident == MAC_MODEL_IIFX) {
264 mac_scsi_regp = via1+0x8000;
265 mac_scsi_drq = via1+0xE000;
266 mac_scsi_nodrq = via1+0xC000;
267 } else {
268 mac_scsi_regp = via1+0x10000;
269 mac_scsi_drq = via1+0x6000;
270 mac_scsi_nodrq = via1+0x12000;
274 instance->io_port = (unsigned long) mac_scsi_regp;
275 instance->irq = IRQ_MAC_SCSI;
277 #ifdef RESET_BOOT
278 mac_scsi_reset_boot(instance);
279 #endif
281 NCR5380_init(instance, 0);
283 instance->n_io_port = 255;
285 ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
287 if (instance->irq != IRQ_NONE)
288 if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, "ncr5380", NCR5380_intr)) {
289 printk("scsi%d: IRQ%d not free, interrupts disabled\n",
290 instance->host_no, instance->irq);
291 instance->irq = IRQ_NONE;
294 printk("scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
295 if (instance->irq == IRQ_NONE)
296 printk ("s disabled");
297 else
298 printk (" %d", instance->irq);
299 printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
300 instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE);
301 printk("\nscsi%d:", instance->host_no);
302 NCR5380_print_options(instance);
303 printk("\n");
304 #if 0 /* multiple adapters */
306 #endif
307 called = 1;
308 return 1;
312 int macscsi_release (struct Scsi_Host *shpnt)
314 if (shpnt->irq != IRQ_NONE)
315 free_irq (shpnt->irq, NCR5380_intr);
317 return 0;
320 #ifdef RESET_BOOT
322 * Our 'bus reset on boot' function
325 static void mac_scsi_reset_boot(struct Scsi_Host *instance)
327 unsigned long end;
329 NCR5380_local_declare();
330 NCR5380_setup(instance);
333 * Do a SCSI reset to clean up the bus during initialization. No messing
334 * with the queues, interrupts, or locks necessary here.
337 printk( "Macintosh SCSI: resetting the SCSI bus..." );
339 /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
340 mac_disable_irq(IRQ_MAC_SCSI);
342 /* get in phase */
343 NCR5380_write( TARGET_COMMAND_REG,
344 PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
346 /* assert RST */
347 NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
348 /* The min. reset hold time is 25us, so 40us should be enough */
349 udelay( 50 );
350 /* reset RST and interrupt */
351 NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
352 NCR5380_read( RESET_PARITY_INTERRUPT_REG );
354 for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; )
355 barrier();
357 /* switch on SCSI IRQ again */
358 mac_enable_irq(IRQ_MAC_SCSI);
360 printk( " done\n" );
362 #endif
364 const char * macscsi_info (struct Scsi_Host *spnt) {
365 return "";
368 void restore_irq(struct pt_regs *regs)
370 unsigned long flags;
372 save_flags(flags);
373 flags = (flags & ~0x0700) | (regs->sr & 0x0700);
374 restore_flags(flags);
378 * pseudo-DMA transfer functions, copied and modified from Russel King's
379 * ARM 5380 driver (cumana_1)
381 * Work in progress (sort of), didn't work last time I checked, don't use!
384 #ifdef NOT_EFFICIENT
385 #define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
386 #define STAT(p) inb((p)+1)
387 #define IN(p) inb((p))
388 #define OUT(v,p) outb((v), (p))
389 #else
390 #if 0
391 #define CTRL(p,v) (p[-2308] = (*ctrl = (v)))
392 #else
393 #define CTRL(p,v) (*ctrl = (v))
394 #endif
395 #define STAT(p) (p[1<<4])
396 #define IN(p) (*(p))
397 #define IN2(p) ((unsigned short)(*(volatile unsigned long *)(p)))
398 #define OUT(v,p) (*(p) = (v))
399 #define OUT2(v,p) (*((volatile unsigned long *)(p)) = (v))
400 #endif
401 #define L(v) (((v)<<16)|((v) & 0x0000ffff))
402 #define H(v) (((v)>>16)|((v) & 0xffff0000))
403 #define ioaddr(v) (v)
405 static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
406 int len)
408 int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
409 int oldctrl = *ctrl;
410 unsigned long *laddr;
411 #ifdef NOT_EFFICIENT
412 int iobase = instance->io_port;
413 int dma_io = mac_scsi_nodrq;
414 #else
415 volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
416 volatile unsigned char *dma_io = (unsigned char *)(mac_scsi_nodrq);
417 #endif
419 if(!len) return 0;
421 CTRL(iobase, 0x02);
422 laddr = (unsigned long *)addr;
423 while(len >= 32)
425 int status;
426 unsigned long v;
427 status = STAT(iobase);
428 if(status & 0x80)
429 goto end;
430 if(!(status & 0x40))
431 continue;
432 v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
433 v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
434 v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
435 v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
436 v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
437 v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
438 v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
439 v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
440 len -= 32;
441 if(len == 0)
442 break;
445 addr = (unsigned char *)laddr;
446 CTRL(iobase, 0x12);
447 while(len > 0)
449 int status;
450 status = STAT(iobase);
451 if(status & 0x80)
452 goto end;
453 if(status & 0x40)
455 OUT(*addr++, dma_io);
456 if(--len == 0)
457 break;
460 status = STAT(iobase);
461 if(status & 0x80)
462 goto end;
463 if(status & 0x40)
465 OUT(*addr++, dma_io);
466 if(--len == 0)
467 break;
470 end:
471 CTRL(iobase, oldctrl|0x40);
472 return len;
475 static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
476 int len)
478 int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
479 int oldctrl = *ctrl;
480 unsigned long *laddr;
481 #ifdef NOT_EFFICIENT
482 int iobase = instance->io_port;
483 int dma_io = mac_scsi_nodrq;
484 #else
485 volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
486 volatile unsigned char *dma_io = (unsigned char *)((int)mac_scsi_nodrq);
487 #endif
489 if(!len) return 0;
491 CTRL(iobase, 0x00);
492 laddr = (unsigned long *)addr;
493 while(len >= 32)
495 int status;
496 status = STAT(iobase);
497 if(status & 0x80)
498 goto end;
499 if(!(status & 0x40))
500 continue;
501 *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
502 *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
503 *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
504 *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
505 *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
506 *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
507 *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
508 *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
509 len -= 32;
510 if(len == 0)
511 break;
514 addr = (unsigned char *)laddr;
515 CTRL(iobase, 0x10);
516 while(len > 0)
518 int status;
519 status = STAT(iobase);
520 if(status & 0x80)
521 goto end;
522 if(status & 0x40)
524 *addr++ = IN(dma_io);
525 if(--len == 0)
526 break;
529 status = STAT(iobase);
530 if(status & 0x80)
531 goto end;
532 if(status & 0x40)
534 *addr++ = IN(dma_io);
535 if(--len == 0)
536 break;
539 end:
540 CTRL(iobase, oldctrl|0x40);
541 return len;
544 #undef STAT
545 #undef CTRL
546 #undef IN
547 #undef OUT
550 * NCR 5380 register access functions
553 #ifdef ORIG
554 #if 0
555 #define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
556 #else
557 #define CTRL(p,v) (*ctrl = (v))
558 #endif
560 static char macscsi_read(struct Scsi_Host *instance, int reg)
562 int iobase = instance->io_port;
563 int i;
564 int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
566 CTRL(iobase, 0);
567 #if 0
568 i = inb(iobase + 64 + reg);
569 #else
570 i = inb(iobase + reg<<4);
571 #endif
572 CTRL(iobase, 0x40);
574 return i;
577 static void macscsi_write(struct Scsi_Host *instance, int reg, int value)
579 int iobase = instance->io_port;
580 int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
582 CTRL(iobase, 0);
583 #if 0
584 outb(value, iobase + 64 + reg);
585 #else
586 outb(value, iobase + reg<<4);
587 #endif
588 CTRL(iobase, 0x40);
591 #undef CTRL
593 #else
594 static char macscsi_read(struct Scsi_Host *instance, int reg)
596 return( mac_scsi_regp[reg << 4] );
599 static void macscsi_write(struct Scsi_Host *instance, int reg, int value)
601 mac_scsi_regp[reg << 4] = value;
604 #endif
606 #include "NCR5380.c"
609 * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
610 * reentering NCR5380_print_status seems to have ugly side effects
613 void scsi_mac_debug (void)
615 unsigned long flags;
616 NCR5380_local_declare();
618 if (default_instance) {
619 #if 0
620 NCR5380_setup(default_instance);
621 if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
622 #endif
623 save_flags(flags);
624 cli();
625 NCR5380_print_status(default_instance);
626 restore_flags(flags);
628 #if 0
629 polled_scsi_on = 1;
630 #endif
633 * Helper function for interrupt trouble. More ugly side effects here.
636 void scsi_mac_polled (void)
638 unsigned long flags;
639 NCR5380_local_declare();
640 struct Scsi_Host *instance;
642 #if 0
643 for (instance = first_instance; instance && (instance->hostt ==
644 the_template); instance = instance->next)
645 if (instance->irq == IRQ_MAC_SCSI && polled_scsi_on) {
646 #else
647 instance = default_instance;
648 #endif
649 NCR5380_setup(instance);
650 if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
652 printk("SCSI poll\n");
653 save_flags(flags);
654 cli();
655 NCR5380_intr(IRQ_MAC_SCSI, instance, NULL);
656 restore_flags(flags);
658 #if 0
660 #endif
665 #ifdef MODULE
667 Scsi_Host_Template driver_template = MAC_NCR5380;
669 #include "scsi_module.c"
670 #endif