Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.5-rc5 412 lines 10 kB view raw
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/io.h> 72#include <linux/blkdev.h> 73#include <linux/interrupt.h> 74#include <linux/init.h> 75#include <linux/module.h> 76 77#include <scsi/scsi_host.h> 78#include "t128.h" 79#define AUTOPROBE_IRQ 80#include "NCR5380.h" 81 82static struct override { 83 unsigned long address; 84 int irq; 85} overrides 86#ifdef T128_OVERRIDE 87 [] __initdata = T128_OVERRIDE; 88#else 89 [4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, 90 {0 ,IRQ_AUTO}, {0, IRQ_AUTO}}; 91#endif 92 93#define NO_OVERRIDES ARRAY_SIZE(overrides) 94 95static struct base { 96 unsigned int address; 97 int noauto; 98} bases[] __initdata = { 99 { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0} 100}; 101 102#define NO_BASES ARRAY_SIZE(bases) 103 104static struct signature { 105 const char *string; 106 int offset; 107} signatures[] __initdata = { 108{"TSROM: SCSI BIOS, Version 1.12", 0x36}, 109}; 110 111#define NO_SIGNATURES ARRAY_SIZE(signatures) 112 113#ifndef MODULE 114/* 115 * Function : t128_setup(char *str, int *ints) 116 * 117 * Purpose : LILO command line initialization of the overrides array, 118 * 119 * Inputs : str - unused, ints - array of integer parameters with ints[0] 120 * equal to the number of ints. 121 * 122 */ 123 124static int __init t128_setup(char *str) 125{ 126 static int commandline_current; 127 int i; 128 int ints[10]; 129 130 get_options(str, ARRAY_SIZE(ints), ints); 131 if (ints[0] != 2) 132 printk("t128_setup : usage t128=address,irq\n"); 133 else 134 if (commandline_current < NO_OVERRIDES) { 135 overrides[commandline_current].address = ints[1]; 136 overrides[commandline_current].irq = ints[2]; 137 for (i = 0; i < NO_BASES; ++i) 138 if (bases[i].address == ints[1]) { 139 bases[i].noauto = 1; 140 break; 141 } 142 ++commandline_current; 143 } 144 return 1; 145} 146 147__setup("t128=", t128_setup); 148#endif 149 150/* 151 * Function : int t128_detect(struct scsi_host_template * tpnt) 152 * 153 * Purpose : detects and initializes T128,T128F, or T228 controllers 154 * that were autoprobed, overridden on the LILO command line, 155 * or specified at compile time. 156 * 157 * Inputs : tpnt - template for this SCSI adapter. 158 * 159 * Returns : 1 if a host adapter was found, 0 if not. 160 * 161 */ 162 163static int __init t128_detect(struct scsi_host_template *tpnt) 164{ 165 static int current_override, current_base; 166 struct Scsi_Host *instance; 167 unsigned long base; 168 void __iomem *p; 169 int sig, count; 170 171 for (count = 0; current_override < NO_OVERRIDES; ++current_override) { 172 base = 0; 173 p = NULL; 174 175 if (overrides[current_override].address) { 176 base = overrides[current_override].address; 177 p = ioremap(bases[current_base].address, 0x2000); 178 if (!p) 179 base = 0; 180 } else 181 for (; !base && (current_base < NO_BASES); ++current_base) { 182 dprintk(NDEBUG_INIT, "t128: probing address 0x%08x\n", 183 bases[current_base].address); 184 if (bases[current_base].noauto) 185 continue; 186 p = ioremap(bases[current_base].address, 0x2000); 187 if (!p) 188 continue; 189 for (sig = 0; sig < NO_SIGNATURES; ++sig) 190 if (check_signature(p + signatures[sig].offset, 191 signatures[sig].string, 192 strlen(signatures[sig].string))) { 193 base = bases[current_base].address; 194 dprintk(NDEBUG_INIT, "t128: detected board\n"); 195 goto found; 196 } 197 iounmap(p); 198 } 199 200 dprintk(NDEBUG_INIT, "t128: base = 0x%08x\n", (unsigned int)base); 201 202 if (!base) 203 break; 204 205found: 206 instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); 207 if(instance == NULL) 208 goto out_unmap; 209 210 instance->base = base; 211 ((struct NCR5380_hostdata *)instance->hostdata)->base = p; 212 213 if (NCR5380_init(instance, 0)) 214 goto out_unregister; 215 216 NCR5380_maybe_reset_bus(instance); 217 218 if (overrides[current_override].irq != IRQ_AUTO) 219 instance->irq = overrides[current_override].irq; 220 else 221 instance->irq = NCR5380_probe_irq(instance, T128_IRQS); 222 223 /* Compatibility with documented NCR5380 kernel parameters */ 224 if (instance->irq == 255) 225 instance->irq = NO_IRQ; 226 227 if (instance->irq != NO_IRQ) 228 if (request_irq(instance->irq, t128_intr, 0, "t128", 229 instance)) { 230 printk("scsi%d : IRQ%d not free, interrupts disabled\n", 231 instance->host_no, instance->irq); 232 instance->irq = NO_IRQ; 233 } 234 235 if (instance->irq == NO_IRQ) { 236 printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); 237 printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); 238 } 239 240 dprintk(NDEBUG_INIT, "scsi%d: irq = %d\n", 241 instance->host_no, instance->irq); 242 243 ++current_override; 244 ++count; 245 } 246 return count; 247 248out_unregister: 249 scsi_unregister(instance); 250out_unmap: 251 iounmap(p); 252 return count; 253} 254 255static int t128_release(struct Scsi_Host *shost) 256{ 257 struct NCR5380_hostdata *hostdata = shost_priv(shost); 258 259 if (shost->irq != NO_IRQ) 260 free_irq(shost->irq, shost); 261 NCR5380_exit(shost); 262 scsi_unregister(shost); 263 iounmap(hostdata->base); 264 return 0; 265} 266 267/* 268 * Function : int t128_biosparam(Disk * disk, struct block_device *dev, int *ip) 269 * 270 * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 271 * the specified device / size. 272 * 273 * Inputs : size = size of device in sectors (512 bytes), dev = block device 274 * major / minor, ip[] = {heads, sectors, cylinders} 275 * 276 * Returns : always 0 (success), initializes ip 277 * 278 */ 279 280/* 281 * XXX Most SCSI boards use this mapping, I could be incorrect. Some one 282 * using hard disks on a trantor should verify that this mapping corresponds 283 * to that used by the BIOS / ASPI driver by running the linux fdisk program 284 * and matching the H_C_S coordinates to what DOS uses. 285 */ 286 287static int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev, 288 sector_t capacity, int *ip) 289{ 290 ip[0] = 64; 291 ip[1] = 32; 292 ip[2] = capacity >> 11; 293 return 0; 294} 295 296/* 297 * Function : int NCR5380_pread (struct Scsi_Host *instance, 298 * unsigned char *dst, int len) 299 * 300 * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to 301 * dst 302 * 303 * Inputs : dst = destination, len = length in bytes 304 * 305 * Returns : 0 on success, non zero on a failure such as a watchdog 306 * timeout. 307 */ 308 309static inline int 310NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) 311{ 312 struct NCR5380_hostdata *hostdata = shost_priv(instance); 313 void __iomem *reg, *base = hostdata->base; 314 unsigned char *d = dst; 315 register int i = len; 316 317 reg = base + T_DATA_REG_OFFSET; 318 319#if 0 320 for (; i; --i) { 321 while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); 322#else 323 while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); 324 for (; i; --i) { 325#endif 326 *d++ = readb(reg); 327 } 328 329 if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) { 330 unsigned char tmp; 331 void __iomem *foo = base + T_CONTROL_REG_OFFSET; 332 tmp = readb(foo); 333 writeb(tmp | T_CR_CT, foo); 334 writeb(tmp, foo); 335 printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", 336 instance->host_no); 337 return -1; 338 } else 339 return 0; 340} 341 342/* 343 * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 344 * unsigned char *src, int len) 345 * 346 * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from 347 * src 348 * 349 * Inputs : src = source, len = length in bytes 350 * 351 * Returns : 0 on success, non zero on a failure such as a watchdog 352 * timeout. 353 */ 354 355static inline int 356NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) 357{ 358 struct NCR5380_hostdata *hostdata = shost_priv(instance); 359 void __iomem *reg, *base = hostdata->base; 360 unsigned char *s = src; 361 register int i = len; 362 363 reg = base + T_DATA_REG_OFFSET; 364 365#if 0 366 for (; i; --i) { 367 while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); 368#else 369 while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); 370 for (; i; --i) { 371#endif 372 writeb(*s++, reg); 373 } 374 375 if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) { 376 unsigned char tmp; 377 void __iomem *foo = base + T_CONTROL_REG_OFFSET; 378 tmp = readb(foo); 379 writeb(tmp | T_CR_CT, foo); 380 writeb(tmp, foo); 381 printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", 382 instance->host_no); 383 return -1; 384 } else 385 return 0; 386} 387 388MODULE_LICENSE("GPL"); 389 390#include "NCR5380.c" 391 392static struct scsi_host_template driver_template = { 393 .name = "Trantor T128/T128F/T228", 394 .detect = t128_detect, 395 .release = t128_release, 396 .proc_name = "t128", 397 .show_info = t128_show_info, 398 .write_info = t128_write_info, 399 .info = t128_info, 400 .queuecommand = t128_queue_command, 401 .eh_abort_handler = t128_abort, 402 .eh_bus_reset_handler = t128_bus_reset, 403 .bios_param = t128_biosparam, 404 .can_queue = 32, 405 .this_id = 7, 406 .sg_tablesize = SG_ALL, 407 .cmd_per_lun = 2, 408 .use_clustering = DISABLE_CLUSTERING, 409 .cmd_size = NCR5380_CMD_SIZE, 410 .max_sectors = 128, 411}; 412#include "scsi_module.c"