-
Notifications
You must be signed in to change notification settings - Fork 63.4k
Expand file tree
/
Copy pathqlogicisp.c
More file actions
1934 lines (1607 loc) · 53 KB
/
Copy pathqlogicisp.c
File metadata and controls
1934 lines (1607 loc) · 53 KB
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
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
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* QLogic ISP1020 Intelligent SCSI Processor Driver (PCI)
* Written by Erik H. Moe, ehm@cris.com
* Copyright 1995, Erik H. Moe
* Copyright 1996, 1997 Michael A. Griffith <grif@acm.org>
* Copyright 2000, Jayson C. Vantuyl <vantuyl@csc.smsu.edu>
* and Bryon W. Roche <bryon@csc.smsu.edu>
*
* 64-bit addressing added by Kanoj Sarcar <kanoj@sgi.com>
* and Leo Dagum <dagum@sgi.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/blkdev.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/unistd.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
/*
* With the qlogic interface, every queue slot can hold a SCSI
* command with up to 4 scatter/gather entries. If we need more
* than 4 entries, continuation entries can be used that hold
* another 7 entries each. Unlike for other drivers, this means
* that the maximum number of scatter/gather entries we can
* support at any given time is a function of the number of queue
* slots available. That is, host->can_queue and host->sg_tablesize
* are dynamic and _not_ independent. This all works fine because
* requests are queued serially and the scatter/gather limit is
* determined for each queue request anew.
*/
#define QLOGICISP_REQ_QUEUE_LEN 63 /* must be power of two - 1 */
#define QLOGICISP_MAX_SG(ql) (4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
/* Configuration section *****************************************************/
/* Set the following macro to 1 to reload the ISP1020's firmware. This is
the latest firmware provided by QLogic. This may be an earlier/later
revision than supplied by your board. */
#define RELOAD_FIRMWARE 1
/* Set the following macro to 1 to reload the ISP1020's defaults from nvram.
If you are not sure of your settings, leave this alone, the driver will
use a set of 'safe' defaults */
#define USE_NVRAM_DEFAULTS 0
/* Macros used for debugging */
#define DEBUG_ISP1020 0
#define DEBUG_ISP1020_INTR 0
#define DEBUG_ISP1020_SETUP 0
#define TRACE_ISP 0
#define DEFAULT_LOOP_COUNT 1000000
/* End Configuration section *************************************************/
#include <linux/module.h>
#if TRACE_ISP
# define TRACE_BUF_LEN (32*1024)
struct {
u_long next;
struct {
u_long time;
u_int index;
u_int addr;
u_char * name;
} buf[TRACE_BUF_LEN];
} trace;
#define TRACE(w, i, a) \
{ \
unsigned long flags; \
\
trace.buf[trace.next].name = (w); \
trace.buf[trace.next].time = jiffies; \
trace.buf[trace.next].index = (i); \
trace.buf[trace.next].addr = (long) (a); \
trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1); \
}
#else
# define TRACE(w, i, a)
#endif
#if DEBUG_ISP1020
#define ENTER(x) printk("isp1020 : entering %s()\n", x);
#define LEAVE(x) printk("isp1020 : leaving %s()\n", x);
#define DEBUG(x) x
#else
#define ENTER(x)
#define LEAVE(x)
#define DEBUG(x)
#endif /* DEBUG_ISP1020 */
#if DEBUG_ISP1020_INTR
#define ENTER_INTR(x) printk("isp1020 : entering %s()\n", x);
#define LEAVE_INTR(x) printk("isp1020 : leaving %s()\n", x);
#define DEBUG_INTR(x) x
#else
#define ENTER_INTR(x)
#define LEAVE_INTR(x)
#define DEBUG_INTR(x)
#endif /* DEBUG ISP1020_INTR */
#define ISP1020_REV_ID 1
#define MAX_TARGETS 16
#define MAX_LUNS 8
/* host configuration and control registers */
#define HOST_HCCR 0xc0 /* host command and control */
/* pci bus interface registers */
#define PCI_ID_LOW 0x00 /* vendor id */
#define PCI_ID_HIGH 0x02 /* device id */
#define ISP_CFG0 0x04 /* configuration register #0 */
#define ISP_CFG0_HWMSK 0x000f /* Hardware revision mask */
#define ISP_CFG0_1020 0x0001 /* ISP1020 */
#define ISP_CFG0_1020A 0x0002 /* ISP1020A */
#define ISP_CFG0_1040 0x0003 /* ISP1040 */
#define ISP_CFG0_1040A 0x0004 /* ISP1040A */
#define ISP_CFG0_1040B 0x0005 /* ISP1040B */
#define ISP_CFG0_1040C 0x0006 /* ISP1040C */
#define ISP_CFG1 0x06 /* configuration register #1 */
#define ISP_CFG1_F128 0x0040 /* 128-byte FIFO threshold */
#define ISP_CFG1_F64 0x0030 /* 128-byte FIFO threshold */
#define ISP_CFG1_F32 0x0020 /* 128-byte FIFO threshold */
#define ISP_CFG1_F16 0x0010 /* 128-byte FIFO threshold */
#define ISP_CFG1_BENAB 0x0004 /* Global Bus burst enable */
#define ISP_CFG1_SXP 0x0001 /* SXP register select */
#define PCI_INTF_CTL 0x08 /* pci interface control */
#define PCI_INTF_STS 0x0a /* pci interface status */
#define PCI_SEMAPHORE 0x0c /* pci semaphore */
#define PCI_NVRAM 0x0e /* pci nvram interface */
#define CDMA_CONF 0x20 /* Command DMA Config */
#define DDMA_CONF 0x40 /* Data DMA Config */
#define DMA_CONF_SENAB 0x0008 /* SXP to DMA Data enable */
#define DMA_CONF_RIRQ 0x0004 /* RISC interrupt enable */
#define DMA_CONF_BENAB 0x0002 /* Bus burst enable */
#define DMA_CONF_DIR 0x0001 /* DMA direction (0=fifo->host 1=host->fifo) */
/* mailbox registers */
#define MBOX0 0x70 /* mailbox 0 */
#define MBOX1 0x72 /* mailbox 1 */
#define MBOX2 0x74 /* mailbox 2 */
#define MBOX3 0x76 /* mailbox 3 */
#define MBOX4 0x78 /* mailbox 4 */
#define MBOX5 0x7a /* mailbox 5 */
#define MBOX6 0x7c /* mailbox 6 */
#define MBOX7 0x7e /* mailbox 7 */
/* mailbox command complete status codes */
#define MBOX_COMMAND_COMPLETE 0x4000
#define INVALID_COMMAND 0x4001
#define HOST_INTERFACE_ERROR 0x4002
#define TEST_FAILED 0x4003
#define COMMAND_ERROR 0x4005
#define COMMAND_PARAM_ERROR 0x4006
/* async event status codes */
#define ASYNC_SCSI_BUS_RESET 0x8001
#define SYSTEM_ERROR 0x8002
#define REQUEST_TRANSFER_ERROR 0x8003
#define RESPONSE_TRANSFER_ERROR 0x8004
#define REQUEST_QUEUE_WAKEUP 0x8005
#define EXECUTION_TIMEOUT_RESET 0x8006
#ifdef CONFIG_QL_ISP_A64
#define IOCB_SEGS 2
#define CONTINUATION_SEGS 5
#define MAX_CONTINUATION_ENTRIES 254
#else
#define IOCB_SEGS 4
#define CONTINUATION_SEGS 7
#endif /* CONFIG_QL_ISP_A64 */
struct Entry_header {
u_char entry_type;
u_char entry_cnt;
u_char sys_def_1;
u_char flags;
};
/* entry header type commands */
#ifdef CONFIG_QL_ISP_A64
#define ENTRY_COMMAND 9
#define ENTRY_CONTINUATION 0xa
#else
#define ENTRY_COMMAND 1
#define ENTRY_CONTINUATION 2
#endif /* CONFIG_QL_ISP_A64 */
#define ENTRY_STATUS 3
#define ENTRY_MARKER 4
#define ENTRY_EXTENDED_COMMAND 5
/* entry header flag definitions */
#define EFLAG_CONTINUATION 1
#define EFLAG_BUSY 2
#define EFLAG_BAD_HEADER 4
#define EFLAG_BAD_PAYLOAD 8
struct dataseg {
u_int d_base;
#ifdef CONFIG_QL_ISP_A64
u_int d_base_hi;
#endif
u_int d_count;
};
struct Command_Entry {
struct Entry_header hdr;
u_int handle;
u_char target_lun;
u_char target_id;
u_short cdb_length;
u_short control_flags;
u_short rsvd;
u_short time_out;
u_short segment_cnt;
u_char cdb[12];
#ifdef CONFIG_QL_ISP_A64
u_int rsvd1;
u_int rsvd2;
#endif
struct dataseg dataseg[IOCB_SEGS];
};
/* command entry control flag definitions */
#define CFLAG_NODISC 0x01
#define CFLAG_HEAD_TAG 0x02
#define CFLAG_ORDERED_TAG 0x04
#define CFLAG_SIMPLE_TAG 0x08
#define CFLAG_TAR_RTN 0x10
#define CFLAG_READ 0x20
#define CFLAG_WRITE 0x40
struct Ext_Command_Entry {
struct Entry_header hdr;
u_int handle;
u_char target_lun;
u_char target_id;
u_short cdb_length;
u_short control_flags;
u_short rsvd;
u_short time_out;
u_short segment_cnt;
u_char cdb[44];
};
struct Continuation_Entry {
struct Entry_header hdr;
#ifndef CONFIG_QL_ISP_A64
u_int reserved;
#endif
struct dataseg dataseg[CONTINUATION_SEGS];
};
struct Marker_Entry {
struct Entry_header hdr;
u_int reserved;
u_char target_lun;
u_char target_id;
u_char modifier;
u_char rsvd;
u_char rsvds[52];
};
/* marker entry modifier definitions */
#define SYNC_DEVICE 0
#define SYNC_TARGET 1
#define SYNC_ALL 2
struct Status_Entry {
struct Entry_header hdr;
u_int handle;
u_short scsi_status;
u_short completion_status;
u_short state_flags;
u_short status_flags;
u_short time;
u_short req_sense_len;
u_int residual;
u_char rsvd[8];
u_char req_sense_data[32];
};
/* status entry completion status definitions */
#define CS_COMPLETE 0x0000
#define CS_INCOMPLETE 0x0001
#define CS_DMA_ERROR 0x0002
#define CS_TRANSPORT_ERROR 0x0003
#define CS_RESET_OCCURRED 0x0004
#define CS_ABORTED 0x0005
#define CS_TIMEOUT 0x0006
#define CS_DATA_OVERRUN 0x0007
#define CS_COMMAND_OVERRUN 0x0008
#define CS_STATUS_OVERRUN 0x0009
#define CS_BAD_MESSAGE 0x000a
#define CS_NO_MESSAGE_OUT 0x000b
#define CS_EXT_ID_FAILED 0x000c
#define CS_IDE_MSG_FAILED 0x000d
#define CS_ABORT_MSG_FAILED 0x000e
#define CS_REJECT_MSG_FAILED 0x000f
#define CS_NOP_MSG_FAILED 0x0010
#define CS_PARITY_ERROR_MSG_FAILED 0x0011
#define CS_DEVICE_RESET_MSG_FAILED 0x0012
#define CS_ID_MSG_FAILED 0x0013
#define CS_UNEXP_BUS_FREE 0x0014
#define CS_DATA_UNDERRUN 0x0015
/* status entry state flag definitions */
#define SF_GOT_BUS 0x0100
#define SF_GOT_TARGET 0x0200
#define SF_SENT_CDB 0x0400
#define SF_TRANSFERRED_DATA 0x0800
#define SF_GOT_STATUS 0x1000
#define SF_GOT_SENSE 0x2000
/* status entry status flag definitions */
#define STF_DISCONNECT 0x0001
#define STF_SYNCHRONOUS 0x0002
#define STF_PARITY_ERROR 0x0004
#define STF_BUS_RESET 0x0008
#define STF_DEVICE_RESET 0x0010
#define STF_ABORTED 0x0020
#define STF_TIMEOUT 0x0040
#define STF_NEGOTIATION 0x0080
/* interface control commands */
#define ISP_RESET 0x0001
#define ISP_EN_INT 0x0002
#define ISP_EN_RISC 0x0004
/* host control commands */
#define HCCR_NOP 0x0000
#define HCCR_RESET 0x1000
#define HCCR_PAUSE 0x2000
#define HCCR_RELEASE 0x3000
#define HCCR_SINGLE_STEP 0x4000
#define HCCR_SET_HOST_INTR 0x5000
#define HCCR_CLEAR_HOST_INTR 0x6000
#define HCCR_CLEAR_RISC_INTR 0x7000
#define HCCR_BP_ENABLE 0x8000
#define HCCR_BIOS_DISABLE 0x9000
#define HCCR_TEST_MODE 0xf000
#define RISC_BUSY 0x0004
/* mailbox commands */
#define MBOX_NO_OP 0x0000
#define MBOX_LOAD_RAM 0x0001
#define MBOX_EXEC_FIRMWARE 0x0002
#define MBOX_DUMP_RAM 0x0003
#define MBOX_WRITE_RAM_WORD 0x0004
#define MBOX_READ_RAM_WORD 0x0005
#define MBOX_MAILBOX_REG_TEST 0x0006
#define MBOX_VERIFY_CHECKSUM 0x0007
#define MBOX_ABOUT_FIRMWARE 0x0008
#define MBOX_CHECK_FIRMWARE 0x000e
#define MBOX_INIT_REQ_QUEUE 0x0010
#define MBOX_INIT_RES_QUEUE 0x0011
#define MBOX_EXECUTE_IOCB 0x0012
#define MBOX_WAKE_UP 0x0013
#define MBOX_STOP_FIRMWARE 0x0014
#define MBOX_ABORT 0x0015
#define MBOX_ABORT_DEVICE 0x0016
#define MBOX_ABORT_TARGET 0x0017
#define MBOX_BUS_RESET 0x0018
#define MBOX_STOP_QUEUE 0x0019
#define MBOX_START_QUEUE 0x001a
#define MBOX_SINGLE_STEP_QUEUE 0x001b
#define MBOX_ABORT_QUEUE 0x001c
#define MBOX_GET_DEV_QUEUE_STATUS 0x001d
#define MBOX_GET_FIRMWARE_STATUS 0x001f
#define MBOX_GET_INIT_SCSI_ID 0x0020
#define MBOX_GET_SELECT_TIMEOUT 0x0021
#define MBOX_GET_RETRY_COUNT 0x0022
#define MBOX_GET_TAG_AGE_LIMIT 0x0023
#define MBOX_GET_CLOCK_RATE 0x0024
#define MBOX_GET_ACT_NEG_STATE 0x0025
#define MBOX_GET_ASYNC_DATA_SETUP_TIME 0x0026
#define MBOX_GET_PCI_PARAMS 0x0027
#define MBOX_GET_TARGET_PARAMS 0x0028
#define MBOX_GET_DEV_QUEUE_PARAMS 0x0029
#define MBOX_SET_INIT_SCSI_ID 0x0030
#define MBOX_SET_SELECT_TIMEOUT 0x0031
#define MBOX_SET_RETRY_COUNT 0x0032
#define MBOX_SET_TAG_AGE_LIMIT 0x0033
#define MBOX_SET_CLOCK_RATE 0x0034
#define MBOX_SET_ACTIVE_NEG_STATE 0x0035
#define MBOX_SET_ASYNC_DATA_SETUP_TIME 0x0036
#define MBOX_SET_PCI_CONTROL_PARAMS 0x0037
#define MBOX_SET_TARGET_PARAMS 0x0038
#define MBOX_SET_DEV_QUEUE_PARAMS 0x0039
#define MBOX_RETURN_BIOS_BLOCK_ADDR 0x0040
#define MBOX_WRITE_FOUR_RAM_WORDS 0x0041
#define MBOX_EXEC_BIOS_IOCB 0x0042
#ifdef CONFIG_QL_ISP_A64
#define MBOX_CMD_INIT_REQUEST_QUEUE_64 0x0052
#define MBOX_CMD_INIT_RESPONSE_QUEUE_64 0x0053
#endif /* CONFIG_QL_ISP_A64 */
#include "qlogicisp_asm.c"
#define PACKB(a, b) (((a)<<4)|(b))
static const u_char mbox_param[] = {
PACKB(1, 1), /* MBOX_NO_OP */
PACKB(5, 5), /* MBOX_LOAD_RAM */
PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */
PACKB(5, 5), /* MBOX_DUMP_RAM */
PACKB(3, 3), /* MBOX_WRITE_RAM_WORD */
PACKB(2, 3), /* MBOX_READ_RAM_WORD */
PACKB(6, 6), /* MBOX_MAILBOX_REG_TEST */
PACKB(2, 3), /* MBOX_VERIFY_CHECKSUM */
PACKB(1, 3), /* MBOX_ABOUT_FIRMWARE */
PACKB(0, 0), /* 0x0009 */
PACKB(0, 0), /* 0x000a */
PACKB(0, 0), /* 0x000b */
PACKB(0, 0), /* 0x000c */
PACKB(0, 0), /* 0x000d */
PACKB(1, 2), /* MBOX_CHECK_FIRMWARE */
PACKB(0, 0), /* 0x000f */
PACKB(5, 5), /* MBOX_INIT_REQ_QUEUE */
PACKB(6, 6), /* MBOX_INIT_RES_QUEUE */
PACKB(4, 4), /* MBOX_EXECUTE_IOCB */
PACKB(2, 2), /* MBOX_WAKE_UP */
PACKB(1, 6), /* MBOX_STOP_FIRMWARE */
PACKB(4, 4), /* MBOX_ABORT */
PACKB(2, 2), /* MBOX_ABORT_DEVICE */
PACKB(3, 3), /* MBOX_ABORT_TARGET */
PACKB(2, 2), /* MBOX_BUS_RESET */
PACKB(2, 3), /* MBOX_STOP_QUEUE */
PACKB(2, 3), /* MBOX_START_QUEUE */
PACKB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */
PACKB(2, 3), /* MBOX_ABORT_QUEUE */
PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */
PACKB(0, 0), /* 0x001e */
PACKB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */
PACKB(1, 2), /* MBOX_GET_INIT_SCSI_ID */
PACKB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */
PACKB(1, 3), /* MBOX_GET_RETRY_COUNT */
PACKB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */
PACKB(1, 2), /* MBOX_GET_CLOCK_RATE */
PACKB(1, 2), /* MBOX_GET_ACT_NEG_STATE */
PACKB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */
PACKB(1, 3), /* MBOX_GET_PCI_PARAMS */
PACKB(2, 4), /* MBOX_GET_TARGET_PARAMS */
PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */
PACKB(0, 0), /* 0x002a */
PACKB(0, 0), /* 0x002b */
PACKB(0, 0), /* 0x002c */
PACKB(0, 0), /* 0x002d */
PACKB(0, 0), /* 0x002e */
PACKB(0, 0), /* 0x002f */
PACKB(2, 2), /* MBOX_SET_INIT_SCSI_ID */
PACKB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */
PACKB(3, 3), /* MBOX_SET_RETRY_COUNT */
PACKB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */
PACKB(2, 2), /* MBOX_SET_CLOCK_RATE */
PACKB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */
PACKB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */
PACKB(3, 3), /* MBOX_SET_PCI_CONTROL_PARAMS */
PACKB(4, 4), /* MBOX_SET_TARGET_PARAMS */
PACKB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */
PACKB(0, 0), /* 0x003a */
PACKB(0, 0), /* 0x003b */
PACKB(0, 0), /* 0x003c */
PACKB(0, 0), /* 0x003d */
PACKB(0, 0), /* 0x003e */
PACKB(0, 0), /* 0x003f */
PACKB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */
PACKB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */
PACKB(2, 3) /* MBOX_EXEC_BIOS_IOCB */
#ifdef CONFIG_QL_ISP_A64
,PACKB(0, 0), /* 0x0043 */
PACKB(0, 0), /* 0x0044 */
PACKB(0, 0), /* 0x0045 */
PACKB(0, 0), /* 0x0046 */
PACKB(0, 0), /* 0x0047 */
PACKB(0, 0), /* 0x0048 */
PACKB(0, 0), /* 0x0049 */
PACKB(0, 0), /* 0x004a */
PACKB(0, 0), /* 0x004b */
PACKB(0, 0), /* 0x004c */
PACKB(0, 0), /* 0x004d */
PACKB(0, 0), /* 0x004e */
PACKB(0, 0), /* 0x004f */
PACKB(0, 0), /* 0x0050 */
PACKB(0, 0), /* 0x0051 */
PACKB(8, 8), /* MBOX_CMD_INIT_REQUEST_QUEUE_64 (0x0052) */
PACKB(8, 8) /* MBOX_CMD_INIT_RESPONSE_QUEUE_64 (0x0053) */
#endif /* CONFIG_QL_ISP_A64 */
};
#define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short))
struct host_param {
u_short fifo_threshold;
u_short host_adapter_enable;
u_short initiator_scsi_id;
u_short bus_reset_delay;
u_short retry_count;
u_short retry_delay;
u_short async_data_setup_time;
u_short req_ack_active_negation;
u_short data_line_active_negation;
u_short data_dma_burst_enable;
u_short command_dma_burst_enable;
u_short tag_aging;
u_short selection_timeout;
u_short max_queue_depth;
};
/*
* Device Flags:
*
* Bit Name
* ---------
* 7 Disconnect Privilege
* 6 Parity Checking
* 5 Wide Data Transfers
* 4 Synchronous Data Transfers
* 3 Tagged Queuing
* 2 Automatic Request Sense
* 1 Stop Queue on Check Condition
* 0 Renegotiate on Error
*/
struct dev_param {
u_short device_flags;
u_short execution_throttle;
u_short synchronous_period;
u_short synchronous_offset;
u_short device_enable;
u_short reserved; /* pad */
};
/*
* The result queue can be quite a bit smaller since continuation entries
* do not show up there:
*/
#define RES_QUEUE_LEN ((QLOGICISP_REQ_QUEUE_LEN + 1) / 8 - 1)
#define QUEUE_ENTRY_LEN 64
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
struct isp_queue_entry {
char __opaque[QUEUE_ENTRY_LEN];
};
struct isp1020_hostdata {
void __iomem *memaddr;
u_char revision;
struct host_param host_param;
struct dev_param dev_param[MAX_TARGETS];
struct pci_dev *pci_dev;
struct isp_queue_entry *res_cpu; /* CPU-side address of response queue. */
struct isp_queue_entry *req_cpu; /* CPU-size address of request queue. */
/* result and request queues (shared with isp1020): */
u_int req_in_ptr; /* index of next request slot */
u_int res_out_ptr; /* index of next result slot */
/* this is here so the queues are nicely aligned */
long send_marker; /* do we need to send a marker? */
/* The cmd->handle has a fixed size, and is only 32-bits. We
* need to take care to handle 64-bit systems correctly thus what
* we actually place in cmd->handle is an index to the following
* table. Kudos to Matt Jacob for the technique. -DaveM
*/
Scsi_Cmnd *cmd_slots[QLOGICISP_REQ_QUEUE_LEN + 1];
dma_addr_t res_dma; /* PCI side view of response queue */
dma_addr_t req_dma; /* PCI side view of request queue */
};
/* queue length's _must_ be power of two: */
#define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql))
#define REQ_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, \
QLOGICISP_REQ_QUEUE_LEN)
#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
static void isp1020_enable_irqs(struct Scsi_Host *);
static void isp1020_disable_irqs(struct Scsi_Host *);
static int isp1020_init(struct Scsi_Host *);
static int isp1020_reset_hardware(struct Scsi_Host *);
static int isp1020_set_defaults(struct Scsi_Host *);
static int isp1020_load_parameters(struct Scsi_Host *);
static int isp1020_mbox_command(struct Scsi_Host *, u_short []);
static int isp1020_return_status(struct Status_Entry *);
static void isp1020_intr_handler(int, void *, struct pt_regs *);
static irqreturn_t do_isp1020_intr_handler(int, void *, struct pt_regs *);
#if USE_NVRAM_DEFAULTS
static int isp1020_get_defaults(struct Scsi_Host *);
static int isp1020_verify_nvram(struct Scsi_Host *);
static u_short isp1020_read_nvram_word(struct Scsi_Host *, u_short);
#endif
#if DEBUG_ISP1020
static void isp1020_print_scsi_cmd(Scsi_Cmnd *);
#endif
#if DEBUG_ISP1020_INTR
static void isp1020_print_status_entry(struct Status_Entry *);
#endif
/* memaddr should be used to determine if memmapped port i/o is being used
* non-null memaddr == mmap'd
* JV 7-Jan-2000
*/
static inline u_short isp_inw(struct Scsi_Host *host, long offset)
{
struct isp1020_hostdata *h = (struct isp1020_hostdata *)host->hostdata;
if (h->memaddr)
return readw(h->memaddr + offset);
else
return inw(host->io_port + offset);
}
static inline void isp_outw(u_short val, struct Scsi_Host *host, long offset)
{
struct isp1020_hostdata *h = (struct isp1020_hostdata *)host->hostdata;
if (h->memaddr)
writew(val, h->memaddr + offset);
else
outw(val, host->io_port + offset);
}
static inline void isp1020_enable_irqs(struct Scsi_Host *host)
{
isp_outw(ISP_EN_INT|ISP_EN_RISC, host, PCI_INTF_CTL);
}
static inline void isp1020_disable_irqs(struct Scsi_Host *host)
{
isp_outw(0x0, host, PCI_INTF_CTL);
}
static int isp1020_detect(Scsi_Host_Template *tmpt)
{
int hosts = 0;
struct Scsi_Host *host;
struct isp1020_hostdata *hostdata;
struct pci_dev *pdev = NULL;
ENTER("isp1020_detect");
tmpt->proc_name = "isp1020";
while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, pdev)))
{
if (pci_enable_device(pdev))
continue;
host = scsi_register(tmpt, sizeof(struct isp1020_hostdata));
if (!host)
continue;
hostdata = (struct isp1020_hostdata *) host->hostdata;
memset(hostdata, 0, sizeof(struct isp1020_hostdata));
hostdata->pci_dev = pdev;
if (isp1020_init(host))
goto fail_and_unregister;
if (isp1020_reset_hardware(host)
#if USE_NVRAM_DEFAULTS
|| isp1020_get_defaults(host)
#else
|| isp1020_set_defaults(host)
#endif /* USE_NVRAM_DEFAULTS */
|| isp1020_load_parameters(host)) {
goto fail_uninit;
}
host->this_id = hostdata->host_param.initiator_scsi_id;
host->max_sectors = 64;
if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
"qlogicisp", host))
{
printk("qlogicisp : interrupt %d already in use\n",
host->irq);
goto fail_uninit;
}
isp_outw(0x0, host, PCI_SEMAPHORE);
isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
isp1020_enable_irqs(host);
hosts++;
continue;
fail_uninit:
iounmap(hostdata->memaddr);
release_region(host->io_port, 0xff);
fail_and_unregister:
if (hostdata->res_cpu)
pci_free_consistent(hostdata->pci_dev,
QSIZE(RES_QUEUE_LEN),
hostdata->res_cpu,
hostdata->res_dma);
if (hostdata->req_cpu)
pci_free_consistent(hostdata->pci_dev,
QSIZE(QLOGICISP_REQ_QUEUE_LEN),
hostdata->req_cpu,
hostdata->req_dma);
scsi_unregister(host);
}
LEAVE("isp1020_detect");
return hosts;
}
static int isp1020_release(struct Scsi_Host *host)
{
struct isp1020_hostdata *hostdata;
ENTER("isp1020_release");
hostdata = (struct isp1020_hostdata *) host->hostdata;
isp_outw(0x0, host, PCI_INTF_CTL);
free_irq(host->irq, host);
iounmap(hostdata->memaddr);
release_region(host->io_port, 0xff);
LEAVE("isp1020_release");
return 0;
}
static const char *isp1020_info(struct Scsi_Host *host)
{
static char buf[80];
struct isp1020_hostdata *hostdata;
ENTER("isp1020_info");
hostdata = (struct isp1020_hostdata *) host->hostdata;
sprintf(buf,
"QLogic ISP1020 SCSI on PCI bus %02x device %02x irq %d %s base 0x%lx",
hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq,
(hostdata->memaddr ? "MEM" : "I/O"),
(hostdata->memaddr ? (unsigned long)hostdata->memaddr : host->io_port));
LEAVE("isp1020_info");
return buf;
}
/*
* The middle SCSI layer ensures that queuecommand never gets invoked
* concurrently with itself or the interrupt handler (though the
* interrupt handler may call this routine as part of
* request-completion handling).
*/
static int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
{
int i, n, num_free;
u_int in_ptr, out_ptr;
struct dataseg * ds;
struct scatterlist *sg;
struct Command_Entry *cmd;
struct Continuation_Entry *cont;
struct Scsi_Host *host;
struct isp1020_hostdata *hostdata;
dma_addr_t dma_addr;
ENTER("isp1020_queuecommand");
host = Cmnd->device->host;
hostdata = (struct isp1020_hostdata *) host->hostdata;
Cmnd->scsi_done = done;
DEBUG(isp1020_print_scsi_cmd(Cmnd));
out_ptr = isp_inw(host, + MBOX4);
in_ptr = hostdata->req_in_ptr;
DEBUG(printk("qlogicisp : request queue depth %d\n",
REQ_QUEUE_DEPTH(in_ptr, out_ptr)));
cmd = (struct Command_Entry *) &hostdata->req_cpu[in_ptr];
in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
if (in_ptr == out_ptr) {
printk("qlogicisp : request queue overflow\n");
return 1;
}
if (hostdata->send_marker) {
struct Marker_Entry *marker;
TRACE("queue marker", in_ptr, 0);
DEBUG(printk("qlogicisp : adding marker entry\n"));
marker = (struct Marker_Entry *) cmd;
memset(marker, 0, sizeof(struct Marker_Entry));
marker->hdr.entry_type = ENTRY_MARKER;
marker->hdr.entry_cnt = 1;
marker->modifier = SYNC_ALL;
hostdata->send_marker = 0;
if (((in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN) == out_ptr) {
isp_outw(in_ptr, host, MBOX4);
hostdata->req_in_ptr = in_ptr;
printk("qlogicisp : request queue overflow\n");
return 1;
}
cmd = (struct Command_Entry *) &hostdata->req_cpu[in_ptr];
in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
}
TRACE("queue command", in_ptr, Cmnd);
memset(cmd, 0, sizeof(struct Command_Entry));
cmd->hdr.entry_type = ENTRY_COMMAND;
cmd->hdr.entry_cnt = 1;
cmd->target_lun = Cmnd->device->lun;
cmd->target_id = Cmnd->device->id;
cmd->cdb_length = cpu_to_le16(Cmnd->cmd_len);
cmd->control_flags = cpu_to_le16(CFLAG_READ | CFLAG_WRITE);
cmd->time_out = cpu_to_le16(30);
memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
if (Cmnd->use_sg) {
int sg_count;
sg = (struct scatterlist *) Cmnd->request_buffer;
ds = cmd->dataseg;
sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg,
Cmnd->sc_data_direction);
cmd->segment_cnt = cpu_to_le16(sg_count);
/* fill in first four sg entries: */
n = sg_count;
if (n > IOCB_SEGS)
n = IOCB_SEGS;
for (i = 0; i < n; i++) {
dma_addr = sg_dma_address(sg);
ds[i].d_base = cpu_to_le32((u32) dma_addr);
#ifdef CONFIG_QL_ISP_A64
ds[i].d_base_hi = cpu_to_le32((u32) (dma_addr>>32));
#endif /* CONFIG_QL_ISP_A64 */
ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
++sg;
}
sg_count -= IOCB_SEGS;
while (sg_count > 0) {
++cmd->hdr.entry_cnt;
cont = (struct Continuation_Entry *)
&hostdata->req_cpu[in_ptr];
in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
if (in_ptr == out_ptr) {
printk("isp1020: unexpected request queue "
"overflow\n");
return 1;
}
TRACE("queue continuation", in_ptr, 0);
cont->hdr.entry_type = ENTRY_CONTINUATION;
cont->hdr.entry_cnt = 0;
cont->hdr.sys_def_1 = 0;
cont->hdr.flags = 0;
#ifndef CONFIG_QL_ISP_A64
cont->reserved = 0;
#endif
ds = cont->dataseg;
n = sg_count;
if (n > CONTINUATION_SEGS)
n = CONTINUATION_SEGS;
for (i = 0; i < n; ++i) {
dma_addr = sg_dma_address(sg);
ds[i].d_base = cpu_to_le32((u32) dma_addr);
#ifdef CONFIG_QL_ISP_A64
ds[i].d_base_hi = cpu_to_le32((u32)(dma_addr>>32));
#endif /* CONFIG_QL_ISP_A64 */
ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
++sg;
}
sg_count -= n;
}
} else if (Cmnd->request_bufflen) {
/*Cmnd->SCp.ptr = (char *)(unsigned long)*/
dma_addr = pci_map_single(hostdata->pci_dev,
Cmnd->request_buffer,
Cmnd->request_bufflen,
Cmnd->sc_data_direction);
Cmnd->SCp.ptr = (char *)(unsigned long) dma_addr;
cmd->dataseg[0].d_base =
cpu_to_le32((u32) dma_addr);
#ifdef CONFIG_QL_ISP_A64
cmd->dataseg[0].d_base_hi =
cpu_to_le32((u32) (dma_addr>>32));
#endif /* CONFIG_QL_ISP_A64 */
cmd->dataseg[0].d_count =
cpu_to_le32((u32)Cmnd->request_bufflen);
cmd->segment_cnt = cpu_to_le16(1);
} else {
cmd->dataseg[0].d_base = 0;
#ifdef CONFIG_QL_ISP_A64
cmd->dataseg[0].d_base_hi = 0;
#endif /* CONFIG_QL_ISP_A64 */
cmd->dataseg[0].d_count = 0;
cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
}
/* Committed, record Scsi_Cmd so we can find it later. */
cmd->handle = in_ptr;
hostdata->cmd_slots[in_ptr] = Cmnd;
isp_outw(in_ptr, host, MBOX4);
hostdata->req_in_ptr = in_ptr;
num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
host->can_queue = host->host_busy + num_free;
host->sg_tablesize = QLOGICISP_MAX_SG(num_free);
LEAVE("isp1020_queuecommand");
return 0;
}
#define ASYNC_EVENT_INTERRUPT 0x01
irqreturn_t do_isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
struct Scsi_Host *host = dev_id;
unsigned long flags;
spin_lock_irqsave(host->host_lock, flags);
isp1020_intr_handler(irq, dev_id, regs);
spin_unlock_irqrestore(host->host_lock, flags);
return IRQ_HANDLED;
}
void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
Scsi_Cmnd *Cmnd;
struct Status_Entry *sts;
struct Scsi_Host *host = dev_id;
struct isp1020_hostdata *hostdata;
u_int in_ptr, out_ptr;
u_short status;
ENTER_INTR("isp1020_intr_handler");
hostdata = (struct isp1020_hostdata *) host->hostdata;