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