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  * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
52  *          only really want to use this if you're having a problem with
53  *          dropped characters during high speed communications, and even
54  *          then, you're going to be better off twiddling with transfersize.
55  *
56  * The card is detected and initialized in one of several ways :
57  * 1.  Autoprobe (default) - since the board is memory mapped,
58  *     a BIOS signature is scanned for to locate the registers.
59  *     An interrupt is triggered to autoprobe for the interrupt
60  *     line.
61  *
62  * 2.  With command line overrides - t128=address,irq may be
63  *     used on the LILO command line to override the defaults.
64  *
65  * 3.  With the T128_OVERRIDE compile time define.  This is
66  *     specified as an array of address, irq tuples.  Ie, for
67  *     one board at the default 0xcc000 address, IRQ5, I could say
68  *     -DT128_OVERRIDE={{0xcc000, 5}}
69  *
70  *     Note that if the override methods are used, place holders must
71  *     be specified for other boards in the system.
72  *
73  * T128/T128F jumper/dipswitch settings (note : on my sample, the switches
74  * were epoxy'd shut, meaning I couldn't change the 0xcc000 base address) :
75  *
76  * T128    Sw7 Sw8 Sw6 = 0ws Sw5 = boot
77  * T128F   Sw6 Sw7 Sw5 = 0ws Sw4 = boot Sw8 = floppy disable
78  * cc000   off off
79  * c8000   off on
80  * dc000   on  off
81  * d8000   on  on
82  *
83  *
84  * Interrupts
85  * There is a 12 pin jumper block, jp1, numbered as follows :
86  *   T128 (JP1)  	 T128F (J5)
87  * 2 4 6 8 10 12	11 9  7 5 3 1
88  * 1 3 5 7 9  11	12 10 8 6 4 2
89  *
90  * 3   2-4
91  * 5   1-3
92  * 7   3-5
93  * T128F only
94  * 10 8-10
95  * 12 7-9
96  * 14 10-12
97  * 15 9-11
98  */
99 
100 #include <asm/system.h>
101 #include <linux/signal.h>
102 #include <linux/sched.h>
103 #include <asm/io.h>
104 #include <linux/blk.h>
105 #include "scsi.h"
106 #include "hosts.h"
107 #include "t128.h"
108 #define AUTOPROBE_IRQ
109 #include "NCR5380.h"
110 #include "constants.h"
111 #include "sd.h"
112 #include <linux/stat.h>
113 #include <linux/init.h>
114 #include <linux/module.h>
115 
116 static struct override {
117 	unsigned long address;
118 	int irq;
119 } overrides
120 #ifdef T128_OVERRIDE
121 [] __initdata = T128_OVERRIDE;
122 #else
123 [4] __initdata = {
124 	{ 0, IRQ_AUTO},
125 	{ 0, IRQ_AUTO},
126 	{ 0, IRQ_AUTO},
127 	{ 0, IRQ_AUTO}
128 };
129 #endif
130 
131 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
132 
133 static struct base {
134 	unsigned int address;
135 	int noauto;
136 } bases[] __initdata = {
137 	{0xcc000, 0},
138 	{0xc8000, 0},
139 	{0xdc000, 0},
140 	{0xd8000, 0}
141 };
142 
143 #define NO_BASES (sizeof (bases) / sizeof (struct base))
144 
145 static struct signature {
146 	const char *string;
147 	int offset;
148 } signatures[] __initdata = {
149 	{"TSROM: SCSI BIOS, Version 1.12", 0x36},
150 };
151 
152 #define NO_SIGNATURES (sizeof (signatures) /  sizeof (struct signature))
153 
154 /**
155  *	t128_setup
156  *	@str: command line
157  *
158  *	LILO command line initialization of the overrides array,
159  */
160 
t128_setup(char * str)161 int __init t128_setup(char *str)
162 {
163 	static int commandline_current = 0;
164 	int ints[10];
165 	int i;
166 
167 	get_options(str, sizeof(ints) / sizeof(int), ints);
168 
169 	if (ints[0] != 2)
170 		printk(KERN_ERR "t128_setup : usage t128=address,irq\n");
171 	else if (commandline_current < NO_OVERRIDES) {
172 		overrides[commandline_current].address = ints[1];
173 		overrides[commandline_current].irq = ints[2];
174 		for (i = 0; i < NO_BASES; ++i)
175 			if (bases[i].address == ints[1]) {
176 				bases[i].noauto = 1;
177 				break;
178 			}
179 		++commandline_current;
180 	}
181 	return 1;
182 }
183 
184 __setup("t128=", t128_setup);
185 
186 /**
187  *	t128_detect	-	detect controllers
188  *	@tpnt: SCSI template
189  *
190  *	Detects and initializes T128,T128F, or T228 controllers
191  *	that were autoprobed, overridden on the LILO command line,
192  *	or specified at compile time.
193  */
194 
t128_detect(Scsi_Host_Template * tpnt)195 int __init t128_detect(Scsi_Host_Template * tpnt)
196 {
197 	static int current_override = 0, current_base = 0;
198 	struct Scsi_Host *instance;
199 	unsigned long base;
200 	int sig, count;
201 
202 	tpnt->proc_name = "t128";
203 	tpnt->proc_info = &t128_proc_info;
204 
205 	for (count = 0; current_override < NO_OVERRIDES; ++current_override)
206 	{
207 		base = 0;
208 
209 		if (overrides[current_override].address)
210 			base = overrides[current_override].address;
211 		else
212 			for (; !base && (current_base < NO_BASES); ++current_base) {
213 				for (sig = 0; sig < NO_SIGNATURES; ++sig)
214 					if (!bases[current_base].noauto &&
215 					    isa_check_signature(bases[current_base].address + signatures[sig].offset,
216 								signatures[sig].string,
217 								strlen(signatures[sig].string)))
218 					{
219 						base = bases[current_base].address;
220 						break;
221 					}
222 			}
223 
224 		if (!base)
225 			break;
226 
227 		instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
228 		if (instance == NULL)
229 			break;
230 
231 		instance->base = base;
232 
233 		NCR5380_init(instance, 0);
234 
235 		if (overrides[current_override].irq != IRQ_AUTO)
236 			instance->irq = overrides[current_override].irq;
237 		else
238 			instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
239 
240 		if (instance->irq != SCSI_IRQ_NONE)
241 			if (request_irq(instance->irq, do_t128_intr, SA_INTERRUPT, "t128", NULL))
242 			{
243 				printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
244 				instance->irq = SCSI_IRQ_NONE;
245 			}
246 
247 		if (instance->irq == SCSI_IRQ_NONE) {
248 			printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
249 			printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
250 		}
251 
252 		printk(KERN_INFO "scsi%d : at 0x%08lx", instance->host_no,instance->base);
253 		if (instance->irq == SCSI_IRQ_NONE)
254 			printk(" interrupts disabled");
255 		else
256 			printk(" irq %d", instance->irq);
257 		printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE);
258 		NCR5380_print_options(instance);
259 		printk("\n");
260 
261 		++current_override;
262 		++count;
263 	}
264 	return count;
265 }
266 
267 /**
268  *	t128_biosparam		-	disk geometry
269  *	@disk: device
270  *	@dev: device major/minor
271  *	@ip: array to return results
272  *
273  *	Generates a BIOS / DOS compatible H-C-S mapping for
274  *	the specified device / size.
275  *
276  *	Most SCSI boards use this mapping, I could be incorrect.  Some one
277  *	using hard disks on a trantor should verify that this mapping
278  *	corresponds to that used by the BIOS / ASPI driver by running the
279  *	linux fdisk program and matching the H_C_S coordinates to those
280  *	that DOS uses.
281  */
282 
t128_biosparam(Disk * disk,kdev_t dev,int * ip)283 int t128_biosparam(Disk * disk, kdev_t dev, int *ip)
284 {
285 	int size = disk->capacity;
286 	ip[0] = 64;
287 	ip[1] = 32;
288 	ip[2] = size >> 11;
289 	return 0;
290 }
291 
292 /**
293  *	NCR5380_pread		-	pseudo DMA read
294  *	@instance: controller
295  *	@dst: buffer to write to
296  *	@len: expect/max length
297  *
298  *	Fast 5380 pseudo-dma read function, transfers len bytes to
299  *	dst from the controller.
300  */
301 
NCR5380_pread(struct Scsi_Host * instance,unsigned char * dst,int len)302 static inline int NCR5380_pread(struct Scsi_Host *instance,
303 				unsigned char *dst, int len)
304 {
305 	unsigned long reg = instance->base + T_DATA_REG_OFFSET;
306 	unsigned char *d = dst;
307 	int i = len;
308 
309 	while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY))
310 	       	barrier();
311 	for (; i; --i) {
312 		*d++ = isa_readb(reg);
313 	}
314 
315 	if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
316 		unsigned char tmp;
317 		unsigned long foo;
318 		foo = instance->base + T_CONTROL_REG_OFFSET;
319 		tmp = isa_readb(foo);
320 		isa_writeb(tmp | T_CR_CT, foo);
321 		isa_writeb(tmp, foo);
322 		printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pread.\n", instance->host_no);
323 		return -1;
324 	} else
325 		return 0;
326 }
327 
328 /**
329  *	NCR5380_pwrite		-	pseudo DMA write
330  *	@instance: controller
331  *	@dst: buffer to write to
332  *	@len: expect/max length
333  *
334  *	Fast 5380 pseudo-dma write function, transfers len bytes from
335  *	dst to the controller.
336  */
337 
338 
NCR5380_pwrite(struct Scsi_Host * instance,unsigned char * src,int len)339 static inline int NCR5380_pwrite(struct Scsi_Host *instance,
340 				 unsigned char *src, int len)
341 {
342 	unsigned long reg = instance->base + T_DATA_REG_OFFSET;
343 	unsigned char *s = src;
344 	int i = len;
345 
346 	while (!(isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_RDY))
347 		barrier();
348 	for (; i; --i) {
349 		isa_writeb(*s++, reg);
350 	}
351 
352 	if (isa_readb(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
353 		unsigned char tmp;
354 		unsigned long foo;
355 		foo = instance->base + T_CONTROL_REG_OFFSET;
356 		tmp = isa_readb(foo);
357 		isa_writeb(tmp | T_CR_CT, foo);
358 		isa_writeb(tmp, foo);
359 		printk(KERN_ERR "scsi%d : watchdog timer fired in t128 NCR5380_pwrite()\n", instance->host_no);
360 		return -1;
361 	} else
362 		return 0;
363 }
364 
365 MODULE_LICENSE("GPL");
366 
367 #include "NCR5380.c"
368 
369 /* Eventually this will go into an include file, but this will be later */
370 static Scsi_Host_Template driver_template = TRANTOR_T128;
371 
372 #include "scsi_module.c"
373