1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168#include <linux/delay.h>
169#include <linux/module.h>
170#include <linux/interrupt.h>
171#include <linux/kernel.h>
172#include <linux/types.h>
173#include <linux/string.h>
174#include <linux/spinlock.h>
175#include <linux/ioport.h>
176#include <linux/proc_fs.h>
177#include <linux/blkdev.h>
178#include <linux/init.h>
179#include <linux/stat.h>
180#include <linux/io.h>
181
182#include <asm/dma.h>
183
184#include <scsi/scsi.h>
185#include <scsi/scsi_cmnd.h>
186#include <scsi/scsi_device.h>
187#include <scsi/scsi_host.h>
188#include <scsi/scsicam.h>
189
190
191#undef WD7000_DEBUG
192#ifdef WD7000_DEBUG
193#define dprintk printk
194#else
195#define dprintk(format,args...)
196#endif
197
198
199
200
201
202
203
204#define OGMB_CNT 16
205#define ICMB_CNT 32
206
207
208
209
210
211
212
213
214#define MAX_SCBS 32
215
216
217
218
219
220
221
222
223
224
225
226
227#define WD7000_Q 16
228#define WD7000_SG 16
229
230
231
232
233
234
235typedef volatile struct mailbox {
236 unchar status;
237 unchar scbptr[3];
238} Mailbox;
239
240
241
242
243
244typedef struct adapter {
245 struct Scsi_Host *sh;
246 int iobase;
247 int irq;
248 int dma;
249 int int_counter;
250 int bus_on;
251 int bus_off;
252 struct {
253 Mailbox ogmb[OGMB_CNT];
254 Mailbox icmb[ICMB_CNT];
255 } mb;
256 int next_ogmb;
257 unchar control;
258 unchar rev1, rev2;
259} Adapter;
260
261
262
263
264static const long wd7000_biosaddr[] = {
265 0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
266 0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
267};
268#define NUM_ADDRS ARRAY_SIZE(wd7000_biosaddr)
269
270static const unsigned short wd7000_iobase[] = {
271 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
272 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
273 0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
274 0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
275};
276#define NUM_IOPORTS ARRAY_SIZE(wd7000_iobase)
277
278static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 };
279#define NUM_IRQS ARRAY_SIZE(wd7000_irq)
280
281static const short wd7000_dma[] = { 5, 6, 7 };
282#define NUM_DMAS ARRAY_SIZE(wd7000_dma)
283
284
285
286
287
288
289#define UNITS 8
290static struct Scsi_Host *wd7000_host[UNITS];
291
292#define BUS_ON 64
293#define BUS_OFF 15
294
295
296
297
298typedef struct {
299 short irq;
300 short dma;
301 unsigned iobase;
302 short bus_on;
303
304 short bus_off;
305
306
307} Config;
308
309
310
311
312static Config configs[] = {
313 {15, 6, 0x350, BUS_ON, BUS_OFF},
314 {11, 5, 0x320, BUS_ON, BUS_OFF},
315 {7, 6, 0x350, BUS_ON, BUS_OFF},
316 {-1, -1, 0x0, BUS_ON, BUS_OFF}
317};
318#define NUM_CONFIGS ARRAY_SIZE(configs)
319
320
321
322
323
324
325typedef struct signature {
326 const char *sig;
327 unsigned long ofs;
328 unsigned len;
329} Signature;
330
331static const Signature signatures[] = {
332 {"SSTBIOS", 0x0000d, 7}
333};
334#define NUM_SIGNATURES ARRAY_SIZE(signatures)
335
336
337
338
339
340
341#define ASC_STAT 0
342#define ASC_COMMAND 0
343#define ASC_INTR_STAT 1
344#define ASC_INTR_ACK 1
345#define ASC_CONTROL 2
346
347
348
349
350#define INT_IM 0x80
351#define CMD_RDY 0x40
352#define CMD_REJ 0x20
353#define ASC_INIT 0x10
354#define ASC_STATMASK 0xf0
355
356
357
358
359
360
361
362
363
364
365#define NO_OP 0
366#define INITIALIZATION 1
367#define DISABLE_UNS_INTR 2
368#define ENABLE_UNS_INTR 3
369#define INTR_ON_FREE_OGMB 4
370#define SOFT_RESET 5
371#define HARD_RESET_ACK 6
372#define START_OGMB 0x80
373#define SCAN_OGMBS 0xc0
374
375
376
377
378typedef struct initCmd {
379 unchar op;
380 unchar ID;
381 unchar bus_on;
382 unchar bus_off;
383 unchar rsvd;
384 unchar mailboxes[3];
385 unchar ogmbs;
386 unchar icmbs;
387} InitCmd;
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405#define MB_INTR 0xC0
406#define IMB_INTR 0x40
407#define MB_MASK 0x3f
408
409
410
411
412#define INT_EN 0x08
413#define DMA_EN 0x04
414#define SCSI_RES 0x02
415#define ASC_RES 0x01
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445typedef struct sgb {
446 unchar len[3];
447 unchar ptr[3];
448} Sgb;
449
450typedef struct scb {
451 unchar op;
452 unchar idlun;
453
454
455
456 unchar cdb[12];
457 volatile unchar status;
458 volatile unchar vue;
459 unchar maxlen[3];
460 unchar dataptr[3];
461 unchar linkptr[3];
462 unchar direc;
463 unchar reserved2[6];
464
465 struct scsi_cmnd *SCpnt;
466 Sgb sgb[WD7000_SG];
467 Adapter *host;
468 struct scb *next;
469} Scb;
470
471
472
473
474
475
476
477
478
479
480
481
482#define ICB_OP_MASK 0x80
483#define ICB_OP_OPEN_RBUF 0x80
484#define ICB_OP_RECV_CMD 0x81
485#define ICB_OP_RECV_DATA 0x82
486#define ICB_OP_RECV_SDATA 0x83
487#define ICB_OP_SEND_DATA 0x84
488#define ICB_OP_SEND_STAT 0x86
489
490#define ICB_OP_READ_INIT 0x88
491#define ICB_OP_READ_ID 0x89
492#define ICB_OP_SET_UMASK 0x8A
493#define ICB_OP_GET_UMASK 0x8B
494#define ICB_OP_GET_REVISION 0x8C
495#define ICB_OP_DIAGNOSTICS 0x8D
496#define ICB_OP_SET_EPARMS 0x8E
497#define ICB_OP_GET_EPARMS 0x8F
498
499typedef struct icbRecvCmd {
500 unchar op;
501 unchar IDlun;
502 unchar len[3];
503 unchar ptr[3];
504 unchar rsvd[7];
505 volatile unchar vue;
506 volatile unchar status;
507 volatile unchar phase;
508} IcbRecvCmd;
509
510typedef struct icbSendStat {
511 unchar op;
512 unchar IDlun;
513 unchar stat;
514 unchar rsvd[12];
515 volatile unchar vue;
516 volatile unchar status;
517 volatile unchar phase;
518} IcbSendStat;
519
520typedef struct icbRevLvl {
521 unchar op;
522 volatile unchar primary;
523 volatile unchar secondary;
524 unchar rsvd[12];
525 volatile unchar vue;
526 volatile unchar status;
527 volatile unchar phase;
528} IcbRevLvl;
529
530typedef struct icbUnsMask {
531 unchar op;
532 volatile unchar mask[14];
533#if 0
534 unchar rsvd[12];
535#endif
536 volatile unchar vue;
537 volatile unchar status;
538 volatile unchar phase;
539} IcbUnsMask;
540
541typedef struct icbDiag {
542 unchar op;
543 unchar type;
544 unchar len[3];
545 unchar ptr[3];
546 unchar rsvd[7];
547 volatile unchar vue;
548 volatile unchar status;
549 volatile unchar phase;
550} IcbDiag;
551
552#define ICB_DIAG_POWERUP 0
553#define ICB_DIAG_WALKING 1
554#define ICB_DIAG_DMA 2
555#define ICB_DIAG_FULL 3
556
557typedef struct icbParms {
558 unchar op;
559 unchar rsvd1;
560 unchar len[3];
561 unchar ptr[3];
562 unchar idx[2];
563 unchar rsvd2[5];
564 volatile unchar vue;
565 volatile unchar status;
566 volatile unchar phase;
567} IcbParms;
568
569typedef struct icbAny {
570 unchar op;
571 unchar data[14];
572 volatile unchar vue;
573 volatile unchar status;
574 volatile unchar phase;
575} IcbAny;
576
577typedef union icb {
578 unchar op;
579 IcbRecvCmd recv_cmd;
580 IcbSendStat send_stat;
581 IcbRevLvl rev_lvl;
582 IcbDiag diag;
583 IcbParms eparms;
584 IcbAny icb;
585 unchar data[18];
586} Icb;
587
588#ifdef MODULE
589static char *wd7000;
590module_param(wd7000, charp, 0);
591#endif
592
593
594
595
596
597
598
599static Scb scbs[MAX_SCBS];
600static Scb *scbfree;
601static int freescbs = MAX_SCBS;
602static spinlock_t scbpool_lock;
603
604
605
606
607static void __init setup_error(char *mesg, int *ints)
608{
609 if (ints[0] == 3)
610 printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n", ints[1], ints[2], ints[3], mesg);
611 else if (ints[0] == 4)
612 printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], mesg);
613 else
614 printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
615}
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632static int __init wd7000_setup(char *str)
633{
634 static short wd7000_card_num;
635 short i;
636 int ints[6];
637
638 (void) get_options(str, ARRAY_SIZE(ints), ints);
639
640 if (wd7000_card_num >= NUM_CONFIGS) {
641 printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __func__);
642 return 0;
643 }
644
645 if ((ints[0] < 3) || (ints[0] > 5)) {
646 printk(KERN_ERR "%s: Error in command line! " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __func__);
647 } else {
648 for (i = 0; i < NUM_IRQS; i++)
649 if (ints[1] == wd7000_irq[i])
650 break;
651
652 if (i == NUM_IRQS) {
653 setup_error("invalid IRQ.", ints);
654 return 0;
655 } else
656 configs[wd7000_card_num].irq = ints[1];
657
658 for (i = 0; i < NUM_DMAS; i++)
659 if (ints[2] == wd7000_dma[i])
660 break;
661
662 if (i == NUM_DMAS) {
663 setup_error("invalid DMA channel.", ints);
664 return 0;
665 } else
666 configs[wd7000_card_num].dma = ints[2];
667
668 for (i = 0; i < NUM_IOPORTS; i++)
669 if (ints[3] == wd7000_iobase[i])
670 break;
671
672 if (i == NUM_IOPORTS) {
673 setup_error("invalid I/O base address.", ints);
674 return 0;
675 } else
676 configs[wd7000_card_num].iobase = ints[3];
677
678 if (ints[0] > 3) {
679 if ((ints[4] < 500) || (ints[4] > 31875)) {
680 setup_error("BUS_ON value is out of range (500" " to 31875 nanoseconds)!", ints);
681 configs[wd7000_card_num].bus_on = BUS_ON;
682 } else
683 configs[wd7000_card_num].bus_on = ints[4] / 125;
684 } else
685 configs[wd7000_card_num].bus_on = BUS_ON;
686
687 if (ints[0] > 4) {
688 if ((ints[5] < 500) || (ints[5] > 31875)) {
689 setup_error("BUS_OFF value is out of range (500" " to 31875 nanoseconds)!", ints);
690 configs[wd7000_card_num].bus_off = BUS_OFF;
691 } else
692 configs[wd7000_card_num].bus_off = ints[5] / 125;
693 } else
694 configs[wd7000_card_num].bus_off = BUS_OFF;
695
696 if (wd7000_card_num) {
697 for (i = 0; i < (wd7000_card_num - 1); i++) {
698 int j = i + 1;
699
700 for (; j < wd7000_card_num; j++)
701 if (configs[i].irq == configs[j].irq) {
702 setup_error("duplicated IRQ!", ints);
703 return 0;
704 }
705 if (configs[i].dma == configs[j].dma) {
706 setup_error("duplicated DMA " "channel!", ints);
707 return 0;
708 }
709 if (configs[i].iobase == configs[j].iobase) {
710 setup_error("duplicated I/O " "base address!", ints);
711 return 0;
712 }
713 }
714 }
715
716 dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, "
717 "BUS_ON=%dns, BUS_OFF=%dns\n", configs[wd7000_card_num].irq, configs[wd7000_card_num].dma, configs[wd7000_card_num].iobase, configs[wd7000_card_num].bus_on * 125, configs[wd7000_card_num].bus_off * 125);
718
719 wd7000_card_num++;
720 }
721 return 1;
722}
723
724__setup("wd7000=", wd7000_setup);
725
726static inline void any2scsi(unchar * scsi, int any)
727{
728 *scsi++ = (unsigned)any >> 16;
729 *scsi++ = (unsigned)any >> 8;
730 *scsi++ = any;
731}
732
733static inline int scsi2int(unchar * scsi)
734{
735 return (scsi[0] << 16) | (scsi[1] << 8) | scsi[2];
736}
737
738static inline void wd7000_enable_intr(Adapter * host)
739{
740 host->control |= INT_EN;
741 outb(host->control, host->iobase + ASC_CONTROL);
742}
743
744
745static inline void wd7000_enable_dma(Adapter * host)
746{
747 unsigned long flags;
748 host->control |= DMA_EN;
749 outb(host->control, host->iobase + ASC_CONTROL);
750
751 flags = claim_dma_lock();
752 set_dma_mode(host->dma, DMA_MODE_CASCADE);
753 enable_dma(host->dma);
754 release_dma_lock(flags);
755
756}
757
758
759#define WAITnexttimeout 200
760
761static inline short WAIT(unsigned port, unsigned mask, unsigned allof, unsigned noneof)
762{
763 unsigned WAITbits;
764 unsigned long WAITtimeout = jiffies + WAITnexttimeout;
765
766 while (time_before_eq(jiffies, WAITtimeout)) {
767 WAITbits = inb(port) & mask;
768
769 if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
770 return (0);
771 }
772
773 return (1);
774}
775
776
777static inline int command_out(Adapter * host, unchar * cmd, int len)
778{
779 if (!WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
780 while (len--) {
781 do {
782 outb(*cmd, host->iobase + ASC_COMMAND);
783 WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
784 } while (inb(host->iobase + ASC_STAT) & CMD_REJ);
785
786 cmd++;
787 }
788
789 return (1);
790 }
791
792 printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1);
793
794 return (0);
795}
796
797
798
799
800
801
802
803
804
805
806
807
808static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
809{
810 Scb *scb, *p = NULL;
811 unsigned long flags;
812 unsigned long timeout = jiffies + WAITnexttimeout;
813 unsigned long now;
814 int i;
815
816 if (needed <= 0)
817 return (NULL);
818
819 spin_unlock_irq(host->host_lock);
820
821 retry:
822 while (freescbs < needed) {
823 timeout = jiffies + WAITnexttimeout;
824 do {
825
826 for (now = jiffies; now == jiffies;)
827 cpu_relax();
828 } while (freescbs < needed && time_before_eq(jiffies, timeout));
829
830
831
832
833 if (freescbs < needed) {
834 printk(KERN_ERR "wd7000: can't get enough free SCBs.\n");
835 return (NULL);
836 }
837 }
838
839
840 spin_lock_irqsave(&scbpool_lock, flags);
841 if (freescbs < needed) {
842 spin_unlock_irqrestore(&scbpool_lock, flags);
843 goto retry;
844 }
845
846 scb = scbfree;
847 freescbs -= needed;
848 for (i = 0; i < needed; i++) {
849 p = scbfree;
850 scbfree = p->next;
851 }
852 p->next = NULL;
853
854 spin_unlock_irqrestore(&scbpool_lock, flags);
855
856 spin_lock_irq(host->host_lock);
857 return (scb);
858}
859
860
861static inline void free_scb(Scb * scb)
862{
863 unsigned long flags;
864
865 spin_lock_irqsave(&scbpool_lock, flags);
866
867 memset(scb, 0, sizeof(Scb));
868 scb->next = scbfree;
869 scbfree = scb;
870 freescbs++;
871
872 spin_unlock_irqrestore(&scbpool_lock, flags);
873}
874
875
876static inline void init_scbs(void)
877{
878 int i;
879
880 spin_lock_init(&scbpool_lock);
881
882
883
884 scbfree = &(scbs[0]);
885 memset(scbs, 0, sizeof(scbs));
886 for (i = 0; i < MAX_SCBS - 1; i++) {
887 scbs[i].next = &(scbs[i + 1]);
888 scbs[i].SCpnt = NULL;
889 }
890 scbs[MAX_SCBS - 1].next = NULL;
891 scbs[MAX_SCBS - 1].SCpnt = NULL;
892}
893
894
895static int mail_out(Adapter * host, Scb * scbptr)
896
897
898
899{
900 int i, ogmb;
901 unsigned long flags;
902 unchar start_ogmb;
903 Mailbox *ogmbs = host->mb.ogmb;
904 int *next_ogmb = &(host->next_ogmb);
905
906 dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
907
908
909 spin_lock_irqsave(host->sh->host_lock, flags);
910 ogmb = *next_ogmb;
911 for (i = 0; i < OGMB_CNT; i++) {
912 if (ogmbs[ogmb].status == 0) {
913 dprintk(" using OGMB 0x%x", ogmb);
914 ogmbs[ogmb].status = 1;
915 any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
916
917 *next_ogmb = (ogmb + 1) % OGMB_CNT;
918 break;
919 } else
920 ogmb = (ogmb + 1) % OGMB_CNT;
921 }
922 spin_unlock_irqrestore(host->sh->host_lock, flags);
923
924 dprintk(", scb is 0x%06lx", (long) scbptr);
925
926 if (i >= OGMB_CNT) {
927
928
929
930
931
932
933
934
935 dprintk(", no free OGMBs.\n");
936 return (0);
937 }
938
939 wd7000_enable_intr(host);
940
941 start_ogmb = START_OGMB | ogmb;
942 command_out(host, &start_ogmb, 1);
943
944 dprintk(", awaiting interrupt.\n");
945
946 return (1);
947}
948
949
950static int make_code(unsigned hosterr, unsigned scsierr)
951{
952#ifdef WD7000_DEBUG
953 int in_error = hosterr;
954#endif
955
956 switch ((hosterr >> 8) & 0xff) {
957 case 0:
958 hosterr = DID_ERROR;
959 break;
960 case 1:
961 hosterr = DID_OK;
962 break;
963 case 2:
964 hosterr = DID_OK;
965 break;
966 case 4:
967 hosterr = DID_TIME_OUT;
968 break;
969 case 5:
970 hosterr = DID_RESET;
971 break;
972 case 6:
973 hosterr = DID_BAD_TARGET;
974 break;
975 case 80:
976 case 81:
977 hosterr = DID_BAD_INTR;
978 break;
979 case 82:
980 hosterr = DID_ABORT;
981 break;
982 case 83:
983 case 84:
984 hosterr = DID_RESET;
985 break;
986 default:
987 hosterr = DID_ERROR;
988 }
989#ifdef WD7000_DEBUG
990 if (scsierr || hosterr)
991 dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", scsierr, in_error, hosterr);
992#endif
993 return (scsierr | (hosterr << 16));
994}
995
996#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK)
997
998
999static irqreturn_t wd7000_intr(int irq, void *dev_id)
1000{
1001 Adapter *host = (Adapter *) dev_id;
1002 int flag, icmb, errstatus, icmb_status;
1003 int host_error, scsi_error;
1004 Scb *scb;
1005 IcbAny *icb;
1006 struct scsi_cmnd *SCpnt;
1007 Mailbox *icmbs = host->mb.icmb;
1008 unsigned long flags;
1009
1010 spin_lock_irqsave(host->sh->host_lock, flags);
1011 host->int_counter++;
1012
1013 dprintk("wd7000_intr: irq = %d, host = 0x%06lx\n", irq, (long) host);
1014
1015 flag = inb(host->iobase + ASC_INTR_STAT);
1016
1017 dprintk("wd7000_intr: intr stat = 0x%02x\n", flag);
1018
1019 if (!(inb(host->iobase + ASC_STAT) & INT_IM)) {
1020
1021
1022
1023
1024
1025
1026
1027
1028 dprintk("wd7000_intr: phantom interrupt...\n");
1029 goto ack;
1030 }
1031
1032 if (!(flag & MB_INTR))
1033 goto ack;
1034
1035
1036 if (!(flag & IMB_INTR)) {
1037 dprintk("wd7000_intr: free outgoing mailbox\n");
1038
1039
1040
1041
1042
1043 goto ack;
1044 }
1045
1046
1047 icmb = flag & MB_MASK;
1048 icmb_status = icmbs[icmb].status;
1049 if (icmb_status & 0x80) {
1050 dprintk("wd7000_intr: unsolicited interrupt 0x%02x\n", icmb_status);
1051 goto ack;
1052 }
1053
1054
1055 scb = isa_bus_to_virt(scsi2int((unchar *) icmbs[icmb].scbptr));
1056 icmbs[icmb].status = 0;
1057 if (scb->op & ICB_OP_MASK) {
1058 icb = (IcbAny *) scb;
1059 icb->status = icmb_status;
1060 icb->phase = 0;
1061 goto ack;
1062 }
1063
1064 SCpnt = scb->SCpnt;
1065 if (--(SCpnt->SCp.phase) <= 0) {
1066 host_error = scb->vue | (icmb_status << 8);
1067 scsi_error = scb->status;
1068 errstatus = make_code(host_error, scsi_error);
1069 SCpnt->result = errstatus;
1070
1071 free_scb(scb);
1072
1073 SCpnt->scsi_done(SCpnt);
1074 }
1075
1076 ack:
1077 dprintk("wd7000_intr: return from interrupt handler\n");
1078 wd7000_intr_ack(host);
1079
1080 spin_unlock_irqrestore(host->sh->host_lock, flags);
1081 return IRQ_HANDLED;
1082}
1083
1084static int wd7000_queuecommand_lck(struct scsi_cmnd *SCpnt,
1085 void (*done)(struct scsi_cmnd *))
1086{
1087 Scb *scb;
1088 Sgb *sgb;
1089 unchar *cdb = (unchar *) SCpnt->cmnd;
1090 unchar idlun;
1091 short cdblen;
1092 int nseg;
1093 Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
1094
1095 cdblen = SCpnt->cmd_len;
1096 idlun = ((SCpnt->device->id << 5) & 0xe0) | (SCpnt->device->lun & 7);
1097 SCpnt->scsi_done = done;
1098 SCpnt->SCp.phase = 1;
1099 scb = alloc_scbs(SCpnt->device->host, 1);
1100 scb->idlun = idlun;
1101 memcpy(scb->cdb, cdb, cdblen);
1102 scb->direc = 0x40;
1103
1104 scb->SCpnt = SCpnt;
1105 SCpnt->host_scribble = (unchar *) scb;
1106 scb->host = host;
1107
1108 nseg = scsi_sg_count(SCpnt);
1109 if (nseg > 1) {
1110 struct scatterlist *sg;
1111 unsigned i;
1112
1113 dprintk("Using scatter/gather with %d elements.\n", nseg);
1114
1115 sgb = scb->sgb;
1116 scb->op = 1;
1117 any2scsi(scb->dataptr, (int) sgb);
1118 any2scsi(scb->maxlen, nseg * sizeof(Sgb));
1119
1120 scsi_for_each_sg(SCpnt, sg, nseg, i) {
1121 any2scsi(sgb[i].ptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
1122 any2scsi(sgb[i].len, sg->length);
1123 }
1124 } else {
1125 scb->op = 0;
1126 if (nseg) {
1127 struct scatterlist *sg = scsi_sglist(SCpnt);
1128 any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
1129 }
1130 any2scsi(scb->maxlen, scsi_bufflen(SCpnt));
1131 }
1132
1133
1134
1135 while (!mail_out(host, scb))
1136 cpu_relax();
1137
1138 return 0;
1139}
1140
1141static DEF_SCSI_QCMD(wd7000_queuecommand)
1142
1143static int wd7000_diagnostics(Adapter * host, int code)
1144{
1145 static IcbDiag icb = { ICB_OP_DIAGNOSTICS };
1146 static unchar buf[256];
1147 unsigned long timeout;
1148
1149 icb.type = code;
1150 any2scsi(icb.len, sizeof(buf));
1151 any2scsi(icb.ptr, (int) &buf);
1152 icb.phase = 1;
1153
1154
1155
1156
1157
1158 mail_out(host, (struct scb *) &icb);
1159 timeout = jiffies + WAITnexttimeout;
1160 while (icb.phase && time_before(jiffies, timeout)) {
1161 cpu_relax();
1162 barrier();
1163 }
1164
1165 if (icb.phase) {
1166 printk("wd7000_diagnostics: timed out.\n");
1167 return (0);
1168 }
1169 if (make_code(icb.vue | (icb.status << 8), 0)) {
1170 printk("wd7000_diagnostics: failed (0x%02x,0x%02x)\n", icb.vue, icb.status);
1171 return (0);
1172 }
1173
1174 return (1);
1175}
1176
1177
1178static int wd7000_adapter_reset(Adapter * host)
1179{
1180 InitCmd init_cmd = {
1181 INITIALIZATION,
1182 7,
1183 host->bus_on,
1184 host->bus_off,
1185 0,
1186 {0, 0, 0},
1187 OGMB_CNT,
1188 ICMB_CNT
1189 };
1190 int diag;
1191
1192
1193
1194
1195 outb(ASC_RES, host->iobase + ASC_CONTROL);
1196 udelay(40);
1197 outb(0, host->iobase + ASC_CONTROL);
1198 host->control = 0;
1199
1200 if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
1201 printk(KERN_ERR "wd7000_init: WAIT timed out.\n");
1202 return -1;
1203 }
1204
1205 if ((diag = inb(host->iobase + ASC_INTR_STAT)) != 1) {
1206 printk("wd7000_init: ");
1207
1208 switch (diag) {
1209 case 2:
1210 printk(KERN_ERR "RAM failure.\n");
1211 break;
1212 case 3:
1213 printk(KERN_ERR "FIFO R/W failed\n");
1214 break;
1215 case 4:
1216 printk(KERN_ERR "SBIC register R/W failed\n");
1217 break;
1218 case 5:
1219 printk(KERN_ERR "Initialization D-FF failed.\n");
1220 break;
1221 case 6:
1222 printk(KERN_ERR "Host IRQ D-FF failed.\n");
1223 break;
1224 case 7:
1225 printk(KERN_ERR "ROM checksum error.\n");
1226 break;
1227 default:
1228 printk(KERN_ERR "diagnostic code 0x%02Xh received.\n", diag);
1229 }
1230 return -1;
1231 }
1232
1233 memset(&(host->mb), 0, sizeof(host->mb));
1234
1235
1236 any2scsi((unchar *) & (init_cmd.mailboxes), (int) &(host->mb));
1237 if (!command_out(host, (unchar *) & init_cmd, sizeof(init_cmd))) {
1238 printk(KERN_ERR "wd7000_adapter_reset: adapter initialization failed.\n");
1239 return -1;
1240 }
1241
1242 if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
1243 printk("wd7000_adapter_reset: WAIT timed out.\n");
1244 return -1;
1245 }
1246 return 0;
1247}
1248
1249static int wd7000_init(Adapter * host)
1250{
1251 if (wd7000_adapter_reset(host) == -1)
1252 return 0;
1253
1254
1255 if (request_irq(host->irq, wd7000_intr, 0, "wd7000", host)) {
1256 printk("wd7000_init: can't get IRQ %d.\n", host->irq);
1257 return (0);
1258 }
1259 if (request_dma(host->dma, "wd7000")) {
1260 printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
1261 free_irq(host->irq, host);
1262 return (0);
1263 }
1264 wd7000_enable_dma(host);
1265 wd7000_enable_intr(host);
1266
1267 if (!wd7000_diagnostics(host, ICB_DIAG_FULL)) {
1268 free_dma(host->dma);
1269 free_irq(host->irq, NULL);
1270 return (0);
1271 }
1272
1273 return (1);
1274}
1275
1276
1277static void wd7000_revision(Adapter * host)
1278{
1279 static IcbRevLvl icb = { ICB_OP_GET_REVISION };
1280
1281 icb.phase = 1;
1282
1283
1284
1285
1286
1287
1288 mail_out(host, (struct scb *) &icb);
1289 while (icb.phase) {
1290 cpu_relax();
1291 barrier();
1292 }
1293 host->rev1 = icb.primary;
1294 host->rev2 = icb.secondary;
1295}
1296
1297
1298#undef SPRINTF
1299#define SPRINTF(args...) { seq_printf(m, ## args); }
1300
1301static int wd7000_set_info(struct Scsi_Host *host, char *buffer, int length)
1302{
1303 dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
1304
1305
1306
1307
1308 dprintk("Sorry, this function is currently out of order...\n");
1309 return (length);
1310}
1311
1312
1313static int wd7000_show_info(struct seq_file *m, struct Scsi_Host *host)
1314{
1315 Adapter *adapter = (Adapter *)host->hostdata;
1316 unsigned long flags;
1317#ifdef WD7000_DEBUG
1318 Mailbox *ogmbs, *icmbs;
1319 short count;
1320#endif
1321
1322 spin_lock_irqsave(host->host_lock, flags);
1323 SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2);
1324 SPRINTF(" IO base: 0x%x\n", adapter->iobase);
1325 SPRINTF(" IRQ: %d\n", adapter->irq);
1326 SPRINTF(" DMA channel: %d\n", adapter->dma);
1327 SPRINTF(" Interrupts: %d\n", adapter->int_counter);
1328 SPRINTF(" BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125);
1329 SPRINTF(" BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
1330
1331#ifdef WD7000_DEBUG
1332 ogmbs = adapter->mb.ogmb;
1333 icmbs = adapter->mb.icmb;
1334
1335 SPRINTF("\nControl port value: 0x%x\n", adapter->control);
1336 SPRINTF("Incoming mailbox:\n");
1337 SPRINTF(" size: %d\n", ICMB_CNT);
1338 SPRINTF(" queued messages: ");
1339
1340 for (i = count = 0; i < ICMB_CNT; i++)
1341 if (icmbs[i].status) {
1342 count++;
1343 SPRINTF("0x%x ", i);
1344 }
1345
1346 SPRINTF(count ? "\n" : "none\n");
1347
1348 SPRINTF("Outgoing mailbox:\n");
1349 SPRINTF(" size: %d\n", OGMB_CNT);
1350 SPRINTF(" next message: 0x%x\n", adapter->next_ogmb);
1351 SPRINTF(" queued messages: ");
1352
1353 for (i = count = 0; i < OGMB_CNT; i++)
1354 if (ogmbs[i].status) {
1355 count++;
1356 SPRINTF("0x%x ", i);
1357 }
1358
1359 SPRINTF(count ? "\n" : "none\n");
1360#endif
1361
1362 spin_unlock_irqrestore(host->host_lock, flags);
1363
1364 return 0;
1365}
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379static __init int wd7000_detect(struct scsi_host_template *tpnt)
1380{
1381 short present = 0, biosaddr_ptr, sig_ptr, i, pass;
1382 short biosptr[NUM_CONFIGS];
1383 unsigned iobase;
1384 Adapter *host = NULL;
1385 struct Scsi_Host *sh;
1386 int unit = 0;
1387
1388 dprintk("wd7000_detect: started\n");
1389
1390#ifdef MODULE
1391 if (wd7000)
1392 wd7000_setup(wd7000);
1393#endif
1394
1395 for (i = 0; i < UNITS; wd7000_host[i++] = NULL);
1396 for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);
1397
1398 tpnt->proc_name = "wd7000";
1399 tpnt->show_info = &wd7000_show_info;
1400 tpnt->write_info = wd7000_set_info;
1401
1402
1403
1404
1405 init_scbs();
1406
1407 for (pass = 0; pass < NUM_CONFIGS; pass++) {
1408
1409
1410
1411 for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
1412 for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {
1413 for (i = 0; i < pass; i++)
1414 if (biosptr[i] == biosaddr_ptr)
1415 break;
1416
1417 if (i == pass) {
1418 void __iomem *biosaddr = ioremap(wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs,
1419 signatures[sig_ptr].len);
1420 short bios_match = 1;
1421
1422 if (biosaddr)
1423 bios_match = check_signature(biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len);
1424
1425 iounmap(biosaddr);
1426
1427 if (bios_match)
1428 goto bios_matched;
1429 }
1430 }
1431
1432 bios_matched:
1433
1434
1435
1436#ifdef WD7000_DEBUG
1437 dprintk("wd7000_detect: pass %d\n", pass + 1);
1438
1439 if (biosaddr_ptr == NUM_ADDRS)
1440 dprintk("WD-7000 SST BIOS not detected...\n");
1441 else
1442 dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n", wd7000_biosaddr[biosaddr_ptr]);
1443#endif
1444
1445 if (configs[pass].irq < 0)
1446 continue;
1447
1448 if (unit == UNITS)
1449 continue;
1450
1451 iobase = configs[pass].iobase;
1452
1453 dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);
1454
1455 if (request_region(iobase, 4, "wd7000")) {
1456
1457 dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
1458
1459
1460
1461 outb(ASC_RES, iobase + ASC_CONTROL);
1462 msleep(10);
1463 outb(0, iobase + ASC_CONTROL);
1464
1465 if (WAIT(iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
1466 dprintk("failed!\n");
1467 goto err_release;
1468 } else
1469 dprintk("ok!\n");
1470
1471 if (inb(iobase + ASC_INTR_STAT) == 1) {
1472
1473
1474
1475
1476
1477
1478
1479 sh = scsi_register(tpnt, sizeof(Adapter));
1480 if (sh == NULL)
1481 goto err_release;
1482
1483 host = (Adapter *) sh->hostdata;
1484
1485 dprintk("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
1486 memset(host, 0, sizeof(Adapter));
1487
1488 host->irq = configs[pass].irq;
1489 host->dma = configs[pass].dma;
1490 host->iobase = iobase;
1491 host->int_counter = 0;
1492 host->bus_on = configs[pass].bus_on;
1493 host->bus_off = configs[pass].bus_off;
1494 host->sh = wd7000_host[unit] = sh;
1495 unit++;
1496
1497 dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma);
1498
1499 if (!wd7000_init(host))
1500 goto err_unregister;
1501
1502
1503
1504
1505 wd7000_revision(host);
1506
1507
1508
1509
1510 if (host->rev1 < 6)
1511 sh->sg_tablesize = 1;
1512
1513 present++;
1514
1515 if (biosaddr_ptr != NUM_ADDRS)
1516 biosptr[pass] = biosaddr_ptr;
1517
1518 printk(KERN_INFO "Western Digital WD-7000 (rev %d.%d) ", host->rev1, host->rev2);
1519 printk("using IO 0x%x, IRQ %d, DMA %d.\n", host->iobase, host->irq, host->dma);
1520 printk(" BUS_ON time: %dns, BUS_OFF time: %dns\n", host->bus_on * 125, host->bus_off * 125);
1521 }
1522 } else
1523 dprintk("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
1524
1525 continue;
1526
1527 err_unregister:
1528 scsi_unregister(sh);
1529 err_release:
1530 release_region(iobase, 4);
1531
1532 }
1533
1534 if (!present)
1535 printk("Failed initialization of WD-7000 SCSI card!\n");
1536
1537 return (present);
1538}
1539
1540static int wd7000_release(struct Scsi_Host *shost)
1541{
1542 if (shost->irq)
1543 free_irq(shost->irq, NULL);
1544 if (shost->io_port && shost->n_io_port)
1545 release_region(shost->io_port, shost->n_io_port);
1546 scsi_unregister(shost);
1547 return 0;
1548}
1549
1550#if 0
1551
1552
1553
1554static int wd7000_abort(Scsi_Cmnd * SCpnt)
1555{
1556 Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
1557
1558 if (inb(host->iobase + ASC_STAT) & INT_IM) {
1559 printk("wd7000_abort: lost interrupt\n");
1560 wd7000_intr_handle(host->irq, NULL, NULL);
1561 return FAILED;
1562 }
1563 return FAILED;
1564}
1565#endif
1566
1567
1568
1569
1570
1571static int wd7000_host_reset(struct scsi_cmnd *SCpnt)
1572{
1573 Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
1574
1575 spin_lock_irq(SCpnt->device->host->host_lock);
1576
1577 if (wd7000_adapter_reset(host) < 0) {
1578 spin_unlock_irq(SCpnt->device->host->host_lock);
1579 return FAILED;
1580 }
1581
1582 wd7000_enable_intr(host);
1583
1584 spin_unlock_irq(SCpnt->device->host->host_lock);
1585 return SUCCESS;
1586}
1587
1588
1589
1590
1591
1592static int wd7000_biosparam(struct scsi_device *sdev,
1593 struct block_device *bdev, sector_t capacity, int *ip)
1594{
1595 char b[BDEVNAME_SIZE];
1596
1597 dprintk("wd7000_biosparam: dev=%s, size=%d, ",
1598 bdevname(bdev, b), capacity);
1599 (void)b;
1600
1601
1602
1603
1604 ip[0] = 64;
1605 ip[1] = 32;
1606 ip[2] = capacity >> 11;
1607
1608
1609
1610
1611 if (ip[2] >= 1024) {
1612 int info[3];
1613
1614
1615
1616
1617 if ((scsicam_bios_param(bdev, capacity, info) < 0) || !(((info[0] == 64) && (info[1] == 32)) || ((info[0] == 255) && (info[1] == 63)))) {
1618 printk("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" " using extended translation.\n");
1619
1620 ip[0] = 255;
1621 ip[1] = 63;
1622 ip[2] = (unsigned long) capacity / (255 * 63);
1623 } else {
1624 ip[0] = info[0];
1625 ip[1] = info[1];
1626 ip[2] = info[2];
1627
1628 if (info[0] == 255)
1629 printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __func__);
1630 }
1631 }
1632
1633 dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
1634 dprintk("WARNING: check, if the bios geometry is correct.\n");
1635
1636 return (0);
1637}
1638
1639MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
1640MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");
1641MODULE_LICENSE("GPL");
1642
1643static struct scsi_host_template driver_template = {
1644 .proc_name = "wd7000",
1645 .show_info = wd7000_show_info,
1646 .write_info = wd7000_set_info,
1647 .name = "Western Digital WD-7000",
1648 .detect = wd7000_detect,
1649 .release = wd7000_release,
1650 .queuecommand = wd7000_queuecommand,
1651 .eh_host_reset_handler = wd7000_host_reset,
1652 .bios_param = wd7000_biosparam,
1653 .can_queue = WD7000_Q,
1654 .this_id = 7,
1655 .sg_tablesize = WD7000_SG,
1656 .cmd_per_lun = 1,
1657 .unchecked_isa_dma = 1,
1658 .use_clustering = ENABLE_CLUSTERING,
1659};
1660
1661#include "scsi_module.c"
1662