#define AUTOSENSE /* #define PSEUDO_DMA */ /* * EcoSCSI Generic NCR5380 driver * * Copyright 1995, Russell King * * ALPHA RELEASE 1. * * For more information, please consult * * NCR 5380 Family * SCSI Protocol Controller * Databook * * NCR Microelectronics * 1635 Aeroplaza Drive * Colorado Springs, CO 80916 * 1+ (719) 578-3400 * 1+ (800) 334-5454 */ /* * Options : * * PARITY - enable parity checking. Not supported. * * SCSI2 - enable support for SCSI-II tagged queueing. Untested. * * USLEEP - enable support for devices that don't disconnect. Untested. */ /* * $Log: ecoscsi.c,v $ * Revision 1.1.1.1 2003/06/23 22:18:24 jharrell * Imported kernel sources * * Revision 1.2 2002/05/29 17:42:32 jharrell * Alignment with MontaVista Linux (2.1) * * Revision 1.2 1998/03/08 05:49:47 davem * Merge to 2.1.89 * * Revision 1.1 1998/02/23 02:45:24 davem * Merge to 2.1.88 * */ #include #include #include #include #include #include #include #include #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" #include "../../scsi/NCR5380.h" #include "../../scsi/constants.h" #define ECOSCSI_PUBLIC_RELEASE 1 static char ecoscsi_read(struct Scsi_Host *instance, int reg) { int iobase = instance->io_port; outb(reg | 8, iobase); return inb(iobase + 1); } static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value) { int iobase = instance->io_port; outb(reg | 8, iobase); outb(value, iobase + 1); } /* * Function : ecoscsi_setup(char *str, int *ints) * * Purpose : LILO command line initialization of the overrides array, * * Inputs : str - unused, ints - array of integer parameters with ints[0] * equal to the number of ints. * */ void ecoscsi_setup(char *str, int *ints) { } /* * Function : int ecoscsi_detect(Scsi_Host_Template * tpnt) * * Purpose : initializes ecoscsi NCR5380 driver based on the * command line / compile time port and irq definitions. * * Inputs : tpnt - template for this SCSI adapter. * * Returns : 1 if a host adapter was found, 0 if not. * */ int ecoscsi_detect(Scsi_Host_Template * tpnt) { struct Scsi_Host *instance; tpnt->proc_name = "ecoscsi"; instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); instance->io_port = 0x80ce8000; instance->n_io_port = 144; instance->irq = IRQ_NONE; if (check_region (instance->io_port, instance->n_io_port)) { scsi_unregister (instance); return 0; } ecoscsi_write (instance, MODE_REG, 0x20); /* Is it really SCSI? */ if (ecoscsi_read (instance, MODE_REG) != 0x20) { /* Write to a reg. */ scsi_unregister(instance); return 0; /* and try to read */ } ecoscsi_write( instance, MODE_REG, 0x00 ); /* it back. */ if (ecoscsi_read (instance, MODE_REG) != 0x00) { scsi_unregister(instance); return 0; } NCR5380_init(instance, 0); request_region (instance->io_port, instance->n_io_port, "ecoscsi"); if (instance->irq != IRQ_NONE) if (request_irq(instance->irq, do_ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) { printk("scsi%d: IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); instance->irq = IRQ_NONE; } if (instance->irq != IRQ_NONE) { printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no); printk("scsi%d: that the board had an interrupt!\n", instance->host_no); } printk("scsi%d: at port %X irq", instance->host_no, instance->io_port); if (instance->irq == IRQ_NONE) printk ("s disabled"); else printk (" %d", instance->irq); printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, ECOSCSI_PUBLIC_RELEASE); printk("\nscsi%d:", instance->host_no); NCR5380_print_options(instance); printk("\n"); return 1; } int ecoscsi_release (struct Scsi_Host *shpnt) { if (shpnt->irq != IRQ_NONE) free_irq (shpnt->irq, NULL); if (shpnt->io_port) release_region (shpnt->io_port, shpnt->n_io_port); return 0; } const char * ecoscsi_info (struct Scsi_Host *spnt) { return ""; } #if 0 #define STAT(p) inw(p + 144) static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, int len) { int iobase = instance->io_port; printk("writing %p len %d\n",addr, len); if(!len) return -1; while(1) { int status; while(((status = STAT(iobase)) & 0x100)==0); } } static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, int len) { int iobase = instance->io_port; int iobase2= instance->io_port + 0x100; unsigned char *start = addr; int s; printk("reading %p len %d\n",addr, len); outb(inb(iobase + 128), iobase + 135); while(len > 0) { int status,b,i, timeout; timeout = 0x07FFFFFF; while(((status = STAT(iobase)) & 0x100)==0) { timeout--; if(status & 0x200 || !timeout) { printk("status = %p\n",status); outb(0, iobase + 135); return 1; } } if(len >= 128) { for(i=0; i<64; i++) { b = inw(iobase + 136); *addr++ = b; *addr++ = b>>8; } len -= 128; } else { b = inw(iobase + 136); *addr ++ = b; len -= 1; if(len) *addr ++ = b>>8; len -= 1; } } outb(0, iobase + 135); printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]); return 1; } #endif #undef STAT #define NCR5380_implementation_fields \ int port, ctrl #define NCR5380_local_declare() \ struct Scsi_Host *_instance #define NCR5380_setup(instance) \ _instance = instance #define NCR5380_read(reg) ecoscsi_read(_instance, reg) #define NCR5380_write(reg, value) ecoscsi_write(_instance, reg, value) #define do_NCR5380_intr do_ecoscsi_intr #define NCR5380_queue_command ecoscsi_queue_command #define NCR5380_abort ecoscsi_abort #define NCR5380_reset ecoscsi_reset #define NCR5380_proc_info ecoscsi_proc_info int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); #define BOARD_NORMAL 0 #define BOARD_NCR53C400 1 #include "../../scsi/NCR5380.c" static Scsi_Host_Template ecoscsi_template = { module: THIS_MODULE, name: "Serial Port EcoSCSI NCR5380", detect: ecoscsi_detect, release: ecoscsi_release, info: ecoscsi_info, queuecommand: ecoscsi_queue_command, abort: ecoscsi_abort, reset: ecoscsi_reset, can_queue: 16, this_id: 7, sg_tablesize: SG_ALL, cmd_per_lun: 2, use_clustering: DISABLE_CLUSTERING }; static int __init ecoscsi_init(void) { scsi_register_module(MODULE_SCSI_HA, &ecoscsi_template); if (ecoscsi_template.present) return 0; scsi_unregister_module(MODULE_SCSI_HA, &ecoscsi_template); return -ENODEV; } static void __exit ecoscsi_exit(void) { scsi_unregister_module(MODULE_SCSI_HA, &ecoscsi_template); } module_init(ecoscsi_init); module_exit(ecoscsi_exit); MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines"); MODULE_LICENSE("GPL"); EXPORT_NO_SYMBOLS;