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 .use_clustering = DISABLE_CLUSTERING, 226 .proc_name = "CumanaSCSI-1", 227 }; 228 229 static int __devinit 230 cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id) 231 { 232 struct Scsi_Host *host; 233 int ret; 234 235 ret = ecard_request_resources(ec); 236 if (ret) 237 goto out; 238 239 host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata)); 240 if (!host) { 241 ret = -ENOMEM; 242 goto out_release; 243 } 244 245 priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW), 246 ecard_resource_len(ec, ECARD_RES_IOCSLOW)); 247 priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), 248 ecard_resource_len(ec, ECARD_RES_MEMC)); 249 if (!priv(host)->base || !priv(host)->dma) { 250 ret = -ENOMEM; 251 goto out_unmap; 252 } 253 254 host->irq = ec->irq; 255 256 NCR5380_init(host, 0); 257 258 priv(host)->ctrl = 0; 259 writeb(0, priv(host)->base + CTRL); 260 261 host->n_io_port = 255; 262 if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) { 263 ret = -EBUSY; 264 goto out_unmap; 265 } 266 267 ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED, 268 "CumanaSCSI-1", host); 269 if (ret) { 270 printk("scsi%d: IRQ%d not free: %d\n", 271 host->host_no, host->irq, ret); 272 goto out_unmap; 273 } 274 275 printk("scsi%d: at port 0x%08lx irq %d", 276 host->host_no, host->io_port, host->irq); 277 printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", 278 host->can_queue, host->cmd_per_lun, CUMANASCSI_PUBLIC_RELEASE); 279 printk("\nscsi%d:", host->host_no); 280 NCR5380_print_options(host); 281 printk("\n"); 282 283 ret = scsi_add_host(host, &ec->dev); 284 if (ret) 285 goto out_free_irq; 286 287 scsi_scan_host(host); 288 goto out; 289 290 out_free_irq: 291 free_irq(host->irq, host); 292 out_unmap: 293 iounmap(priv(host)->base); 294 iounmap(priv(host)->dma); 295 scsi_host_put(host); 296 out_release: 297 ecard_release_resources(ec); 298 out: 299 return ret; 300 } 301 302 static void __devexit cumanascsi1_remove(struct expansion_card *ec) 303 { 304 struct Scsi_Host *host = ecard_get_drvdata(ec); 305 306 ecard_set_drvdata(ec, NULL); 307 308 scsi_remove_host(host); 309 free_irq(host->irq, host); 310 NCR5380_exit(host); 311 iounmap(priv(host)->base); 312 iounmap(priv(host)->dma); 313 scsi_host_put(host); 314 ecard_release_resources(ec); 315 } 316 317 static const struct ecard_id cumanascsi1_cids[] = { 318 { MANU_CUMANA, PROD_CUMANA_SCSI_1 }, 319 { 0xffff, 0xffff } 320 }; 321 322 static struct ecard_driver cumanascsi1_driver = { 323 .probe = cumanascsi1_probe, 324 .remove = __devexit_p(cumanascsi1_remove), 325 .id_table = cumanascsi1_cids, 326 .drv = { 327 .name = "cumanascsi1", 328 }, 329 }; 330 331 static int __init cumanascsi_init(void) 332 { 333 return ecard_register_driver(&cumanascsi1_driver); 334 } 335 336 static void __exit cumanascsi_exit(void) 337 { 338 ecard_remove_driver(&cumanascsi1_driver); 339 } 340 341 module_init(cumanascsi_init); 342 module_exit(cumanascsi_exit); 343 344 MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines"); 345 MODULE_LICENSE("GPL"); 346