Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / drivers / scsi / mac_scsi.c
blobcbc805e4d8f5dbff3a7ef7d79c7ea6aede365af8
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 voidmac_scsi_reset_boot(struct Scsi_Host *instance);
97 #endif
98 static charmacscsi_read(struct Scsi_Host *instance,int reg);
99 static voidmacscsi_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 staticvolatileunsigned char*mac_scsi_regp = NULL;
123 staticvolatileunsigned char*mac_scsi_drq = NULL;
124 staticvolatileunsigned 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 return0;
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 return1;
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 intmacscsi_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 if(instance == NULL)
262 continue;
263 default_instance = instance;
265 if(macintosh_config->ident == MAC_MODEL_IIFX) {
266 mac_scsi_regp = via1+0x8000;
267 mac_scsi_drq = via1+0xE000;
268 mac_scsi_nodrq = via1+0xC000;
269 }else{
270 mac_scsi_regp = via1+0x10000;
271 mac_scsi_drq = via1+0x6000;
272 mac_scsi_nodrq = via1+0x12000;
276 instance->io_port = (unsigned long) mac_scsi_regp;
277 instance->irq = IRQ_MAC_SCSI;
279 #ifdef RESET_BOOT
280 mac_scsi_reset_boot(instance);
281 #endif
283 NCR5380_init(instance,0);
285 instance->n_io_port =255;
287 ((struct NCR5380_hostdata *)instance->hostdata)->ctrl =0;
289 if(instance->irq != IRQ_NONE)
290 if(request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW,"ncr5380", NCR5380_intr)) {
291 printk("scsi%d: IRQ%d not free, interrupts disabled\n",
292 instance->host_no, instance->irq);
293 instance->irq = IRQ_NONE;
296 printk("scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
297 if(instance->irq == IRQ_NONE)
298 printk("s disabled");
299 else
300 printk(" %d", instance->irq);
301 printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
302 instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE);
303 printk("\nscsi%d:", instance->host_no);
304 NCR5380_print_options(instance);
305 printk("\n");
306 #if 0/* multiple adapters */
308 #endif
309 called =1;
310 return1;
314 intmacscsi_release(struct Scsi_Host *shpnt)
316 if(shpnt->irq != IRQ_NONE)
317 free_irq(shpnt->irq, NCR5380_intr);
319 return0;
322 #ifdef RESET_BOOT
324 * Our 'bus reset on boot' function
327 static voidmac_scsi_reset_boot(struct Scsi_Host *instance)
329 unsigned long end;
331 NCR5380_local_declare();
332 NCR5380_setup(instance);
335 * Do a SCSI reset to clean up the bus during initialization. No messing
336 * with the queues, interrupts, or locks necessary here.
339 printk("Macintosh SCSI: resetting the SCSI bus...");
341 /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
342 mac_disable_irq(IRQ_MAC_SCSI);
344 /* get in phase */
345 NCR5380_write( TARGET_COMMAND_REG,
346 PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) ));
348 /* assert RST */
349 NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
350 /* The min. reset hold time is 25us, so 40us should be enough */
351 udelay(50);
352 /* reset RST and interrupt */
353 NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
354 NCR5380_read( RESET_PARITY_INTERRUPT_REG );
356 for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; )
357 barrier();
359 /* switch on SCSI IRQ again */
360 mac_enable_irq(IRQ_MAC_SCSI);
362 printk(" done\n");
364 #endif
366 const char*macscsi_info(struct Scsi_Host *spnt) {
367 return"";
370 voidrestore_irq(struct pt_regs *regs)
372 unsigned long flags;
374 save_flags(flags);
375 flags = (flags & ~0x0700) | (regs->sr &0x0700);
376 restore_flags(flags);
380 * pseudo-DMA transfer functions, copied and modified from Russel King's
381 * ARM 5380 driver (cumana_1)
383 * Work in progress (sort of), didn't work last time I checked, don't use!
386 #ifdef NOT_EFFICIENT
387 #define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
388 #define STAT(p) inb((p)+1)
389 #define IN(p) inb((p))
390 #define OUT(v,p) outb((v), (p))
391 #else
392 #if 0
393 #define CTRL(p,v) (p[-2308] = (*ctrl = (v)))
394 #else
395 #define CTRL(p,v) (*ctrl = (v))
396 #endif
397 #define STAT(p) (p[1<<4])
398 #define IN(p) (*(p))
399 #define IN2(p) ((unsigned short)(*(volatile unsigned long *)(p)))
400 #define OUT(v,p) (*(p) = (v))
401 #define OUT2(v,p) (*((volatile unsigned long *)(p)) = (v))
402 #endif
403 #define L(v) (((v)<<16)|((v) & 0x0000ffff))
404 #define H(v) (((v)>>16)|((v) & 0xffff0000))
405 #define ioaddr(v) (v)
407 staticinlineintNCR5380_pwrite(struct Scsi_Host *instance,unsigned char*addr,
408 int len)
410 int*ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
411 int oldctrl = *ctrl;
412 unsigned long*laddr;
413 #ifdef NOT_EFFICIENT
414 int iobase = instance->io_port;
415 int dma_io = mac_scsi_nodrq;
416 #else
417 volatileunsigned char*iobase = (unsigned char*)ioaddr(instance->io_port);
418 volatileunsigned char*dma_io = (unsigned char*)(mac_scsi_nodrq);
419 #endif
421 if(!len)return0;
423 CTRL(iobase,0x02);
424 laddr = (unsigned long*)addr;
425 while(len >=32)
427 int status;
428 unsigned long v;
429 status =STAT(iobase);
430 if(status &0x80)
431 goto end;
432 if(!(status &0x40))
433 continue;
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 v=*laddr++;OUT2(L(v),dma_io);OUT2(H(v),dma_io);
441 v=*laddr++;OUT2(L(v),dma_io);OUT2(H(v),dma_io);
442 len -=32;
443 if(len ==0)
444 break;
447 addr = (unsigned char*)laddr;
448 CTRL(iobase,0x12);
449 while(len >0)
451 int status;
452 status =STAT(iobase);
453 if(status &0x80)
454 goto end;
455 if(status &0x40)
457 OUT(*addr++, dma_io);
458 if(--len ==0)
459 break;
462 status =STAT(iobase);
463 if(status &0x80)
464 goto end;
465 if(status &0x40)
467 OUT(*addr++, dma_io);
468 if(--len ==0)
469 break;
472 end:
473 CTRL(iobase, oldctrl|0x40);
474 return len;
477 staticinlineintNCR5380_pread(struct Scsi_Host *instance,unsigned char*addr,
478 int len)
480 int*ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
481 int oldctrl = *ctrl;
482 unsigned long*laddr;
483 #ifdef NOT_EFFICIENT
484 int iobase = instance->io_port;
485 int dma_io = mac_scsi_nodrq;
486 #else
487 volatileunsigned char*iobase = (unsigned char*)ioaddr(instance->io_port);
488 volatileunsigned char*dma_io = (unsigned char*)((int)mac_scsi_nodrq);
489 #endif
491 if(!len)return0;
493 CTRL(iobase,0x00);
494 laddr = (unsigned long*)addr;
495 while(len >=32)
497 int status;
498 status =STAT(iobase);
499 if(status &0x80)
500 goto end;
501 if(!(status &0x40))
502 continue;
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 *laddr++ =IN2(dma_io)|(IN2(dma_io)<<16);
510 *laddr++ =IN2(dma_io)|(IN2(dma_io)<<16);
511 len -=32;
512 if(len ==0)
513 break;
516 addr = (unsigned char*)laddr;
517 CTRL(iobase,0x10);
518 while(len >0)
520 int status;
521 status =STAT(iobase);
522 if(status &0x80)
523 goto end;
524 if(status &0x40)
526 *addr++ =IN(dma_io);
527 if(--len ==0)
528 break;
531 status =STAT(iobase);
532 if(status &0x80)
533 goto end;
534 if(status &0x40)
536 *addr++ =IN(dma_io);
537 if(--len ==0)
538 break;
541 end:
542 CTRL(iobase, oldctrl|0x40);
543 return len;
546 #undef STAT
547 #undef CTRL
548 #undef IN
549 #undef OUT
552 * NCR 5380 register access functions
555 #ifdef ORIG
556 #if 0
557 #define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
558 #else
559 #define CTRL(p,v) (*ctrl = (v))
560 #endif
562 static charmacscsi_read(struct Scsi_Host *instance,int reg)
564 int iobase = instance->io_port;
565 int i;
566 int*ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
568 CTRL(iobase,0);
569 #if 0
570 i =inb(iobase +64+ reg);
571 #else
572 i =inb(iobase + reg<<4);
573 #endif
574 CTRL(iobase,0x40);
576 return i;
579 static voidmacscsi_write(struct Scsi_Host *instance,int reg,int value)
581 int iobase = instance->io_port;
582 int*ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
584 CTRL(iobase,0);
585 #if 0
586 outb(value, iobase +64+ reg);
587 #else
588 outb(value, iobase + reg<<4);
589 #endif
590 CTRL(iobase,0x40);
593 #undef CTRL
595 #else
596 static charmacscsi_read(struct Scsi_Host *instance,int reg)
598 return( mac_scsi_regp[reg <<4] );
601 static voidmacscsi_write(struct Scsi_Host *instance,int reg,int value)
603 mac_scsi_regp[reg <<4] = value;
606 #endif
608 #include"NCR5380.c"
611 * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
612 * reentering NCR5380_print_status seems to have ugly side effects
615 voidscsi_mac_debug(void)
617 unsigned long flags;
618 NCR5380_local_declare();
620 if(default_instance) {
621 #if 0
622 NCR5380_setup(default_instance);
623 if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
624 #endif
625 save_flags(flags);
626 cli();
627 NCR5380_print_status(default_instance);
628 restore_flags(flags);
630 #if 0
631 polled_scsi_on =1;
632 #endif
635 * Helper function for interrupt trouble. More ugly side effects here.
638 voidscsi_mac_polled(void)
640 unsigned long flags;
641 NCR5380_local_declare();
642 struct Scsi_Host *instance;
644 #if 0
645 for(instance = first_instance; instance && (instance->hostt ==
646 the_template); instance = instance->next)
647 if(instance->irq == IRQ_MAC_SCSI && polled_scsi_on) {
648 #else
649 instance = default_instance;
650 #endif
651 NCR5380_setup(instance);
652 if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
654 printk("SCSI poll\n");
655 save_flags(flags);
656 cli();
657 NCR5380_intr(IRQ_MAC_SCSI, instance, NULL);
658 restore_flags(flags);
660 #if 0
662 #endif
667 static Scsi_Host_Template driver_template = MAC_NCR5380;
669 #include"scsi_module.c"
close