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