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/slab.h>
175#include <linux/spinlock.h>
176#include <linux/ioport.h>
177#include <linux/proc_fs.h>
178#include <linux/blkdev.h>
179#include <linux/init.h>
180#include <linux/stat.h>
181#include <linux/io.h>
182
183#include <asm/system.h>
184#include <asm/dma.h>
185
186#include <scsi/scsi.h>
187#include <scsi/scsi_cmnd.h>
188#include <scsi/scsi_device.h>
189#include <scsi/scsi_host.h>
190#include <scsi/scsicam.h>
191
192
193#undef WD7000_DEBUG
194#ifdef WD7000_DEBUG
195#define dprintk printk
196#else
197#define dprintk(format,args...)
198#endif
199
200
201
202
203
204
205
206#define OGMB_CNT 16
207#define ICMB_CNT 32
208
209
210
211
212
213
214
215
216#define MAX_SCBS 32
217
218
219
220
221
222
223
224
225
226
227
228
229#define WD7000_Q 16
230#define WD7000_SG 16
231
232
233
234
235
236
237typedef volatile struct mailbox {
238 unchar status;
239 unchar scbptr[3];
240} Mailbox;
241
242
243
244
245
246typedef struct adapter {
247 struct Scsi_Host *sh;
248 int iobase;
249 int irq;
250 int dma;
251 int int_counter;
252 int bus_on;
253 int bus_off;
254 struct {
255 Mailbox ogmb[OGMB_CNT];
256 Mailbox icmb[ICMB_CNT];
257 } mb;
258 int next_ogmb;
259 unchar control;
260 unchar rev1, rev2;
261} Adapter;
262
263
264
265
266static const long wd7000_biosaddr[] = {
267 0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
268 0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
269};
270#define NUM_ADDRS ARRAY_SIZE(wd7000_biosaddr)
271
272static const unsigned short wd7000_iobase[] = {
273 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
274 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
275 0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
276 0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
277};
278#define NUM_IOPORTS ARRAY_SIZE(wd7000_iobase)
279
280static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 };
281#define NUM_IRQS ARRAY_SIZE(wd7000_irq)
282
283static const short wd7000_dma[] = { 5, 6, 7 };
284#define NUM_DMAS ARRAY_SIZE(wd7000_dma)
285
286
287
288
289
290
291#define UNITS 8
292static struct Scsi_Host *wd7000_host[UNITS];
293
294#define BUS_ON 64
295#define BUS_OFF 15
296
297
298
299
300typedef struct {
301 short irq;
302 short dma;
303 unsigned iobase;
304 short bus_on;
305
306 short bus_off;
307
308
309} Config;
310
311
312
313
314static Config configs[] = {
315 {15, 6, 0x350, BUS_ON, BUS_OFF},
316 {11, 5, 0x320, BUS_ON, BUS_OFF},
317 {7, 6, 0x350, BUS_ON, BUS_OFF},
318 {-1, -1, 0x0, BUS_ON, BUS_OFF}
319};
320#define NUM_CONFIGS ARRAY_SIZE(configs)
321
322
323
324
325
326
327typedef struct signature {
328 const char *sig;
329 unsigned long ofs;
330 unsigned len;
331} Signature;
332
333static const Signature signatures[] = {
334 {"SSTBIOS", 0x0000d, 7}
335};
336#define NUM_SIGNATURES ARRAY_SIZE(signatures)
337
338
339
340
341
342
343#define ASC_STAT 0
344#define ASC_COMMAND 0
345#define ASC_INTR_STAT 1
346#define ASC_INTR_ACK 1
347#define ASC_CONTROL 2
348
349
350
351
352#define INT_IM 0x80
353#define CMD_RDY 0x40
354#define CMD_REJ 0x20
355#define ASC_INIT 0x10
356#define ASC_STATMASK 0xf0
357
358
359
360
361
362
363
364
365
366
367#define NO_OP 0
368#define INITIALIZATION 1
369#define DISABLE_UNS_INTR 2
370#define ENABLE_UNS_INTR 3
371#define INTR_ON_FREE_OGMB 4
372#define SOFT_RESET 5
373#define HARD_RESET_ACK 6
374#define START_OGMB 0x80
375#define SCAN_OGMBS 0xc0
376
377
378
379
380typedef struct initCmd {
381 unchar op;
382 unchar ID;
383 unchar bus_on;
384 unchar bus_off;
385 unchar rsvd;
386 unchar mailboxes[3];
387 unchar ogmbs;
388 unchar icmbs;
389} InitCmd;
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407#define MB_INTR 0xC0
408#define IMB_INTR 0x40
409#define MB_MASK 0x3f
410
411
412
413
414#define INT_EN 0x08
415#define DMA_EN 0x04
416#define SCSI_RES 0x02
417#define ASC_RES 0x01
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
446
447typedef struct sgb {
448 unchar len[3];
449 unchar ptr[3];
450} Sgb;
451
452typedef struct scb {
453 unchar op;
454 unchar idlun;
455
456
457
458 unchar cdb[12];
459 volatile unchar status;
460 volatile unchar vue;
461 unchar maxlen[3];
462 unchar dataptr[3];
463 unchar linkptr[3];
464 unchar direc;
465 unchar reserved2[6];
466
467 struct scsi_cmnd *SCpnt;
468 Sgb sgb[WD7000_SG];
469 Adapter *host;
470 struct scb *next;
471} Scb;
472
473
474
475
476
477
478
479
480
481
482
483
484#define ICB_OP_MASK 0x80
485#define ICB_OP_OPEN_RBUF 0x80
486#define ICB_OP_RECV_CMD 0x81
487#define ICB_OP_RECV_DATA 0x82
488#define ICB_OP_RECV_SDATA 0x83
489#define ICB_OP_SEND_DATA 0x84
490#define ICB_OP_SEND_STAT 0x86
491
492#define ICB_OP_READ_INIT 0x88
493#define ICB_OP_READ_ID 0x89
494#define ICB_OP_SET_UMASK 0x8A
495#define ICB_OP_GET_UMASK 0x8B
496#define ICB_OP_GET_REVISION 0x8C
497#define ICB_OP_DIAGNOSTICS 0x8D
498#define ICB_OP_SET_EPARMS 0x8E
499#define ICB_OP_GET_EPARMS 0x8F
500
501typedef struct icbRecvCmd {
502 unchar op;
503 unchar IDlun;
504 unchar len[3];
505 unchar ptr[3];
506 unchar rsvd[7];
507 volatile unchar vue;
508 volatile unchar status;
509 volatile unchar phase;
510} IcbRecvCmd;
511
512typedef struct icbSendStat {
513 unchar op;
514 unchar IDlun;
515 unchar stat;
516 unchar rsvd[12];
517 volatile unchar vue;
518 volatile unchar status;
519 volatile unchar phase;
520} IcbSendStat;
521
522typedef struct icbRevLvl {
523 unchar op;
524 volatile unchar primary;
525 volatile unchar secondary;
526 unchar rsvd[12];
527 volatile unchar vue;
528 volatile unchar status;
529 volatile unchar phase;
530} IcbRevLvl;
531
532typedef struct icbUnsMask {
533 unchar op;
534 volatile unchar mask[14];
535#if 0
536 unchar rsvd[12];
537#endif
538 volatile unchar vue;
539 volatile unchar status;
540 volatile unchar phase;
541} IcbUnsMask;
542
543typedef struct icbDiag {
544 unchar op;
545 unchar type;
546 unchar len[3];
547 unchar ptr[3];
548 unchar rsvd[7];
549 volatile unchar vue;
550 volatile unchar status;
551 volatile unchar phase;
552} IcbDiag;
553
554#define ICB_DIAG_POWERUP 0
555#define ICB_DIAG_WALKING 1
556#define ICB_DIAG_DMA 2
557#define ICB_DIAG_FULL 3
558
559typedef struct icbParms {
560 unchar op;
561 unchar rsvd1;
562 unchar len[3];
563 unchar ptr[3];
564 unchar idx[2];
565 unchar rsvd2[5];
566 volatile unchar vue;
567 volatile unchar status;
568 volatile unchar phase;
569} IcbParms;
570
571typedef struct icbAny {
572 unchar op;
573 unchar data[14];
574 volatile unchar vue;
575 volatile unchar status;
576 volatile unchar phase;
577} IcbAny;
578
579typedef union icb {
580 unchar op;
581 IcbRecvCmd recv_cmd;
582 IcbSendStat send_stat;
583 IcbRevLvl rev_lvl;
584 IcbDiag diag;
585 IcbParms eparms;
586 IcbAny icb;
587 unchar data[18];
588} Icb;
589
590#ifdef MODULE
591static char *wd7000;
592module_param(wd7000, charp, 0);
593#endif
594
595
596
597
598
599
600
601static Scb scbs[MAX_SCBS];
602static Scb *scbfree;
603static int freescbs = MAX_SCBS;
604static spinlock_t scbpool_lock;
605
606
607
608
609static void __init setup_error(char *mesg, int *ints)
610{
611 if (ints[0] == 3)
612 printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n", ints[1], ints[2], ints[3], mesg);
613 else if (ints[0] == 4)
614 printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], mesg);
615 else
616 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);
617}
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634static int __init wd7000_setup(char *str)
635{
636 static short wd7000_card_num;
637 short i;
638 int ints[6];
639
640 (void) get_options(str, ARRAY_SIZE(ints), ints);
641
642 if (wd7000_card_num >= NUM_CONFIGS) {
643 printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __func__);
644 return 0;
645 }
646
647 if ((ints[0] < 3) || (ints[0] > 5)) {
648 printk(KERN_ERR "%s: Error in command line! " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __func__);
649 } else {
650 for (i = 0; i < NUM_IRQS; i++)
651 if (ints[1] == wd7000_irq[i])
652 break;
653
654 if (i == NUM_IRQS) {
655 setup_error("invalid IRQ.", ints);
656 return 0;
657 } else
658 configs[wd7000_card_num].irq = ints[1];
659
660 for (i = 0; i < NUM_DMAS; i++)
661 if (ints[2] == wd7000_dma[i])
662 break;
663
664 if (i == NUM_DMAS) {
665 setup_error("invalid DMA channel.", ints);
666 return 0;
667 } else
668 configs[wd7000_card_num].dma = ints[2];
669
670 for (i = 0; i < NUM_IOPORTS; i++)
671 if (ints[3] == wd7000_iobase[i])
672 break;
673
674 if (i == NUM_IOPORTS) {
675 setup_error("invalid I/O base address.", ints);
676 return 0;
677 } else
678 configs[wd7000_card_num].iobase = ints[3];
679
680 if (ints[0] > 3) {
681 if ((ints[4] < 500) || (ints[4] > 31875)) {
682 setup_error("BUS_ON value is out of range (500" " to 31875 nanoseconds)!", ints);
683 configs[wd7000_card_num].bus_on = BUS_ON;
684 } else
685 configs[wd7000_card_num].bus_on = ints[4] / 125;
686 } else
687 configs[wd7000_card_num].bus_on = BUS_ON;
688
689 if (ints[0] > 4) {
690 if ((ints[5] < 500) || (ints[5] > 31875)) {
691 setup_error("BUS_OFF value is out of range (500" " to 31875 nanoseconds)!", ints);
692 configs[wd7000_card_num].bus_off = BUS_OFF;
693 } else
694 configs[wd7000_card_num].bus_off = ints[5] / 125;
695 } else
696 configs[wd7000_card_num].bus_off = BUS_OFF;
697
698 if (wd7000_card_num) {
699 for (i = 0; i < (wd7000_card_num - 1); i++) {
700 int j = i + 1;
701
702 for (; j < wd7000_card_num; j++)
703 if (configs[i].irq == configs[j].irq) {
704 setup_error("duplicated IRQ!", ints);
705 return 0;
706 }
707 if (configs[i].dma == configs[j].dma) {
708 setup_error("duplicated DMA " "channel!", ints);
709 return 0;
710 }
711 if (configs[i].iobase == configs[j].iobase) {
712 setup_error("duplicated I/O " "base address!", ints);
713 return 0;
714 }
715 }
716 }
717
718 dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, "
719 "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);
720
721 wd7000_card_num++;
722 }
723 return 1;
724}
725
726__setup("wd7000=", wd7000_setup);
727
728static inline void any2scsi(unchar * scsi, int any)
729{
730 *scsi++ = (unsigned)any >> 16;
731 *scsi++ = (unsigned)any >> 8;
732 *scsi++ = any;
733}
734
735static inline int scsi2int(unchar * scsi)
736{
737 return (scsi[0] << 16) | (scsi[1] << 8) | scsi[2];
738}
739
740static inline void wd7000_enable_intr(Adapter * host)
741{
742 host->control |= INT_EN;
743 outb(host->control, host->iobase + ASC_CONTROL);
744}
745
746
747static inline void wd7000_enable_dma(Adapter * host)
748{
749 unsigned long flags;
750 host->control |= DMA_EN;
751 outb(host->control, host->iobase + ASC_CONTROL);
752
753 flags = claim_dma_lock();
754 set_dma_mode(host->dma, DMA_MODE_CASCADE);
755 enable_dma(host->dma);
756 release_dma_lock(flags);
757
758}
759
760
761#define WAITnexttimeout 200
762
763static inline short WAIT(unsigned port, unsigned mask, unsigned allof, unsigned noneof)
764{
765 unsigned WAITbits;
766 unsigned long WAITtimeout = jiffies + WAITnexttimeout;
767
768 while (time_before_eq(jiffies, WAITtimeout)) {
769 WAITbits = inb(port) & mask;
770
771 if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
772 return (0);
773 }
774
775 return (1);
776}
777
778
779static inline int command_out(Adapter * host, unchar * cmd, int len)
780{
781 if (!WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
782 while (len--) {
783 do {
784 outb(*cmd, host->iobase + ASC_COMMAND);
785 WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
786 } while (inb(host->iobase + ASC_STAT) & CMD_REJ);
787
788 cmd++;
789 }
790
791 return (1);
792 }
793
794 printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1);
795
796 return (0);
797}
798
799
800
801
802
803
804
805
806
807
808
809
810static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
811{
812 Scb *scb, *p = NULL;
813 unsigned long flags;
814 unsigned long timeout = jiffies + WAITnexttimeout;
815 unsigned long now;
816 int i;
817
818 if (needed <= 0)
819 return (NULL);
820
821 spin_unlock_irq(host->host_lock);
822
823 retry:
824 while (freescbs < needed) {
825 timeout = jiffies + WAITnexttimeout;
826 do {
827
828 for (now = jiffies; now == jiffies;)
829 cpu_relax();
830 } while (freescbs < needed && time_before_eq(jiffies, timeout));
831
832
833
834
835 if (freescbs < needed) {
836 printk(KERN_ERR "wd7000: can't get enough free SCBs.\n");
837 return (NULL);
838 }
839 }
840
841
842 spin_lock_irqsave(&scbpool_lock, flags);
843 if (freescbs < needed) {
844 spin_unlock_irqrestore(&scbpool_lock, flags);
845 goto retry;
846 }
847
848 scb = scbfree;
849 freescbs -= needed;
850 for (i = 0; i < needed; i++) {
851 p = scbfree;
852 scbfree = p->next;
853 }
854 p->next = NULL;
855
856 spin_unlock_irqrestore(&scbpool_lock, flags);
857
858 spin_lock_irq(host->host_lock);
859 return (scb);
860}
861
862
863static inline void free_scb(Scb * scb)
864{
865 unsigned long flags;
866
867 spin_lock_irqsave(&scbpool_lock, flags);
868
869 memset(scb, 0, sizeof(Scb));
870 scb->next = scbfree;
871 scbfree = scb;
872 freescbs++;
873
874 spin_unlock_irqrestore(&scbpool_lock, flags);
875}
876
877
878static inline void init_scbs(void)
879{
880 int i;
881
882 spin_lock_init(&scbpool_lock);
883
884
885
886 scbfree = &(scbs[0]);
887 memset(scbs, 0, sizeof(scbs));
888 for (i = 0; i < MAX_SCBS - 1; i++) {
889 scbs[i].next = &(scbs[i + 1]);
890 scbs[i].SCpnt = NULL;
891 }
892 scbs[MAX_SCBS - 1].next = NULL;
893 scbs[MAX_SCBS - 1].SCpnt = NULL;
894}
895
896
897static int mail_out(Adapter * host, Scb * scbptr)
898
899
900
901{
902 int i, ogmb;
903 unsigned long flags;
904 unchar start_ogmb;
905 Mailbox *ogmbs = host->mb.ogmb;
906 int *next_ogmb = &(host->next_ogmb);
907
908 dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
909
910
911 spin_lock_irqsave(host->sh->host_lock, flags);
912 ogmb = *next_ogmb;
913 for (i = 0; i < OGMB_CNT; i++) {
914 if (ogmbs[ogmb].status == 0) {
915 dprintk(" using OGMB 0x%x", ogmb);
916 ogmbs[ogmb].status = 1;
917 any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
918
919 *next_ogmb = (ogmb + 1) % OGMB_CNT;
920 break;
921 } else
922 ogmb = (ogmb + 1) % OGMB_CNT;
923 }
924 spin_unlock_irqrestore(host->sh->host_lock, flags);
925
926 dprintk(", scb is 0x%06lx", (long) scbptr);
927
928 if (i >= OGMB_CNT) {
929
930
931
932
933
934
935
936
937 dprintk(", no free OGMBs.\n");
938 return (0);
939 }
940
941 wd7000_enable_intr(host);
942
943 start_ogmb = START_OGMB | ogmb;
944 command_out(host, &start_ogmb, 1);
945
946 dprintk(", awaiting interrupt.\n");
947
948 return (1);
949}
950
951
952static int make_code(unsigned hosterr, unsigned scsierr)
953{
954#ifdef WD7000_DEBUG
955 int in_error = hosterr;
956#endif
957
958 switch ((hosterr >> 8) & 0xff) {
959 case 0:
960 hosterr = DID_ERROR;
961 break;
962 case 1:
963 hosterr = DID_OK;
964 break;
965 case 2:
966 hosterr = DID_OK;
967 break;
968 case 4:
969 hosterr = DID_TIME_OUT;
970 break;
971 case 5:
972 hosterr = DID_RESET;
973 break;
974 case 6:
975 hosterr = DID_BAD_TARGET;
976 break;
977 case 80:
978 case 81:
979 hosterr = DID_BAD_INTR;
980 break;
981 case 82:
982 hosterr = DID_ABORT;
983 break;
984 case 83:
985 case 84:
986 hosterr = DID_RESET;
987 break;
988 default:
989 hosterr = DID_ERROR;
990 }
991#ifdef WD7000_DEBUG
992 if (scsierr || hosterr)
993 dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", scsierr, in_error, hosterr);
994#endif
995 return (scsierr | (hosterr << 16));
996}
997
998#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK)
999
1000
1001static irqreturn_t wd7000_intr(int irq, void *dev_id)
1002{
1003 Adapter *host = (Adapter *) dev_id;
1004 int flag, icmb, errstatus, icmb_status;
1005 int host_error, scsi_error;
1006 Scb *scb;
1007 IcbAny *icb;
1008 struct scsi_cmnd *SCpnt;
1009 Mailbox *icmbs = host->mb.icmb;
1010 unsigned long flags;
1011
1012 spin_lock_irqsave(host->sh->host_lock, flags);
1013 host->int_counter++;
1014
1015 dprintk("wd7000_intr: irq = %d, host = 0x%06lx\n", irq, (long) host);
1016
1017 flag = inb(host->iobase + ASC_INTR_STAT);
1018
1019 dprintk("wd7000_intr: intr stat = 0x%02x\n", flag);
1020
1021 if (!(inb(host->iobase + ASC_STAT) & INT_IM)) {
1022
1023
1024
1025
1026
1027
1028
1029
1030 dprintk("wd7000_intr: phantom interrupt...\n");
1031 goto ack;
1032 }
1033
1034 if (!(flag & MB_INTR))
1035 goto ack;
1036
1037
1038 if (!(flag & IMB_INTR)) {
1039 dprintk("wd7000_intr: free outgoing mailbox\n");
1040
1041
1042
1043
1044
1045 goto ack;
1046 }
1047
1048
1049 icmb = flag & MB_MASK;
1050 icmb_status = icmbs[icmb].status;
1051 if (icmb_status & 0x80) {
1052 dprintk("wd7000_intr: unsolicited interrupt 0x%02x\n", icmb_status);
1053 goto ack;
1054 }
1055
1056
1057 scb = isa_bus_to_virt(scsi2int((unchar *) icmbs[icmb].scbptr));
1058 icmbs[icmb].status = 0;
1059 if (scb->op & ICB_OP_MASK) {
1060 icb = (IcbAny *) scb;
1061 icb->status = icmb_status;
1062 icb->phase = 0;
1063 goto ack;
1064 }
1065
1066 SCpnt = scb->SCpnt;
1067 if (--(SCpnt->SCp.phase) <= 0) {
1068 host_error = scb->vue | (icmb_status << 8);
1069 scsi_error = scb->status;
1070 errstatus = make_code(host_error, scsi_error);
1071 SCpnt->result = errstatus;
1072
1073 free_scb(scb);
1074
1075 SCpnt->scsi_done(SCpnt);
1076 }
1077
1078 ack:
1079 dprintk("wd7000_intr: return from interrupt handler\n");
1080 wd7000_intr_ack(host);
1081
1082 spin_unlock_irqrestore(host->sh->host_lock, flags);
1083 return IRQ_HANDLED;
1084}
1085
1086static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
1087 void (*done)(struct scsi_cmnd *))
1088{
1089 Scb *scb;
1090 Sgb *sgb;
1091 unchar *cdb = (unchar *) SCpnt->cmnd;
1092 unchar idlun;
1093 short cdblen;
1094 int nseg;
1095 Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
1096
1097 cdblen = SCpnt->cmd_len;
1098 idlun = ((SCpnt->device->id << 5) & 0xe0) | (SCpnt->device->lun & 7);
1099 SCpnt->scsi_done = done;
1100 SCpnt->SCp.phase = 1;
1101 scb = alloc_scbs(SCpnt->device->host, 1);
1102 scb->idlun = idlun;
1103 memcpy(scb->cdb, cdb, cdblen);
1104 scb->direc = 0x40;
1105
1106 scb->SCpnt = SCpnt;
1107 SCpnt->host_scribble = (unchar *) scb;
1108 scb->host = host;
1109
1110 nseg = scsi_sg_count(SCpnt);
1111 if (nseg > 1) {
1112 struct scatterlist *sg;
1113 unsigned i;
1114
1115 dprintk("Using scatter/gather with %d elements.\n", nseg);
1116
1117 sgb = scb->sgb;
1118 scb->op = 1;
1119 any2scsi(scb->dataptr, (int) sgb);
1120 any2scsi(scb->maxlen, nseg * sizeof(Sgb));
1121
1122 scsi_for_each_sg(SCpnt, sg, nseg, i) {
1123 any2scsi(sgb[i].ptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
1124 any2scsi(sgb[i].len, sg->length);
1125 }
1126 } else {
1127 scb->op = 0;
1128 if (nseg) {
1129 struct scatterlist *sg = scsi_sglist(SCpnt);
1130 any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
1131 }
1132 any2scsi(scb->maxlen, scsi_bufflen(SCpnt));
1133 }
1134
1135
1136
1137 while (!mail_out(host, scb))
1138 cpu_relax();
1139
1140 return 0;
1141}
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_unlock_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