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