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