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