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, IRQF_DISABLED, "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...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
1300
1301static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host)
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_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
1314{
1315 Adapter *adapter = (Adapter *)host->hostdata;
1316 unsigned long flags;
1317 char *pos = buffer;
1318#ifdef WD7000_DEBUG
1319 Mailbox *ogmbs, *icmbs;
1320 short count;
1321#endif
1322
1323
1324
1325
1326 if (inout)
1327 return (wd7000_set_info(buffer, length, host));
1328
1329 spin_lock_irqsave(host->host_lock, flags);
1330 SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2);
1331 SPRINTF(" IO base: 0x%x\n", adapter->iobase);
1332 SPRINTF(" IRQ: %d\n", adapter->irq);
1333 SPRINTF(" DMA channel: %d\n", adapter->dma);
1334 SPRINTF(" Interrupts: %d\n", adapter->int_counter);
1335 SPRINTF(" BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125);
1336 SPRINTF(" BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
1337
1338#ifdef WD7000_DEBUG
1339 ogmbs = adapter->mb.ogmb;
1340 icmbs = adapter->mb.icmb;
1341
1342 SPRINTF("\nControl port value: 0x%x\n", adapter->control);
1343 SPRINTF("Incoming mailbox:\n");
1344 SPRINTF(" size: %d\n", ICMB_CNT);
1345 SPRINTF(" queued messages: ");
1346
1347 for (i = count = 0; i < ICMB_CNT; i++)
1348 if (icmbs[i].status) {
1349 count++;
1350 SPRINTF("0x%x ", i);
1351 }
1352
1353 SPRINTF(count ? "\n" : "none\n");
1354
1355 SPRINTF("Outgoing mailbox:\n");
1356 SPRINTF(" size: %d\n", OGMB_CNT);
1357 SPRINTF(" next message: 0x%x\n", adapter->next_ogmb);
1358 SPRINTF(" queued messages: ");
1359
1360 for (i = count = 0; i < OGMB_CNT; i++)
1361 if (ogmbs[i].status) {
1362 count++;
1363 SPRINTF("0x%x ", i);
1364 }
1365
1366 SPRINTF(count ? "\n" : "none\n");
1367#endif
1368
1369 spin_unlock_irqrestore(host->host_lock, flags);
1370
1371
1372
1373
1374 *start = buffer + offset;
1375
1376 if ((pos - buffer) < offset)
1377 return (0);
1378 else if ((pos - buffer - offset) < length)
1379 return (pos - buffer - offset);
1380 else
1381 return (length);
1382}
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396static __init int wd7000_detect(struct scsi_host_template *tpnt)
1397{
1398 short present = 0, biosaddr_ptr, sig_ptr, i, pass;
1399 short biosptr[NUM_CONFIGS];
1400 unsigned iobase;
1401 Adapter *host = NULL;
1402 struct Scsi_Host *sh;
1403 int unit = 0;
1404
1405 dprintk("wd7000_detect: started\n");
1406
1407#ifdef MODULE
1408 if (wd7000)
1409 wd7000_setup(wd7000);
1410#endif
1411
1412 for (i = 0; i < UNITS; wd7000_host[i++] = NULL);
1413 for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);
1414
1415 tpnt->proc_name = "wd7000";
1416 tpnt->proc_info = &wd7000_proc_info;
1417
1418
1419
1420
1421 init_scbs();
1422
1423 for (pass = 0; pass < NUM_CONFIGS; pass++) {
1424
1425
1426
1427 for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
1428 for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {
1429 for (i = 0; i < pass; i++)
1430 if (biosptr[i] == biosaddr_ptr)
1431 break;
1432
1433 if (i == pass) {
1434 void __iomem *biosaddr = ioremap(wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs,
1435 signatures[sig_ptr].len);
1436 short bios_match = 1;
1437
1438 if (biosaddr)
1439 bios_match = check_signature(biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len);
1440
1441 iounmap(biosaddr);
1442
1443 if (bios_match)
1444 goto bios_matched;
1445 }
1446 }
1447
1448 bios_matched:
1449
1450
1451
1452#ifdef WD7000_DEBUG
1453 dprintk("wd7000_detect: pass %d\n", pass + 1);
1454
1455 if (biosaddr_ptr == NUM_ADDRS)
1456 dprintk("WD-7000 SST BIOS not detected...\n");
1457 else
1458 dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n", wd7000_biosaddr[biosaddr_ptr]);
1459#endif
1460
1461 if (configs[pass].irq < 0)
1462 continue;
1463
1464 if (unit == UNITS)
1465 continue;
1466
1467 iobase = configs[pass].iobase;
1468
1469 dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);
1470
1471 if (request_region(iobase, 4, "wd7000")) {
1472
1473 dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
1474
1475
1476
1477 outb(ASC_RES, iobase + ASC_CONTROL);
1478 msleep(10);
1479 outb(0, iobase + ASC_CONTROL);
1480
1481 if (WAIT(iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
1482 dprintk("failed!\n");
1483 goto err_release;
1484 } else
1485 dprintk("ok!\n");
1486
1487 if (inb(iobase + ASC_INTR_STAT) == 1) {
1488
1489
1490
1491
1492
1493
1494
1495 sh = scsi_register(tpnt, sizeof(Adapter));
1496 if (sh == NULL)
1497 goto err_release;
1498
1499 host = (Adapter *) sh->hostdata;
1500
1501 dprintk("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
1502 memset(host, 0, sizeof(Adapter));
1503
1504 host->irq = configs[pass].irq;
1505 host->dma = configs[pass].dma;
1506 host->iobase = iobase;
1507 host->int_counter = 0;
1508 host->bus_on = configs[pass].bus_on;
1509 host->bus_off = configs[pass].bus_off;
1510 host->sh = wd7000_host[unit] = sh;
1511 unit++;
1512
1513 dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma);
1514
1515 if (!wd7000_init(host))
1516 goto err_unregister;
1517
1518
1519
1520
1521 wd7000_revision(host);
1522
1523
1524
1525
1526 if (host->rev1 < 6)
1527 sh->sg_tablesize = 1;
1528
1529 present++;
1530
1531 if (biosaddr_ptr != NUM_ADDRS)
1532 biosptr[pass] = biosaddr_ptr;
1533
1534 printk(KERN_INFO "Western Digital WD-7000 (rev %d.%d) ", host->rev1, host->rev2);
1535 printk("using IO 0x%x, IRQ %d, DMA %d.\n", host->iobase, host->irq, host->dma);
1536 printk(" BUS_ON time: %dns, BUS_OFF time: %dns\n", host->bus_on * 125, host->bus_off * 125);
1537 }
1538 } else
1539 dprintk("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
1540
1541 continue;
1542
1543 err_unregister:
1544 scsi_unregister(sh);
1545 err_release:
1546 release_region(iobase, 4);
1547
1548 }
1549
1550 if (!present)
1551 printk("Failed initialization of WD-7000 SCSI card!\n");
1552
1553 return (present);
1554}
1555
1556static int wd7000_release(struct Scsi_Host *shost)
1557{
1558 if (shost->irq)
1559 free_irq(shost->irq, NULL);
1560 if (shost->io_port && shost->n_io_port)
1561 release_region(shost->io_port, shost->n_io_port);
1562 scsi_unregister(shost);
1563 return 0;
1564}
1565
1566#if 0
1567
1568
1569
1570static int wd7000_abort(Scsi_Cmnd * SCpnt)
1571{
1572 Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
1573
1574 if (inb(host->iobase + ASC_STAT) & INT_IM) {
1575 printk("wd7000_abort: lost interrupt\n");
1576 wd7000_intr_handle(host->irq, NULL, NULL);
1577 return FAILED;
1578 }
1579 return FAILED;
1580}
1581#endif
1582
1583
1584
1585
1586
1587static int wd7000_host_reset(struct scsi_cmnd *SCpnt)
1588{
1589 Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
1590
1591 spin_lock_irq(SCpnt->device->host->host_lock);
1592
1593 if (wd7000_adapter_reset(host) < 0) {
1594 spin_unlock_irq(SCpnt->device->host->host_lock);
1595 return FAILED;
1596 }
1597
1598 wd7000_enable_intr(host);
1599
1600 spin_unlock_irq(SCpnt->device->host->host_lock);
1601 return SUCCESS;
1602}
1603
1604
1605
1606
1607
1608static int wd7000_biosparam(struct scsi_device *sdev,
1609 struct block_device *bdev, sector_t capacity, int *ip)
1610{
1611 char b[BDEVNAME_SIZE];
1612
1613 dprintk("wd7000_biosparam: dev=%s, size=%d, ",
1614 bdevname(bdev, b), capacity);
1615 (void)b;
1616
1617
1618
1619
1620 ip[0] = 64;
1621 ip[1] = 32;
1622 ip[2] = capacity >> 11;
1623
1624
1625
1626
1627 if (ip[2] >= 1024) {
1628 int info[3];
1629
1630
1631
1632
1633 if ((scsicam_bios_param(bdev, capacity, info) < 0) || !(((info[0] == 64) && (info[1] == 32)) || ((info[0] == 255) && (info[1] == 63)))) {
1634 printk("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" " using extended translation.\n");
1635
1636 ip[0] = 255;
1637 ip[1] = 63;
1638 ip[2] = (unsigned long) capacity / (255 * 63);
1639 } else {
1640 ip[0] = info[0];
1641 ip[1] = info[1];
1642 ip[2] = info[2];
1643
1644 if (info[0] == 255)
1645 printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __func__);
1646 }
1647 }
1648
1649 dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
1650 dprintk("WARNING: check, if the bios geometry is correct.\n");
1651
1652 return (0);
1653}
1654
1655MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
1656MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");
1657MODULE_LICENSE("GPL");
1658
1659static struct scsi_host_template driver_template = {
1660 .proc_name = "wd7000",
1661 .proc_info = wd7000_proc_info,
1662 .name = "Western Digital WD-7000",
1663 .detect = wd7000_detect,
1664 .release = wd7000_release,
1665 .queuecommand = wd7000_queuecommand,
1666 .eh_host_reset_handler = wd7000_host_reset,
1667 .bios_param = wd7000_biosparam,
1668 .can_queue = WD7000_Q,
1669 .this_id = 7,
1670 .sg_tablesize = WD7000_SG,
1671 .cmd_per_lun = 1,
1672 .unchecked_isa_dma = 1,
1673 .use_clustering = ENABLE_CLUSTERING,
1674};
1675
1676#include "scsi_module.c"
1677