This source file includes following definitions.
- aha1542_stat
- aha1542_out
- makecode
- aha1542_test_port
- aha1542_info
- aha1542_intr_handle
- aha1542_queuecommand
- internal_done
- aha1542_command
- setup_mailboxes
- call_buh
- aha1542_detect
- aha1542_abort
- aha1542_reset
1
2
3
4
5
6
7 #include <linux/config.h>
8 #include <linux/kernel.h>
9 #include <linux/head.h>
10 #include <linux/string.h>
11 #include <asm/system.h>
12 #include <asm/io.h>
13 #include "scsi.h"
14 #include "hosts.h"
15
16 #include "aha1542.h"
17 #ifdef DEBUG
18 #define DEB(x) x
19 #else
20 #define DEB(x)
21 #endif
22
23
24
25
26
27 #define base 0x330
28 #define intr_chan 11
29
30 static struct mailbox mb[2];
31 static struct ccb ccb;
32
33 long WAITtimeout, WAITnexttimeout = 3000000;
34
35 void (*do_done)() = NULL;
36 extern void aha1542_interrupt();
37
38 #define aha1542_intr_reset() outb(IRST, CONTROL)
39 #define aha1542_enable_intr() outb(inb_p(0xA1) & ~8, 0xA1)
40 #define aha1542_disable_intr() outb(inb_p(0xA1) | 8, 0xA1)
41
42 #define WAIT(port, mask, allof, noneof) \
43 { register WAITbits; \
44 register WAITtimeout = WAITnexttimeout; \
45 while (1) { \
46 WAITbits = inb(port) & (mask); \
47 if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
48 break; \
49 if (--WAITtimeout == 0) goto fail; \
50 } \
51 }
52
53 static void aha1542_stat(void)
54 {
55 int s = inb(STATUS), i = inb(INTRFLAGS);
56
57 printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout);
58 }
59
60 static int aha1542_out(unchar *cmdp, int len)
61 {
62 while (len--)
63 {
64 WAIT(STATUS, CDF, 0, CDF);
65 outb(*cmdp++, DATA);
66 }
67 return 0;
68 fail:
69 printk("aha1542_out failed(%d): ", len+1); aha1542_stat();
70 return 1;
71 }
72
73 int makecode(unsigned hosterr, unsigned scsierr)
74 {
75 switch (hosterr) {
76 case 0x0:
77 case 0xa:
78 case 0xb:
79 hosterr = 0;
80 break;
81
82 case 0x11:
83
84 hosterr = DID_TIME_OUT;
85 break;
86
87 case 0x12:
88
89
90
91 case 0x13:
92
93 case 0x15:
94
95
96 case 0x16:
97
98
99 case 0x17:
100
101
102 case 0x18:
103
104
105 case 0x19:
106
107
108
109 case 0x1a:
110
111
112 hosterr = DID_ERROR;
113 break;
114
115 case 0x14:
116
117
118
119 hosterr = DID_RESET;
120 break;
121 default:
122 printk("makecode: unknown hoststatus %x\n", hosterr);
123 break;
124 }
125 return scsierr|(hosterr << 16);
126 }
127
128 int aha1542_test_port(void)
129 {
130 volatile int debug = 0;
131
132
133
134
135
136 outb(SRST|IRST, CONTROL);
137
138 debug = 1;
139
140 WAIT(STATUS, STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
141
142 debug = 2;
143
144 if (inb(INTRFLAGS)&INTRMASK) goto fail;
145
146 debug = 3;
147
148 outb(CMD_ECHO, DATA);
149
150 debug = 4;
151
152 WAIT(STATUS, STATMASK, 0, STST|DIAGF|INVDCMD|DF|CDF);
153
154 debug = 5;
155
156 outb(42, DATA);
157
158 debug = 6;
159
160 WAIT(STATUS, STATMASK, DF, STST|DIAGF|CDF|INVDCMD);
161
162 debug = 7;
163
164 if (inb(DATA) != 42) goto fail;
165
166 debug = 8;
167
168 if (inb(STATUS) & DF) goto fail;
169
170 debug = 9;
171
172 WAIT(INTRFLAGS, HACC, HACC, 0);
173
174
175 debug = 10;
176
177 outb(IRST, CONTROL);
178
179 debug = 11;
180
181 return debug;
182 fail:
183 return 0;
184 }
185
186
187 char *aha1542_info(void)
188 {
189 static char buffer[] = "Adaptec 1542";
190 return buffer;
191 }
192
193
194 void aha1542_intr_handle(void)
195 {
196 int flag = inb(INTRFLAGS);
197 void (*my_done)() = do_done;
198 int errstatus;
199
200 do_done = NULL;
201 #ifdef DEBUG
202 printk("aha1542_intr_handle: ");
203 if (!(flag&ANYINTR)) printk("no interrupt?");
204 if (flag&MBIF) printk("MBIF ");
205 if (flag&MBOA) printk("MBOF ");
206 if (flag&HACC) printk("HACC ");
207 if (flag&SCRD) printk("SCRD ");
208 printk("status %02x\n", inb(STATUS));
209 if (ccb.tarstat|ccb.hastat)
210 printk("aha1542_command: returning %x (status %d)\n", ccb.tarstat + ((int) ccb.hastat << 16), mb[1].status);
211 #endif
212 aha1542_intr_reset();
213 if (!my_done) {
214 printk("aha1542_intr_handle: Unexpected interrupt\n");
215 return;
216 }
217
218
219
220 if (!mb[1].status) {
221 DEB(printk("aha1542_intr_handle: strange: mbif but no mail!\n"));
222 my_done(DID_TIME_OUT << 16);
223 return;
224 }
225
226
227 if (mb[1].status != 1)
228
229 errstatus = makecode(ccb.hastat, ccb.tarstat);
230 else
231 errstatus = 0;
232
233 mb[1].status = 0;
234
235 if (ccb.tarstat == 2) {
236 int i;
237 DEB(printk("aha1542_intr_handle: sense:"));
238 for (i = 0; i < 12; i++)
239 printk("%02x ", ccb.cdb[ccb.cdblen+i]);
240 printk("\n");
241
242
243
244
245
246
247 }
248 DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
249 my_done(errstatus);
250 return;
251 }
252
253 int aha1542_queuecommand(unchar target, const void *cmnd, void *buff, int bufflen, void (*done)(int))
254 {
255 unchar ahacmd = CMD_START_SCSI;
256 int i;
257 unchar *cmd = (unchar *) cmnd;
258
259 DEB(if (target > 1) {done(DID_TIME_OUT << 16); return 0;});
260
261 #ifdef DEBUG
262 if (*cmd == READ_10 || *cmd == WRITE_10)
263 i = xscsi2int(cmd+2);
264 else if (*cmd == READ_6 || *cmd == WRITE_6)
265 i = scsi2int(cmd+2);
266 else
267 i = -1;
268 if (done)
269 printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
270 else
271 printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
272 aha1542_stat();
273 printk("aha1542_queuecommand: dumping scsi cmd:");
274 for (i = 0; i < (*cmd<=0x1f?6:10); i++) printk("%02x ", cmd[i]);
275 printk("\n");
276 if (*cmd == WRITE_10 || *cmd == WRITE_6)
277 return 0;
278 #endif
279 memset(&ccb, 0, sizeof ccb);
280
281 ccb.cdblen = (*cmd<=0x1f)?6:10;
282
283 memcpy(ccb.cdb, cmd, ccb.cdblen);
284 ccb.op = 0;
285 ccb.idlun = (target&7)<<5;
286 ccb.rsalen = 12;
287 any2scsi(ccb.datalen, bufflen);
288 any2scsi(ccb.dataptr, buff);
289 ccb.linkptr[0] = ccb.linkptr[1] = ccb.linkptr[2] = 0;
290 ccb.commlinkid = 0;
291
292 mb[0].status = 1;
293 mb[1].status = 0;
294
295 #ifdef DEBUGd
296 printk("aha1542_command: sending.. ");
297 for (i = 0; i < sizeof(ccb)-10; i++)
298 printk("%02x ", ((unchar *)&ccb)[i]);
299 #endif
300
301 if (done) {
302 DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat());
303 if (do_done)
304 printk("aha1542_queuecommand: Two concurrent queuecommand?\n");
305 else
306 do_done = done;
307 aha1542_out(&ahacmd, 1);
308 DEB(aha1542_stat());
309 aha1542_enable_intr();
310 }
311 else
312 printk("aha1542_queuecommand: done can't be NULL\n");
313
314 return 0;
315 }
316
317 volatile static int internal_done_flag = 0;
318 volatile static int internal_done_errcode = 0;
319 static void internal_done(int errcode)
320 {
321 internal_done_errcode = errcode;
322 ++internal_done_flag;
323 }
324
325 int aha1542_command(unchar target, const void *cmnd, void *buff, int bufflen)
326 {
327 DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
328 aha1542_queuecommand(target, cmnd, buff, bufflen, internal_done);
329
330 while (!internal_done_flag);
331 internal_done_flag = 0;
332 return internal_done_errcode;
333 }
334
335
336 static void setup_mailboxes()
337 {
338 static unchar cmd[5] = {CMD_MBINIT, 1};
339
340 mb[0].status = mb[1].status = 0;
341 aha1542_intr_reset();
342 any2scsi((cmd+2), mb);
343 any2scsi(mb[0].ccbptr, &ccb);
344 aha1542_out(cmd, 5);
345 WAIT(INTRFLAGS, INTRMASK, HACC, 0);
346 while (0) {
347 fail:
348 printk("aha1542_detect: failed setting up mailboxes\n");
349 }
350 aha1542_intr_reset();
351 }
352
353
354
355 void call_buh()
356 {
357 set_intr_gate(0x2b,&aha1542_interrupt);
358 }
359
360
361 int aha1542_detect(int hostnum)
362 {
363 int i;
364
365 DEB(printk("aha1542_detect: \n"));
366
367 if (!(i = aha1542_test_port())) {
368 return 0;
369 }
370
371
372 {
373 static unchar oncmd[] = {CMD_BUSON_TIME, 5};
374 static unchar offcmd[] = {CMD_BUSOFF_TIME, 9};
375
376 aha1542_intr_reset();
377 aha1542_out(oncmd, 2);
378 WAIT(INTRFLAGS, INTRMASK, HACC, 0);
379 aha1542_intr_reset();
380 aha1542_out(offcmd, 2);
381 WAIT(INTRFLAGS, INTRMASK, HACC, 0);
382 while (0) {
383 fail:
384 printk("aha1542_detect: setting bus on/off-time failed\n");
385 }
386 aha1542_intr_reset();
387 }
388
389 aha1542_stat();
390 setup_mailboxes();
391
392 aha1542_stat();
393
394 DEB(printk("aha1542_detect: enable interrupt channel %d\n", intr_chan));
395 call_buh();
396
397 if (intr_chan >= 8)
398 outb(inb_p(0x21)&0xfb,0x21);
399
400 DEB(printk("aha1542_detect: enabling interrupts\n"));
401 aha1542_enable_intr();
402
403 #ifdef DEBUG
404 DEB(printk(" *** READ CAPACITY ***\n"));
405
406 {
407 unchar buf[8];
408 static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0};
409 int i;
410
411 for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87;
412 for (i = 0; i < 2; ++i)
413 if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
414 printk("aha_detect: LU %d sector_size %d device_size %d\n",
415 i, xscsi2int(buf+4), xscsi2int(buf));
416 }
417 }
418
419 DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
420
421 for (i = 0; i < 4; ++i)
422 {
423 unsigned char cmd[10];
424 static buffer[512];
425
426 cmd[0] = READ_10;
427 cmd[1] = 0;
428 xany2scsi(cmd+2, i);
429 cmd[6] = 0;
430 cmd[7] = 0;
431 cmd[8] = 1;
432 cmd[9] = 0;
433 aha1542_command(0, cmd, buffer, 512);
434 }
435 #endif
436 return 1;
437 }
438
439 int aha1542_abort(int i)
440 {
441 DEB(printk("aha1542_abort\n"));
442 return 0;
443 }
444
445 int aha1542_reset(void)
446 {
447 DEB(printk("aha1542_reset called\n"));
448 return 0;
449 }
450
451 __asm__("
452 _aha1542_interrupt:
453 cld
454 pushl %eax
455 pushl %ecx
456 pushl %edx
457 push %ds
458 push %es
459 push %fs
460 movl $0x10,%eax
461 mov %ax,%ds
462 mov %ax,%es
463 movl $0x17,%eax
464 mov %ax,%fs
465 movb $0x20,%al
466 outb %al,$0xA0 # EOI to interrupt controller #1
467 jmp 1f # give port chance to breathe
468 1: jmp 1f
469 1: outb %al,$0x20
470 # Please, someone, change this to use the timer
471 # andl $0xfffeffff,_timer_active
472 movl $_aha1542_intr_handle,%edx
473 call *%edx # ``interesting'' way of handling intr.
474 pop %fs
475 pop %es
476 pop %ds
477 popl %edx
478 popl %ecx
479 popl %eax
480 iret
481 ");