Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.38-rc2 447 lines 12 kB view raw
1#define AUTOSENSE 2#define PSEUDO_DMA 3 4/* 5 * Trantor T128/T128F/T228 driver 6 * Note : architecturally, the T100 and T130 are different and won't 7 * work 8 * 9 * Copyright 1993, Drew Eckhardt 10 * Visionary Computing 11 * (Unix and Linux consulting and custom programming) 12 * drew@colorado.edu 13 * +1 (303) 440-4894 14 * 15 * DISTRIBUTION RELEASE 3. 16 * 17 * For more information, please consult 18 * 19 * Trantor Systems, Ltd. 20 * T128/T128F/T228 SCSI Host Adapter 21 * Hardware Specifications 22 * 23 * Trantor Systems, Ltd. 24 * 5415 Randall Place 25 * Fremont, CA 94538 26 * 1+ (415) 770-1400, FAX 1+ (415) 770-9910 27 * 28 * and 29 * 30 * NCR 5380 Family 31 * SCSI Protocol Controller 32 * Databook 33 * 34 * NCR Microelectronics 35 * 1635 Aeroplaza Drive 36 * Colorado Springs, CO 80916 37 * 1+ (719) 578-3400 38 * 1+ (800) 334-5454 39 */ 40 41/* 42 * Options : 43 * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically 44 * for commands that return with a CHECK CONDITION status. 45 * 46 * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance 47 * increase compared to polled I/O. 48 * 49 * PARITY - enable parity checking. Not supported. 50 * 51 * SCSI2 - enable support for SCSI-II tagged queueing. Untested. 52 * 53 * 54 * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You 55 * only really want to use this if you're having a problem with 56 * dropped characters during high speed communications, and even 57 * then, you're going to be better off twiddling with transfersize. 58 * 59 * USLEEP - enable support for devices that don't disconnect. Untested. 60 * 61 * The card is detected and initialized in one of several ways : 62 * 1. Autoprobe (default) - since the board is memory mapped, 63 * a BIOS signature is scanned for to locate the registers. 64 * An interrupt is triggered to autoprobe for the interrupt 65 * line. 66 * 67 * 2. With command line overrides - t128=address,irq may be 68 * used on the LILO command line to override the defaults. 69 * 70 * 3. With the T128_OVERRIDE compile time define. This is 71 * specified as an array of address, irq tuples. Ie, for 72 * one board at the default 0xcc000 address, IRQ5, I could say 73 * -DT128_OVERRIDE={{0xcc000, 5}} 74 * 75 * Note that if the override methods are used, place holders must 76 * be specified for other boards in the system. 77 * 78 * T128/T128F jumper/dipswitch settings (note : on my sample, the switches 79 * were epoxy'd shut, meaning I couldn't change the 0xcc000 base address) : 80 * 81 * T128 Sw7 Sw8 Sw6 = 0ws Sw5 = boot 82 * T128F Sw6 Sw7 Sw5 = 0ws Sw4 = boot Sw8 = floppy disable 83 * cc000 off off 84 * c8000 off on 85 * dc000 on off 86 * d8000 on on 87 * 88 * 89 * Interrupts 90 * There is a 12 pin jumper block, jp1, numbered as follows : 91 * T128 (JP1) T128F (J5) 92 * 2 4 6 8 10 12 11 9 7 5 3 1 93 * 1 3 5 7 9 11 12 10 8 6 4 2 94 * 95 * 3 2-4 96 * 5 1-3 97 * 7 3-5 98 * T128F only 99 * 10 8-10 100 * 12 7-9 101 * 14 10-12 102 * 15 9-11 103 */ 104 105/* 106 * $Log: t128.c,v $ 107 */ 108 109#include <asm/system.h> 110#include <linux/signal.h> 111#include <linux/io.h> 112#include <linux/blkdev.h> 113#include <linux/interrupt.h> 114#include <linux/stat.h> 115#include <linux/init.h> 116#include <linux/module.h> 117#include <linux/delay.h> 118 119#include "scsi.h" 120#include <scsi/scsi_host.h> 121#include "t128.h" 122#define AUTOPROBE_IRQ 123#include "NCR5380.h" 124 125static struct override { 126 unsigned long address; 127 int irq; 128} overrides 129#ifdef T128_OVERRIDE 130 [] __initdata = T128_OVERRIDE; 131#else 132 [4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, 133 {0 ,IRQ_AUTO}, {0, IRQ_AUTO}}; 134#endif 135 136#define NO_OVERRIDES ARRAY_SIZE(overrides) 137 138static struct base { 139 unsigned int address; 140 int noauto; 141} bases[] __initdata = { 142 { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0} 143}; 144 145#define NO_BASES ARRAY_SIZE(bases) 146 147static struct signature { 148 const char *string; 149 int offset; 150} signatures[] __initdata = { 151{"TSROM: SCSI BIOS, Version 1.12", 0x36}, 152}; 153 154#define NO_SIGNATURES ARRAY_SIZE(signatures) 155 156/* 157 * Function : t128_setup(char *str, int *ints) 158 * 159 * Purpose : LILO command line initialization of the overrides array, 160 * 161 * Inputs : str - unused, ints - array of integer parameters with ints[0] 162 * equal to the number of ints. 163 * 164 */ 165 166void __init t128_setup(char *str, int *ints){ 167 static int commandline_current = 0; 168 int i; 169 if (ints[0] != 2) 170 printk("t128_setup : usage t128=address,irq\n"); 171 else 172 if (commandline_current < NO_OVERRIDES) { 173 overrides[commandline_current].address = ints[1]; 174 overrides[commandline_current].irq = ints[2]; 175 for (i = 0; i < NO_BASES; ++i) 176 if (bases[i].address == ints[1]) { 177 bases[i].noauto = 1; 178 break; 179 } 180 ++commandline_current; 181 } 182} 183 184/* 185 * Function : int t128_detect(struct scsi_host_template * tpnt) 186 * 187 * Purpose : detects and initializes T128,T128F, or T228 controllers 188 * that were autoprobed, overridden on the LILO command line, 189 * or specified at compile time. 190 * 191 * Inputs : tpnt - template for this SCSI adapter. 192 * 193 * Returns : 1 if a host adapter was found, 0 if not. 194 * 195 */ 196 197int __init t128_detect(struct scsi_host_template * tpnt){ 198 static int current_override = 0, current_base = 0; 199 struct Scsi_Host *instance; 200 unsigned long base; 201 void __iomem *p; 202 int sig, count; 203 204 tpnt->proc_name = "t128"; 205 tpnt->proc_info = &t128_proc_info; 206 207 for (count = 0; current_override < NO_OVERRIDES; ++current_override) { 208 base = 0; 209 p = NULL; 210 211 if (overrides[current_override].address) { 212 base = overrides[current_override].address; 213 p = ioremap(bases[current_base].address, 0x2000); 214 if (!p) 215 base = 0; 216 } else 217 for (; !base && (current_base < NO_BASES); ++current_base) { 218#if (TDEBUG & TDEBUG_INIT) 219 printk("scsi-t128 : probing address %08x\n", bases[current_base].address); 220#endif 221 if (bases[current_base].noauto) 222 continue; 223 p = ioremap(bases[current_base].address, 0x2000); 224 if (!p) 225 continue; 226 for (sig = 0; sig < NO_SIGNATURES; ++sig) 227 if (check_signature(p + signatures[sig].offset, 228 signatures[sig].string, 229 strlen(signatures[sig].string))) { 230 base = bases[current_base].address; 231#if (TDEBUG & TDEBUG_INIT) 232 printk("scsi-t128 : detected board.\n"); 233#endif 234 goto found; 235 } 236 iounmap(p); 237 } 238 239#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) 240 printk("scsi-t128 : base = %08x\n", (unsigned int) base); 241#endif 242 243 if (!base) 244 break; 245 246found: 247 instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); 248 if(instance == NULL) 249 break; 250 251 instance->base = base; 252 ((struct NCR5380_hostdata *)instance->hostdata)->base = p; 253 254 NCR5380_init(instance, 0); 255 256 if (overrides[current_override].irq != IRQ_AUTO) 257 instance->irq = overrides[current_override].irq; 258 else 259 instance->irq = NCR5380_probe_irq(instance, T128_IRQS); 260 261 if (instance->irq != SCSI_IRQ_NONE) 262 if (request_irq(instance->irq, t128_intr, IRQF_DISABLED, "t128", 263 instance)) { 264 printk("scsi%d : IRQ%d not free, interrupts disabled\n", 265 instance->host_no, instance->irq); 266 instance->irq = SCSI_IRQ_NONE; 267 } 268 269 if (instance->irq == SCSI_IRQ_NONE) { 270 printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); 271 printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); 272 } 273 274#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) 275 printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); 276#endif 277 278 printk("scsi%d : at 0x%08lx", instance->host_no, instance->base); 279 if (instance->irq == SCSI_IRQ_NONE) 280 printk (" interrupts disabled"); 281 else 282 printk (" irq %d", instance->irq); 283 printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", 284 CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE); 285 NCR5380_print_options(instance); 286 printk("\n"); 287 288 ++current_override; 289 ++count; 290 } 291 return count; 292} 293 294static int t128_release(struct Scsi_Host *shost) 295{ 296 NCR5380_local_declare(); 297 NCR5380_setup(shost); 298 if (shost->irq) 299 free_irq(shost->irq, shost); 300 NCR5380_exit(shost); 301 if (shost->io_port && shost->n_io_port) 302 release_region(shost->io_port, shost->n_io_port); 303 scsi_unregister(shost); 304 iounmap(base); 305 return 0; 306} 307 308/* 309 * Function : int t128_biosparam(Disk * disk, struct block_device *dev, int *ip) 310 * 311 * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 312 * the specified device / size. 313 * 314 * Inputs : size = size of device in sectors (512 bytes), dev = block device 315 * major / minor, ip[] = {heads, sectors, cylinders} 316 * 317 * Returns : always 0 (success), initializes ip 318 * 319 */ 320 321/* 322 * XXX Most SCSI boards use this mapping, I could be incorrect. Some one 323 * using hard disks on a trantor should verify that this mapping corresponds 324 * to that used by the BIOS / ASPI driver by running the linux fdisk program 325 * and matching the H_C_S coordinates to what DOS uses. 326 */ 327 328int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev, 329 sector_t capacity, int * ip) 330{ 331 ip[0] = 64; 332 ip[1] = 32; 333 ip[2] = capacity >> 11; 334 return 0; 335} 336 337/* 338 * Function : int NCR5380_pread (struct Scsi_Host *instance, 339 * unsigned char *dst, int len) 340 * 341 * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to 342 * dst 343 * 344 * Inputs : dst = destination, len = length in bytes 345 * 346 * Returns : 0 on success, non zero on a failure such as a watchdog 347 * timeout. 348 */ 349 350static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, 351 int len) { 352 NCR5380_local_declare(); 353 void __iomem *reg; 354 unsigned char *d = dst; 355 register int i = len; 356 357 NCR5380_setup(instance); 358 reg = base + T_DATA_REG_OFFSET; 359 360#if 0 361 for (; i; --i) { 362 while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); 363#else 364 while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); 365 for (; i; --i) { 366#endif 367 *d++ = readb(reg); 368 } 369 370 if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) { 371 unsigned char tmp; 372 void __iomem *foo = base + T_CONTROL_REG_OFFSET; 373 tmp = readb(foo); 374 writeb(tmp | T_CR_CT, foo); 375 writeb(tmp, foo); 376 printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", 377 instance->host_no); 378 return -1; 379 } else 380 return 0; 381} 382 383/* 384 * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 385 * unsigned char *src, int len) 386 * 387 * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from 388 * src 389 * 390 * Inputs : src = source, len = length in bytes 391 * 392 * Returns : 0 on success, non zero on a failure such as a watchdog 393 * timeout. 394 */ 395 396static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, 397 int len) { 398 NCR5380_local_declare(); 399 void __iomem *reg; 400 unsigned char *s = src; 401 register int i = len; 402 403 NCR5380_setup(instance); 404 reg = base + T_DATA_REG_OFFSET; 405 406#if 0 407 for (; i; --i) { 408 while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); 409#else 410 while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); 411 for (; i; --i) { 412#endif 413 writeb(*s++, reg); 414 } 415 416 if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) { 417 unsigned char tmp; 418 void __iomem *foo = base + T_CONTROL_REG_OFFSET; 419 tmp = readb(foo); 420 writeb(tmp | T_CR_CT, foo); 421 writeb(tmp, foo); 422 printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", 423 instance->host_no); 424 return -1; 425 } else 426 return 0; 427} 428 429MODULE_LICENSE("GPL"); 430 431#include "NCR5380.c" 432 433static struct scsi_host_template driver_template = { 434 .name = "Trantor T128/T128F/T228", 435 .detect = t128_detect, 436 .release = t128_release, 437 .queuecommand = t128_queue_command, 438 .eh_abort_handler = t128_abort, 439 .eh_bus_reset_handler = t128_bus_reset, 440 .bios_param = t128_biosparam, 441 .can_queue = CAN_QUEUE, 442 .this_id = 7, 443 .sg_tablesize = SG_ALL, 444 .cmd_per_lun = CMD_PER_LUN, 445 .use_clustering = DISABLE_CLUSTERING, 446}; 447#include "scsi_module.c"