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