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