1 /* 2 * Oak Generic NCR5380 driver 3 * 4 * Copyright 1995-2002, Russell King 5 */ 6 7 #include <linux/module.h> 8 #include <linux/signal.h> 9 #include <linux/ioport.h> 10 #include <linux/delay.h> 11 #include <linux/blkdev.h> 12 #include <linux/init.h> 13 14 #include <asm/ecard.h> 15 #include <asm/io.h> 16 #include <asm/system.h> 17 18 #include "../scsi.h" 19 #include <scsi/scsi_host.h> 20 21 #define AUTOSENSE 22 /*#define PSEUDO_DMA*/ 23 24 #define OAKSCSI_PUBLIC_RELEASE 1 25 26 #define NCR5380_read(reg) oakscsi_read(_instance, reg) 27 #define NCR5380_write(reg, value) oakscsi_write(_instance, reg, value) 28 #define NCR5380_intr oakscsi_intr 29 #define NCR5380_queue_command oakscsi_queue_command 30 #define NCR5380_proc_info oakscsi_proc_info 31 32 #define NCR5380_implementation_fields int port, ctrl 33 #define NCR5380_local_declare() struct Scsi_Host *_instance 34 #define NCR5380_setup(instance) _instance = instance 35 36 #define BOARD_NORMAL 0 37 #define BOARD_NCR53C400 1 38 39 #include "../NCR5380.h" 40 41 #undef START_DMA_INITIATOR_RECEIVE_REG 42 #define START_DMA_INITIATOR_RECEIVE_REG (7 + 128) 43 44 const char * oakscsi_info (struct Scsi_Host *spnt) 45 { 46 return ""; 47 } 48 49 #define STAT(p) inw(p + 144) 50 extern void inswb(int from, void *to, int len); 51 52 static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, 53 int len) 54 { 55 int iobase = instance->io_port; 56 printk("writing %p len %d\n",addr, len); 57 if(!len) return -1; 58 59 while(1) 60 { 61 int status; 62 while(((status = STAT(iobase)) & 0x100)==0); 63 } 64 } 65 66 static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, 67 int len) 68 { 69 int iobase = instance->io_port; 70 printk("reading %p len %d\n", addr, len); 71 while(len > 0) 72 { 73 int status, timeout; 74 unsigned long b; 75 76 timeout = 0x01FFFFFF; 77 78 while(((status = STAT(iobase)) & 0x100)==0) 79 { 80 timeout--; 81 if(status & 0x200 || !timeout) 82 { 83 printk("status = %08X\n",status); 84 return 1; 85 } 86 } 87 if(len >= 128) 88 { 89 inswb(iobase + 136, addr, 128); 90 addr += 128; 91 len -= 128; 92 } 93 else 94 { 95 b = (unsigned long) inw(iobase + 136); 96 *addr ++ = b; 97 len -= 1; 98 if(len) 99 *addr ++ = b>>8; 100 len -= 1; 101 } 102 } 103 return 0; 104 } 105 106 #define oakscsi_read(instance,reg) (inb((instance)->io_port + (reg))) 107 #define oakscsi_write(instance,reg,val) (outb((val), (instance)->io_port + (reg))) 108 109 #undef STAT 110 111 #include "../NCR5380.c" 112 113 static struct scsi_host_template oakscsi_template = { 114 .module = THIS_MODULE, 115 .proc_info = oakscsi_proc_info, 116 .name = "Oak 16-bit SCSI", 117 .info = oakscsi_info, 118 .queuecommand = oakscsi_queue_command, 119 .eh_abort_handler = NCR5380_abort, 120 .eh_bus_reset_handler = NCR5380_bus_reset, 121 .can_queue = 16, 122 .this_id = 7, 123 .sg_tablesize = SG_ALL, 124 .cmd_per_lun = 2, 125 .use_clustering = DISABLE_CLUSTERING, 126 .proc_name = "oakscsi", 127 }; 128 129 static int __devinit 130 oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id) 131 { 132 struct Scsi_Host *host; 133 int ret = -ENOMEM; 134 135 host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata)); 136 if (!host) 137 goto out; 138 139 host->io_port = ecard_address(ec, ECARD_MEMC, 0); 140 host->irq = IRQ_NONE; 141 host->n_io_port = 255; 142 143 ret = -EBUSY; 144 if (!request_region (host->io_port, host->n_io_port, "Oak SCSI")) 145 goto unreg; 146 147 NCR5380_init(host, 0); 148 149 printk("scsi%d: at port 0x%08lx irqs disabled", 150 host->host_no, host->io_port); 151 printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", 152 host->can_queue, host->cmd_per_lun, OAKSCSI_PUBLIC_RELEASE); 153 printk("\nscsi%d:", host->host_no); 154 NCR5380_print_options(host); 155 printk("\n"); 156 157 ret = scsi_add_host(host, &ec->dev); 158 if (ret) 159 goto out_release; 160 161 scsi_scan_host(host); 162 goto out; 163 164 out_release: 165 release_region(host->io_port, host->n_io_port); 166 unreg: 167 scsi_host_put(host); 168 out: 169 return ret; 170 } 171 172 static void __devexit oakscsi_remove(struct expansion_card *ec) 173 { 174 struct Scsi_Host *host = ecard_get_drvdata(ec); 175 176 ecard_set_drvdata(ec, NULL); 177 scsi_remove_host(host); 178 179 NCR5380_exit(host); 180 release_region(host->io_port, host->n_io_port); 181 scsi_host_put(host); 182 } 183 184 static const struct ecard_id oakscsi_cids[] = { 185 { MANU_OAK, PROD_OAK_SCSI }, 186 { 0xffff, 0xffff } 187 }; 188 189 static struct ecard_driver oakscsi_driver = { 190 .probe = oakscsi_probe, 191 .remove = __devexit_p(oakscsi_remove), 192 .id_table = oakscsi_cids, 193 .drv = { 194 .name = "oakscsi", 195 }, 196 }; 197 198 static int __init oakscsi_init(void) 199 { 200 return ecard_register_driver(&oakscsi_driver); 201 } 202 203 static void __exit oakscsi_exit(void) 204 { 205 ecard_remove_driver(&oakscsi_driver); 206 } 207 208 module_init(oakscsi_init); 209 module_exit(oakscsi_exit); 210 211 MODULE_AUTHOR("Russell King"); 212 MODULE_DESCRIPTION("Oak SCSI driver"); 213 MODULE_LICENSE("GPL"); 214 215