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