1 /* 2 * Generic Generic NCR5380 driver 3 * 4 * Copyright 1995-2002, Russell King 5 */ 6 #include <linux/module.h> 7 #include <linux/signal.h> 8 #include <linux/ioport.h> 9 #include <linux/delay.h> 10 #include <linux/blkdev.h> 11 #include <linux/init.h> 12 13 #include <asm/ecard.h> 14 #include <asm/io.h> 15 16 #include <scsi/scsi_host.h> 17 18 #include <scsi/scsicam.h> 19 20 #define PSEUDO_DMA 21 22 #define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata) 23 #define NCR5380_local_declare() struct Scsi_Host *_instance 24 #define NCR5380_setup(instance) _instance = instance 25 #define NCR5380_read(reg) cumanascsi_read(_instance, reg) 26 #define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value) 27 #define NCR5380_intr cumanascsi_intr 28 #define NCR5380_queue_command cumanascsi_queue_command 29 #define NCR5380_info cumanascsi_info 30 31 #define NCR5380_implementation_fields \ 32 unsigned ctrl; \ 33 void __iomem *base; \ 34 void __iomem *dma 35 36 #include "../NCR5380.h" 37 38 void cumanascsi_setup(char *str, int *ints) 39 { 40 } 41 42 #define CTRL 0x16fc 43 #define STAT 0x2004 44 #define L(v) (((v)<<16)|((v) & 0x0000ffff)) 45 #define H(v) (((v)>>16)|((v) & 0xffff0000)) 46 47 static inline int 48 NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr, int len) 49 { 50 unsigned long *laddr; 51 void __iomem *dma = priv(host)->dma + 0x2000; 52 53 if(!len) return 0; 54 55 writeb(0x02, priv(host)->base + CTRL); 56 laddr = (unsigned long *)addr; 57 while(len >= 32) 58 { 59 unsigned int status; 60 unsigned long v; 61 status = readb(priv(host)->base + STAT); 62 if(status & 0x80) 63 goto end; 64 if(!(status & 0x40)) 65 continue; 66 v=*laddr++; writew(L(v), dma); writew(H(v), dma); 67 v=*laddr++; writew(L(v), dma); writew(H(v), dma); 68 v=*laddr++; writew(L(v), dma); writew(H(v), dma); 69 v=*laddr++; writew(L(v), dma); writew(H(v), dma); 70 v=*laddr++; writew(L(v), dma); writew(H(v), dma); 71 v=*laddr++; writew(L(v), dma); writew(H(v), dma); 72 v=*laddr++; writew(L(v), dma); writew(H(v), dma); 73 v=*laddr++; writew(L(v), dma); writew(H(v), dma); 74 len -= 32; 75 if(len == 0) 76 break; 77 } 78 79 addr = (unsigned char *)laddr; 80 writeb(0x12, priv(host)->base + CTRL); 81 82 while(len > 0) 83 { 84 unsigned int status; 85 status = readb(priv(host)->base + STAT); 86 if(status & 0x80) 87 goto end; 88 if(status & 0x40) 89 { 90 writeb(*addr++, dma); 91 if(--len == 0) 92 break; 93 } 94 95 status = readb(priv(host)->base + STAT); 96 if(status & 0x80) 97 goto end; 98 if(status & 0x40) 99 { 100 writeb(*addr++, dma); 101 if(--len == 0) 102 break; 103 } 104 } 105 end: 106 writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL); 107 return len; 108 } 109 110 static inline int 111 NCR5380_pread(struct Scsi_Host *host, unsigned char *addr, int len) 112 { 113 unsigned long *laddr; 114 void __iomem *dma = priv(host)->dma + 0x2000; 115 116 if(!len) return 0; 117 118 writeb(0x00, priv(host)->base + CTRL); 119 laddr = (unsigned long *)addr; 120 while(len >= 32) 121 { 122 unsigned int status; 123 status = readb(priv(host)->base + STAT); 124 if(status & 0x80) 125 goto end; 126 if(!(status & 0x40)) 127 continue; 128 *laddr++ = readw(dma) | (readw(dma) << 16); 129 *laddr++ = readw(dma) | (readw(dma) << 16); 130 *laddr++ = readw(dma) | (readw(dma) << 16); 131 *laddr++ = readw(dma) | (readw(dma) << 16); 132 *laddr++ = readw(dma) | (readw(dma) << 16); 133 *laddr++ = readw(dma) | (readw(dma) << 16); 134 *laddr++ = readw(dma) | (readw(dma) << 16); 135 *laddr++ = readw(dma) | (readw(dma) << 16); 136 len -= 32; 137 if(len == 0) 138 break; 139 } 140 141 addr = (unsigned char *)laddr; 142 writeb(0x10, priv(host)->base + CTRL); 143 144 while(len > 0) 145 { 146 unsigned int status; 147 status = readb(priv(host)->base + STAT); 148 if(status & 0x80) 149 goto end; 150 if(status & 0x40) 151 { 152 *addr++ = readb(dma); 153 if(--len == 0) 154 break; 155 } 156 157 status = readb(priv(host)->base + STAT); 158 if(status & 0x80) 159 goto end; 160 if(status & 0x40) 161 { 162 *addr++ = readb(dma); 163 if(--len == 0) 164 break; 165 } 166 } 167 end: 168 writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL); 169 return len; 170 } 171 172 static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg) 173 { 174 void __iomem *base = priv(host)->base; 175 unsigned char val; 176 177 writeb(0, base + CTRL); 178 179 val = readb(base + 0x2100 + (reg << 2)); 180 181 priv(host)->ctrl = 0x40; 182 writeb(0x40, base + CTRL); 183 184 return val; 185 } 186 187 static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value) 188 { 189 void __iomem *base = priv(host)->base; 190 191 writeb(0, base + CTRL); 192 193 writeb(value, base + 0x2100 + (reg << 2)); 194 195 priv(host)->ctrl = 0x40; 196 writeb(0x40, base + CTRL); 197 } 198 199 #include "../NCR5380.c" 200 201 static struct scsi_host_template cumanascsi_template = { 202 .module = THIS_MODULE, 203 .name = "Cumana 16-bit SCSI", 204 .info = cumanascsi_info, 205 .queuecommand = cumanascsi_queue_command, 206 .eh_abort_handler = NCR5380_abort, 207 .eh_bus_reset_handler = NCR5380_bus_reset, 208 .can_queue = 16, 209 .this_id = 7, 210 .sg_tablesize = SG_ALL, 211 .cmd_per_lun = 2, 212 .use_clustering = DISABLE_CLUSTERING, 213 .proc_name = "CumanaSCSI-1", 214 }; 215 216 static int cumanascsi1_probe(struct expansion_card *ec, 217 const struct ecard_id *id) 218 { 219 struct Scsi_Host *host; 220 int ret; 221 222 ret = ecard_request_resources(ec); 223 if (ret) 224 goto out; 225 226 host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata)); 227 if (!host) { 228 ret = -ENOMEM; 229 goto out_release; 230 } 231 232 priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW), 233 ecard_resource_len(ec, ECARD_RES_IOCSLOW)); 234 priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), 235 ecard_resource_len(ec, ECARD_RES_MEMC)); 236 if (!priv(host)->base || !priv(host)->dma) { 237 ret = -ENOMEM; 238 goto out_unmap; 239 } 240 241 host->irq = ec->irq; 242 243 NCR5380_init(host, 0); 244 245 priv(host)->ctrl = 0; 246 writeb(0, priv(host)->base + CTRL); 247 248 host->n_io_port = 255; 249 if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) { 250 ret = -EBUSY; 251 goto out_unmap; 252 } 253 254 ret = request_irq(host->irq, cumanascsi_intr, 0, 255 "CumanaSCSI-1", host); 256 if (ret) { 257 printk("scsi%d: IRQ%d not free: %d\n", 258 host->host_no, host->irq, ret); 259 goto out_unmap; 260 } 261 262 ret = scsi_add_host(host, &ec->dev); 263 if (ret) 264 goto out_free_irq; 265 266 scsi_scan_host(host); 267 goto out; 268 269 out_free_irq: 270 free_irq(host->irq, host); 271 out_unmap: 272 iounmap(priv(host)->base); 273 iounmap(priv(host)->dma); 274 scsi_host_put(host); 275 out_release: 276 ecard_release_resources(ec); 277 out: 278 return ret; 279 } 280 281 static void cumanascsi1_remove(struct expansion_card *ec) 282 { 283 struct Scsi_Host *host = ecard_get_drvdata(ec); 284 285 ecard_set_drvdata(ec, NULL); 286 287 scsi_remove_host(host); 288 free_irq(host->irq, host); 289 NCR5380_exit(host); 290 iounmap(priv(host)->base); 291 iounmap(priv(host)->dma); 292 scsi_host_put(host); 293 ecard_release_resources(ec); 294 } 295 296 static const struct ecard_id cumanascsi1_cids[] = { 297 { MANU_CUMANA, PROD_CUMANA_SCSI_1 }, 298 { 0xffff, 0xffff } 299 }; 300 301 static struct ecard_driver cumanascsi1_driver = { 302 .probe = cumanascsi1_probe, 303 .remove = cumanascsi1_remove, 304 .id_table = cumanascsi1_cids, 305 .drv = { 306 .name = "cumanascsi1", 307 }, 308 }; 309 310 static int __init cumanascsi_init(void) 311 { 312 return ecard_register_driver(&cumanascsi1_driver); 313 } 314 315 static void __exit cumanascsi_exit(void) 316 { 317 ecard_remove_driver(&cumanascsi1_driver); 318 } 319 320 module_init(cumanascsi_init); 321 module_exit(cumanascsi_exit); 322 323 MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines"); 324 MODULE_LICENSE("GPL"); 325