diff options
Diffstat (limited to 'drivers/scsi/arm/ecoscsi.c')
-rw-r--r-- | drivers/scsi/arm/ecoscsi.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c new file mode 100644 index 00000000000..303648a8470 --- /dev/null +++ b/drivers/scsi/arm/ecoscsi.c @@ -0,0 +1,239 @@ +#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 + */ + +#include <linux/module.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/blkdev.h> + +#include <asm/io.h> +#include <asm/system.h> + +#include "../scsi.h" +#include <scsi/scsi_host.h> + +#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 NCR5380_intr ecoscsi_intr +#define NCR5380_queue_command ecoscsi_queue_command +#define NCR5380_proc_info ecoscsi_proc_info + +#include "../NCR5380.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) +{ +} + +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 *host, unsigned char *addr, + int len) +{ + int iobase = host->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 *host, unsigned char *addr, + int len) +{ + int iobase = host->io_port; + int iobase2= host->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 BOARD_NORMAL 0 +#define BOARD_NCR53C400 1 + +#include "../NCR5380.c" + +static Scsi_Host_Template ecoscsi_template = { + .module = THIS_MODULE, + .name = "Serial Port EcoSCSI NCR5380", + .proc_name = "ecoscsi", + .info = ecoscsi_info, + .queuecommand = ecoscsi_queue_command, + .eh_abort_handler = NCR5380_abort, + .eh_device_reset_handler= NCR5380_device_reset, + .eh_bus_reset_handler = NCR5380_bus_reset, + .eh_host_reset_handler = NCR5380_host_reset, + .can_queue = 16, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 2, + .use_clustering = DISABLE_CLUSTERING +}; + +static struct Scsi_Host *host; + +static int __init ecoscsi_init(void) +{ + + host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata)); + if (!host) + return 0; + + host->io_port = 0x80ce8000; + host->n_io_port = 144; + host->irq = IRQ_NONE; + + if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) ) + goto unregister_scsi; + + ecoscsi_write(host, MODE_REG, 0x20); /* Is it really SCSI? */ + if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg. */ + goto release_reg; + + ecoscsi_write(host, MODE_REG, 0x00 ); /* it back. */ + if (ecoscsi_read(host, MODE_REG) != 0x00) + goto release_reg; + + NCR5380_init(host, 0); + + printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", + host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE); + printk("\nscsi%d:", host->host_no); + NCR5380_print_options(host); + printk("\n"); + + scsi_add_host(host, NULL); /* XXX handle failure */ + scsi_scan_host(host); + return 0; + +release_reg: + release_region(host->io_port, host->n_io_port); +unregister_scsi: + scsi_host_put(host); + return -ENODEV; +} + +static void __exit ecoscsi_exit(void) +{ + scsi_remove_host(host); + + if (shpnt->irq != IRQ_NONE) + free_irq(shpnt->irq, NULL); + NCR5380_exit(host); + if (shpnt->io_port) + release_region(shpnt->io_port, shpnt->n_io_port); + + scsi_host_put(host); + return 0; +} + +module_init(ecoscsi_init); +module_exit(ecoscsi_exit); + +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines"); +MODULE_LICENSE("GPL"); + |